Thermocouple voltage to temperature conversion code - Page 1
Forum section: electronics / general

author: miceuz
author_rank: Frequent Contributor
timestamp: April 24, 2014, 01:09:34 pm
content: Hi all,I was surprised that no open source code to convert thermocouple voltage exists that is suitable for embedded applications, so I've written a library for that:http://wemakethings.net/2014/04/24/k-thermocouple-libEnjoy.

author: gxti
author_rank: Frequent Contributor
timestamp: April 24, 2014, 06:27:32 pm
content: Consider making a self-contained Python script to generate the table. For example, here's one I did a while back:http://hg.partiallystapled.com/circuits/tcdisplay/file/2045cb4d129a/code. It's ugly, and I can't believe I wrote any of this PIC assembly as it looks foreign to me now, but it's serviceable and if I needed to change the type of thermocouple it would be trivial to build a new table from the ITS-90 parameters. In fact I already did, because when I built this project initially I had the brilliant idea to use a J-type thermocouple because it was more sensitive, then quickly found out that the rather small benefits were outweighed by the vastly greater availability of K-type thermocouples for purchase. But all it took was a minute or two to add the K-type parameters to the script and out popped an updated lookup table with no copy-paste needed. And each row is annotated with what real-world values it represents.For my implementation a great deal of the hardware and processor details are baked in e.g. the voltage reference, ADC resolution, and desired output precision are all baked in so the result is simply a 16-bit LUT (split into two tables) that directly turns an ADC code into a value. This makes it fast and compact but difficult to adapt for other people's uses, in fact I couldn't even explain it today because I haven't really touched this since I built it. I would say it's because I don'tneedto touch it, except that lately I've noticed the stupid thing locks up sometimes which is rather unfortunate.

author: mariush
author_rank: Super Contributor
timestamp: April 24, 2014, 07:12:09 pm
content: It's funny, just yesterday I remembered I have anAD595K thermocouple amp in my box of parts.I bought it a year ago because I wanted to make a reflow oven and read temperature and also use it for other things, but I set aside the reflow oven project and ended up buying an infrared temperature gun for my other needs.I should use it with a pic and some 4 digit display and maybe a precision opamp to reduce the ad595 output voltage by 2 or 3 times (to use pic adc and internal voltage reference of 4.096v) , after all it's a fairly expensive IC... I

author: poorchava
author_rank: Super Contributor
timestamp: April 25, 2014, 09:16:32 am
content: As microcontrollers have so much power nowadays, I tend to use polynominal approach for approximation. Since it's only addition and multiplication, although on floating point variables.http://srdata.nist.gov/its90/download/download.htmlA combination of sparse lookup table + linear interpolation is also nice way to do it if your mcu doesn't cope that well with floats.

author: miceuz
author_rank: Frequent Contributor
timestamp: April 26, 2014, 08:37:42 am
content: Quote from: gxti on April 24, 2014, 06:27:32 pmI have a python script to generate the table, but I'm using the table of measured voltages as a source for my table - as far as I understand, this is the most accurate thing we have. Your code uses polynomials which approximate the measured data to generate the table and polynomials give 0.06°C error over the full temperature range which is not much, but can be easily avoided.Quote from: gxti on April 24, 2014, 06:27:32 pmAnother thing is calibration - you would need to account for system offset and gain error when generating the table, this makes it ok for one off, but a pain when doing bulk production.

author: miceuz
author_rank: Frequent Contributor
timestamp: April 26, 2014, 08:43:06 am
content: Quote from: poorchava on April 25, 2014, 09:16:32 amWhat about the exponential part?E = sum(i=0 to n) c_i t^i + a0 exp(a1 (t - a2)^2).

author: daveatol
author_rank: Regular Contributor
timestamp: April 26, 2014, 09:32:10 am
content: Nice write up regarding the error.To make it more suitable for sub-32bit microcontrollers, the linear searches (max 65 comparisons) can be replaced by binary searches (max 6-7 comparisons) as the tables are sorted, and the unsigned longs in the table could be replaced by unsigned shorts without loss of precision.

author: miceuz
author_rank: Frequent Contributor
timestamp: April 26, 2014, 09:39:18 am
content: Quote from: daveatol on April 26, 2014, 09:32:10 amI had a binary search running in pyton prototype code, but I have disregarded it, don't remember why

author: T3sl4co1l
author_rank: Super Contributor
timestamp: April 27, 2014, 04:02:07 am
content: QuoteI disagree... If you think floats and math.h are required for this sort of thing, you're not trying nearly hard enough... if at all!If that's the case, then I suggest embracing fixed point. Do the hard work and figure out what's actually going on, in the core, down to the bit level if possible! It's hard work, but it's rewarding, and often worthwhile.Just don't get carried away: standard advice -- save the optimization for the end, once you've got a working program, trimmed down, that finally needs it!Anyway, I've written a 7th order polynomial function -- for thermistors, not thermocouples -- which runs on AVR and doesn't take too much time (around 300 cycles), and little memory (74 words, including the coefficient table I think). It could be optimized better for either constraint, if desired.The function converts a 12 bit ADC reading to a 12.4 fixed point temperature with < +/- 0.25C error from the manufacturer's typical data. Actual error of a given 1% thermistor will probably be worse than this, so I consider it more than sufficient numerically. The math is exact, in that the final result is rounded no worse than a high-precision calculation truncated to the same scale, give or take one LSB.The alternative on this particular platform would be a massive 4k word lookup table with a few cycles worth of code to grab it, or a reduced lookup table with linear interpolation. I consider the former unsuitable because of its size. I consider the latter unsuitable for both size (the minimal table still requires ~40 words) and computation time (the divisions required for a linear interpolation will probably not cost much space, but will take over 400 cycles easily; the table lookup also has to be either a linear or binary search, which takes more time, and is variable).I also considered a more creative approximation particular to thermistors of this type (a sum-of-reciprocals form), which took around 420 cycles and 81 words. Not bad, but even a single crude division costs more than four MACs, so it's just not a good approach.These methods could easily be applied to 16 and 32 bit platforms; the sum-of-reciprocals would probably end up preferable on a platform without hardware multiply (although these days, how many architectures don't offer it?), but otherwise, the boring old polynomial is hard to beat.For thermocouples in particular, there might be some interesting analytical functions that could be applied (that error term has sort of an oscillating tail to it, which might be a close fit to some polynomial or trig functions, or combinations thereof), which might lead to an interesting solution. But otherwise, yeah, the polynomial method again is hard to beat. Especially with how easily most platforms can calculate it.On something like an ARM Cortex M4, there should be plenty of resources (bits, clock cycles, hardware, and powerful instructions) to pull together even more bits (16+ bit ADC?), a higher order polynomial (11+ order polynomial would give a near-exact fit to manufacturers' data) and desired output formatting (whatever number format, or string, you want) in even fewer cycles.BTW, I developed the functions and coefficients for these functions with only a spreadsheet. Matlab/Octave might be a little neater method -- certainly if larger datasets were involved. The spreadsheet is kind of ugly at times (I needed a matrix of Chebychev polynomials to get the "solver" to do anything -- the raw polynomial was simply too awkward to manipulate directly), but I'm reasonably certain that the coefficients were close to optimal in any of the approaches I've mentioned. This includes simulating the derived (and truncated) coefficients, in fixed point, as the final hardware would: which again isn't hard to do, just a little messy. Main thing is to make sure you get the rounding right! (I also checked the "simulation" against the realin silico* results, which were exact.)*Err... wait.in silicois usually meant as "we simulated it on a computer". But what if I'm comparing a computer...to a simulation of that computer? Is the simulation doubly-in-silico?!.....nevermind.Tim

author: daveatol
author_rank: Regular Contributor
timestamp: April 27, 2014, 05:38:17 am
content: Quote from: T3sl4co1l on April 27, 2014, 04:02:07 amThe lookup table and interpolation can be done without using physical division or shifts, and if the curve is near linear (like the thermocouple), the lookup only need contain the error w.r.t. a linear response, and each entry can probably be reduced to 8 bits. The binary search can be constant time (depending on processor).Quote from: T3sl4co1l on April 27, 2014, 04:02:07 amCan you provide you code for thermocouple voltage to temperature function so that it can be benchmarked? I'm guessing it's not actually that hard to beat.

author: miguelvp
author_rank: Super Contributor
timestamp: April 27, 2014, 05:52:48 am
content: TMP36 gives 750 mV output at 25°C and 10 mV/°C. up or down.So pretty much is V-500mV to get 10th of °C from -40°C to +125°C or 100mV to 1750mV, each milli Volt is 0.1°C, but it's only ±2°C accurate across the whole rangeBut the math sure is simple

author: T3sl4co1l
author_rank: Super Contributor
timestamp: April 27, 2014, 06:47:41 am
content: Quote from: daveatol on April 27, 2014, 05:38:17 amAnd like I said, it depends on the nature of it. Thermistors are very nonlinear, so I explored very nonlinear functions: polynomials, log, exp, 1/x, those sorts of things.QuoteThermistor, not thermocouple; sure:http://seventransistorlabs.com/PolyCountToTemp.asmTim

author: miceuz
author_rank: Frequent Contributor
timestamp: April 27, 2014, 04:49:56 pm
content: Quote from: T3sl4co1l on April 27, 2014, 06:47:41 amCool, how did you deal with exp function? I'm fairly comfortable with dealing with fixed point math, but K-type thermocouple polynomial has an exponential member in it - that's what drove me lookup table and interpolation path.

author: T3sl4co1l
author_rank: Super Contributor
timestamp: April 28, 2014, 05:51:32 am
content: I didn't.That was on the spreadsheet, playing around with "best fit" functions. I know a moderate range of squiggly curves and sort-of how they play, so, put a few together, this and that, see if I can get something that matches well...And the inverse (inverse problems are common too, suppose you need to know what voltage to set a temperature regulator to), applying these functions (or their inverses) to the dataset until you get a straight line, or something like that. Simple example: apply log(x) to the datapoints of the current through a diode; like magic, it looks great.I had thought of using a log function in my example (the traditional approximation of a thermistor is a log-of-sum-of-reciprocals form), which still isn't terrifically bad to compute, but does take a few iterations. A fixed point lg2(x) is done by first counting the number of bits in the operand (which is the rounded-down, integral part of the result), then treating the operand as a 1.(N-1) fixed point fraction, and repeatedly squaring it; each time the integral part (high bit) goes above 1 (i.e., overflows), divide it by 2 (i.e., shift right) and shift a 1-bit into the result, else shift a 0. The squaring isn't so bad on a hardware multiply (the inner loop might be around 30 cycles on AVR), but you're still doing a lot of it (N passes for an N-bit result).The inverse process, of course, applies to generating exponents, but iterating square roots isn't very appealing. I didn't look into good methods to compute fractional exponents at the time.Tim

author: poorchava
author_rank: Super Contributor
timestamp: April 28, 2014, 12:45:13 pm
content: Quote from: miceuz on April 27, 2014, 04:49:56 pmThere's no exp when converting voltage to temperature. Expontnt is used when calculating voltage from temperature. Exponent, by the way, can be calculated as Taylor series with quite good accuracy (actually, accuracy is up to programmer).