adc2.c -- Determine scale and offset calibration for Analog to Digital converter input.
/* adc2.c */
/* Copyright(c) 1991-2002 by Motion Engineering, Inc. All rights reserved.
*
* This software contains proprietary and confidential information of
* Motion Engineering Inc., and its suppliers. Except as may be set forth
* in the license agreement under which this software is supplied, use,
* disclosure, or reproduction is prohibited without the prior express
* written consent of Motion Engineering, Inc.
*/
#if defined(MEI_RCS)
static const char MEIAppRCS[] =
"$Header: /MainTree/XMPLib/XMP/app/adc2.c 5 8/01/01 2:08p Kevinh $";
#endif
#if defined(ARG_MAIN_RENAME)
#define main adc2Main
argMainRENAME(main, adc2)
#endif
/*
:Determine scale and offset calibration for Analog to Digital converter input.
This sample code demonstrates how to determine calibration factors for
an ADC input channel. This sample requires an external source to generate
the analog voltage into an ADC channel.
The calibration factors are determined by sampling two known voltages.
The default voltages are 5 volts and -5 volts. Other voltages can be set by
changing the definitions of the #define's LINE_VOLTAGE_1 and LINE_VOLTAGE_2.
This default input lines are Analog_IN_0 and Analog_IN_1. These can be changed
by changing the definitions of the #define's LINE_INPUT_1 and LINE_INPUT_2.
ATTENTION: The uncertanties of the input voltage lines should also be specified
for an accurate analysis. The smaller these uncertainties, the better analysis
you will receive. The default values are 0.01 Volts and can be specified by
changing the #define's LINE_VOLTAGE_UNCERTAINTY_1 and
LINE_VOLTAGE_UNCERTAINTY_2.
Using the ADC values, voltage values, and uncertainties, displayAdcAnalysis()
determines the linear "scale" factor (m) and the "offset" (b). These
calibration factors can be applied to future ADC value conversions in
application code, to improve the ADC accuracy and analysis of the values read.
Warning! This is a sample program to assist in the integration of the
XMP motion controller with your application. It may not contain all
of the logic and safety features that your application requires.
*/
#include <stdlib.h>
#include <stdio.h>
#include <math.h>
#include "stdmpi.h"
#include "stdmei.h"
#include "apputil.h"
#define ADC_COUNT (8)
#define ADC_RANGE (10.0) /* 10.0, 5.0, 2.5, or 1.25 volts */
#define LINE_VOLTAGE_1 (5.00)
#define LINE_VOLTAGE_2 (-5.00)
#define LINE_VOLTAGE_UNCERTAINTY_1 (0.01)
#define LINE_VOLTAGE_UNCERTAINTY_2 (0.01)
#define LINE_INPUT_1 (MEIAdcMuxANALOG_IN_0)
#define LINE_INPUT_2 (MEIAdcMuxANALOG_IN_1)
#define SAMPLES (1000) /* Samples per input line */
/* Perform basic command line parsing. (-control -server -port -trace) */
void basicParsing(int argc,
char *argv[],
MPIControlType *controlType,
MPIControlAddress *controlAddress)
{
long argIndex;
/* Parse command line for Control type and address */
argIndex = argControl(argc, argv, controlType, controlAddress);
/* Check for unknown/invalid command line arguments */
if (argIndex < argc) {
fprintf(stderr,"usage: %s %s\n", argv[0], ArgUSAGE);
exit(MPIMessageARG_INVALID);
}
}
/* Create and initialize MPI objects */
void programInit(MPIControl *control,
MPIControlType controlType,
MPIControlAddress *controlAddress,
MPIAdc *adc,
long adcCount)
{
long index;
long returnValue;
/* Create motion controller object */
*control =
mpiControlCreate(controlType,
controlAddress);
msgCHECK(mpiControlValidate(*control));
/* Initialize motion controller */
returnValue =
mpiControlInit(*control);
msgCHECK(returnValue);
/* Create adc objects */
for (index = 0; index < adcCount; index++) {
adc[index] =
mpiAdcCreate(*control,
index);
msgCHECK(mpiAdcValidate(adc[index]));
}
}
/* Perform certain cleanup actions and delete MPI objects */
void programCleanup(MPIControl *control,
MPIAdc *adc,
long adcCount)
{
long index;
long returnValue;
/* Delete adc objects */
for (index = 0; index < adcCount; index++) {
returnValue =
mpiAdcDelete(adc[index]);
msgCHECK(returnValue);
}
/* Delete motion controller object */
returnValue =
mpiControlDelete(*control);
msgCHECK(returnValue);
}
/* Enable adcs */
void enableAdcs(MPIControl control,
long adcCount)
{
MPIControlConfig controlConfig;
long returnValue;
/* Read controller configuration */
returnValue =
mpiControlConfigGet(control,
&controlConfig,
NULL);
msgCHECK(returnValue);
controlConfig.adcCount = adcCount;
/* Write controller configuration */
returnValue =
mpiControlConfigSet(control,
&controlConfig,
NULL);
msgCHECK(returnValue);
}
/* Configure adc object */
void adcConfigure(MPIAdc adc,
MEIAdcMux input,
double range)
{
MPIAdcConfig adcConfig;
MEIAdcConfig adcConfigXmp;
long returnValue;
/* Read adc configuration */
returnValue =
mpiAdcConfigGet(adc,
&adcConfig,
&adcConfigXmp);
msgCHECK(returnValue);
/* Set voltage range */
adcConfig.range = range;
/* Set voltage input */
adcConfigXmp.mux = input;
/* Write adc configuration */
returnValue =
mpiAdcConfigSet(adc,
&adcConfig,
&adcConfigXmp);
msgCHECK(returnValue);
}
/* Calculate stastical input information */
void getAdcInputInfo(MPIAdc *adc,
long adcCount,
long samples,
double *inputMean,
double *inputVar)
{
MPIAdcConfig adcConfig;
double sumInput = 0.0;
double sumInputSq = 0.0;
long input;
long index;
long returnValue;
/* Read adc configuration */
returnValue =
mpiAdcConfigGet(adc[0],
&adcConfig,
NULL);
msgCHECK(returnValue);
for (index=0; index<samples; index++) {
/* Read ADC input value */
returnValue =
mpiAdcInput(adc[index%adcCount],
(unsigned long*)&input);
msgCHECK(returnValue);
/* Record input information */
sumInput+=input;
sumInputSq+=input * 1.0 * input;
if (index%adcCount == 0) {
/* Wait one controller sample */
meiControlSampleWait(mpiAdcControl(adc[0]),
1);
}
}
/* Calculate stastical input information */
*inputMean = sumInput / samples;
*inputVar = (sumInputSq - (sumInput*sumInput)/samples)/(samples-1);
}
/* Display ADC analysis */
void displayAdcAnalysis(double *lineVoltage,
double *lineUncertainty,
double *inputMean,
double *inputVar)
{
double b;
double bStdDev;
double m;
double mStdDev;
double deltaInput;
double deltaInputSq;
deltaInput = inputMean[1] - inputMean[0];
deltaInputSq = deltaInput * deltaInput;
b = (lineVoltage[0]*inputMean[1] - lineVoltage[1]*inputMean[0]) /
deltaInput;
m = (lineVoltage[1] - lineVoltage[0]) / deltaInput;
bStdDev = sqrt(
((b - lineVoltage[1])*(b - lineVoltage[1])*inputVar[0] +
(b - lineVoltage[0])*(b - lineVoltage[0])*inputVar[1] +
inputMean[0]*inputMean[0]*lineUncertainty[1]*lineUncertainty[1] +
inputMean[1]*inputMean[1]*lineUncertainty[0]*lineUncertainty[0]) /
deltaInputSq);
mStdDev = sqrt(
(m*m*(inputVar[0] + inputVar[1]) +
lineUncertainty[0]*lineUncertainty[0] +
lineUncertainty[1]*lineUncertainty[1]) /
deltaInputSq);
printf("Voltage = m * (ADC input) + b\n\n"
" m = %le +/- %le \t(Volts/ADC_UNIT)\n"
" b = %le +/- %le \t(Volts)\n\n",
m, mStdDev,
b, bStdDev);
}
int main(int argc,
char *argv[])
{
MPIControl control;
MPIControlType controlType;
MPIControlAddress controlAddress;
MPIAdc adc[ADC_COUNT];
double inputMean[2];
double inputVar[2];
double lineVoltage[2] =
{LINE_VOLTAGE_1, LINE_VOLTAGE_2};
double lineUncertainty[2] =
{LINE_VOLTAGE_UNCERTAINTY_1, LINE_VOLTAGE_UNCERTAINTY_2};
long index;
/* Perform basic command line parsing. (-control -server -port -trace) */
basicParsing(argc,
argv,
&controlType,
&controlAddress);
/* Create and initialize MPI objects */
programInit(&control,
controlType,
&controlAddress,
adc,
ADC_COUNT);
/* Enable adcs */
enableAdcs(control,
ADC_COUNT);
/* Configure adc objects to read LINE_INPUT_1 */
for (index = 0; index < ADC_COUNT; index++) {
adcConfigure(adc[index],
LINE_INPUT_1,
ADC_RANGE);
}
/* Delay so that adc object can read values from LINE_INPUT_1 */
meiPlatformSleep(1);
/* Calculate stastical input information for LINE_INPUT_1 */
getAdcInputInfo(adc,
ADC_COUNT,
SAMPLES,
&inputMean[0],
&inputVar[0]);
/* Configure adc objects to read LINE_INPUT_2 */
for (index = 0; index < ADC_COUNT; index++) {
adcConfigure(adc[index],
LINE_INPUT_2,
ADC_RANGE);
}
/* Delay so that adc object can read values from LINE_INPUT_1 */
meiPlatformSleep(1);
/* Calculate stastical input information for LINE_INPUT_2 */
getAdcInputInfo(adc,
ADC_COUNT,
SAMPLES,
&inputMean[1],
&inputVar[1]);
/* Display ADC analysis */
displayAdcAnalysis(lineVoltage,
lineUncertainty,
inputMean,
inputVar);
/* Perform certain cleanup actions and delete MPI objects */
programCleanup(&control,
adc,
ADC_COUNT);
return (MPIMessageOK);
}