Thermal hysteresis and comparing current to previous temp


I am trying to write some to code to control a heater around a set point, but after quite a bit of work I want to try to incorporate some hysteresis so a different set point is used when the temperature is rising versus when the temperature is falling. So I need to compare the current temperature to the previous temperature to see which whether the system is heating up or cooling down, and then utilize the correct set point to determine whether to turn the heater on.

To test things out I have the following code set up inside the main loop, where temp is the current temperature and Tprev is the previous temperature. When the system is warming, I want to turn off the heater at the lower set temperature (Tset - 0.3), than when the system is cooling I want to use the higher set temperature (Tset).

In the set-up loop I specified Tprev = temp so the initial value of Tprev would be the initial temperature. I hoped then that Tprev would be updated each loop to be the current temp. Unfortunately, what I am finding is that temp and Tprev are always the same. I think this has to do with the fact that I am not actually saving the Tprev as the previous temperature state, but simply equating them (I obviously am equating them in each if loop). It should be a simple fix I imagine, moving the specification of Tprev outside of one of the loops, but I can’t see it! Can someone offer a solution?

Hopefully I have provided sufficient information as I realize the code below is just a snippet and not the entire sketch. If more information is necessary to answer this, let me know and I’ll provide more.

Thanks for your help,

 if(temp - Tprev > 0) {
      if(temp <= (Tset-0.3)){
          digitalWrite(Heater_Relay, HIGH);
          digitalWrite(Heater_LED, HIGH);
          Tprev = temp;
        }else if(temp > (Tset- 0.3)){
          digitalWrite(Heater_Relay, LOW);
          digitalWrite(Heater_LED, LOW);
          Tprev = temp;
     } else if(temp - Tprev <= 0) {
       if(temp < Tset) {
         digitalWrite(Heater_Relay, HIGH);
          digitalWrite(Heater_LED, HIGH);
          Tprev = temp;
       } else if(temp >= Tset){
         digitalWrite(Heater_Relay, LOW);
          digitalWrite(Heater_LED, LOW);
          Tprev = temp;

Read Reply#8 of this post:


That is a useful construct, but the band gap doesn't really do what I want in this case. I'm having an issue with my heater overshooting the set point.

So for example, when the system is cooling down (current temperature is less than previous temperature) I want to turn on the heater at a temperature of (Setpoint - 0.3). However, once the system has begun heating and current temperature is higher than the previous temperature I want to switch the heater off (either just set it LOW, or give assign it a lower set point (Setpoint - 0.5) so it goes off. There is a lag between when the heater is turned on and the heating is registered at the temperature sensor and I need to control for this.

I have spent days trying to do this with a PID and it has been impossible to tune properly so I'm trying this as an alternative. I think the previous code is close I just need to retain the "previous temperature" so I can compare it to the current temperature and determine whether the system is warming or cooling.

Thanks for any additional help with the programming,


Pretend your driving a bus with crappy brakes and you have to start stopping half a block in advance of the stop light. You can't wait for the temp to read the higher temperature. (at least you say that approach isn't working) You have to turn the heater on and then control the turning off based on TIME , not temperature (because apparently your sensors are not where they should be or you could use temp to control turning it off). What is the response time of the heater for a given temperature increase. (Response time= [ (temp setpoint) - T (0)] ? What is the typical temp range (working range)

Can you give us some more details about your application?

When the system is warming, I want to turn off the heater at the lower set temperature (Tset - 0.3), than when the system is cooling I want to use the higher set temperature (Tset).

Out of context, this doesn't make any sense.

If you really need to keep the temperature very close to the setpoint, you should look at modulating the power to the heater. On/off control is rarely optimal.

I believe what he is saying (even though it doesn't make any sense as you noticed) is that the response time is SO BAD that when he is warming it, he has to STOP warming it when it gets to the lower end of the range in order to avoid overshooting the setpoint I think it would make more sense to use a variable called toffset and substact or add that to the setpoints.

With on/off control, the temperature is going to oscillate. If you want the temperature to oscillate below the setpoint rather than around it do as raschemmel suggests. First code the control to oscillate around the setpoint and observe the amplitude of the oscillation. Divide the amplitude by 2 and use this as an offset to the setpoint. You will need a small amount of hysteresis, slightly larger than the noise in your temperature measurement.

Thank you. I’ll try to clarify.

I have a silicon heater pad situated between two aluminum plates. This is waterproofed and placed partially submerged in water held at 13C. I then wish to increase the temperature of the upper surface of the plate (out of the water) at a specified rate (0.05C per minute, from 13C to 30C in 6 hours). So I have the interplay between the cold water and the heater to achieve this ramp. I have a temperature sensor (DS18b20) secured to the top of the aluminum plate which is secured inside an epoxy that it replicates the thermal conductivity of the intertidal animals (limpets, think snails) that will be living on these aluminum plates. Thus what I really am trying to ramp is the temperature inside the epoxy (fake limpet), through the aluminum plate. Limpets face far higher temperatures in the field than we’ll expose them to and we’re curious about how they deal with warming temperatures

When I originally tested the system it was just on my desk (not in the water) and I was able to pretty easily tune a PID to control it and get a great ramp with errors of +/- 0.25C. But, since having moved it into the water I have been unable to get the PID to work well. Dramatic increases in temperature at random times, followed by pretty decent tracking. I’ve tried just P control at lots of different values, PI control, PID control, and simply haven’t been able to get anything consistent from the PID.

I am up against the deadline now and I need to get something working so I am trying to go simple. I’ve attached two figures to show some of the data. The second is a bit sparse, because it is actually running right now (but rather poorly as you can see). In the first figure I just had the heater turn on when the temperature went below (Tset - 0.3). The idea being, I would be ok with small undershoots to 0.3 or so and this would limit the overshoot. It does, but I’d like to get this tighter.

The second figure is with the bandgap method, just to explore it. Heater turns on at Tset - 0.2 and off at Tset. It clearly overshoots, though not all that unexpectedly.

I don’t have the means (I guess I’m just not sure how) to modulate the 120VAC power to the heater. Currently I’m using a relay to simply turn it on and off.

Thanks for your advice,

Forum On_Off at Tset-0.3.pdf (6.04 KB)

Forum On at Tset-0.2_Off at Tset.pdf (5.5 KB)

Why don't you use a Solid State Relay and use a PWM signal as the dc control voltage ?

You should be able to buy one at any hardware or electronic store. It shouldn't take you more than 10 minutes to 30 minutes to wire it up. Just cut the hot wire of the heater and connect the two ends of the wire to the two screw terminals on the right half of the relay (it is functionally an SPST RELAY). Connect the arduino GND to the -V dc input terminal and connect the arduino PWM signal to the +V dc input terminal. Use the analogWrite statement to set the duty cycle (0-255).

Full PID control is what is required for good temp control if the objective is tight control. The D term is the key for preventing overshoot on temp control. But tuning temp loops are the most difficult of all the standard control loops to tune properly (pressure, temp, level, flow) as the process lag tends to be slowest of all the other standard process variables. You might try cutting your heating capacity by lowering it's voltage or adding series resistance and see if you can't tune it easier.

So you while you might be able to kluge something as your are trying, but I doubt it will ever be stable in all phases, start-up, tracking, process load change, etc.


Use a triac if you want to modulate power to your heater. Turn the triac on for the first X cycles out of 100 for X% power. You'll need a zero crossing detector to know when to turn on.

You'll need a zero crossing detector to know when to turn on.

That's built into a solid state relay. They would never work if it wasn't.


You'll need a zero crossing detector to know when to turn on.

That's built into a solid state relay. They would never work if it wasn't.

They actually come in two flavors, the more common zero crossing types and the 'phase control' types where you can trigger the internal triac at any phase angled desired, but you still need an external zero crossing detector to use as a timing reference. Anyway for temperature control you don't require any such fine/fast control for the heating element as the process lag is usually in minuets or hours, so just duty cycling control around a say 10 second period window is all that is really need for the heater output control.

Hello Nate

When I originally tested the system it was just on my desk (not in the water) and I was able to pretty easily tune a PID to control it and get a great ramp with errors of +/- 0.25C.

I imagine in this configuration, the temperature of the ambient air and your desk was higher than the 13C at which the water is being held?

Would it help (or even be possible) to insulate the bottom half of your plate - heater - plate assembly, the half that is in the water, to reduce heat loss to the water and direct more of the heating towards the top surface and the sensor?

All the best


Thanks folks,

Great advice. I have a Crydom D1225 SSR around the lab. Expensive buggers and I haven't been using it because I was hoping to use the PID and the associated "pseudoPWM" involving window size, etc.

In any case I have one here. The idea with this is then that I test different % duty cycles and "tune" it so it follows the ramp? It would obviously be nice to have the % duty cycle be proportional on distance from the set temperature.

For the basic loop it might look like this? Maybe?

unsigned long timer = millis();

while(heat == TRUE){
dutyCycle = 10000;
if(timer - millis() > dutyCycle){
proportionOn = if(temp - Tset) > 0) {
                                      (temp - Tset)/10; //this could be changed
                                     } else {
heaterOn = (dutyCycle/255)*((proportionOn*255)

analogWrite(HeaterPin, analogValue)

Not sure if I'm thinking about that quite right, but I can imagine it could work. I couldn't get proportional control with the PID to follow the ramp all that well, but maybe this will be simpler to tune. Does this seems reasonable?

Thank you, Nate

I would change the name of the value to PWM because it isn't analog.

Hi, can you post a diagram of the physical setup of your heater, from your description you have a flat heater. On the down side it is heating water On the upside it is heating air. Two totally different thermal masses. Each side will heat up at different rate. If your sensor is on the top, that side will naturally heat quicker, the other side will not be up to temperature yet. Also the temperature of the water will increase, are you stirring it to keep the temperature even and hence an even thermal mass. You are heating the top at the rate needed, using the water to help prevent overshoot by taking the excess away, the problem is the water is on the other side of the heating plate.

Can I suggest a new approach, heat the high thermal mass water, stirring it, make the surface that you need heated in contact with the water surface and place the sensor on the plate. This way the plate is part of the high thermal mass of the water. Also place an insulated cover over the plate to help heat loss.

I have serviced lab equipment and it is very hard to do what you need.

Tom.... :)


I don't see how making the heater variable wattage the pulsed SSR really changes the control problem. As you are delivering energy to the plates, does it really matter, for example, if you have 200 watts on for 25% of the time or 100 watts on for 50% or 50 watts for 100%.

I can see that if the heater is so powerful so that you can not achieve control with small percent on time near setpoint, then being able to lower the power would help. What is the cycle time you are using? Even with a mechanical relay turning the full wattage heater on and off you shouldn't be restricted to long cycle times.

Do you have an analysis of the heat loss to the air and the water and how it matches up with the heater, the wattage, and the proposed duty cycles? If the system worked with air/air you should be able to tune it with air/water. Your little epoxy limpet doesn't know what's on the other side of the plate. Perhaps you could try and tune it with one side air, and the other side sitting on a big metal plate. The underside heat loss won't be as severe as in the water, and it should help you move your tuning in the right direction.


One additional thought. You may achieve better control with using the SSR and pulse control to essentially vary the heater from low to full wattage but think of it as analog, and leave it "on" 100% of the duty cycle.

Controlling both the wattage and the on/off periods during the cycle time seems an overly complex approach. You have a difficult application, so it might be necessary, but I'd suggest working through standard PID tuning algorithms with either the wattage or the time on/off varying.

I don't agree. I think there sure be a variable and as the temp approaches the target , the variable representing the duty cycle is decremented reducing the duty cycle, so it functions like a feedback PID. every measurement results in the duty cycle being increased or decreased and the amount of the increase/decrease is a function of current_temp/target_temp so when they are equal the duty cycle is 0 %. That's the only thing that makes sense .