Split up comedi_calibrate.c, additional hacking

This commit is contained in:
David Schleef 2001-10-09 23:45:16 +00:00
parent 909b845030
commit f3681b41fa
4 changed files with 717 additions and 578 deletions

View file

@ -7,11 +7,12 @@ LDFLAGS += -L../lib/ -lcomedi -lm
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)

181
comedi_calibrate/calib.h Normal file
View file

@ -0,0 +1,181 @@
#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

View file

@ -33,203 +33,38 @@
#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;
comedi_t *dev;
typedef struct{
char *name;
int ad_subdev;
int da_subdev;
int eeprom_subdev;
int caldac_subdev;
comedi_insn preobserve_insn;
lsampl_t preobserve_data;
comedi_insn observe_insn;
//comedi_range *range;
//int maxdata;
double target;
}observable;
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 },
@ -240,7 +75,7 @@ struct board_struct drivers[] = {
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[] = {
@ -257,6 +92,8 @@ 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 },
};
@ -264,8 +101,6 @@ int main(int argc, char *argv[])
{
char *fn = NULL;
int c;
char *drivername = NULL;
char *devicename = NULL;
int i;
struct board_struct *this_board;
int index;
@ -353,147 +188,12 @@ ok:
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;
@ -641,264 +341,6 @@ void cal1(int obs, int dac)
}
}
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;

515
comedi_calibrate/ni.c Normal file
View file

@ -0,0 +1,515 @@
/*
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