A common need in automation and control is to perform a certain action when an input value crosses a reference value, which we will call setpoint or threshold.
Control by means of a threshold is one of the simplest forms of regulation we can implement. It frequently appears when we have an all-or-nothing type actuator, so, not having the option to modulate, another more sophisticated type of controller is not possible.
When the variable to be controlled is independent of the registered variable, we can use a single threshold as the condition for activation and deactivation. For example, turning on a light or an alarm when the measurement of a sensor is lower (or higher) than a certain setpoint.
However, when the variable to be controlled has feedback in the registered variable, we generally need to use a double threshold, that is, to use different setpoints for the activation and deactivation conditions.
For example, a thermostat that turns on or off a heat emitter depending on the registered temperature, or a pumping system that is activated if the level of a tank exceeds a certain level.
The interest of the double threshold, or hysteresis, is to avoid multiple activations in the actuator that would result in premature wear. In fact, in an ideal world where the action taken had an immediate effect and in the absence of noise, at the moment the threshold was crossed, the actuator would be activated, correcting the variable by a differential magnitude, sufficient to cause its disconnection. In other words, we would have infinite activations once the setpoint is reached, and the system would not be able to evolve to another state.
Of course, a real system has inertia, delays, inhomogeneities, etc. Therefore, we will not have an infinite number of activations, although it can still generate a large number of activations.
This leads us to the other reason for the double threshold, the noise in the registered variable. If, for example, we take the temperature measurement, when the sensor reaches the threshold, the room temperature is not perfectly homogeneous. Any small variation (noise) in the signal will again cause multiple triggers around the threshold.
The noise in the registered variable makes the double threshold advisable even for independent variables. For example, if we want to turn on a light if the water in a tank exceeds a level, it may also be advisable not to turn it off until it drops below a value lower than the turn-on value. Otherwise, the waves and turbulence on the liquid surface could cause a flickering effect in the sensor when crossing the threshold.
In this post we are going to see two simple implementations for an on/off control with single or double threshold in a programmable logic controller or processor such as Arduino.
Single threshold in Arduino
Implementing a single threshold is really simple. We will use a GetMeasure() function that simulates obtaining a measurement from a sensor.
We store the previous state, and based on the previous state and the current state, we determine if it is necessary to perform the activation or deactivation action.
// Simulates the capture of a sensor or reading from a sensor
int values[] = { 7729, 7330, ... };
size_t valuesLength = sizeof(values) / sizeof(values[0]);
int getMeasure()
{
size_t static index = 0;
index++;
return values[index - 1];
}
bool state;
int threshold = 15000;
void calculateThreshold(int value)
{
if (state == false && value > threshold)
{
state = true;
Rising();
}
else if (state == true && value < threshold)
{
state = false;
Falling();
}
}
void Rising()
{
Serial.println("Rising");
}
void Falling()
{
Serial.println("Falling");
}
void setup()
{
Serial.begin(9600);
state = true;
for (size_t index = 0; index < valuesLength; index++)
{
// Get simulated measurement
int rawMeasure = getMeasure();
calculateThreshold(rawMeasure);
}
}
void loop()
{
}
The system’s response is as follows. As we can see, the signal switches every time the signal crosses the setpoint in either direction. We also see that noise can cause multiple triggers around the setpoint, as we mentioned before.
For this reason, except in very simple systems, we will generally always use a double threshold in our projects.
Double threshold (hysteresis) in Arduino
Implementing a double threshold is not much more difficult. This time we will have two different setpoints, and the state change will depend on the previous state, the signal value, and both setpoints.
// Simulates the capture of a sensor or reading from a sensor
int values[] = { 7729, 7330, ... };
size_t valuesLength = sizeof(values) / sizeof(values[0]);
int getMeasure()
{
size_t static index = 0;
index++;
return values[index - 1];
}
bool state;
int riseThreshold = 20000;
int fallThreshold = 15000;
void calculateThreshold(int value)
{
if (state == false && value > riseThreshold)
{
state = true;
Rising();
}
else if (state == true && value < fallThreshold)
{
state = false;
Falling();
}
}
void Rising()
{
Serial.println("Rising");
}
void Falling()
{
Serial.println("Falling");
}
void setup()
{
Serial.begin(9600);
state = true;
for (size_t index = 0; index < valuesLength; index++)
{
// Get simulated measurement
int rawMeasure = getMeasure();
calculateThreshold(rawMeasure);
}
}
void loop()
{
}
The system’s response is as follows.
The system output is activated when the input exceeds the rising threshold, but it is not deactivated until it crosses the lower threshold. In this way, we eliminate the triggers that occurred due to noise in the case of a single threshold.
Threshold and double threshold in a library
What if we clean up and improve the code, and put it in a library to make it more comfortable to use? Of course, here is a Threshold library for Arduino. Enjoy it!
Download the code
All the code from this post is available for download on Github.