Как определить, когда выходной сигнал датчика значительно меняется?
Начиная с аналогового сигнала от любого датчика, как я могу автоматически определить, есть ли реальное изменение сигнала или сброс? Ниже приведен пример кода, который лучше объясняет мою цель:
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
}
Таким образом, если value(current) = 0.5
и value_old = 100
, то произошло реальное изменение сигнала, даже если из-за шума значение не совсем равно 0.
Это очень сырой код, и я хотел бы использовать более профессиональный подход, который может обнаруживать как инкременты, так и декременты. В идеале подходящая библиотека или, альтернативно, более эффективный алгоритм были бы идеальными.
@boromyr, 👍4
Обсуждение1 ответ
Лучший ответ:
Не существует простого и универсального способа решить, что считать “значительным” изменением. Моя рекомендация состояла бы в том, чтобы создать алгоритм, играя с данными на вашем компьютере:
Загрузите скетч на ардуино, который просто считывает датчик и передает показания на ваш компьютер по
последовательному
каналу.Запишите длинный цикл таких показаний в файл.
Составьте график показаний и внимательно посмотрите на графики: что бы вы сочли существенным изменением? Какие критерии вы могли бы использовать, чтобы решить , что изменение является значительным? Разработайте алгоритм принятия этого решения.
Реализуйте и протестируйте алгоритм на своем компьютере, используя записанные данные.
Перенесите код на Arduino.
Ниже приведены два примера, которые, возможно, могли бы дать вам некоторые идеи. Сначала приходит самое простое, что я могу придумать: он говорит, что изменение является значительным, если текущее значение достаточно далеко от ранее записанного значения. Это записанное значение обновляется только после обнаружения значительных изменений.
bool changed_significantly(int value) {
const int change_threshold = 4; // настройте по вкусу
static int old_value;
bool changed = abs(value - old_value) >= change_threshold;
if (changed)
old_value = value;
return changed;
}
Он будет использоваться следующим образом:
void loop() {
int value = sensorRead();
if (changed_significantly(value))
Serial.println("Signal changed.");
}
Обратите внимание, что с помощью этого алгоритма очень медленный дрейф будет периодически вызывать обнаружение значительных изменений. Если это не то, что вы хотите, вы можете предпочесть обнаруживать только те изменения, которые происходят достаточно быстро. Это может быть обнаружено с помощью фильтра высоких частот. Приведенная ниже функция реализует простой фильтр нижних частот (экспоненциально взвешенное скользящее среднее) и сравнивает текущий вход с предыдущим выходом. Разница эквивалентна фильтру высоких частот. Если эта разница достаточно велика, обнаруживается значительное изменение, затем фильтр сбрасывается , чтобы предотвратить его повторное срабатывание из - за дрейфа:
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: некоторые подробности о фильтре.
Один только этот фильтр высоких частот можно упростить следующим образом:
float filter(float x)
{
static float y;
float delta = x - y;
y += filter_constant * delta;
return delta;
}
Заметим, что если бы эта функция возвращала y
, то у нас был бы обычный
фильтр нижних частот первого порядка (экспоненциально взвешенная скользящая средняя).
Поскольку вместо этого он возвращает разницу между входным и
предыдущим значением с фильтрацией нижних частот, он ведет себя как фильтр верхних частот. Его
передаточная функция такова:
H = (z − 1) / (z + k − 1)
где k - постоянная фильтра. Эта константа связана с частотой среза следующим образом:
fc ≈ k fs / (2π)
где fs-частота дискретизации. Обратите внимание, что для частот, значительно меньших среза, фильтр ведет себя как масштабированная производная:
H x ≈ 1/(k fs) dx/dt
Мы не заслуживаем тебя, Эдгар!, @Zhelyazko Grudov
Почему небольшой дрейф со временем вызывает первый код? Не потому ли, что он накапливается в течение длительного периода времени? В принципе, это математика или проблема программирования?, @Zhelyazko Grudov
@ZhelyazkoGrudov: Это алгоритм. Записанное значение обновляется только после обнаружения значительных изменений. Если происходит медленный дрейф, он будет накапливать изменения до тех пор, пока это обнаружение не сработает., @Edgar Bonet
Большое вам спасибо, я попробовал вашу последнюю функцию, и она работает как надо, просто и эффективно!!!! Я действительно не понимаю функцию filter_constant, как я могу оценить идеальное значение на основе использования?, @boromyr
@boromyr: См. Расширенный ответ., @Edgar Bonet
- Вычисление отклонения от курса по магнитометру и акселерометру
- Как вы справляетесь с дрейфом датчиков?
- Ошибка поворота робота, решающего лабиринт, из-за увеличения расстояния датчика до угла во время поворота
- Получение точных показаний скорости от IMU
- Результаты Arduino FFT "красивого" сигнала кажутся противоречивыми
- Как правильно сделать сканер массива символов?
- Как запрограммировать Arduino Uno для сбора данных с помощью прерывания таймера и анализа этих данных в matlab?
- Как обнаружить закономерности в выводе БПФ?
https://www.best-microcontroller-projects.com/arduino-absolute-value.html, @jsotola
вы можете усреднить показания за определенный период времени, @jsotola
if (millis() > t + 1000) {
столкнется с проблемами примерно через 49 дней после сброса arduino ... прочтите это https://www.norwegiancreations.com/2018/10/arduino-tutorial-avoiding-the-overflow-issue-when-using-millis-and-micros/, @jsotolaПроблема не в millis(). Значения уже отфильтрованы по скользящей средней, я хочу различать приращения., @boromyr
Что вы знаете о незначительном шуме процесса? Вы заботитесь о дрифте? Например, будет ли +0.1 за цикл заслуживать внимания?, @Dave X