2 A little auto-calibration utility, for boards
5 Right now, it only supports NI E series boards,
6 but it should be easily portable.
8 A few things need improvement here:
9 - current system gets "close", but doesn't
11 - no pre/post gain discrimination for the
13 - should read (and use) the actual reference
14 voltage value from eeprom
15 - statistics would be nice, to show how good
17 - doesn't check unipolar ranges
18 - "alternate calibrations" would be cool--to
19 accurately measure 0 in a unipolar range
26 #include <comedilib.h>
45 void ni_setup_board(void);
46 void ni_setup_observables(void);
48 void cal_ni_at_mio_16e_2(void);
49 void cal_ni_daqcard_ai_16xe_50(void);
50 void cal_ni_at_mio_16e_1(void);
51 void cal_ni_pci_mio_16e_1(void);
52 void cal_ni_pci_6035e(void);
53 void cal_ni_pci_6071e(void);
54 void cal_ni_pxi_6071e(void);
55 void cal_ni_at_mio_16e_10(void);
56 void cal_ni_pci_mio_16xe_50(void);
57 void cal_ni_pci_6023e(void);
59 struct board_struct boards[]={
60 { "at-mio-16e-2", STATUS_DONE, cal_ni_at_mio_16e_2 },
61 { "DAQCard-ai-16xe-50", STATUS_DONE, cal_ni_daqcard_ai_16xe_50 },
62 { "at-mio-16e-1", STATUS_SOME, cal_ni_at_mio_16e_1 },
63 { "pci-mio-16e-1", STATUS_SOME, cal_ni_pci_mio_16e_1 },
64 { "pci-6035e", STATUS_GUESS, cal_ni_pci_6035e },
65 { "pci-6071e", STATUS_GUESS, cal_ni_pci_6071e },
66 { "pxi-6071e", STATUS_GUESS, cal_ni_pxi_6071e },
67 { "at-mio-16e-10", STATUS_GUESS, cal_ni_at_mio_16e_10 },
68 { "pci-mio-16xe-50", STATUS_GUESS, cal_ni_pci_mio_16xe_50 },
69 { "pci-6023e", STATUS_GUESS, cal_ni_pci_6023e },
71 // { "at-mio-16de-10", cal_ni_unknown },
72 { "at-mio-64e-3", cal_ni_16e_1 },
73 // { "at-mio-16xe-50", cal_ni_unknown },
74 // { "at-mio-16xe-10", cal_ni_unknown },
75 // { "at-ai-16xe-10", cal_ni_unknown },
76 { "pci-mio-16xe-10", cal_ni_16xe_10 },
77 // { "pxi-6030e", cal_ni_unknown },
78 // { "pci-mio-16e-4", cal_ni_unknown },
79 // { "pxi-6040e", cal_ni_unknown },
80 // { "pci-6031e", cal_ni_unknown },
81 // { "pci-6032e", cal_ni_unknown },
82 // { "pci-6033e", cal_ni_unknown },
83 // { "pci-6071e", cal_ni_unknown },
84 { "pci-6024e", cal_ni_6023e }, // guess
85 { "pci-6025e", cal_ni_6023e }, // guess
86 { "pxi-6025e", cal_ni_6023e }, // guess
87 { "pci-6034e", cal_ni_6023e }, // guess
88 { "pci-6035e", cal_ni_6023e },
89 // { "pci-6052e", cal_ni_unknown },
90 // { "pci-6110e", cal_ni_unknown },
91 // { "pci-6111e", cal_ni_unknown },
92 // { "pci-6711", cal_ni_unknown },
93 // { "pci-6713", cal_ni_unknown },
94 // { "pxi-6070e", cal_ni_unknown },
95 // { "pxi-6052e", cal_ni_unknown },
96 // { "DAQCard-ai-16e-4", cal_ni_unknown },
97 // { "DAQCard-6062e", cal_ni_unknown },
98 // { "DAQCard-6024e", cal_ni_unknown },
101 #define n_boards (sizeof(boards)/sizeof(boards[0]))
104 ni_zero_offset_low = 0,
117 ni_setup_observables();
121 void ni_setup_board(void)
125 for(i=0;i<n_boards;i++){
126 if(!strcmp(devicename,boards[i].name)){
127 device_status = boards[i].status;
128 do_cal = boards[i].cal;
135 void ni_setup_observables(void)
139 int bipolar_highgain;
140 int unipolar_lowgain;
141 double voltage_reference;
144 bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
145 bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
146 unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
148 voltage_reference = 5.000;
150 memset(&tmpl,0,sizeof(tmpl));
151 tmpl.insn = INSN_READ;
153 tmpl.subdev = ad_subdev;
155 /* 0 offset, low gain */
156 o = observables + ni_zero_offset_low;
157 o->name = "ai, bipolar zero offset, low gain";
158 o->observe_insn = tmpl;
159 o->observe_insn.chanspec = CR_PACK(0,bipolar_lowgain,AREF_OTHER);
162 /* 0 offset, high gain */
163 o = observables + ni_zero_offset_high;
164 o->name = "ai, bipolar zero offset, high gain";
165 o->observe_insn = tmpl;
166 o->observe_insn.chanspec = CR_PACK(0,bipolar_highgain,AREF_OTHER);
169 /* voltage reference */
170 o = observables + ni_reference_low;
171 o->name = "ai, bipolar voltage reference, low gain";
172 o->observe_insn = tmpl;
173 o->observe_insn.chanspec = CR_PACK(5,bipolar_lowgain,AREF_OTHER);
174 o->target = voltage_reference;
176 n_observables = ni_reference_low + 1;
178 if(unipolar_lowgain>=0){
179 /* unip/bip offset */
180 o = observables + ni_unip_offset_low;
181 o->name = "ai, unipolar zero offset, low gain";
182 o->observe_insn = tmpl;
183 o->observe_insn.chanspec =
184 CR_PACK(0,unipolar_lowgain,AREF_OTHER);
189 o = observables + ni_unip_reference_low;
190 o->name = "ai, unipolar voltage reference, low gain";
191 o->observe_insn = tmpl;
192 o->observe_insn.chanspec =
193 CR_PACK(5,unipolar_lowgain,AREF_OTHER);
194 o->target = voltage_reference;
197 n_observables = ni_unip_offset_low + 1;
203 memset(&po_tmpl,0,sizeof(po_tmpl));
204 po_tmpl.insn = INSN_WRITE;
206 po_tmpl.subdev = da_subdev;
208 /* ao 0, zero offset */
209 o = observables + ni_ao0_zero_offset;
210 o->name = "ao 0, zero offset, low gain";
211 o->preobserve_insn = po_tmpl;
212 o->preobserve_insn.chanspec = CR_PACK(0,0,0);
213 o->preobserve_insn.data = &o->preobserve_data;
214 o->observe_insn = tmpl;
215 o->observe_insn.chanspec =
216 CR_PACK(2,bipolar_lowgain,AREF_OTHER);
217 set_target(ni_ao0_zero_offset,0.0);
220 o = observables + ni_ao0_reference;
221 o->name = "ao 0, reference voltage, low gain";
222 o->preobserve_insn = po_tmpl;
223 o->preobserve_insn.chanspec = CR_PACK(0,0,0);
224 o->preobserve_insn.data = &o->preobserve_data;
225 o->observe_insn = tmpl;
226 o->observe_insn.chanspec =
227 CR_PACK(6,bipolar_lowgain,AREF_OTHER);
228 set_target(ni_ao0_reference,5.0);
229 o->target -= voltage_reference;
231 /* ao 1, zero offset */
232 o = observables + ni_ao1_zero_offset;
233 o->name = "ao 1, zero offset, low gain";
234 o->preobserve_insn = po_tmpl;
235 o->preobserve_insn.chanspec = CR_PACK(1,0,0);
236 o->preobserve_insn.data = &o->preobserve_data;
237 o->observe_insn = tmpl;
238 o->observe_insn.chanspec =
239 CR_PACK(3,bipolar_lowgain,AREF_OTHER);
240 set_target(ni_ao1_zero_offset,0.0);
243 o = observables + ni_ao1_reference;
244 o->name = "ao 1, reference voltage, low gain";
245 o->preobserve_insn = po_tmpl;
246 o->preobserve_insn.chanspec = CR_PACK(1,0,0);
247 o->preobserve_insn.data = &o->preobserve_data;
248 o->observe_insn = tmpl;
249 o->observe_insn.chanspec =
250 CR_PACK(7,bipolar_lowgain,AREF_OTHER);
251 set_target(ni_ao1_reference,5.0);
252 o->target -= voltage_reference;
254 n_observables = ni_ao1_reference + 1;
258 void cal_ni_at_mio_16e_2(void)
260 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
261 cal1(ni_zero_offset_high,0);
262 cal1(ni_reference_low,3);
263 cal1(ni_unip_offset_low,2);
265 cal1(ni_ao0_zero_offset,5);
266 cal1(ni_ao0_reference,6);
267 cal1(ni_ao1_zero_offset,8);
268 cal1(ni_ao1_reference,9);
273 * Device name: DAQCard-ai-16xe-50
274 * Comedi version: 0.7.60
275 * ai, bipolar zero offset, low gain
276 * offset 5.87(63)e-3, target 0
277 * caldac[0] gain=-2.243(21)e-6 V/bit S_min=208.079 dof=254
278 * caldac[2] gain=1.56378(22)e-4 V/bit S_min=1782.91 dof=254
279 * caldac[8] gain=2.499(14)e-7 V/bit S_min=234.915 dof=254
280 * ai, bipolar zero offset, high gain
281 * offset 4.251(49)e-5, target 0
282 * caldac[0] gain=-2.396(30)e-8 V/bit S_min=231.387 dof=254
283 * caldac[2] gain=1.56428(28)e-6 V/bit S_min=829.096 dof=254
284 * caldac[8] gain=2.61244(18)e-7 V/bit S_min=773.092 dof=254
285 * ai, bipolar voltage reference, low gain
286 * offset 4.99650(81), target 5
287 * caldac[0] gain=-3.78250(23)e-4 V/bit S_min=12207.6 dof=254
288 * caldac[1] gain=-9.878(22)e-6 V/bit S_min=346.795 dof=254
289 * caldac[2] gain=1.57172(23)e-4 V/bit S_min=969.526 dof=254
290 * caldac[8] gain=2.795(14)e-7 V/bit S_min=245.703 dof=254
291 * ai, unipolar zero offset, low gain
292 * offset 0.0133(14), target 0
293 * caldac[0] gain=3.73923(29)e-4 V/bit S_min=2855.79 dof=151
294 * caldac[1] gain=9.784(11)e-6 V/bit S_min=727.295 dof=254
295 * caldac[2] gain=7.8670(11)e-5 V/bit S_min=903.291 dof=254
296 * caldac[8] gain=2.7732(74)e-7 V/bit S_min=415.399 dof=254
298 void cal_ni_daqcard_ai_16xe_50(void)
300 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,2);
301 cal1(ni_zero_offset_high,8);
302 cal1(ni_reference_low,0);
305 void cal_ni_at_mio_16e_1(void)
307 cal_ni_at_mio_16e_2();
310 void cal_ni_pci_mio_16e_1(void)
312 cal_ni_at_mio_16e_2();
315 void cal_ni_pci_6035e(void)
318 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
319 cal1(ni_zero_offset_high,0);
320 cal1(ni_reference_low,3);
326 void cal_ni_pci_6071e(void)
329 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
330 cal1(ni_zero_offset_high,0);
331 cal1(ni_reference_low,3);
337 void cal_ni_pxi_6071e(void)
340 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
341 cal1(ni_zero_offset_high,0);
342 cal1(ni_reference_low,3);
348 void cal_ni_at_mio_16e_10(void)
351 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
352 cal1(ni_zero_offset_high,10);
353 cal1(ni_zero_offset_high,0);
354 cal1(ni_reference_low,3);
355 cal1(ni_unip_offset_low,2);
357 cal1(ni_ao0_zero_offset,5); // guess
358 cal1(ni_ao0_reference,6); // guess
359 cal1(ni_ao0_zero_offset,8); // guess
360 cal1(ni_ao0_reference,9); // guess
364 void cal_ni_pci_mio_16xe_50(void)
366 // 16xe-50 (old) (same as daqcard?)
367 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,2);
368 cal1(ni_zero_offset_high,8);
369 cal1(ni_reference_low,0);
375 void cal_ni_pci_6023e(void)
380 double ni_get_reference(int lsb_loc,int msb_loc)
386 lsb=read_eeprom(lsb_loc);
387 msb=read_eeprom(msb_loc);
388 printf("lsb=%d msb=%d\n",read_eeprom(425),read_eeprom(426));
391 if(uv>=0x8000)uv-=0x10000;
393 printf("ref=%g\n",ref);
399 void cal_ni_results(void)
403 int bipolar_highgain;
404 int unipolar_lowgain;
408 bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
409 bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
410 unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
412 /* 0 offset, low gain */
413 range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
414 read_chan2(s,0,bipolar_lowgain);
415 DPRINT(0,"bipolar zero offset, low gain [%g,%g]: %s\n",
416 range->min,range->max,s);
418 /* 0 offset, high gain */
419 range = comedi_get_range(dev,ad_subdev,0,bipolar_highgain);
420 read_chan2(s,0,bipolar_highgain);
421 DPRINT(0,"bipolar zero offset, high gain [%g,%g]: %s\n",
422 range->min,range->max,s);
424 /* unip/bip offset */
425 range = comedi_get_range(dev,ad_subdev,0,unipolar_lowgain);
426 read_chan2(s,0,unipolar_lowgain);
427 DPRINT(0,"unipolar zero offset, low gain [%g,%g]: %s\n",
428 range->min,range->max,s);
432 void ni_mio_ai_postgain_cal(void)
440 check_gain_chan_x(&l,CR_PACK(0,0,AREF_OTHER),1);
441 offset_r0=linear_fit_func_y(&l,caldacs[1].current);
442 printf("offset r0 %g\n",offset_r0);
444 check_gain_chan_x(&l,CR_PACK(0,7,AREF_OTHER),1);
445 offset_r7=linear_fit_func_y(&l,caldacs[1].current);
446 printf("offset r7 %g\n",offset_r7);
450 a=(offset_r0-offset_r7)/(200.0-1.0);
451 a=caldacs[1].current-a/gain;
455 caldacs[1].current=rint(a);
459 void ni_mio_ai_postgain_cal_2(int chan,int dac,int range_lo,int range_hi,double gain)
461 double offset_lo,offset_hi;
466 check_gain_chan_x(&l,CR_PACK(chan,range_lo,AREF_OTHER),dac);
467 offset_lo=linear_fit_func_y(&l,caldacs[dac].current);
468 printf("offset lo %g\n",offset_lo);
470 check_gain_chan_x(&l,CR_PACK(chan,range_hi,AREF_OTHER),dac);
471 offset_hi=linear_fit_func_y(&l,caldacs[dac].current);
472 printf("offset hi %g\n",offset_hi);
476 a=(offset_lo-offset_hi)/(gain-1.0);
477 a=caldacs[dac].current-a/slope;
481 caldacs[dac].current=rint(a);