-
Notifications
You must be signed in to change notification settings - Fork 0
/
model.h
270 lines (225 loc) · 7.81 KB
/
model.h
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
243
244
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
/******************************************************************************
@file: ad9106_model.h
@brief: Model abstracting the EVAL-AD9106 board
******************************************************************************/
#ifndef MODEL_H
#define MODEL_H
#include <AD9106.h>
#include "Arduino.h"
#include "config.h"
#include "global_error.h"
extern GlobalError system_error;
class Model {
public:
AD9106 dac;
Model(int CS) : dac(CS) {};
/**
* @brief: Initialize the AD9106 and start SPI communication
*/
void begin() {
// Initialize pins on device with op-amps enabled
dac.begin(true);
// Start SPI communication at 14MHz (Arduino Clock Speed)
dac.spi_init(14000000);
reset();
}
/**
* @brief: Update the AD9106 model with new register values
*/
void update() {
dac.update_pattern();
// Check for errors after updating
AD9106::ErrorCode err = dac._last_error;
if (err != AD9106::NO_ERROR) {
system_error.set_error(err);
}
}
/**
* @brief: Reset the AD9106 and configure sinew waves
*/
void reset() {
// Reset registers
dac.reg_reset();
delay(1);
// Configure sine waves on each channel
for (int i = 1; i < 5; i++) {
dac.setDDSsine(CHNL(i));
}
// Default Frequency
dac.setDDSfreq(50000);
// Characterized phases/amplitides with this pattern period. Not necessary
dac.spi_write(dac.PAT_PERIOD, 0x8fff);
}
// Pattern functions
void start() { dac.start_pattern(); }
void stop_pattern() { dac.stop_pattern(); }
/**
* @brief: Set voltage on channel
* @param chnl: Channel number
* @param voltage: Voltage to set
*
* @returns 0 if voltage was set, 1 otherwise
*/
int setVoltage(int chnl, float voltage) {
float lower_bound = ((float)dac_amp_thesholds[0]) / 10.0;
float upper_bound = ((float)dac_amp_thesholds[3]) / 10.0;
if (voltage < lower_bound || voltage > upper_bound) {
system_error.set_error(GenericError::ParamOutOfRange);
return NULL;
}
int16_t val = v_to_addr(voltage, chnl);
if (val != NULL) {
dac.set_CHNL_DGAIN(static_cast<CHNL>(chnl), val);
return 1;
}
return 0;
}
float getVoltage(int chnl) { ; }
// AD9106 register access functions
uint16_t readReg(uint16_t add) { return dac.spi_read(add); }
void writeReg(uint16_t add, int16_t val) {
dac.stop_pattern();
dac.spi_write(add, val);
}
// DDS Frequency functions
void setFreq(float freq) { dac.setDDSfreq(freq); }
float getFreq() { return dac.getDDSfreq(); }
/**
* @brief: Set phase on channel
*/
void setPhase(int chnl, float phase) {
if (phase < 0) {
phase += 360;
}
// Define channel 1 to be baseline for phase offsets
// if (chnl != 1) {
// float offset = interpolate_offset(chnl);
// // interface.println(offset);
// phase -= offset;
// }
uint16_t val = (uint16_t)round_float(phase * (pow(2, 16) - 1) / 360);
dac.set_CHNL_prop(DDS_PHASE, static_cast<CHNL>(chnl), val);
}
/**
* @brief: Get phase on channel
* @param chnl: Channel number
*
* @returns Phase in degrees (-180 to 180)
*/
float getPhase(int chnl) {
uint16_t reg_val = dac.get_CHNL_prop(DDS_PHASE, static_cast<CHNL>(chnl));
// Brackets important to avoid overflow errors
float phase = 360.0f * (reg_val / (pow(2, 16) - 1));
if (phase > 180) {
phase -= 360;
}
return phase;
}
private:
// Interpolate phase offset using offsets array
// float interpolate_offset(int chan) {
// float freq = dac.getDDSfreq();
// float f_step = dac.fclk / pow(2, 24);
// // get pointer to offset array for channel in PROGMEM
// const int* offset_ptr =
// (const int*)pgm_read_word_near(&(dacphase_offsets[chan - 2]));
// if (offset_ptr == NULL) {
// return 0;
// }
// int index = _get_index(&freq);
// int freq_val = _get_freq_val(index, f_step);
// // TODO: add offsets for frequency vals up to 15 to avoid ugly code here
// if (freq_val <= 15 && !(freq_val == 11 || freq_val == 13)) {
// int offset = (int)pgm_read_word_near(offset_ptr + freq_val - 1);
// return (float)offset / 10000.0;
// }
// if (f_step * _get_freq_val(index, f_step) > freq) {
// index -= 1;
// }
// float freq_1 = f_step * _get_freq_val(index + 1, f_step);
// float freq_2 = f_step * _get_freq_val(index, f_step);
// index -=
// 8; // subtract 8 for removal of duplicates in offset array (see SOP)
// int off_1 = pgm_read_word_near(offset_ptr + index + 1);
// int off_2 = pgm_read_word_near(offset_ptr + index);
// float off_1f = (float)off_1 / 10000.0;
// float off_2f = (float)off_2 / 10000.0;
// float slope = (float)(off_1f - off_2f) / (freq_1 - freq_2);
// return slope * (freq - freq_1) + off_1f;
// }
// int _get_index(float* freq) {
// float index = (log10(*freq) - 1) * 69 / 4;
// return round(index);
// }
// int _get_freq_val(int index, float f_step) {
// // index * 4/69. Hardcoded to avoid floating point errors
// float inc = (float)index * (4.0 / 69);
// float val = pow(10, 1 + inc);
// return round_float(val / f_step);
// }
int round_float(float num) {
return (num >= 0) ? (int)(num + 0.5f) : (int)(num - 0.5f);
}
/**
* @brief: Convert voltage to value for address
*
* @param voltage: Voltage to convert
* @param chan: Channel number
*
* @returns value for address
*/
int16_t v_to_addr(float voltage, int chan) {
// const float *coeffs = (const float*) pgm_read_ptr(&(dac_amp_coeffs[chan
// - 1]));
int range_index = 0;
for (int i = 0; i < 3; i++) {
if (dac_amp_thesholds[i] / 10 <= voltage &&
voltage <= dac_amp_thesholds[i + 1] / 10) {
range_index = 6 * i;
break;
}
}
float freq = dac.getDDSfreq();
float float_reader_buff;
// absorb factor of 10^(-5) from fit function
read_pgm_float(chan, range_index + 4, &float_reader_buff);
float numerator = (100 * voltage) - (10 * float_reader_buff);
float freq_poly = 0;
int freq_order = get_order(freq);
for (int i = 0; i < 4; i++) {
// get difference in magnitudes of polynomial term
int order_diff = (exps[i] - 5) - freq_order * (i + 1);
if (-10 <= order_diff && order_diff <= 10) {
float freq_sigval = freq / pow(10, freq_order);
read_pgm_float(chan, range_index + i, &float_reader_buff);
freq_poly +=
float_reader_buff * pow(freq_sigval, i + 1) * pow(10, -order_diff);
}
}
read_pgm_float(chan, range_index + 5, &float_reader_buff);
float addr = numerator / (freq_poly + float_reader_buff);
return addr;
}
void read_pgm_float(int chan, int index, float* dest) {
*dest = pgm_read_float_near(&dac_amp_coeffs[chan - 1][index]);
}
// float _get_amp_addr(float voltage, const float coeffs[6]) {
// float freq = dac.getDDSfreq();
// // absorb factor of 10^(-5) from fit function
// float numerator = (100 * voltage) - (10 * coeffs[4]);
// float freq_poly = 0;
// int freq_order = get_order(freq);
// for (int i = 0; i < 4; i++) {
// // get difference in magnitudes of polynomial term
// int order_diff = (exps[i] - 5) - freq_order * (i + 1);
// if (-10 <= order_diff && order_diff <= 10) {
// float freq_sigval = freq / pow(10, freq_order);
// freq_poly += coeffs[i] * pow(freq_sigval, i + 1) * pow(10,
// -order_diff);
// }
// }
// float addr = numerator / (freq_poly + coeffs[5]);
// return addr;
// }
};
#endif