Two point calibration; 8/16 bit MCU; complex operation

Thread Starter

aamirali

Joined Feb 2, 2012
412
1. I have to measure voltage in 8/16 bit MCU & have to do its calibration also.
I have selected 2 point calibration as it corrects both gain & offset error.

2. Voltage to measure = 0-5V.
Let measured at two pint: Vm1 & Vm2
Let actual volatge at those point = Vo1 & Vo2

Gain error = (Vm2-Vm1)/ (Vo1-Vo2)
offset error = Vm1 - (gain_error * Vo1)

reading = (Vm - offset_error)/gain_error;

3. Problem is this involves complex math & generally goes to float. Now using float operation on 8/16 bit MCU is very intensive.

Queries:
1. Is there any better method for which I don't have to do such float calculation. If yes any example code?

2. If no to 1, can above method be made less operation intensive like by fixed point math. If yes any example code
 

NorthGuy

Joined Jun 28, 2014
611
Is it self-calibrating, or you're doing the calibration once, do calculation outside MCU, and then program MCU to only do "reading = ..."?
 

MrChips

Joined Oct 2, 2009
30,823
I never use floating-point for such simple calculations.

For example, I can convert from degrees C to F and F to C to two decimal places without having to resort to floating point.
 

NorthGuy

Joined Jun 28, 2014
611
For the calibration, you must do division, but even if done in MCU it is not done very often. "User" cannot want it at 10kHz, right? No need to optimize that part.

For your main fomula, you pre-calculate:

k = 65536/gain_error;

Then you do

reading = (Vm - offset_error)*k>>16;

(>>16 is the same as /65536 but is really fast)

Multiplication is way faster than division, so it'll be efficient.

Measure voltage in mV. Integers will give you enough resolution.

You will need to find a correct sze for your varibales so that it doesn't overflow.
 

Thread Starter

aamirali

Joined Feb 2, 2012
412
@MrChips :

Done calibration at two pints 0.5V & 4.5V

Vm = 0.41V , 4.7V
Vo = .5V , 4.5V


So offset error = -0.12625
gain error = 1.0725


Edit: adc is 10 bit. Vref = 5V. Measurable range = 0-5V
 
Last edited:

MrChips

Joined Oct 2, 2009
30,823
What are you actually trying to do?
Analog input voltages are digitzed to binary values, 0-1023 for 10-bit ADC.
Is your software doing a floating point conversion and then displaying voltage as in a digital voltmeter?
 

Thread Starter

aamirali

Joined Feb 2, 2012
412
@MrChips :

  1. actually I wanted to show how much voltage value I get when I apply 0.5v & 4.5V. It code i have only 10 bit adc data
  2. Below are actual digital values which i get
  3. V0 = 0.5V , digital data I get = 84
  4. V0= 4.5V , digital data I get = 962

    Now I have to apply offset error & gain error.
 

MrChips

Joined Oct 2, 2009
30,823
I still do not understand what you are doing.
Forget about gain and offset error for now. I understand that and how to calculate the correct results.
What are you using to show the result?
What numbers do you want to display?
 

Thread Starter

aamirali

Joined Feb 2, 2012
412
1. I have measured the voltage 0-5V.
2. Since adc have offset & gain errors, I have to adjust them, before sending the final data over uart to PC.
I cannot put the error data to PC. Since user may connect the board I made to any PC. So have to calculate & store error correction values in MCU only.
3. As shown in previous post, calculating these errors, include float.
 

MrChips

Joined Oct 2, 2009
30,823
There is no need to do floating point arithmetic or to transmit fractional decimals to a PC.
You can simplify the data transmission by sending data scaled to 0-500 or 0-1023.

I will assume that your calibration points are fixed at 0.5V and 4.5V.

Suppose the ADC recorded value at 0.5V input is x1.
Suppose the ADC recoded value at 4.5V input is x2.

We will scale the voltages by 100.

Then the slope m = (450 - 50)/(x2-x1) = 400/(x2 - x1)
Don't perform the calculation yet. Simply record the difference dx = x2 - x1
Hence the slope m = 400/dx

The intercept c = 50 - m*x1

Hence any ADC value x is corrected to value y given by

y = m*x + c

y = m*x + 50 - m*x1

y = m*(x - x1) + 50

y = (x-x1)*400/dx + 50

This reduces to one multiplication and one division using integer arithmetic.
 
Top