## K Thermocouple conversion by polynomial conversion formula

8 posts / 0 new
Author
Message

Was writing code to convert thermocouple k type conversion formula for best accuracy. Goal is to use polynomial functions and not the table or other method, that I will write in next code. Currently accuracy is concern. Below is my code, any one found any issue in that?
Currently i have simulated only by putting different millivolt values & cold junction value as 0c.  Any way it can be improved further for accuracy or any other error in code.

```/*
1. Convert the cold-junction temperature (TCJ) to a voltage (VCJ)
2. Add the cold-junction voltage to the measured thermocouple voltage (VCJ + VTC)
3. Convert the summed cold-junction voltage and thermocouple voltage to the thermocouple temperature
(TTC)
*/

#define float32_t  float

const float32_t ci_i0_below0 = 0.000000000000E+00;
const float32_t ci_i1_below0 = 0.394501280250E-01;
const float32_t ci_i2_below0 = 0.236223735980E-04;
const float32_t ci_i3_below0 = -0.328589067840E-06;
const float32_t ci_i4_below0 = -0.499048287770E-08;
const float32_t ci_i5_below0 = -0.675090591730E-10;
const float32_t ci_i6_below0 = -0.574103274280E-12;
const float32_t ci_i7_below0 = -0.310888728940E-14;
const float32_t ci_i8_below0 = -0.104516093650E-16;
const float32_t ci_i9_below0 = -0.198892668780E-19;
const float32_t ci_i10_below0 = -0.163226974860E-22;

const float32_t ci_i0_above0 = -0.176004136860E-01;
const float32_t ci_i1_above0 = 0.389212049750E-01;
const float32_t ci_i2_above0 = 0.185587700320E-04;
const float32_t ci_i3_above0 = -0.994575928740E-07;
const float32_t ci_i4_above0 = 0.318409457190E-09;
const float32_t ci_i5_above0 = -0.560728448890E-12;
const float32_t ci_i6_above0 = 0.560750590590E-15;
const float32_t ci_i7_above0 = -0.320207200030E-18;
const float32_t ci_i8_above0 = 0.971511471520E-22;
const float32_t ci_i9_above0 = -0.121047212750E-25;

const float32_t a0_above0 = 0.118597600000E+00;
const float32_t a1_above0 = -0.118343200000E-03;
const float32_t a2_above0 = 0.126968600000E+03;

const float32_t d0_i0 = 0.0000000E+00;
const float32_t d0_i1 = 2.5173462E+01;
const float32_t d0_i2 = -1.1662878E+00;
const float32_t d0_i3 = -1.0833638E+00;
const float32_t d0_i4 = -8.9773540E-01;
const float32_t d0_i5 = -3.7342377E-01;
const float32_t d0_i6 = -8.6632643E-02;
const float32_t d0_i7 = -1.0450598E-02;
const float32_t d0_i8 = -5.1920577E-04;
const float32_t d0_i9 = 0.0000000E+00;

const float32_t d1_i0 = 0.000000E+00;
const float32_t d1_i1 = 2.508355E+01;
const float32_t d1_i2 = 7.860106E-02;
const float32_t d1_i3 = -2.503131E-01;
const float32_t d1_i4 = 8.315270E-02;
const float32_t d1_i5 = -1.228034E-02;
const float32_t d1_i6 = 9.804036E-04;
const float32_t d1_i7 = -4.413030E-05;
const float32_t d1_i8 = 1.057734E-06;
const float32_t d1_i9 = -1.052755E-08;

const float32_t d2_i0 = -1.318058E+02;
const float32_t d2_i1 = 4.830222E+01;
const float32_t d2_i2 = -1.646031E+00;
const float32_t d2_i3 = 5.464731E-02;
const float32_t d2_i4 = -9.650715E-04;
const float32_t d2_i5 = 8.802193E-06;
const float32_t d2_i6 = -3.110810E-08;
const float32_t d2_i7 = 0.000000E+00;
const float32_t d2_i8 = 0.000000E+00;
const float32_t d2_i9 = 0.000000E+00;

void setup()
{
Serial.begin(9600);

}

void loop()
{
uint32_t err;
float32_t tempc;

err = thermocouple_tempc(54.819f, 0.0f , &tempc);

Serial.print(err);
Serial.print("     ");
Serial.println(tempc);

}

uint32_t thermocouple_tempc(float32_t vtc_mV , float32_t cj_tempc , float32_t *tc_tempc_return)
{
uint32_t err = 0U;
float32_t vcj_mV = 0.0f;
float32_t vsum = 0.0f;
float32_t tempc = 0.0f;

//////////////// STEP-A cold-junction temperature (TCJ) to a voltage (VCJ)
/* convert cj_temp into mv by below equation
*
* E = sum(i=0 to n) c_i t^i.
*
* The equation above 0 °C is of the form
* E = sum(i=0 to n) c_i t^i + a0 exp(a1 (t - a2)^2).
*
*/
if(cj_tempc < -270.0f)
{
err = 1U;  //cold-junction undertemperatyre
}
else if((cj_tempc >= -270.0f) && (cj_tempc < 0.0f))
{
vcj_mV =         ( ci_i0_below0  * pow(cj_tempc , 0U) )
+ ( ci_i1_below0  * pow(cj_tempc , 1U) )
+ ( ci_i2_below0  * pow(cj_tempc , 2U) )
+ ( ci_i3_below0  * pow(cj_tempc , 3U) )
+ ( ci_i4_below0  * pow(cj_tempc , 4U) )
+ ( ci_i5_below0  * pow(cj_tempc , 5U) )
+ ( ci_i6_below0  * pow(cj_tempc , 6U) )
+ ( ci_i7_below0  * pow(cj_tempc , 7U) )
+ ( ci_i8_below0  * pow(cj_tempc , 8U) )
+ ( ci_i9_below0  * pow(cj_tempc , 9U) )
+ ( ci_i10_below0  * pow(cj_tempc , 10U) );
}
else if((cj_tempc >= 0.0f) && (cj_tempc <= 1372.0f))
{
vcj_mV =         ( ci_i0_above0  * pow(cj_tempc , 0U) )
+ ( ci_i1_above0  * pow(cj_tempc , 1U) )
+ ( ci_i2_above0  * pow(cj_tempc , 2U) )
+ ( ci_i3_above0  * pow(cj_tempc , 3U) )
+ ( ci_i4_above0  * pow(cj_tempc , 4U) )
+ ( ci_i5_above0  * pow(cj_tempc , 5U) )
+ ( ci_i6_above0  * pow(cj_tempc , 6U) )
+ ( ci_i7_above0  * pow(cj_tempc , 7U) )
+ ( ci_i8_above0  * pow(cj_tempc , 8U) )
+ ( ci_i9_above0  * pow(cj_tempc , 9U) )
+ ( a0_above0 * ( exp(a1_above0 * pow((cj_tempc - a2_above0), 2U) ) )   );

}
else if(cj_tempc > 1372.0f)
{
err = 2U;    //cold-junction overtemperatyre
}
else
{
err = 3U;    //NAN or unknown error
}

//////////////// STEP-B cold-junction voltage to the measured thermocouple voltage (VCJ + VTC)
if(0U == err)
{
vsum = vcj_mV + vtc_mV;
if(vsum < -5.891f)
{
err = 4U;   //sum voltage falls below convertable range
}
else if((vsum >= -5.891f) && (vsum <= 54.886f))
{
//err = 0U; this is conevertiable range
}
else if(vsum > 54.886f)
{
err = 5U;   //sum voltage above convertable range
}
else
{
err = 6U;  //NAN or unknown error
}

}

//////////////// STEP-C vsum coversion to temperature
if(0U == err)
{
if(vsum < -5.891f)
{
err = 7U;  //under-voltage for final ocnversion
}
else if((vsum >= -5.891f) && (vsum < 0.0f))
{
tempc =              ( d0_i0  * pow(vsum , 0U) )
+ ( d0_i1  * pow(vsum , 1U) )
+ ( d0_i2  * pow(vsum , 2U) )
+ ( d0_i3  * pow(vsum , 3U) )
+ ( d0_i4  * pow(vsum , 4U) )
+ ( d0_i5  * pow(vsum , 5U) )
+ ( d0_i6  * pow(vsum , 6U) )
+ ( d0_i7  * pow(vsum , 7U) )
+ ( d0_i8  * pow(vsum , 8U) )
+ ( d0_i9  * pow(vsum , 9U) );
}
else if((vsum >= 0.0f) && (vsum < 20.644f))
{
tempc =              ( d1_i0  * pow(vsum , 0U) )
+ ( d1_i1  * pow(vsum , 1U) )
+ ( d1_i2  * pow(vsum , 2U) )
+ ( d1_i3  * pow(vsum , 3U) )
+ ( d1_i4  * pow(vsum , 4U) )
+ ( d1_i5  * pow(vsum , 5U) )
+ ( d1_i6  * pow(vsum , 6U) )
+ ( d1_i7  * pow(vsum , 7U) )
+ ( d1_i8  * pow(vsum , 8U) )
+ ( d1_i9  * pow(vsum , 9U) );
}
else if((vsum >= 20.644f) && (vsum <= 54.886f))
{
tempc =              ( d2_i0  * pow(vsum , 0U) )
+ ( d2_i1  * pow(vsum , 1U) )
+ ( d2_i2  * pow(vsum , 2U) )
+ ( d2_i3  * pow(vsum , 3U) )
+ ( d2_i4  * pow(vsum , 4U) )
+ ( d2_i5  * pow(vsum , 5U) )
+ ( d2_i6  * pow(vsum , 6U) )
+ ( d2_i7  * pow(vsum , 7U) )
+ ( d2_i8  * pow(vsum , 8U) )
+ ( d2_i9  * pow(vsum , 9U) );
}
else if(vsum > 54.886f)
{
err = 8U;   //over-voltage for final ocnversion
}
else
{
err = 9U;  //NAN or unknown error
}
}

if(0U == err)
{
if(tempc < -200.0f)
{
err = 10U;  //final calcualtions result in under temperature
}
else if(tempc > 1372.0f)
{
err = 11U;  //final calcualtions result in over temperature
}
else
{
*tc_tempc_return = tempc;
//err = 0U; //final calcualtions ok
}

}

return err;

}

```

How are you measuring these millivolt values?

Jim

Jim Wagner Oregon Research Electronics, Consulting Div. Tangent, OR, USA http://www.orelectronics.net

This is just formula demonstration. Checking if code for formula is ok or not.

For thermoocuple ADS1248 voltage will be measured.

Vindhyachal Takniki wrote:
Checking if code for formula is ok or not.

I hope you're not asking someone to check if you've entered your coefficients correctly I would run it on a PC and run a unit test [https://en.wikipedia.org/wiki/Unit_testing] using a selection of millivolt vales over the whole valid (and invalid) range.

I wrote my equivalent of this function using a for loop in which I read the coefficients out of a table. The code (without tables) became about 10 lines.

Last Edited: Thu. Nov 7, 2019 - 08:19 AM

Why do you need floating point?...seems the brute force way (though it might be beneficial if the calcs are extremely complex)

Why do you need 12 digit coeff? Who measures temperature to more than 2 decimals, at most (like 174.62 deg)  Would 5 or 6 digits coeffs be accurate enough for a 2 digit result?

When in the dark remember-the future looks brighter than ever.   I look forward to being able to predict the future!

Last Edited: Thu. Nov 7, 2019 - 09:16 AM

Remember that  you can't make a silk purse out of a sow's ear. At the end of the day the AVR ADC is going to return 0..255 or 0..1023 so there can only be 256 or 1024 distinct readings. So I don't see a lot of point in much other than a precalculated (probably in Excel) table that maps readings to results with 256 or 1024 entries.

I would hope OP is using at least 16-bit ADC for thermocouples. I use a Microchip MCP3553 "22-bit Single-Channel 22-Bit Delta-Sigma ADC"

Oh --- I read OP is actually using ADS1248 "24-Bit, 2kSPS, 8-Ch Delta-Sigma ADC for Precision Sensor Measurement". So there's plenty of resolution.

The code is only for getting best mathematical accuracy & demonstration by using polynomial function.

Later i will shift code to look up table. But I want to try code on polynomial also, just to use & experiment

So wanted to know if the method used is correctly used or somewhere i have done any mistake like converting cold junction temperature to voltage or any other.

This is just for fun/hobby. Made a loop on arduinio Leonardo to see what is max time it take to convert with fixed cold junction temperature 0C & varying  thermocouple voltage from -5.891 to 54.886 with 0.01 step, all done in code only.

Max time to convert I get is 3776us even with this float intensive operation

Code is O3 optimized.