make it loop through gain/offset calibrations until the readings are
within specified tolerance of targets.
This commit is contained in:
parent
57f038f35c
commit
49b521c21c
5 changed files with 114 additions and 28 deletions
|
@ -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;
|
||||
}
|
||||
|
|
|
@ -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 );
|
||||
|
|
|
@ -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
|
||||
|
|
|
@ -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 );
|
||||
}
|
||||
|
||||
|
|
|
@ -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;
|
||||
}
|
||||
|
|
Loading…
Add table
Reference in a new issue