make it loop through gain/offset calibrations until the readings are

within specified tolerance of targets.
This commit is contained in:
Frank Mori Hess 2003-06-17 23:57:49 +00:00
parent 57f038f35c
commit 49b521c21c
5 changed files with 114 additions and 28 deletions

View file

@ -17,10 +17,12 @@
* (at your option) any later version. *
* *
***************************************************************************/
#define _GNU_SOURCE
#include "calib.h"
#include <assert.h>
#include <stdlib.h>
#include <math.h>
void generic_do_cal( calibration_setup_t *setup,
comedi_calibration_setting_t *saved_cal, int observable, int caldac )
@ -132,49 +134,84 @@ static void generic_prep_adc_for_dac( calibration_setup_t *setup, const generic_
adc_channel, adc_range, 0, calibration );
}
static int dac_cal_is_good( calibration_setup_t *setup, const generic_layout_t *layout,
unsigned int channel, unsigned int range )
{
if( fabs( fractional_offset( setup, setup->da_subdev, channel, range,
layout->dac_ground_observable( setup, channel, range ) ) ) > layout->dac_fractional_tolerance )
return 0;
else if( fabs( fractional_offset( setup, setup->da_subdev, channel, range,
layout->dac_high_observable( setup, channel, range ) ) ) > layout->dac_fractional_tolerance )
return 0;
return 1;
}
static void generic_do_dac_channel( calibration_setup_t *setup, const generic_layout_t *layout ,
comedi_calibration_t *calibration, comedi_calibration_setting_t *current_cal,
unsigned int channel, unsigned int range )
{
static const int max_iterations = 4;
int i;
generic_prep_adc_for_dac( setup, layout, calibration,
layout->dac_ground_observable( setup, channel, range ) );
generic_do_relative( setup, current_cal, layout->dac_high_observable( setup, channel, range ),
layout->dac_ground_observable( setup, channel, range ),layout->dac_gain( channel ) );
generic_do_cal( setup, current_cal, layout->dac_ground_observable( setup, channel, range ),
layout->dac_offset( channel ) );
generic_do_relative( setup, current_cal, layout->dac_high_observable( setup, channel, range ),
layout->dac_ground_observable( setup, channel, range ), layout->dac_gain_fine( channel ) );
generic_do_cal( setup, current_cal, layout->dac_ground_observable( setup, channel, range ),
layout->dac_offset_fine( channel ) );
for( i = 0; i < max_iterations; i++ )
{
generic_do_relative( setup, current_cal, layout->dac_high_observable( setup, channel, range ),
layout->dac_ground_observable( setup, channel, range ),layout->dac_gain( channel ) );
generic_do_cal( setup, current_cal, layout->dac_ground_observable( setup, channel, range ),
layout->dac_offset( channel ) );
generic_do_relative( setup, current_cal, layout->dac_high_observable( setup, channel, range ),
layout->dac_ground_observable( setup, channel, range ), layout->dac_gain_fine( channel ) );
generic_do_cal( setup, current_cal, layout->dac_ground_observable( setup, channel, range ),
layout->dac_offset_fine( channel ) );
if( dac_cal_is_good( setup, layout, channel, range ) ) break;
}
if( i == max_iterations )
DPRINT(0, "WARNING: unable to calibrate dac channel %i, range %i to desired %g tolerance\n",
channel, range, layout->dac_fractional_tolerance );
current_cal->subdevice = setup->da_subdev;
sc_push_channel( current_cal, channel );
sc_push_range( current_cal, range );
sc_push_aref( current_cal, SC_ALL_AREFS );
}
static int adc_cal_is_good( calibration_setup_t *setup, const generic_layout_t *layout,
unsigned int channel, unsigned int range )
{
if( fabs( fractional_offset( setup, setup->ad_subdev, channel, range,
layout->adc_ground_observable( setup, channel, range ) ) ) > layout->adc_fractional_tolerance )
return 0;
else if( fabs( fractional_offset( setup, setup->ad_subdev, channel, range,
layout->adc_high_observable( setup, channel, range ) ) ) > layout->adc_fractional_tolerance )
return 0;
return 1;
}
static void generic_do_adc_channel( calibration_setup_t *setup, const generic_layout_t *layout,
comedi_calibration_setting_t *current_cal, unsigned int channel, unsigned int range )
{
/* make sure unipolar ground observable isn't out-of-range before
* doing gain calibrations */
if( is_unipolar( setup->dev, setup->ad_subdev, channel, range ) )
static const int max_iterations = 4;
int i;
for( i = 0; i < max_iterations; i++ )
{
generic_do_relative( setup, current_cal, layout->adc_high_observable( setup, channel, range ),
layout->adc_ground_observable( setup, channel, range ), layout->adc_gain( channel ) );
generic_do_cal( setup, current_cal, layout->adc_ground_observable( setup, channel, range ),
layout->adc_offset( channel ) );
generic_do_relative( setup, current_cal, layout->adc_high_observable( setup, channel, range ),
layout->adc_ground_observable( setup, channel, range ), layout->adc_gain_fine( channel ) );
generic_do_cal( setup, current_cal, layout->adc_ground_observable( setup, channel, range ),
layout->adc_offset_fine( channel ) );
if( adc_cal_is_good( setup, layout, channel, range ) ) break;
}
generic_do_relative( setup, current_cal, layout->adc_high_observable( setup, channel, range ),
layout->adc_ground_observable( setup, channel, range ), layout->adc_gain( channel ) );
generic_do_cal( setup, current_cal, layout->adc_ground_observable( setup, channel, range ),
layout->adc_offset( channel ) );
generic_do_relative( setup, current_cal, layout->adc_high_observable( setup, channel, range ),
layout->adc_ground_observable( setup, channel, range ), layout->adc_gain_fine( channel ) );
generic_do_cal( setup, current_cal, layout->adc_ground_observable( setup, channel, range ),
layout->adc_offset_fine( channel ) );
if( i == max_iterations )
DPRINT(0, "WARNING: unable to calibrate adc channel %i, range %i to desired %g tolerance\n",
channel, range, layout->adc_fractional_tolerance );
current_cal->subdevice = setup->ad_subdev;
sc_push_channel( current_cal, channel );
sc_push_range( current_cal, range );
@ -395,5 +432,7 @@ void init_generic_layout( generic_layout_t *layout )
layout->adc_ground_observable = dummy_observable;
layout->dac_high_observable = dummy_observable;
layout->dac_ground_observable = dummy_observable;
layout->do_adc_unipolar_postgain = 1;
layout->adc_fractional_tolerance = INFINITY;
layout->adc_fractional_tolerance = INFINITY;
layout->do_adc_unipolar_postgain = 0;
}

View file

@ -152,6 +152,11 @@ int is_bipolar( comedi_t *dev, unsigned int subdevice,
int is_unipolar( comedi_t *dev, unsigned int subdevice,
unsigned int channel, unsigned int range );
double fractional_offset( calibration_setup_t *setup, int subdevice,
unsigned int channel, unsigned int range, int obs );
double get_tolerance( calibration_setup_t *setup, int subdevice,
double num_bits );
/* other */
void comedi_nanodelay(comedi_t *dev, unsigned int delay);
@ -251,6 +256,8 @@ typedef struct
unsigned int channel, unsigned int range );
int (*dac_ground_observable)( const calibration_setup_t *setup,
unsigned int channel, unsigned int range );
double adc_fractional_tolerance;
double dac_fractional_tolerance;
unsigned do_adc_unipolar_postgain : 1;
} generic_layout_t;
void init_generic_layout( generic_layout_t *layout );

View file

@ -64,11 +64,6 @@ static struct board_struct boards[]={
static const int num_boards = ( sizeof(boards) / sizeof(boards[0]) );
enum observables_1602_16 {
OBS_0V_RANGE_10V_BIP_1602_16 = 0,
OBS_7V_RANGE_10V_BIP_1602_16,
};
enum calibration_source_1xxx
{
CS_1XXX_GROUND = 0,
@ -140,8 +135,10 @@ static int setup_cb_pci_1602_16( calibration_setup_t *setup )
DPRINT(0, "WARNING: you need comedi driver version 0.7.67 or later\n"
"for this calibration to work properly\n" );
}
setup->sv_settling_time_ns = 10000000;
setup->sv_order = 12;
retval = init_observables_1xxx( setup );
if( retval < 0 ) return retval;
setup_caldacs( setup, caldac_subdev );
setup_caldacs( setup, calpot_subdev );
@ -424,6 +421,8 @@ static int cal_cb_pci_1xxx( calibration_setup_t *setup )
layout.adc_ground_observable = ai_ground_observable_1xxx;
layout.dac_high_observable = ao_high_observable_1xxx;
layout.dac_ground_observable = ao_ground_observable_1xxx;
layout.adc_fractional_tolerance = get_tolerance( setup, setup->ad_subdev, 1 );
layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1 );
return generic_cal_by_range( setup, &layout );
}
@ -489,6 +488,8 @@ static int cal_cb_pci_1602_16( calibration_setup_t *setup )
layout.adc_ground_observable = ai_ground_observable_1xxx;
layout.dac_high_observable = ao_high_observable_1xxx;
layout.dac_ground_observable = ao_ground_observable_1xxx;
layout.adc_fractional_tolerance = get_tolerance( setup, setup->ad_subdev, 1 );
layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1 );
/* The bipolar postgain calibration should be good for both
* bipolar and unipolar ranges, so disable separate
* unipolar postgain offset calibration (it will fail

View file

@ -763,6 +763,8 @@ static int cal_cb_pci_64xx( calibration_setup_t *setup )
layout.adc_ground_observable = ai_ground_observable_index_64xx;
layout.dac_high_observable = ao_high_observable_index_64xx;
layout.dac_ground_observable = ao_ground_observable_index_64xx;
layout.adc_fractional_tolerance = get_tolerance( setup, setup->ad_subdev, 1 );
layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1 );
return generic_cal_by_range( setup, &layout );
}
@ -807,6 +809,8 @@ static int cal_cb_pci_60xx( calibration_setup_t *setup )
layout.adc_ground_observable = ai_ground_observable_index_60xx;
layout.dac_high_observable = ao_high_observable_index_60xx;
layout.dac_ground_observable = ao_ground_observable_index_60xx;
layout.adc_fractional_tolerance = get_tolerance( setup, setup->ad_subdev, 1 );
layout.dac_fractional_tolerance = get_tolerance( setup, setup->da_subdev, 1 );
return generic_cal_by_range( setup, &layout );
}
@ -828,6 +832,7 @@ static int cal_cb_pci_4020( calibration_setup_t *setup )
layout.adc_gain = adc_gain_4020;
layout.adc_high_observable = ai_high_observable_index_4020;
layout.adc_ground_observable = ai_low_observable_index_4020;
layout.adc_fractional_tolerance = get_tolerance( setup, setup->ad_subdev, 1 );
return generic_cal_by_channel_and_range( setup, &layout );
}

View file

@ -1587,4 +1587,38 @@ double very_low_target( comedi_t *dev, unsigned int subdevice,
return comedi_to_phys( 1, range_ptr, max_data ) / 2.0;
}
double fractional_offset( calibration_setup_t *setup, int subdevice,
unsigned int channel, unsigned int range, int obs )
{
comedi_range *range_ptr;
double target = setup->observables[obs].target;
double reading;
unsigned int chanspec = setup->observables[obs].observe_insn.chanspec;
new_sv_t sv;
if( subdevice < 0 || obs < 0 ) return 0.0;
range_ptr = comedi_get_range( setup->dev, subdevice, channel, range );
assert( range_ptr != NULL );
comedi_set_global_oor_behavior( COMEDI_OOR_NUMBER );
preobserve( setup, obs);
my_sv_init( &sv, setup, setup->ad_subdev, chanspec );
new_sv_measure( setup->dev, &sv );
reading = sv.average;
return ( reading - target ) / ( range_ptr->max - range_ptr->min );
}
double get_tolerance( calibration_setup_t *setup, int subdevice,
double num_bits )
{
int maxdata;
if( subdevice < 0 ) return INFINITY;
maxdata = comedi_get_maxdata( setup->dev, subdevice, 0 );
assert( maxdata > 0 );
return num_bits / maxdata;
}