BINS=comedi_calibrate
+objs = comedi_calibrate.o ni.o
all: $(BINS)
-comedi_calibrate: comedi_calibrate.o
- $(CC) -o comedi_calibrate comedi_calibrate.o $(LDFLAGS)
+comedi_calibrate: $(objs)
+ $(CC) -o $@ $(objs) $(LDFLAGS)
clean:
-rm -f *.o $(BINS)
--- /dev/null
+
+#ifndef __CALIB_H_
+#define __CALIB_H_
+
+#include <comedilib.h>
+#if 0
+#include <stdio.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+#endif
+
+#define DPRINT(level,fmt,args...) do{if(verbose>=level)printf(fmt, ## args);}while(0)
+
+#define N_CALDACS 32
+#define N_OBSERVABLES 32
+
+typedef struct{
+ int subdev;
+ int chan;
+
+ int maxdata;
+ int current;
+
+ int type;
+ double gain;
+}caldac;
+
+typedef struct{
+ char *name;
+
+ comedi_insn preobserve_insn;
+ lsampl_t preobserve_data;
+
+ comedi_insn observe_insn;
+
+ //comedi_range *range;
+ //int maxdata;
+
+ double target;
+}observable;
+
+extern caldac caldacs[N_CALDACS];
+extern int n_caldacs;
+
+extern observable observables[N_OBSERVABLES];
+extern int n_observables;
+
+extern comedi_t *dev;
+
+extern int ad_subdev;
+extern int da_subdev;
+extern int eeprom_subdev;
+extern int caldac_subdev;
+
+extern char *devicename;
+extern char *drivername;
+
+extern int verbose;
+
+enum {
+ STATUS_UNKNOWN = 0,
+ STATUS_GUESS,
+ STATUS_SOME,
+ STATUS_DONE
+};
+extern int device_status;
+
+extern int do_output;
+
+/* high level */
+
+void observe(void);
+void preobserve(int obs);
+void observable_dependence(int obs);
+void measure_observable(int obs);
+void reset_caldacs(void);
+
+/* drivers */
+
+void ni_setup(void);
+
+/* low level */
+
+void set_target(int obs,double target);
+void update_caldac(int i);
+void setup_caldacs(void);
+void postgain_cal(int obs1, int obs2, int dac);
+void cal1(int obs, int dac);
+
+/* misc and temp */
+
+void channel_dependence(int adc,int range);
+void caldac_dependence(int caldac);
+void dump_curve(int adc,int caldac);
+void chan_cal(int adc,int caldac,int range,double target);
+int read_eeprom(int addr);
+
+double read_chan(int adc,int range);
+int read_chan2(char *s,int adc,int range);
+void set_ao(comedi_t *dev,int subdev,int chan,int range,double value);
+void check_gain(int ad_chan,int range);
+double check_gain_chan(int ad_chan,int range,int cdac);
+
+void (*do_cal)(void);
+void cal_ni_results(void);
+
+/* helper functions */
+
+int get_bipolar_lowgain(comedi_t *dev,int subdev);
+int get_bipolar_highgain(comedi_t *dev,int subdev);
+int get_unipolar_lowgain(comedi_t *dev,int subdev);
+
+/* printing scientific numbers */
+
+int sci_sprint(char *s,double x,double y);
+int sci_sprint_alt(char *s,double x,double y);
+
+/* linear fitting */
+
+typedef struct {
+ int n;
+
+ double *y_data;
+ double *yerr_data;
+ double *x_data;
+
+ double x0;
+ double dx;
+ double yerr;
+
+ /* stats */
+ double s1,sx,sy,sxy,sxx;
+
+ double min,max;
+
+ /* results */
+ double ave_x;
+ double ave_y;
+ double slope;
+ double err_slope;
+ double err_ave_y;
+ double S_min;
+ double dof;
+
+}linear_fit_t;
+int linear_fit_monotonic(linear_fit_t *l);
+double linear_fit_func_y(linear_fit_t *l,double x);
+double check_gain_chan_x(linear_fit_t *l,unsigned int ad_chanspec,int cdac);
+
+/* slowly varying measurements */
+
+typedef struct{
+ comedi_t *dev;
+
+ int maxdata;
+ int order;
+ int aref;
+ int range;
+ int subd;
+ int chan;
+
+ comedi_range *rng;
+
+ int n;
+ double average;
+ double stddev;
+ double error;
+}new_sv_t;
+
+int new_sv_measure(new_sv_t *sv);
+int new_sv_init(new_sv_t *sv,comedi_t *dev,int subdev,int chan,int range,int aref);
+
+
+#endif
+
#include <stdlib.h>
#include <string.h>
-#define DPRINT(level,fmt,args...) do{if(verbose>=level)printf(fmt, ## args);}while(0)
+#include "calib.h"
-#define N_CALDACS 32
-#define N_OBSERVABLES 32
+/* global variables */
-typedef struct{
- int subdev;
- int chan;
+caldac caldacs[N_CALDACS];
+int n_caldacs;
- int maxdata;
- int current;
+observable observables[N_OBSERVABLES];
+int n_observables;
- int type;
- double gain;
-}caldac;
-
-typedef struct{
- char *name;
-
- comedi_insn preobserve_insn;
- lsampl_t preobserve_data;
+comedi_t *dev;
- comedi_insn observe_insn;
-
- //comedi_range *range;
- //int maxdata;
-
- double target;
-}observable;
+int ad_subdev;
+int da_subdev;
+int eeprom_subdev;
+int caldac_subdev;
-static caldac caldacs[N_CALDACS];
-static observable observables[N_OBSERVABLES];
-
-static int n_caldacs;
-static int n_observables;
-
-static comedi_t *dev;
-
-static int ad_subdev;
-static int da_subdev;
-static int eeprom_subdev;
-static int caldac_subdev;
-
-double read_chan(int adc,int range);
-int read_chan2(char *s,int adc,int range);
-void set_ao(comedi_t *dev,int subdev,int chan,int range,double value);
-void check_gain(int ad_chan,int range);
-double check_gain_chan(int ad_chan,int range,int cdac);
+char *drivername = NULL;
+char *devicename = NULL;
int verbose = 0;
-enum {
- STATUS_UNKNOWN = 0,
- STATUS_SOME,
- STATUS_DONE
-};
int device_status = STATUS_UNKNOWN;
-/* tmep */
-void do_cal(void);
-
-void observe(void);
-void preobserve(int obs);
-void observable_dependence(int obs);
-void measure_observable(int obs);
-void ni_setup(void);
-void set_target(int obs,double target);
-
-void cal_ni_results(void);
-
-void update_caldac(int i);
-void reset_caldacs(void);
-void setup_caldacs(void);
-void cal_ni_mio_E(void);
-void ni_mio_ai_postgain_cal(void);
-void ni_mio_ai_postgain_cal_2(int chan,int dac,int range_lo,int range_hi,double gain);
-void channel_dependence(int adc,int range);
-void caldac_dependence(int caldac);
-void dump_curve(int adc,int caldac);
-void chan_cal(int adc,int caldac,int range,double target);
-int read_eeprom(int addr);
-
-int get_bipolar_lowgain(comedi_t *dev,int subdev);
-int get_bipolar_highgain(comedi_t *dev,int subdev);
-int get_unipolar_lowgain(comedi_t *dev,int subdev);
-
-int sci_sprint(char *s,double x,double y);
-int sci_sprint_alt(char *s,double x,double y);
-
-
-typedef struct {
- int n;
-
- double *y_data;
- double *yerr_data;
- double *x_data;
-
- double x0;
- double dx;
- double yerr;
-
- /* stats */
- double s1,sx,sy,sxy,sxx;
-
- double min,max;
-
- /* results */
- double ave_x;
- double ave_y;
- double slope;
- double err_slope;
- double err_ave_y;
- double S_min;
- double dof;
-
-}linear_fit_t;
-int linear_fit_monotonic(linear_fit_t *l);
-double linear_fit_func_y(linear_fit_t *l,double x);
-double check_gain_chan_x(linear_fit_t *l,unsigned int ad_chanspec,int cdac);
+/* */
-typedef struct{
- comedi_t *dev;
-
- int maxdata;
- int order;
- int aref;
- int range;
- int subd;
- int chan;
-
- comedi_range *rng;
-
- int n;
- double average;
- double stddev;
- double error;
-}new_sv_t;
-
-int new_sv_measure(new_sv_t *sv);
-int new_sv_init(new_sv_t *sv,comedi_t *dev,int subdev,int chan,int range,int aref);
struct board_struct{
char *name;
void (*setup)(void);
};
-#if 0
-void cal_ni_16e_1(void);
-void cal_ni_16e_10(void);
-void cal_ni_16xe_50(void);
-void cal_ni_16xe_10(void);
-void cal_ni_6023e(void);
-void cal_ni_6071e(void);
-void cal_ni_daqcard_ai_16xe_50(void);
-void cal_ni_unknown(void);
-
-struct board_struct boards[]={
- { "at-mio-16e-1", cal_ni_16e_1 },
- { "at-mio-16e-2", cal_ni_16e_1 },
- { "at-mio-16e-10", cal_ni_16e_10 },
-// { "at-mio-16de-10", cal_ni_unknown },
- { "at-mio-64e-3", cal_ni_16e_1 },
-// { "at-mio-16xe-50", cal_ni_unknown },
-// { "at-mio-16xe-10", cal_ni_unknown },
-// { "at-ai-16xe-10", cal_ni_unknown },
- { "pci-mio-16xe-50", cal_ni_16xe_50 },
- { "pci-mio-16xe-10", cal_ni_16xe_10 },
-// { "pxi-6030e", cal_ni_unknown },
- { "pci-mio-16e-1", cal_ni_16e_1 },
-// { "pci-mio-16e-4", cal_ni_unknown },
-// { "pxi-6040e", cal_ni_unknown },
-// { "pci-6031e", cal_ni_unknown },
-// { "pci-6032e", cal_ni_unknown },
-// { "pci-6033e", cal_ni_unknown },
-// { "pci-6071e", cal_ni_unknown },
- { "pci-6023e", cal_ni_6023e },
- { "pci-6024e", cal_ni_6023e }, // guess
- { "pci-6025e", cal_ni_6023e }, // guess
- { "pxi-6025e", cal_ni_6023e }, // guess
- { "pci-6034e", cal_ni_6023e }, // guess
- { "pci-6035e", cal_ni_6023e },
-// { "pci-6052e", cal_ni_unknown },
-// { "pci-6110e", cal_ni_unknown },
-// { "pci-6111e", cal_ni_unknown },
-// { "pci-6711", cal_ni_unknown },
-// { "pci-6713", cal_ni_unknown },
- { "pxi-6071e", cal_ni_6071e },
-// { "pxi-6070e", cal_ni_unknown },
-// { "pxi-6052e", cal_ni_unknown },
- { "DAQCard-ai-16xe-50", cal_ni_daqcard_ai_16xe_50 },
-// { "DAQCard-ai-16e-4", cal_ni_unknown },
-// { "DAQCard-6062e", cal_ni_unknown },
-// { "DAQCard-6024e", cal_ni_unknown },
-};
-#define n_boards (sizeof(boards)/sizeof(boards[0]))
-#endif
-
struct board_struct drivers[] = {
{ "ni_pcimio", ni_setup },
{ "ni_atmio", ni_setup },
int do_dump = 0;
int do_reset = 1;
int do_calibrate = 1;
-int do_results = 1;
+int do_results = 0;
int do_output = 1;
struct option options[] = {
{ "no-dump", 0, &do_dump, 0 },
{ "results", 0, &do_results, 1 },
{ "no-results", 0, &do_results, 0 },
+ { "output", 0, &do_output, 1 },
+ { "no-output", 0, &do_output, 0 },
{ 0 },
};
{
char *fn = NULL;
int c;
- char *drivername = NULL;
- char *devicename = NULL;
int i;
struct board_struct *this_board;
int index;
if(do_reset)reset_caldacs();
if(do_dump)observe();
- if(do_calibrate)do_cal();
+ if(do_calibrate && do_cal)do_cal();
if(do_results)observe();
return 0;
}
-enum {
- ni_zero_offset_low = 0,
- ni_zero_offset_high,
- ni_reference_low,
- ni_unip_offset_low,
- ni_ao0_zero_offset,
- ni_ao0_reference,
- ni_ao1_zero_offset,
- ni_ao1_reference,
-};
-
-void ni_setup(void)
-{
- comedi_insn tmpl;
- int bipolar_lowgain;
- int bipolar_highgain;
- int unipolar_lowgain;
- double voltage_reference;
- observable *o;
-
- bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
- bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
- unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
-
- voltage_reference = 5.000;
-
- memset(&tmpl,0,sizeof(tmpl));
- tmpl.insn = INSN_READ;
- tmpl.n = 1;
- tmpl.subdev = ad_subdev;
-
- /* 0 offset, low gain */
- o = observables + ni_zero_offset_low;
- o->name = "ai, bipolar zero offset, low gain";
- o->observe_insn = tmpl;
- o->observe_insn.chanspec = CR_PACK(0,bipolar_lowgain,AREF_OTHER);
- o->target = 0;
-
- /* 0 offset, high gain */
- o = observables + ni_zero_offset_high;
- o->name = "ai, bipolar zero offset, high gain";
- o->observe_insn = tmpl;
- o->observe_insn.chanspec = CR_PACK(0,bipolar_highgain,AREF_OTHER);
- o->target = 0;
-
- /* voltage reference */
- o = observables + ni_reference_low;
- o->name = "ai, bipolar voltage reference, low gain";
- o->observe_insn = tmpl;
- o->observe_insn.chanspec = CR_PACK(5,bipolar_lowgain,AREF_OTHER);
- o->target = voltage_reference;
-
- if(unipolar_lowgain>=0){
- /* unip/bip offset */
- o = observables + ni_unip_offset_low;
- o->name = "ai, unipolar zero offset, low gain";
- o->observe_insn = tmpl;
- o->observe_insn.chanspec =
- CR_PACK(0,unipolar_lowgain,AREF_OTHER);
- o->target = 0;
-
-#if 0
- /* unip gain */
- o = observables + ni_unip_reference_low;
- o->name = "ai, unipolar voltage reference, low gain";
- o->observe_insn = tmpl;
- o->observe_insn.chanspec =
- CR_PACK(5,unipolar_lowgain,AREF_OTHER);
- o->target = voltage_reference;
- i++;
-#endif
- }
-
- if(da_subdev>=0){
- comedi_insn po_tmpl;
-
- memset(&po_tmpl,0,sizeof(po_tmpl));
- po_tmpl.insn = INSN_WRITE;
- po_tmpl.n = 1;
- po_tmpl.subdev = da_subdev;
-
- /* ao 0, zero offset */
- o = observables + ni_ao0_zero_offset;
- o->name = "ao 0, zero offset, low gain";
- o->preobserve_insn = po_tmpl;
- o->preobserve_insn.chanspec = CR_PACK(0,0,0);
- o->preobserve_insn.data = &o->preobserve_data;
- o->observe_insn = tmpl;
- o->observe_insn.chanspec =
- CR_PACK(2,bipolar_lowgain,AREF_OTHER);
- set_target(ni_ao0_zero_offset,0.0);
-
- /* ao 0, gain */
- o = observables + ni_ao0_reference;
- o->name = "ao 0, reference voltage, low gain";
- o->preobserve_insn = po_tmpl;
- o->preobserve_insn.chanspec = CR_PACK(0,0,0);
- o->preobserve_insn.data = &o->preobserve_data;
- o->observe_insn = tmpl;
- o->observe_insn.chanspec =
- CR_PACK(6,bipolar_lowgain,AREF_OTHER);
- set_target(ni_ao0_reference,5.0);
- o->target -= voltage_reference;
-
- /* ao 1, zero offset */
- o = observables + ni_ao1_zero_offset;
- o->name = "ao 1, zero offset, low gain";
- o->preobserve_insn = po_tmpl;
- o->preobserve_insn.chanspec = CR_PACK(1,0,0);
- o->preobserve_insn.data = &o->preobserve_data;
- o->observe_insn = tmpl;
- o->observe_insn.chanspec =
- CR_PACK(3,bipolar_lowgain,AREF_OTHER);
- set_target(ni_ao1_zero_offset,0.0);
-
- /* ao 1, gain */
- o = observables + ni_ao1_reference;
- o->name = "ao 1, reference voltage, low gain";
- o->preobserve_insn = po_tmpl;
- o->preobserve_insn.chanspec = CR_PACK(1,0,0);
- o->preobserve_insn.data = &o->preobserve_data;
- o->observe_insn = tmpl;
- o->observe_insn.chanspec =
- CR_PACK(7,bipolar_lowgain,AREF_OTHER);
- set_target(ni_ao1_reference,5.0);
- o->target -= voltage_reference;
-
- }
- n_observables = ni_ao1_reference + 1;
-
- setup_caldacs();
-
-
-}
-
void set_target(int obs,double target)
{
comedi_range *range;
}
}
-void do_cal(void)
-{
-#if 0
- // daqcard
- postgain_cal(ni_zero_offset_low,ni_zero_offset_high,2);
- cal1(ni_zero_offset_high,8);
- cal1(ni_reference_low,0);
-#endif
-
- // 16e-2
- postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
- cal1(ni_zero_offset_high,0);
- cal1(ni_reference_low,3);
- cal1(ni_unip_offset_low,2);
- if(do_output){
- cal1(ni_ao0_zero_offset,5);
- cal1(ni_ao0_reference,6);
- cal1(ni_ao1_zero_offset,8);
- cal1(ni_ao1_reference,9);
- }
-
-#if 0
- // 16e-10 (old)
- postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
- cal1(ni_zero_offset_high,10);
- cal1(ni_zero_offset_high,0);
- cal1(ni_reference_low,3);
- cal1(ni_unip_offset_low,2);
- if(do_output){
- cal1(ni_ao0_zero_offset,5); // guess
- cal1(ni_ao0_reference,6); // guess
- cal1(ni_ao0_zero_offset,8); // guess
- cal1(ni_ao0_reference,9); // guess
- }
-#endif
-
-#if 0
- // 16xe-50 (old) (same as daqcard?)
- postgain_cal(ni_zero_offset_low,ni_zero_offset_high,2);
- cal1(ni_zero_offset_high,8);
- cal1(ni_reference_low,0);
- if(do_output){
- // unknown
- }
-#endif
-
-#if 0
- // 6035e (old)
- postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
- cal1(ni_zero_offset_high,0);
- cal1(ni_reference_low,3);
- if(do_output){
- // unknown
- }
-#endif
-
-#if 0
- // 6071e (old)
- postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
- cal1(ni_zero_offset_high,0);
- cal1(ni_reference_low,3);
- if(do_output){
- // unknown
- }
-#endif
-}
-
-
-double ni_get_reference(int lsb_loc,int msb_loc)
-{
- int lsb,msb;
- int uv;
- double ref;
-
- lsb=read_eeprom(lsb_loc);
- msb=read_eeprom(msb_loc);
- printf("lsb=%d msb=%d\n",read_eeprom(425),read_eeprom(426));
-
- uv=lsb | (msb<<8);
- if(uv>=0x8000)uv-=0x10000;
- ref=5.000+1.0e-6*uv;
- printf("ref=%g\n",ref);
-
- return ref;
-}
-
-void cal_ni_unknown(void)
-{
- comedi_range *range;
- int bipolar_lowgain;
- int bipolar_highgain;
- int unipolar_lowgain;
- int have_ao = 1;
-
- reset_caldacs();
- printf("Warning: device not calibrated due to insufficient information\n");
- printf("Please send this output to <ds@schleef.org>\n");
- printf("$Id$\n");
- printf("Device name: %s\n",comedi_get_board_name(dev));
- printf("Comedi version: %d.%d.%d\n",
- (comedi_get_version_code(dev)>>16)&0xff,
- (comedi_get_version_code(dev)>>8)&0xff,
- (comedi_get_version_code(dev))&0xff);
-
- bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
- bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
- unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
-
- /* 0 offset, low gain */
- range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
- DPRINT(0,"bipolar zero offset, low gain [%g,%g]\n",
- range->min,range->max);
- channel_dependence(0,bipolar_lowgain);
-
- /* 0 offset, high gain */
- range = comedi_get_range(dev,ad_subdev,0,bipolar_highgain);
- DPRINT(0,"bipolar zero offset, high gain [%g,%g]\n",
- range->min,range->max);
- channel_dependence(0,bipolar_highgain);
-
- /* unip/bip offset */
- range = comedi_get_range(dev,ad_subdev,0,unipolar_lowgain);
- DPRINT(0,"unipolar zero offset, low gain [%g,%g]\n",
- range->min,range->max);
- channel_dependence(0,unipolar_lowgain);
-
- /* voltage reference */
- range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
- DPRINT(0,"bipolar voltage reference, low gain [%g,%g]\n",
- range->min,range->max);
- channel_dependence(5,bipolar_lowgain);
-
- have_ao = (comedi_get_subdevice_type(dev,da_subdev)==COMEDI_SUBD_AO);
- if(have_ao){
- int ao_chan;
-
- /* ao 0, zero offset */
- ao_chan = 0;
- set_ao(dev,da_subdev,ao_chan,0,0.0);
- range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
- DPRINT(0,"ao 0, zero offset, low gain [%g,%g]\n",
- range->min,range->max);
- channel_dependence(2,bipolar_lowgain);
-
- /* ao 0, gain */
- ao_chan = 0;
- set_ao(dev,da_subdev,ao_chan,0,5.0);
- range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
- DPRINT(0,"ao 0, gain, low gain [%g,%g]\n",
- range->min,range->max);
- channel_dependence(6,bipolar_lowgain);
-
- /* ao 1, zero offset */
- ao_chan = 1;
- set_ao(dev,da_subdev,ao_chan,0,0.0);
- range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
- DPRINT(0,"ao 1, zero offset, low gain [%g,%g]\n",
- range->min,range->max);
- channel_dependence(3,bipolar_lowgain);
-
- /* ao 1, gain */
- ao_chan = 1;
- set_ao(dev,da_subdev,ao_chan,0,5.0);
- range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
- DPRINT(0,"ao 1, gain, low gain [%g,%g]\n",
- range->min,range->max);
- channel_dependence(7,bipolar_lowgain);
- }
-
- cal_ni_results();
-}
-
-void cal_ni_results(void)
-{
- comedi_range *range;
- int bipolar_lowgain;
- int bipolar_highgain;
- int unipolar_lowgain;
- //int have_ao;
- char s[32];
-
- bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
- bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
- unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
-
- /* 0 offset, low gain */
- range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
- read_chan2(s,0,bipolar_lowgain);
- DPRINT(0,"bipolar zero offset, low gain [%g,%g]: %s\n",
- range->min,range->max,s);
-
- /* 0 offset, high gain */
- range = comedi_get_range(dev,ad_subdev,0,bipolar_highgain);
- read_chan2(s,0,bipolar_highgain);
- DPRINT(0,"bipolar zero offset, high gain [%g,%g]: %s\n",
- range->min,range->max,s);
-
- /* unip/bip offset */
- range = comedi_get_range(dev,ad_subdev,0,unipolar_lowgain);
- read_chan2(s,0,unipolar_lowgain);
- DPRINT(0,"unipolar zero offset, low gain [%g,%g]: %s\n",
- range->min,range->max,s);
-
-}
-
-void ni_mio_ai_postgain_cal(void)
-{
- linear_fit_t l;
- double offset_r0;
- double offset_r7;
- double gain;
- double a;
-
- check_gain_chan_x(&l,CR_PACK(0,0,AREF_OTHER),1);
- offset_r0=linear_fit_func_y(&l,caldacs[1].current);
- printf("offset r0 %g\n",offset_r0);
-
- check_gain_chan_x(&l,CR_PACK(0,7,AREF_OTHER),1);
- offset_r7=linear_fit_func_y(&l,caldacs[1].current);
- printf("offset r7 %g\n",offset_r7);
-
- gain=l.slope;
-
- a=(offset_r0-offset_r7)/(200.0-1.0);
- a=caldacs[1].current-a/gain;
-
- printf("%g\n",a);
-
- caldacs[1].current=rint(a);
- update_caldac(1);
-}
-
-void ni_mio_ai_postgain_cal_2(int chan,int dac,int range_lo,int range_hi,double gain)
-{
- double offset_lo,offset_hi;
- linear_fit_t l;
- double slope;
- double a;
-
- check_gain_chan_x(&l,CR_PACK(chan,range_lo,AREF_OTHER),dac);
- offset_lo=linear_fit_func_y(&l,caldacs[dac].current);
- printf("offset lo %g\n",offset_lo);
-
- check_gain_chan_x(&l,CR_PACK(chan,range_hi,AREF_OTHER),dac);
- offset_hi=linear_fit_func_y(&l,caldacs[dac].current);
- printf("offset hi %g\n",offset_hi);
-
- slope=l.slope;
-
- a=(offset_lo-offset_hi)/(gain-1.0);
- a=caldacs[dac].current-a/slope;
-
- printf("%g\n",a);
-
- caldacs[dac].current=rint(a);
- update_caldac(dac);
-}
-
void chan_cal(int adc,int cdac,int range,double target)
{
linear_fit_t l;
--- /dev/null
+/*
+ A little auto-calibration utility, for boards
+ that support it.
+
+ Right now, it only supports NI E series boards,
+ but it should be easily portable.
+
+ A few things need improvement here:
+ - current system gets "close", but doesn't
+ do any fine-tuning
+ - no pre/post gain discrimination for the
+ A/D zero offset.
+ - should read (and use) the actual reference
+ voltage value from eeprom
+ - statistics would be nice, to show how good
+ the calibration is.
+ - doesn't check unipolar ranges
+ - "alternate calibrations" would be cool--to
+ accurately measure 0 in a unipolar range
+ - more portable
+ */
+
+#define _GNU_SOURCE
+
+#include <stdio.h>
+#include <comedilib.h>
+#include <fcntl.h>
+#include <unistd.h>
+#include <errno.h>
+#include <getopt.h>
+#include <ctype.h>
+#include <math.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include "calib.h"
+
+
+struct board_struct{
+ char *name;
+ int status;
+ void (*cal)(void);
+};
+
+void ni_setup_board(void);
+void ni_setup_observables(void);
+
+void cal_ni_16e_1(void);
+void cal_ni_daqcard_ai_16xe_50(void);
+void cal_ni_6035e(void);
+void cal_ni_6071e(void);
+void cal_ni_16e_10(void);
+void cal_ni_16xe_50(void);
+
+struct board_struct boards[]={
+ { "at-mio-16e-2", STATUS_DONE, cal_ni_16e_1 },
+ { "DAQCard-ai-16xe-50", STATUS_DONE, cal_ni_daqcard_ai_16xe_50 },
+ { "at-mio-16e-1", STATUS_SOME, cal_ni_16e_1 },
+ { "pci-mio-16e-1", STATUS_SOME, cal_ni_16e_1 },
+ { "pci-6035e", STATUS_GUESS, cal_ni_6035e },
+ { "pci-6071e", STATUS_GUESS, cal_ni_6071e },
+ { "pxi-6071e", STATUS_GUESS, cal_ni_6071e },
+ { "at-mio-16e-10", STATUS_GUESS, cal_ni_16e_10 },
+ { "pci-mio-16xe-50", STATUS_GUESS, cal_ni_16xe_50 },
+ { "pci-6023e", STATUS_GUESS, cal_ni_6035e },
+#if 0
+// { "at-mio-16de-10", cal_ni_unknown },
+ { "at-mio-64e-3", cal_ni_16e_1 },
+// { "at-mio-16xe-50", cal_ni_unknown },
+// { "at-mio-16xe-10", cal_ni_unknown },
+// { "at-ai-16xe-10", cal_ni_unknown },
+ { "pci-mio-16xe-10", cal_ni_16xe_10 },
+// { "pxi-6030e", cal_ni_unknown },
+// { "pci-mio-16e-4", cal_ni_unknown },
+// { "pxi-6040e", cal_ni_unknown },
+// { "pci-6031e", cal_ni_unknown },
+// { "pci-6032e", cal_ni_unknown },
+// { "pci-6033e", cal_ni_unknown },
+// { "pci-6071e", cal_ni_unknown },
+ { "pci-6024e", cal_ni_6023e }, // guess
+ { "pci-6025e", cal_ni_6023e }, // guess
+ { "pxi-6025e", cal_ni_6023e }, // guess
+ { "pci-6034e", cal_ni_6023e }, // guess
+ { "pci-6035e", cal_ni_6023e },
+// { "pci-6052e", cal_ni_unknown },
+// { "pci-6110e", cal_ni_unknown },
+// { "pci-6111e", cal_ni_unknown },
+// { "pci-6711", cal_ni_unknown },
+// { "pci-6713", cal_ni_unknown },
+// { "pxi-6070e", cal_ni_unknown },
+// { "pxi-6052e", cal_ni_unknown },
+// { "DAQCard-ai-16e-4", cal_ni_unknown },
+// { "DAQCard-6062e", cal_ni_unknown },
+// { "DAQCard-6024e", cal_ni_unknown },
+#endif
+};
+#define n_boards (sizeof(boards)/sizeof(boards[0]))
+
+enum {
+ ni_zero_offset_low = 0,
+ ni_zero_offset_high,
+ ni_reference_low,
+ ni_unip_offset_low,
+ ni_ao0_zero_offset,
+ ni_ao0_reference,
+ ni_ao1_zero_offset,
+ ni_ao1_reference,
+};
+
+void ni_setup(void)
+{
+ ni_setup_board();
+ ni_setup_observables();
+ setup_caldacs();
+}
+
+void ni_setup_board(void)
+{
+ int i;
+
+ for(i=0;i<n_boards;i++){
+ if(!strcmp(devicename,boards[i].name)){
+ device_status = boards[i].status;
+ do_cal = boards[i].cal;
+ return;
+ }
+ }
+
+}
+
+void ni_setup_observables(void)
+{
+ comedi_insn tmpl;
+ int bipolar_lowgain;
+ int bipolar_highgain;
+ int unipolar_lowgain;
+ double voltage_reference;
+ observable *o;
+
+ bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
+ bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
+ unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
+
+ voltage_reference = 5.000;
+
+ memset(&tmpl,0,sizeof(tmpl));
+ tmpl.insn = INSN_READ;
+ tmpl.n = 1;
+ tmpl.subdev = ad_subdev;
+
+ /* 0 offset, low gain */
+ o = observables + ni_zero_offset_low;
+ o->name = "ai, bipolar zero offset, low gain";
+ o->observe_insn = tmpl;
+ o->observe_insn.chanspec = CR_PACK(0,bipolar_lowgain,AREF_OTHER);
+ o->target = 0;
+
+ /* 0 offset, high gain */
+ o = observables + ni_zero_offset_high;
+ o->name = "ai, bipolar zero offset, high gain";
+ o->observe_insn = tmpl;
+ o->observe_insn.chanspec = CR_PACK(0,bipolar_highgain,AREF_OTHER);
+ o->target = 0;
+
+ /* voltage reference */
+ o = observables + ni_reference_low;
+ o->name = "ai, bipolar voltage reference, low gain";
+ o->observe_insn = tmpl;
+ o->observe_insn.chanspec = CR_PACK(5,bipolar_lowgain,AREF_OTHER);
+ o->target = voltage_reference;
+
+ if(unipolar_lowgain>=0){
+ /* unip/bip offset */
+ o = observables + ni_unip_offset_low;
+ o->name = "ai, unipolar zero offset, low gain";
+ o->observe_insn = tmpl;
+ o->observe_insn.chanspec =
+ CR_PACK(0,unipolar_lowgain,AREF_OTHER);
+ o->target = 0;
+
+#if 0
+ /* unip gain */
+ o = observables + ni_unip_reference_low;
+ o->name = "ai, unipolar voltage reference, low gain";
+ o->observe_insn = tmpl;
+ o->observe_insn.chanspec =
+ CR_PACK(5,unipolar_lowgain,AREF_OTHER);
+ o->target = voltage_reference;
+ i++;
+#endif
+ }
+
+ if(da_subdev>=0){
+ comedi_insn po_tmpl;
+
+ memset(&po_tmpl,0,sizeof(po_tmpl));
+ po_tmpl.insn = INSN_WRITE;
+ po_tmpl.n = 1;
+ po_tmpl.subdev = da_subdev;
+
+ /* ao 0, zero offset */
+ o = observables + ni_ao0_zero_offset;
+ o->name = "ao 0, zero offset, low gain";
+ o->preobserve_insn = po_tmpl;
+ o->preobserve_insn.chanspec = CR_PACK(0,0,0);
+ o->preobserve_insn.data = &o->preobserve_data;
+ o->observe_insn = tmpl;
+ o->observe_insn.chanspec =
+ CR_PACK(2,bipolar_lowgain,AREF_OTHER);
+ set_target(ni_ao0_zero_offset,0.0);
+
+ /* ao 0, gain */
+ o = observables + ni_ao0_reference;
+ o->name = "ao 0, reference voltage, low gain";
+ o->preobserve_insn = po_tmpl;
+ o->preobserve_insn.chanspec = CR_PACK(0,0,0);
+ o->preobserve_insn.data = &o->preobserve_data;
+ o->observe_insn = tmpl;
+ o->observe_insn.chanspec =
+ CR_PACK(6,bipolar_lowgain,AREF_OTHER);
+ set_target(ni_ao0_reference,5.0);
+ o->target -= voltage_reference;
+
+ /* ao 1, zero offset */
+ o = observables + ni_ao1_zero_offset;
+ o->name = "ao 1, zero offset, low gain";
+ o->preobserve_insn = po_tmpl;
+ o->preobserve_insn.chanspec = CR_PACK(1,0,0);
+ o->preobserve_insn.data = &o->preobserve_data;
+ o->observe_insn = tmpl;
+ o->observe_insn.chanspec =
+ CR_PACK(3,bipolar_lowgain,AREF_OTHER);
+ set_target(ni_ao1_zero_offset,0.0);
+
+ /* ao 1, gain */
+ o = observables + ni_ao1_reference;
+ o->name = "ao 1, reference voltage, low gain";
+ o->preobserve_insn = po_tmpl;
+ o->preobserve_insn.chanspec = CR_PACK(1,0,0);
+ o->preobserve_insn.data = &o->preobserve_data;
+ o->observe_insn = tmpl;
+ o->observe_insn.chanspec =
+ CR_PACK(7,bipolar_lowgain,AREF_OTHER);
+ set_target(ni_ao1_reference,5.0);
+ o->target -= voltage_reference;
+
+ }
+ n_observables = ni_ao1_reference + 1;
+}
+
+void cal_ni_daqcard_ai_16xe_50(void)
+{
+ // daqcard
+ postgain_cal(ni_zero_offset_low,ni_zero_offset_high,2);
+ cal1(ni_zero_offset_high,8);
+ cal1(ni_reference_low,0);
+}
+
+void cal_ni_16e_1(void)
+{
+ // 16e-2
+ postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
+ cal1(ni_zero_offset_high,0);
+ cal1(ni_reference_low,3);
+ cal1(ni_unip_offset_low,2);
+ if(do_output){
+ cal1(ni_ao0_zero_offset,5);
+ cal1(ni_ao0_reference,6);
+ cal1(ni_ao1_zero_offset,8);
+ cal1(ni_ao1_reference,9);
+ }
+}
+
+void cal_ni_16e_10(void)
+{
+ // 16e-10 (old)
+ postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
+ cal1(ni_zero_offset_high,10);
+ cal1(ni_zero_offset_high,0);
+ cal1(ni_reference_low,3);
+ cal1(ni_unip_offset_low,2);
+ if(do_output){
+ cal1(ni_ao0_zero_offset,5); // guess
+ cal1(ni_ao0_reference,6); // guess
+ cal1(ni_ao0_zero_offset,8); // guess
+ cal1(ni_ao0_reference,9); // guess
+ }
+}
+
+void cal_ni_16xe_50(void)
+{
+ // 16xe-50 (old) (same as daqcard?)
+ postgain_cal(ni_zero_offset_low,ni_zero_offset_high,2);
+ cal1(ni_zero_offset_high,8);
+ cal1(ni_reference_low,0);
+ if(do_output){
+ // unknown
+ }
+}
+
+void cal_ni_6035e(void)
+{
+ // 6035e (old)
+ postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
+ cal1(ni_zero_offset_high,0);
+ cal1(ni_reference_low,3);
+ if(do_output){
+ // unknown
+ }
+}
+
+void cal_ni_6071e(void)
+{
+ // 6071e (old)
+ postgain_cal(ni_zero_offset_low,ni_zero_offset_high,1);
+ cal1(ni_zero_offset_high,0);
+ cal1(ni_reference_low,3);
+ if(do_output){
+ // unknown
+ }
+}
+
+
+double ni_get_reference(int lsb_loc,int msb_loc)
+{
+ int lsb,msb;
+ int uv;
+ double ref;
+
+ lsb=read_eeprom(lsb_loc);
+ msb=read_eeprom(msb_loc);
+ printf("lsb=%d msb=%d\n",read_eeprom(425),read_eeprom(426));
+
+ uv=lsb | (msb<<8);
+ if(uv>=0x8000)uv-=0x10000;
+ ref=5.000+1.0e-6*uv;
+ printf("ref=%g\n",ref);
+
+ return ref;
+}
+
+void cal_ni_unknown(void)
+{
+ comedi_range *range;
+ int bipolar_lowgain;
+ int bipolar_highgain;
+ int unipolar_lowgain;
+ int have_ao = 1;
+
+ reset_caldacs();
+ printf("Warning: device not calibrated due to insufficient information\n");
+ printf("Please send this output to <ds@schleef.org>\n");
+ printf("$Id$\n");
+ printf("Device name: %s\n",comedi_get_board_name(dev));
+ printf("Comedi version: %d.%d.%d\n",
+ (comedi_get_version_code(dev)>>16)&0xff,
+ (comedi_get_version_code(dev)>>8)&0xff,
+ (comedi_get_version_code(dev))&0xff);
+
+ bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
+ bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
+ unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
+
+ /* 0 offset, low gain */
+ range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+ DPRINT(0,"bipolar zero offset, low gain [%g,%g]\n",
+ range->min,range->max);
+ channel_dependence(0,bipolar_lowgain);
+
+ /* 0 offset, high gain */
+ range = comedi_get_range(dev,ad_subdev,0,bipolar_highgain);
+ DPRINT(0,"bipolar zero offset, high gain [%g,%g]\n",
+ range->min,range->max);
+ channel_dependence(0,bipolar_highgain);
+
+ /* unip/bip offset */
+ range = comedi_get_range(dev,ad_subdev,0,unipolar_lowgain);
+ DPRINT(0,"unipolar zero offset, low gain [%g,%g]\n",
+ range->min,range->max);
+ channel_dependence(0,unipolar_lowgain);
+
+ /* voltage reference */
+ range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+ DPRINT(0,"bipolar voltage reference, low gain [%g,%g]\n",
+ range->min,range->max);
+ channel_dependence(5,bipolar_lowgain);
+
+ have_ao = (comedi_get_subdevice_type(dev,da_subdev)==COMEDI_SUBD_AO);
+ if(have_ao){
+ int ao_chan;
+
+ /* ao 0, zero offset */
+ ao_chan = 0;
+ set_ao(dev,da_subdev,ao_chan,0,0.0);
+ range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+ DPRINT(0,"ao 0, zero offset, low gain [%g,%g]\n",
+ range->min,range->max);
+ channel_dependence(2,bipolar_lowgain);
+
+ /* ao 0, gain */
+ ao_chan = 0;
+ set_ao(dev,da_subdev,ao_chan,0,5.0);
+ range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+ DPRINT(0,"ao 0, gain, low gain [%g,%g]\n",
+ range->min,range->max);
+ channel_dependence(6,bipolar_lowgain);
+
+ /* ao 1, zero offset */
+ ao_chan = 1;
+ set_ao(dev,da_subdev,ao_chan,0,0.0);
+ range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+ DPRINT(0,"ao 1, zero offset, low gain [%g,%g]\n",
+ range->min,range->max);
+ channel_dependence(3,bipolar_lowgain);
+
+ /* ao 1, gain */
+ ao_chan = 1;
+ set_ao(dev,da_subdev,ao_chan,0,5.0);
+ range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+ DPRINT(0,"ao 1, gain, low gain [%g,%g]\n",
+ range->min,range->max);
+ channel_dependence(7,bipolar_lowgain);
+ }
+
+ cal_ni_results();
+}
+
+void cal_ni_results(void)
+{
+ comedi_range *range;
+ int bipolar_lowgain;
+ int bipolar_highgain;
+ int unipolar_lowgain;
+ //int have_ao;
+ char s[32];
+
+ bipolar_lowgain = get_bipolar_lowgain(dev,ad_subdev);
+ bipolar_highgain = get_bipolar_highgain(dev,ad_subdev);
+ unipolar_lowgain = get_unipolar_lowgain(dev,ad_subdev);
+
+ /* 0 offset, low gain */
+ range = comedi_get_range(dev,ad_subdev,0,bipolar_lowgain);
+ read_chan2(s,0,bipolar_lowgain);
+ DPRINT(0,"bipolar zero offset, low gain [%g,%g]: %s\n",
+ range->min,range->max,s);
+
+ /* 0 offset, high gain */
+ range = comedi_get_range(dev,ad_subdev,0,bipolar_highgain);
+ read_chan2(s,0,bipolar_highgain);
+ DPRINT(0,"bipolar zero offset, high gain [%g,%g]: %s\n",
+ range->min,range->max,s);
+
+ /* unip/bip offset */
+ range = comedi_get_range(dev,ad_subdev,0,unipolar_lowgain);
+ read_chan2(s,0,unipolar_lowgain);
+ DPRINT(0,"unipolar zero offset, low gain [%g,%g]: %s\n",
+ range->min,range->max,s);
+
+}
+
+#if 0
+void ni_mio_ai_postgain_cal(void)
+{
+ linear_fit_t l;
+ double offset_r0;
+ double offset_r7;
+ double gain;
+ double a;
+
+ check_gain_chan_x(&l,CR_PACK(0,0,AREF_OTHER),1);
+ offset_r0=linear_fit_func_y(&l,caldacs[1].current);
+ printf("offset r0 %g\n",offset_r0);
+
+ check_gain_chan_x(&l,CR_PACK(0,7,AREF_OTHER),1);
+ offset_r7=linear_fit_func_y(&l,caldacs[1].current);
+ printf("offset r7 %g\n",offset_r7);
+
+ gain=l.slope;
+
+ a=(offset_r0-offset_r7)/(200.0-1.0);
+ a=caldacs[1].current-a/gain;
+
+ printf("%g\n",a);
+
+ caldacs[1].current=rint(a);
+ update_caldac(1);
+}
+
+void ni_mio_ai_postgain_cal_2(int chan,int dac,int range_lo,int range_hi,double gain)
+{
+ double offset_lo,offset_hi;
+ linear_fit_t l;
+ double slope;
+ double a;
+
+ check_gain_chan_x(&l,CR_PACK(chan,range_lo,AREF_OTHER),dac);
+ offset_lo=linear_fit_func_y(&l,caldacs[dac].current);
+ printf("offset lo %g\n",offset_lo);
+
+ check_gain_chan_x(&l,CR_PACK(chan,range_hi,AREF_OTHER),dac);
+ offset_hi=linear_fit_func_y(&l,caldacs[dac].current);
+ printf("offset hi %g\n",offset_hi);
+
+ slope=l.slope;
+
+ a=(offset_lo-offset_hi)/(gain-1.0);
+ a=caldacs[dac].current-a/slope;
+
+ printf("%g\n",a);
+
+ caldacs[dac].current=rint(a);
+ update_caldac(dac);
+}
+#endif
+