make it loop through gain/offset calibrations until the readings are
authorFrank Mori Hess <fmhess@speakeasy.net>
Tue, 17 Jun 2003 23:57:49 +0000 (23:57 +0000)
committerFrank Mori Hess <fmhess@speakeasy.net>
Tue, 17 Jun 2003 23:57:49 +0000 (23:57 +0000)
within specified tolerance of targets.

comedi_calibrate/cal_common.c
comedi_calibrate/calib.h
comedi_calibrate/cb.c
comedi_calibrate/cb64.c
comedi_calibrate/comedi_calibrate.c

index 8a8777734875ae533c11f0f9ac7a59e5e0477250..611cb0fdc484dfe912a742a24ff4346de5bbc295 100644 (file)
  *   (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;
 }
index 6e76d84932ad3295c806c1bb466d65fe34156253..7cc9e130269a79a65daf5d19927dd3c19fe6380d 100644 (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 );
index 5e410be12ef051877355971bc722af66eb64ae57..0848367483c2338c7d4959ed14fe8d05166d2e48 100644 (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
index 7ae31156747b1fcffc86aba70e5335c402de6aae..61b1123f0adc7884caf9101440c872e130688608 100644 (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 );
 }
 
index 90b80e6697a23da50cdf2cff4de37618cf5c9e3b..117dc44b64f6fd1f7f1e43a59104c131213acedf 100644 (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;
+}