A practical method for calibrating NTC thermistors

This post describes a thermistor calibration achievable by people who don’t have access to lab equipment with an accuracy better than ±0.15°C. This method is particularly suitable for the 10k NTC on our 2-module data logger handling them in a way that is easy to standardize for batch processing (ie: at the classroom scale). We use brackets to keep the loggers completely submerged because the thermal conductivity of the water around the housing is required or the two sensors would diverge. The target range of 0-40°C used here covers moderate environments including the underwater and underground locations we typically deploy into. This method is unique in that it uses the freeze process rather than melting ice for the 0°C data point.

Use stainless steel washers in your hold-downs to avoid contamination of the distilled water and provide nucleation points to limit super-cooling. Before creating this bracket we simply used zip-ties to hold the washer weights.

Reading the thermistor with digital pins uses far less power, and gives you the resistance of the NTC directly from the ratio of two times. Resolution is not set by the bit depth of your ADC, but by the size of the reservoir capacitor: a small ceramic 0.1µF [104] delivers about 0.01°C with jitter in the main system clock imposing a second limit on resolution near 0.01°C when using a small res-cap. However, this calibration procedure will work no matter what method you use to read your NTC thermistor.

The I2C reference sensor is connected temporarily during the calibration via Dupont headers.

Off-the-shelf sensors can be used as  ‘good enough’ reference thermometers provided you keep in mind that most accuracy specifications follow a U-shaped curve around some sweet spot that’s been chosen for a particular application. The Si7051 used here has been optimized for the medical market, so it has ±0.1°C accuracy from 35.8 to 41°Celsius, but that falls to ±0.13 at room temperatures and only  ±0.25 at the ice point. If you use some other sensor (like the MAX30205 or the TSYS01) make sure it’s datasheet specifies how the accuracy changes over the range of temperatures you are targeting.

Likewise, the shortened three term Steinhart–Hart equation is not considered sufficiently accurate for scientific instruments which often use a four or five term polynomial. To calculate the equation constants you need to collect three temperature & resistance data pairs which can be entered into the online calculator at SRS or processed with a spreadsheet.

While these technical sources of error limit the accuracy you can achieve with this method, issues like thermal lag in the physical system and your overall technique are equally important. In general, you want each step of this process to occur as slowly as possible. If the data from a run doesn’t look the way you were expecting – then do the procedure over again until those curves are well behaved and smooth.

Data Point #1: The freezing point of water

The most common method of obtaining a 0°C reference is to place the sensor into an insulated cup of stirred ice slurry that plateaus as the ice melts. This is fine for waterproof sensors on the end of a cable but it is not easily done with sensors mounted directly on a PCB. So we immerse the loggers in a 1200ml silicone food container filled with distilled water. This is placed inside of a well insulated lunch box and the combined assembly is left in the freezer overnight, reading every 30 seconds.

Weighted holders keep each logger completely immersed. Soft-walled silicone containers expand to accommodate any volume change as the water freezes. This prevents the centrifuge tube housings from being subjected to too much pressure.
The outer lunch box provides insulation to slow the freezing process. After testing several brands it was found that the Land’s End EZ wipe and Pottery Barn Kids Mackenzie Classic boxes provided the best thermal insulation because they have no seams on the molded foam interior which doesn’t absorb water spilled while moving the container.

For the purpose of this calibration (at ambient pressure) we can treat the freezing point of pure water as a physical constant. So no reference sensor is needed on the logger while you collect the 0°C data. Leave the lunch box in the freezer long enough for a rind of ice to form around the outer edges while the main volume of water surrounding the loggers remains liquid. I left the set in this photo a bit too long as that outer ice rind is much thicker than it needed to be for the data collection.

The larger bubbles in this photo were not present during the freeze, but were created by moving the container around afterward.

The trick is recognizing which data represents the true freezing point of water. Distilled water super-cools by several degrees, and then rises to 0°C for a brief period after ice nucleation because the phase change releases 80 calories per gram while the specific heat capacity of water is only one calorie per degree per gram. So freezing at the outer edges warms the rest of the liquid – but this process is inherently self-limiting which gives you a plateau at exactly 0°C after the rise:

NTC (ohms) gathered during the freeze/thaw process with the y axis is inverted because of the negative coefficient. Several hours of warm temperature data has been removed from the graphs above to display only the relevant cold temperature data. Cooling the water from it’s initial room temperature starting point to the supercooling spike shown above took eight hours, and the complete thaw took another eight hours.

Depending on the strength of your freezer, and the quality of the outer insulating container, the ice-point may only last a few minutes before temperatures start to fall again. An average of the NTC readings from that initial peak is your 0°C calibration data point.  This is usually near 33000 ohms for a 10k 3950 thermistor. Only the data immediately after super cooling ends is relevant and the insulated box can be removed from the freezer any time after that.

If the supercooling spike is not obvious in your data then change your physical configuration to slow the cooling process until it appears. You want the inner surface of your silicone container to have smooth rounded edges, as sharp corners can nucleate the ice at 0°C, preventing the supercooling. Use as much water as the container will safely hold. You do not want the water to freeze solid as this will subject the loggers to stress that could crack the housings.

Unexpected thermal excursions may happen if the freezer goes into a defrost cycle or an automatic ice-maker kicks in during the run. If you put the box in the freezer between 6-7pm, it usually reaches the supercooling point around 2am, reducing the chance that someone will open the freezer door at that plateau.

Data Point #2:  Near 40°C

We have used the boiling point of water for calibration in the past, but the centrifuge tube housings would soften considerably at those temperatures. Ideally you want to bracket your data with equally spaced calibration points and 100°C is far from the conditions we monitor. Heated water baths can be found on eBay for about $50, but my initial tests with a Fisher Scientific IsoTemp revealed thermal cycling that was far too aggressive to use for calibration – even with a circulation pump and many layers of added insulation. So we created an inexpensive DIY version made with an Arctic Zone Zipperless Coldloc hard-shell lunch box and a 4×6 inch reptile heating mat (8 watt). Unlike the ice point which must be done with distilled water, ordinary tap water can be used to collect the warm data pairs.

These hard-sided lunch boxes can often be obtained for a few dollars at local charity shops.
Place the 8-watt heating pad under the hard shell of the lunch box. At 100% power this tiny heater takes ~24 hours to bring the bath up to ~38°C. The bath temp is relatively stable since the heater does not cycle, but it does experience a slow drift based on losses to the environment. The heating pads sell for less than $15 on Amazon.

To record the temperature inside each logger, an Si7051 breakout module (from Closed Cube) is attached to the logger. A hold down of some kind must keep the logger completely submerged for the duration of the calibration. If a logger floats to the surface then air within the housing can thermally stratify and the two sensors will diverge. That data is not usable for calibration so the run must be done again with that logger.

Data Point #3: Room Temperature

The loggers stay in the heated bath overnight, and then in the morning they are transferred to an unheated water-filled container (in this case a second Arctic Zone lunch box) where they run at ambient temperatures for another eight to twelve hours. This provides the final reference data pair:

Si7051 temperature readings inside a logger at a 30 second sampling interval. The logger was transferred between the two baths at 8am. Both baths are affected by the temperature changes in the external environment.
Detail: Warm temp. NTC ohms (y-axis inverted)
Detail: Room temp. NTC ohms (y-axis inverted)

As the environment around the box changes, losses through the insulation create gentle crests or troughs where the lag difference between the sensors will change sign. So averaging several readings across those inflection points cancels out any lag error between the reference sensor and the NTC. Take care that you average exactly the same set of readings from both the Si7051 and from the NTC data. At this point you should have three Temperature / Resistance data pairs that can be entered into the SRS online calculator to calculate the equation constants ->

I generally use six figures from the reference pairs, which is more than I’d trust in the temperature output later. I also record the Beta constants for live screen output because that low accuracy calculation takes less time on limited processors.

The final step is to use those constants to calculate the temperature from the NTC data with:
Temperature °C = 1/(A+(B*LN(ohms))+(C*(LN(ohms))^3))-273.15

Then graph the calculated temperatures from the NTC over top of the original reference data from your commercial sensor. Provided the loggers were completely immersed in the water bath, flatter areas of the two curves should overlap one another precisely. However, the two plots will diverge when the temperature is changing rapidly because the NTC exhibits more thermal lag than the Si7051. This is because the NTC is located near the thermal mass of the ProMini circuit board.

Si reference & NTC calculated temperatures: If your calibration has gone well, the curves should be nearly identical as shown above. With exceptions only in areas where the temperature was changing rapidly or when the logger was exposed in air.

Also note that the hot and warm bath data points can be collected with separate runs. In fact, you could recapture any data pair and recalculate the equation constants with two older ones any time you suspect a run did not go smoothly. Add the constants to all of the data column headers, and record them in a google doc with the three reference pairs and the date of the calibration. Re-run the calibration in a year. You can then apply compensation techniques to correct for sensor drift in your dataset.

Validation

You should always do a final test to validate your calibrations, because even when the data is good it’s easy to make a typo somewhere in the process. Here, a set of nine calibrated NTC loggers are run together for a few days in a gently circulated water bath at ambient temperature –>

(Click to enlarge)

Two from this set are a bit high and could be redone, but all of the NTC temperature readings now fall within a 0.1°C band. This is a decent result from a method you can do without laboratory grade equipment, and they could be brought even closer together by normalizing the set.

Comments

Calibrating the onboard thermistor a good idea even if you plan to add a dedicated temperature sensor because you always have to do some kind of burn-in testing on a newly built logger – so you might as well do something productive with that time. I generally record as much data as possible during the calibration to fill more memory and flag potentially bad areas in the EEprom. (Note: Our code on GitHub allows only 1,2,4,8, or 16 bytes per record to align with EEprom page boundaries) . And always look at the battery record during the calibration as it’s often your first clue that a logger might not be performing as expected. It’s also worth mentioning that if you also save the RTC temperatures as you gather the NTC calibration data, this procedure gives you enough information to calibrate that register. The resolution is only 0.25°C, but it does give you a way to check if your ‘good’ temperature sensors are drifting because the DS3231 tends to be quite stable.

For any sensor calibration the reference points should span the range you hope to collect later in the field. To extend this procedure for cold climates you could replace the ice point with the freezing point of Galinstan (-20°C) although a domestic freezer will struggle to reach that. If you need a high point above 40°C, you can use a stronger heat source. Using two of those 8 watt pads in one hard sided lunch box requires some non-optimal bending at the sides, but it does boost the bath temp to 50°C. 3D printed hold-downs will start to soften at higher temps so you may need to alter the design to prevent the loggers from popping out.

If your NTC data is so noisy you can’t see where to draw an average, check the stability of your regulator because any noise on the rail will affect the Schmitt trigger thresholds used by the ICU/timer. This isn’t an issue running from a battery, but even bench supplies can give you noise related grief if you’ve ended up with some kind of ground loop. You could also try oversampling, or a leaky integrator to smooth the data – but be careful to apply those techniques to both the reference and the NTC readings in exactly the same way because they introduce significant lag. Also note that the digital pin ICU based method for reading resistors does not work well with temperature compensated system oscillators because that circuitry could kick in between the reference resistor and NTC sensor readings.

And finally, the procedure described here is not ‘normalization’, which people sometimes confuse with calibration.  In fact, it’s a good idea to huddle-test your sensors in a circulating water bath after calibration to bring a set closer together even though that may not improve accuracy. Creating post-calibration y=Mx+B correction constants is especially useful when monitoring systems that are driven by relative deltas rather than by absolute temperatures. Other types of sensors like pressure or humidity have so much variation from the factory that they almost always need to be normalized before deployment – even on ‘commercial’ loggers. Normalize your set of reference sensors to each other before you start using them to calibrate your NTC sensors.


References & Links:

SRS Thermistor Constant Calculator
Steinhart-Hart Equation Errors BAPI Application Note Nov 11, 2015
The e360: A DIY Classroom Data Logger for Science
How to make Resistive Sensor Readings with DIGITAL I/O pins
How to Normalize a Set of Sensors

5 thoughts on “A practical method for calibrating NTC thermistors

  1. andrew

    Yet another brilliant post – thanks so much – I made a BIG effort a few years ago after reading & being inspired by your previous post(s) on NTC thermistors, but just used a freezer instead of frozen water, and always had thermal lag issues. I made my own insulated (not waterproof) box (40mm foam walls), and had a series of 20 x 0.5R resistors for the heating element for the high temp point. It was never much good. Your post *may* give me the kick to revisit the concept although I since bought 10 x Si7051 & 3 x TSYS01 modules.

    Reply
    1. edmallon Post author

      It took some time to work through different prototypes for this idea, but we really needed something that would scale easily. At the moment, three students are calibrating their loggers with this method for deployment on summer projects. The real key is spotting the good data to draw your averages from. I usually average over 20-30 of those 30-second readings as this smooths over any noise in the NTC readings, and compensates somewhat for the lower resolution of the reference sensor.

      Reply
  2. Brian Davis

    Again, this is invaluable… and just when I was going to comment on the “calibration vs. normalization” issue, you popped that up as well, fantastic! Frankly I’m amazed at what you are getting your students to do and understand in the course of a class, but i’m (still!) inspired by it, and hope to get (much) better at it.

    I do wonder what this looks like on the field end – things like thermal inertia and thermal exchange with the environment being so different and difficult to handle, that while all this looks great on the bench, how much of it is reliable in the field? For example, a properly calibrated temperature sensor is great… but I’ve had significant problems just trying to get an effective Stevenson Screen shield or enclosure that I can somewhat trust.

    Link: https://thecavepearlproject.org/2024/05/01/how-to-normalize-a-set-of-pressure-sensors/

    Reply
    1. edmallon Post author

      After years of trying all sorts of shield designs, and having them torn up by storms, we just went back to putting the loggers inside cinder block stacks. [ https://thecavepearlproject.org/2023/04/15/insights-from-a-decade-of-tipping-bucket-rain-gauge-deployment/} ] Yes, theres lots of thermal inertia, but also lots of free airflow. But most importantly, they look uninteresting so nobody messes with them.
      That said, I still keep my eye open for small used temp sensor screens on eBay, but quite frankly none last more than a year unless they are 100% metal construction. Otherwise the tropical sun just eats them.

      Reply
  3. Pingback: How to Normalize a Set of Pressure Sensors « Adafruit Industries – Makers, hackers, artists, designers and engineers!

Leave a comment