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_16e_1(void);
49 void cal_ni_daqcard_ai_16xe_50(void);
50 void cal_ni_6035e(void);
51 void cal_ni_6071e(void);
52 void cal_ni_16e_10(void);
53 void cal_ni_16xe_50(void);
55 struct board_struct boards[]={
56 { "at-mio-16e-2", STATUS_DONE, cal_ni_16e_1 },
57 { "DAQCard-ai-16xe-50", STATUS_DONE, cal_ni_daqcard_ai_16xe_50 },
58 { "at-mio-16e-1", STATUS_SOME, cal_ni_16e_1 },
59 { "pci-mio-16e-1", STATUS_SOME, cal_ni_16e_1 },
60 { "pci-6035e", STATUS_GUESS, cal_ni_6035e },
61 { "pci-6071e", STATUS_GUESS, cal_ni_6071e },
62 { "pxi-6071e", STATUS_GUESS, cal_ni_6071e },
63 { "at-mio-16e-10", STATUS_GUESS, cal_ni_16e_10 },
64 { "pci-mio-16xe-50", STATUS_GUESS, cal_ni_16xe_50 },
65 { "pci-6023e", STATUS_GUESS, cal_ni_6035e },
67 // { "at-mio-16de-10", cal_ni_unknown },
68 { "at-mio-64e-3", cal_ni_16e_1 },
69 // { "at-mio-16xe-50", cal_ni_unknown },
70 // { "at-mio-16xe-10", cal_ni_unknown },
71 // { "at-ai-16xe-10", cal_ni_unknown },
72 { "pci-mio-16xe-10", cal_ni_16xe_10 },
73 // { "pxi-6030e", cal_ni_unknown },
74 // { "pci-mio-16e-4", cal_ni_unknown },
75 // { "pxi-6040e", cal_ni_unknown },
76 // { "pci-6031e", cal_ni_unknown },
77 // { "pci-6032e", cal_ni_unknown },
78 // { "pci-6033e", cal_ni_unknown },
79 // { "pci-6071e", cal_ni_unknown },
80 { "pci-6024e", cal_ni_6023e }, // guess
81 { "pci-6025e", cal_ni_6023e }, // guess
82 { "pxi-6025e", cal_ni_6023e }, // guess
83 { "pci-6034e", cal_ni_6023e }, // guess
84 { "pci-6035e", cal_ni_6023e },
85 // { "pci-6052e", cal_ni_unknown },
86 // { "pci-6110e", cal_ni_unknown },
87 // { "pci-6111e", cal_ni_unknown },
88 // { "pci-6711", cal_ni_unknown },
89 // { "pci-6713", cal_ni_unknown },
90 // { "pxi-6070e", cal_ni_unknown },
91 // { "pxi-6052e", cal_ni_unknown },
92 // { "DAQCard-ai-16e-4", cal_ni_unknown },
93 // { "DAQCard-6062e", cal_ni_unknown },
94 // { "DAQCard-6024e", cal_ni_unknown },
97 #define n_boards (sizeof(boards)/sizeof(boards[0]))
100 ni_zero_offset_low = 0,
113 ni_setup_observables();
117 void ni_setup_board(void)
121 for(i=0;i<n_boards;i++){
122 if(!strcmp(devicename,boards[i].name)){
123 device_status = boards[i].status;
124 do_cal = boards[i].cal;
131 void ni_setup_observables(void)
135 int bipolar_highgain;
136 int unipolar_lowgain;
137 double voltage_reference;
140 bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
141 bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
142 unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
144 voltage_reference = 5.000;
146 memset(&tmpl,0,sizeof(tmpl));
147 tmpl.insn = INSN_READ;
149 tmpl.subdev = ad_subdev;
151 /* 0 offset, low gain */
152 o = observables + ni_zero_offset_low;
153 o->name = "ai, bipolar zero offset, low gain";
154 o->observe_insn = tmpl;
155 o->observe_insn.chanspec = CR_PACK(0,bipolar_lowgain,AREF_OTHER);
158 /* 0 offset, high gain */
159 o = observables + ni_zero_offset_high;
160 o->name = "ai, bipolar zero offset, high gain";
161 o->observe_insn = tmpl;
162 o->observe_insn.chanspec = CR_PACK(0,bipolar_highgain,AREF_OTHER);
165 /* voltage reference */
166 o = observables + ni_reference_low;
167 o->name = "ai, bipolar voltage reference, low gain";
168 o->observe_insn = tmpl;
169 o->observe_insn.chanspec = CR_PACK(5,bipolar_lowgain,AREF_OTHER);
170 o->target = voltage_reference;
172 if(unipolar_lowgain>=0){
173 /* unip/bip offset */
174 o = observables + ni_unip_offset_low;
175 o->name = "ai, unipolar zero offset, low gain";
176 o->observe_insn = tmpl;
177 o->observe_insn.chanspec =
178 CR_PACK(0,unipolar_lowgain,AREF_OTHER);
183 o = observables + ni_unip_reference_low;
184 o->name = "ai, unipolar voltage reference, low gain";
185 o->observe_insn = tmpl;
186 o->observe_insn.chanspec =
187 CR_PACK(5,unipolar_lowgain,AREF_OTHER);
188 o->target = voltage_reference;
196 memset(&po_tmpl,0,sizeof(po_tmpl));
197 po_tmpl.insn = INSN_WRITE;
199 po_tmpl.subdev = da_subdev;
201 /* ao 0, zero offset */
202 o = observables + ni_ao0_zero_offset;
203 o->name = "ao 0, zero offset, low gain";
204 o->preobserve_insn = po_tmpl;
205 o->preobserve_insn.chanspec = CR_PACK(0,0,0);
206 o->preobserve_insn.data = &o->preobserve_data;
207 o->observe_insn = tmpl;
208 o->observe_insn.chanspec =
209 CR_PACK(2,bipolar_lowgain,AREF_OTHER);
210 set_target(ni_ao0_zero_offset,0.0);
213 o = observables + ni_ao0_reference;
214 o->name = "ao 0, reference voltage, low gain";
215 o->preobserve_insn = po_tmpl;
216 o->preobserve_insn.chanspec = CR_PACK(0,0,0);
217 o->preobserve_insn.data = &o->preobserve_data;
218 o->observe_insn = tmpl;
219 o->observe_insn.chanspec =
220 CR_PACK(6,bipolar_lowgain,AREF_OTHER);
221 set_target(ni_ao0_reference,5.0);
222 o->target -= voltage_reference;
224 /* ao 1, zero offset */
225 o = observables + ni_ao1_zero_offset;
226 o->name = "ao 1, zero offset, low gain";
227 o->preobserve_insn = po_tmpl;
228 o->preobserve_insn.chanspec = CR_PACK(1,0,0);
229 o->preobserve_insn.data = &o->preobserve_data;
230 o->observe_insn = tmpl;
231 o->observe_insn.chanspec =
232 CR_PACK(3,bipolar_lowgain,AREF_OTHER);
233 set_target(ni_ao1_zero_offset,0.0);
236 o = observables + ni_ao1_reference;
237 o->name = "ao 1, reference voltage, low gain";
238 o->preobserve_insn = po_tmpl;
239 o->preobserve_insn.chanspec = CR_PACK(1,0,0);
240 o->preobserve_insn.data = &o->preobserve_data;
241 o->observe_insn = tmpl;
242 o->observe_insn.chanspec =
243 CR_PACK(7,bipolar_lowgain,AREF_OTHER);
244 set_target(ni_ao1_reference,5.0);
245 o->target -= voltage_reference;
248 n_observables = ni_ao1_reference + 1;
251 void cal_ni_daqcard_ai_16xe_50(void)
254 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,2);
255 cal1(ni_zero_offset_high,8);
256 cal1(ni_reference_low,0);
259 void cal_ni_16e_1(void)
262 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
263 cal1(ni_zero_offset_high,0);
264 cal1(ni_reference_low,3);
265 cal1(ni_unip_offset_low,2);
267 cal1(ni_ao0_zero_offset,5);
268 cal1(ni_ao0_reference,6);
269 cal1(ni_ao1_zero_offset,8);
270 cal1(ni_ao1_reference,9);
274 void cal_ni_16e_10(void)
277 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
278 cal1(ni_zero_offset_high,10);
279 cal1(ni_zero_offset_high,0);
280 cal1(ni_reference_low,3);
281 cal1(ni_unip_offset_low,2);
283 cal1(ni_ao0_zero_offset,5); // guess
284 cal1(ni_ao0_reference,6); // guess
285 cal1(ni_ao0_zero_offset,8); // guess
286 cal1(ni_ao0_reference,9); // guess
290 void cal_ni_16xe_50(void)
292 // 16xe-50 (old) (same as daqcard?)
293 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,2);
294 cal1(ni_zero_offset_high,8);
295 cal1(ni_reference_low,0);
301 void cal_ni_6035e(void)
304 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
305 cal1(ni_zero_offset_high,0);
306 cal1(ni_reference_low,3);
312 void cal_ni_6071e(void)
315 postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
316 cal1(ni_zero_offset_high,0);
317 cal1(ni_reference_low,3);
324 double ni_get_reference(int lsb_loc,int msb_loc)
330 lsb=read_eeprom(lsb_loc);
331 msb=read_eeprom(msb_loc);
332 printf("lsb=%d msb=%d\n",read_eeprom(425),read_eeprom(426));
335 if(uv>=0x8000)uv-=0x10000;
337 printf("ref=%g\n",ref);
342 void cal_ni_unknown(void)
346 int bipolar_highgain;
347 int unipolar_lowgain;
351 printf("Warning: device not calibrated due to insufficient information\n");
352 printf("Please send this output to <ds@schleef.org>\n");
354 printf("Device name: %s\n",comedi_get_board_name(dev));
355 printf("Comedi version: %d.%d.%d\n",
356 (comedi_get_version_code(dev)>>16)&0xff,
357 (comedi_get_version_code(dev)>>8)&0xff,
358 (comedi_get_version_code(dev))&0xff);
360 bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
361 bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
362 unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
364 /* 0 offset, low gain */
365 range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
366 DPRINT(0,"bipolar zero offset, low gain [%g,%g]\n",
367 range->min,range->max);
368 channel_dependence(0,bipolar_lowgain);
370 /* 0 offset, high gain */
371 range = comedi_get_range(dev,ad_subdev,0,bipolar_highgain);
372 DPRINT(0,"bipolar zero offset, high gain [%g,%g]\n",
373 range->min,range->max);
374 channel_dependence(0,bipolar_highgain);
376 /* unip/bip offset */
377 range = comedi_get_range(dev,ad_subdev,0,unipolar_lowgain);
378 DPRINT(0,"unipolar zero offset, low gain [%g,%g]\n",
379 range->min,range->max);
380 channel_dependence(0,unipolar_lowgain);
382 /* voltage reference */
383 range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
384 DPRINT(0,"bipolar voltage reference, low gain [%g,%g]\n",
385 range->min,range->max);
386 channel_dependence(5,bipolar_lowgain);
388 have_ao = (comedi_get_subdevice_type(dev,da_subdev)==COMEDI_SUBD_AO);
392 /* ao 0, zero offset */
394 set_ao(dev,da_subdev,ao_chan,0,0.0);
395 range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
396 DPRINT(0,"ao 0, zero offset, low gain [%g,%g]\n",
397 range->min,range->max);
398 channel_dependence(2,bipolar_lowgain);
402 set_ao(dev,da_subdev,ao_chan,0,5.0);
403 range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
404 DPRINT(0,"ao 0, gain, low gain [%g,%g]\n",
405 range->min,range->max);
406 channel_dependence(6,bipolar_lowgain);
408 /* ao 1, zero offset */
410 set_ao(dev,da_subdev,ao_chan,0,0.0);
411 range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
412 DPRINT(0,"ao 1, zero offset, low gain [%g,%g]\n",
413 range->min,range->max);
414 channel_dependence(3,bipolar_lowgain);
418 set_ao(dev,da_subdev,ao_chan,0,5.0);
419 range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
420 DPRINT(0,"ao 1, gain, low gain [%g,%g]\n",
421 range->min,range->max);
422 channel_dependence(7,bipolar_lowgain);
428 void cal_ni_results(void)
432 int bipolar_highgain;
433 int unipolar_lowgain;
437 bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
438 bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
439 unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
441 /* 0 offset, low gain */
442 range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
443 read_chan2(s,0,bipolar_lowgain);
444 DPRINT(0,"bipolar zero offset, low gain [%g,%g]: %s\n",
445 range->min,range->max,s);
447 /* 0 offset, high gain */
448 range = comedi_get_range(dev,ad_subdev,0,bipolar_highgain);
449 read_chan2(s,0,bipolar_highgain);
450 DPRINT(0,"bipolar zero offset, high gain [%g,%g]: %s\n",
451 range->min,range->max,s);
453 /* unip/bip offset */
454 range = comedi_get_range(dev,ad_subdev,0,unipolar_lowgain);
455 read_chan2(s,0,unipolar_lowgain);
456 DPRINT(0,"unipolar zero offset, low gain [%g,%g]: %s\n",
457 range->min,range->max,s);
462 void ni_mio_ai_postgain_cal(void)
470 check_gain_chan_x(&l,CR_PACK(0,0,AREF_OTHER),1);
471 offset_r0=linear_fit_func_y(&l,caldacs[1].current);
472 printf("offset r0 %g\n",offset_r0);
474 check_gain_chan_x(&l,CR_PACK(0,7,AREF_OTHER),1);
475 offset_r7=linear_fit_func_y(&l,caldacs[1].current);
476 printf("offset r7 %g\n",offset_r7);
480 a=(offset_r0-offset_r7)/(200.0-1.0);
481 a=caldacs[1].current-a/gain;
485 caldacs[1].current=rint(a);
489 void ni_mio_ai_postgain_cal_2(int chan,int dac,int range_lo,int range_hi,double gain)
491 double offset_lo,offset_hi;
496 check_gain_chan_x(&l,CR_PACK(chan,range_lo,AREF_OTHER),dac);
497 offset_lo=linear_fit_func_y(&l,caldacs[dac].current);
498 printf("offset lo %g\n",offset_lo);
500 check_gain_chan_x(&l,CR_PACK(chan,range_hi,AREF_OTHER),dac);
501 offset_hi=linear_fit_func_y(&l,caldacs[dac].current);
502 printf("offset hi %g\n",offset_hi);
506 a=(offset_lo-offset_hi)/(gain-1.0);
507 a=caldacs[dac].current-a/slope;
511 caldacs[dac].current=rint(a);