Starting with an analog signal from any sensor, how do I automatically determine if there is a real signal change or a reset? Below is the sample code that better explains my goal:
value = sensorRead();
if (millis() > t + 1000) {
value_old = value;
t = millis();
}
float d = value - value_old;
if (d < -3) {
print("signal change")
myfunction(); //ex. bink led
}
So if value(current) = 0.5
and value_old = 100
there has been a real change in signal, even if, because of noise, the value is not exactly 0.
It's very raw code, and I'd like to use a more professional approach that can detect both increments and decrements. Ideally, a suitable library, or alternatively a more efficient algorithm, would be ideal.
1 Answer 1
There is no simple and universal way of deciding what is to be considered a "significant" change. My recommendation would be to create an algorithm by playing with the data on your computer:
Upload a sketch to your Arduino that simply reads the sensor and transmits the readings to your computer via
Serial
.Capture a long run of such readings in a file.
Graph the readings and look carefully at the graphs: what would you consider a significant change? What criteria could you use to decide that a change is significant? Devise an algorithm to take this decision.
Implement and test the algorithm on your computer, using the recorded data.
Port the code to the Arduino.
Below are two examples that maybe could give you some ideas. First comes the simplest I can think of: it says the change is significant if the current value is far enough from a previously recorded value. That recorded value is only updated after a significant change has been detected.
bool changed_significantly(int value) {
const int change_threshold = 4; // tune to taste
static int old_value;
bool changed = abs(value - old_value) >= change_threshold;
if (changed)
old_value = value;
return changed;
}
It would be used like this:
void loop() {
int value = sensorRead();
if (changed_significantly(value))
Serial.println("Signal changed.");
}
Note that, with this algorithm, a very slow drift would periodically trigger the detection of significant changes. If this is not what you want, you may prefer to only detect changes that happen fast enough. This can be detected by the use of a high-pass filter. The function below implements a simple low-pass filter (exponentially weighted moving average) and compares the current input to the previous output. The difference is equivalent to a high-pass filter. If that difference is large enough, a significant change is detected, then the filter is reset in order to prevent it from being repeatedly triggered by a drift:
bool changed_significantly(int value) {
const float change_threshold = 4; // tune to taste
const float filter_constant = 0.1; // this one also
static float filtered_value;
float delta = value - filtered_value;
bool changed = abs(delta) >= change_threshold;
if (changed)
filtered_value = value;
else
filtered_value += filter_constant * delta; // low-pass filter
return changed;
}
Edit: some details about the filter.
This high-pass filter alone could be simplified as this:
float filter(float x)
{
static float y;
float delta = x - y;
y += filter_constant * delta;
return delta;
}
Note that, if this function returned y
, we would have a conventional
first-order low pass filter (exponentially weighted moving average).
Since it returns instead the difference between the input and the
previous low-pass-filtered value, it behaves as a high-pass filter. Its
transfer function is
H = (z − 1) / (z + k − 1)
where k is the filter constant. This constant is related to the cut-off frequency as
fc ≈ k fs / (2π)
where fs is the sampling frequency. Note that, for frequencies significantly smaller than the cut-off, the filter behaves like a scaled derivative:
H x ≈ 1/(k fs) dx/dt
-
We don't deserve you Edgar!Zhelyazko Grudov– Zhelyazko Grudov2022年01月27日 19:54:35 +00:00Commented Jan 27, 2022 at 19:54
-
Why would small drift over time trigger the first code? Is it because it accumulates over a long period of time? Basically, is it a math thing, or a programming issue?Zhelyazko Grudov– Zhelyazko Grudov2022年01月27日 20:09:54 +00:00Commented Jan 27, 2022 at 20:09
-
1@ZhelyazkoGrudov: It's the algorithm. The recorded value is only updated after a significant change has been detected. If there is a slow drift, it will accumulate change until that detection is triggered.Edgar Bonet– Edgar Bonet2022年01月27日 20:22:40 +00:00Commented Jan 27, 2022 at 20:22
-
Thank you so much, I tried your last function, and it works as desired, simple and effective!!!! I don't really understand the filter_constant function, how can I estimate the ideal value based on usage?boromyr– boromyr2022年01月28日 20:55:06 +00:00Commented Jan 28, 2022 at 20:55
-
@boromyr: See expanded answer.Edgar Bonet– Edgar Bonet2022年01月28日 22:53:45 +00:00Commented Jan 28, 2022 at 22:53
Explore related questions
See similar questions with these tags.
if (millis() > t + 1000) {
will run into problems about 49 days after arduino reset ... read this norwegiancreations.com/2018/10/…