Saturday, November 14, 2015

Working with a Thermistor: a C Programming Example

Recently I worked on a project that needed to monitor temperature using a thermistor. A thermistor is a resistor that measures temperature: the resistance changes depending on how hot it is. They are used in all kinds of electronic devices to monitor temperature and keep components from oveheating.

I searched for a good, simple worked-out example for how to get an accurate reading from the thermistor, but had trouble finding something readable. I am not actually an electrical engineer and have never studied the math behind thermistors formally, but I was able to adapt the formulas from some existing sources, with a little help. I am sharing this example in the hope that it might be useful to someone trying to solve a similar problem. Please note the way I have adapted the general thermistor math to our particular part and circuit; unless you have an identical part and measurement circuit, you will probably not be able to use this example exactly "as-is."

As I understand it, most modern thermistor components are "NTC," which means that they have a "negative temperature coefficient," meaning that their resistance has an inverse relationship to temperature: higher temperature, lower resistance. Thermistors have highly non-linear response, and are usually characterized by the Steinhart-Hart equation. This equation is a general equation that can be parameterized to model the response curve associated with a specific thermistor device. The original form of the equation takes three coefficients, A, B, and C, and describes the relationship between thermistor resistance and temperature in degrees Kelvin (K). It turns out that the three-coefficient form is overkill for a lot of parts and their response curve can be characterized accurately with a single parameter, using a simplified version of the equation This single parameter is called "beta" and so the equation can be called the Beta Parameter Equation.

Reading a thermistor is complicated by the fact that in a typical application we are first using resistance as a measurment of, or proxy for, temperature; that's the basic thing a thermistor does. But in a circuit we don't read resistance directly; instead, we would typically read voltage as a measure of, or proxy for, resistance. To read the resistance from a thermistor we treat it like we would treat a variable resistor, aka potentiometer. We use a voltage divider. This consists of two resistors in series. In our case we place the thermistor after a fixed resistor, and tap the voltage in between. This goes to an ADC - and analog-to-digital converter. I'm going to assume that you already have a reasonably accurate ADC and working code to take a reading from it.

So now I'm going to describe how I took the general thermistor math and adapted it for a specific part and circuit. Our specific thermistor is a Murata NCP18XH103F03RB. So you can Google the vendor and part number and find a datasheet. You need to find out a few things from the datasheet, specifically the nominal resistance at the reference temperature, which is usually 25 degrees Celsius, or 298.15K (or if it is not, note the reference voltage). Also, the datasheet should specify the beta value for your part; in our case, it is 3380.

The beta parameter equation, solved for resistance, reads:

Rt = R0 * e^( -B * ( 1 / T0 - 1 / T ) )

Where Rt is the resistance as a proxy for temperature, e is the mathematical constant e, B is beta, T0 is the reference temperature in K, and T is the measured temperature in degrees Kelvin. We want temperature given resistance, so we can solve it for temperature, like so:

T = B / ln( R / ( R0 * e^( -B / T0 ) ) )

Plugging in our R0 = 10,000 ohms, B = 3380, and T0 = 298.15 K we get:

t = 10000 * e^( -3380 * ( 1 / 298.15 - 1 / T ) )


T = 3380 / ln( R / ( 10000 * e^( -3380 / 298.15 ) ) )

Now, we need to have something to plug in for R, given the fact that we're reading a voltage from a voltage divider. In our case, the fixed resistor in our voltage divider has the same resistance value in ohms as the nominal resistance for our thermistor at 25 C, 10 kohms (10,000 ohms). Our voltage going into the voltage divider is 2.5V. The standard formula for a voltage divider like this, arranged with the fixed resistor first in the series, before the thermistor, is:

V = 2.5 * ( R / ( 10000 + R ) )

If your thermistor comes before the fixed resistor, you will want to swap the two R values values (see the Wikipedia article on voltage dividers I mentioned above). To get resistance given voltage, we can solve the above for R:

R = 20000 * v / ( 5 - 2 * v )

Now we've got a formula that we can use to convert a voltage reading to a thermistor resistance reading R. We can actually plug the right hand side of that right into our beta parameter equation from above, replacing R:

T = 3380 / ln( ( 20000 * v / ( 5 - 2 * v ) ) / ( 10000 * e^( -3380 / 298.15 ) ) )

That looks kind of monstrous; it really seems like this ought to be simpler than that. But Wolfram Alpha could simplify it when my own algebra skills gave out. You can just go to the Wolfram Alpha site and paste in that equation, being careful to get the parentheses in the right place. You will want to change the T to a t so that Wolfram Alpha interprets it as a variable, rather than Tesla units. Here's the result. Note that Wolfram Alpha has provided a nicely simplified version of the equation, perfect for our needs:

t = 3380 / ln( 167665 * v / ( 5 - 2 * v ) )

That equation describes temperature, in K, as a function of the measured voltage from our specific thermistor and voltage divider circuit. Again, keep in mind that unless you have an identical part and circuit, you will not be able to use this formula as-is. Testing against a thermocouple and hand-held infrared thermometer suggests, so far, that our temperature readings seemed to be accurate to within a degree C. We have not tested it with extremely high or low temperatures yet, but I expect it to be reasonably accurate; for this application, which involves setting fan speed and determining if we need to shut down components, we don't need a high degree of accuracy.

Finally, remember that the results of this formula are in degrees Kelvin. A C programming language expression for converting degrees Kelvin to degrees Celsius is simply:

k - 273.15F

where k is a floating-point value representing degrees Kelvin. Similarly, you can convert to degrees Fahrenheit like so:

k * 9.0F / 5.0F - 459.67F

and the C expression to implement our voltage-to-temperature function is:

3380.0F / log( ( 167665.0F * v ) / ( 5.0F - ( 2.0F * v ) ) )

where v is a floating-point value representing the voltage from our voltage divider, and log is the C programming language's natural logarithm function, part of the C standard library of math functions.

Please take care when using expressions like this. Note that it contains floating-point division operations. You must check to make sure that the values you are dividing by are non-zero! If not, the result will be a floating-point "not-a-number" value (NaN). Depending on your platform, this may happen silently, without any sort of runtime error, and the result will then "poison" any downstream calculations carried out with this value.

I hope this has been helpful. Please leave a comment (note: comments are moderated, so you will not see them appear immediately) if you were able to adapt this approach to your project! If you have a question, you can leave a comment too, although keep in mind that I'm not actually an electrical engineer and so would be better at answering programming questions than circuit design questions. Happy measuring!

Thursday, February 05, 2015

A Deep Dive: the Velocity Manufacturing Simulation

In 1989 I graduated from the College of Wooster and then spent a year as an intern with Academic Computing Services there, writing newsletters and little software tools. In the summer of 1990 I moved to Ann Arbor, without a clear idea what I was going to do next.

I worked for a short while with the Department of Anthropology, but by the end of 1990, I had found a job with the Office of Instructional Technology.

OIT was sort of the University's answer to the MIT Media Lab. It was an organization where instructional designers, programmers, and faculty members could work together on projects to bring technology into classrooms. It was a pretty remarkable workplace, and although it is long gone, I am truly grateful for the varied experiences I had there. It was the early days of computer multimedia, a sort of wild west of platforms and tools, and I learned a lot.

In January of 1993 my girlfriend and her parents visited my two workplaces, OIT headquarters and the Instructional Technology Lab, a site in the Chemistry building. I handed my girlfriend a video camera and proceeded to give a very boring little talk to her, and her extremely patient parents. Wow, I was a geek. I'd like to think my social skills and ability to make eye contact are a lot better now, but I probably haven't changed as much as I imagine that I have. I'm an extraverted geek now: when I am having a conversation with you, I can stare at your shoes.

I have carried the original analog Hi-8 videocassette around through many moves, and life changes, and only today figured out a good way to get it into my computer -- after giving the camcorder heads a very thorough cleaning. I thought the tape was pretty much a lost cause, and was going to try working with my last-ditch backup, a dub to VHS tape, but I'm pleased to learn that the video is still playable, and pleased that I could finally get this made, such as it is.

This project, the Velocity Manufacturing Simulation, was written in Visual BASIC, long before it became VB.NET. I remember that it involved a fair amount of code, although I don't have the source to look at. I remember painstakingly writing code for GUI elements like the animated disclosure triangles. There was some kind of custom controls library we bought separately; the details escape me. There was some kind of ODBC (maybe?) database plug-in that I can barely recall; I think Pete did most of the work on that part. Pete wrote parts of it, and I wrote parts of it. Now it seems almost laughably primitive, but you'll just have to take my word for it that back in the day it seemed pretty cool. It won an award. As far as I know, this is the only video footage of the project.

The code is 147 years old in Internet years. It was almost half my lifetime ago. But at the same time it seems like I just left that office, and somehow if I could figure out where it was, I could still go back and find everyone there in the conference room having lunch, and after lunch settle back into my old office with the vintage, antique computers.

This was only one of several projects I worked on while I worked at OIT. I have some other bits of video for a few of them, but not all. I will get clips up for at least one more. I wish there was more tape, and better tape, even if the only one nostalgic about these projects is me.

Perhaps "enjoy" is the wrong word, but take a moment to remember what instructional multimedia was like, a few months before a group called NCSA released a program called Mosaic and the world started to hear about this exciting new thing called the World Wide Web... but grandpa's tired, kids, and that's a story for a different day.