Sensors & Signal Processing
How to linearise a sensor with a lookup table
To turn a curved sensor reading into real units, measure the sensor at known points, store the pairs in a lookup table, find the two entries a new reading falls between, and draw a straight line across just that band. That's linear interpolation. The curve may bend, but over any short band it's nearly straight.
Why one line isn't enough
A thermistor in a voltage divider gives a reading that falls as it warms, steeply when cold and gently when hot. At 0 °C this one reads 788; at 100 °C, 67. A single straight line through those two ends, which is what map() draws, is out by about 22 degrees in the middle, near 52 °C.
The table
Measure it once every 10 degrees:
| °C | 0 | 10 | 20 | 30 | 40 | 50 | 60 | 70 | 80 | 90 | 100 |
|---|---|---|---|---|---|---|---|---|---|---|---|
| Reading | 788 | 684 | 569 | 456 | 354 | 270 | 204 | 153 | 115 | 87 | 67 |
Interpolate across the band
A reading of 520 falls between 569 (20 °C) and 456 (30 °C). It's (569 − 520) ÷ (569 − 456) = 49 ÷ 113 = 0.43 of the way across, so the temperature is 20 + 4.3 = 24.3 °C.
const int RAW[11] = {788, 684, 569, 456, 354, 270, 204, 153, 115, 87, 67};
const float TEMP[11] = {0, 10, 20, 30, 40, 50, 60, 70, 80, 90, 100};
float celsius(int raw) {
if (raw >= RAW[0]) return 0; // colder than the table
for (int i = 0; i < 10; i++) {
if (raw >= RAW[i + 1]) { // in band i
return TEMP[i] + (RAW[i] - raw) * 10.0 / (RAW[i] - RAW[i + 1]);
}
}
return 100; // hotter than the table
}
Live experiment
Straighten a thermistor curve
A thermistor warms from 0 to 100 °C and its reading falls from 788 to 67 along a curve. Convert it three ways and watch the error: one straight line through the ends is out by 22 degrees, the table alone by 10, the table with interpolation by about 1.2.
“Lookup tables” is lesson 2 of 5 in Dither Delta, Sensors & Signal Processing World 2. Free with an account. Lessons unlock in order, so you’ll do the 8 before it first.
How good is it?
| Method | Worst error |
|---|---|
| One straight line, end to end | about 22 °C |
| Table, answering each band's bottom edge | about 10 °C |
| Table with interpolation | about 1.2 °C |
Tips
- The reading falls as the temperature rises, so band i is where RAW[i] ≥ raw ≥ RAW[i + 1]. A rising sensor flips the test.
- Decide what to return off the ends of the table, and treat a reading far off the ends as a possible fault.
- Points don't have to be evenly spaced. Crowd them where the curve bends.
Car engine computers look up fuel and ignition timing this way hundreds of times a second, and so do colour profiles on screens and synthesizers' wave tables.
Free lesson
Now build it yourself
Each lesson comes in three short parts: see the idea, try it on a live board, then build it yourself, with quick checks as you go.
“Lookup tables” is lesson 2 of 5 in Dither Delta, Sensors & Signal Processing World 2. Free with an account. Lessons unlock in order, so you’ll do the 8 before it first.
Or start from the very first lesson, no account neededPractice questions
Three quick questions from the lessons. Pick an answer to check it.
Show the answer
Answer: RAW[i] ≥ raw ≥ RAW[i + 1]. Readings get smaller as it warms, so each band runs from a bigger number down to a smaller one.
- Why not “raw > RAW[0]”? A reading above RAW[0] is off the cold end of the table, not inside any band.
- Why not “raw == RAW[i]”? Only readings exactly on a table point would match. Every reading between points would be missed.
- Why not “RAW[i] ≤ raw ≤ RAW[i + 1]”? That's the test for a table that rises with temperature. Here each band runs from a bigger number down to a smaller one.
Show the answer
Answer: One straight line end to end: out by 20 degrees in the middle. map() is linear interpolation across the whole range: one band. The curve needs ten.
- Why not “The same as the table”? map() uses only the two end points, so it can't follow the curve between them.
- Why not “An error”? map() runs fine on these numbers. It just draws one straight line across a curve.
- Why not “The right answer”? It's right only at the two ends. In the middle the curve sags far from the straight line.
Show the answer
Answer: Between the two table entries a reading falls between. Short straight lines between neighbours, one band at a time.
- Why not “Through the whole range”? That's a single straight line, which is what the table is there to avoid.
- Why not “From zero”? Nothing ties the line to zero; it runs between the two neighbouring table points.
- Why not “Nowhere”? Interpolation is exactly a straight line, just a short one across one band.
“Lookup tables” is lesson 2 of 5 in Dither Delta, Sensors & Signal Processing World 2. Free with an account. Lessons unlock in order, so you’ll do the 8 before it first.
Questions people ask
Why use a lookup table instead of the Steinhart-Hart equation?
Steinhart-Hart needs a logarithm and a cube, which a small microcontroller computes slowly. A table with interpolation takes a few multiplications, and works for any sensor curve, even one with no formula at all, as long as you can measure it.
How many points does a lookup table need?
Enough that the curve is nearly straight between neighbours. Eleven points, every 10 degrees, bring a thermistor within about 1.2 degrees. Put extra points where the curve bends hardest, since that's where straight lines between points are worst.
Can I use Arduino's map() between table points?
Yes: map() is linear interpolation across one band. But it works in whole numbers and rounds down, so for a fractional answer write the formula yourself with floating-point maths.
Related topics
- How to measure temperature with a thermistor and ArduinoAn NTC thermistor, a divider and two ways to turn readings into degrees.
- How the Arduino map() function worksRescale a reading from one range to another, and the traps that come with it.
- How to calibrate a sensor with two known pointsTwo known readings fix a straight line: where it starts and how steep it is.
- How Arduino analogRead worksHow analogRead turns 0–5 V into 0–1023, and how to scale it for analogWrite.