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
if (millis() > t + 1000) {
will run into problems about 49 days after arduino reset ... read this norwegiancreations.com/2018/10/…