Как определить, когда выходной сигнал датчика значительно меняется?

Начиная с аналогового сигнала от любого датчика, как я могу автоматически определить, есть ли реальное изменение сигнала или сброс? Ниже приведен пример кода, который лучше объясняет мою цель:

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.

Это очень сырой код, и я хотел бы использовать более профессиональный подход, который может обнаруживать как инкременты, так и декременты. В идеале подходящая библиотека или, альтернативно, более эффективный алгоритм были бы идеальными.

, 👍4

Обсуждение

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


1 ответ


Лучший ответ:

4

Не существует простого и универсального способа решить, что считать “значительным” изменением. Моя рекомендация состояла бы в том, чтобы создать алгоритм, играя с данными на вашем компьютере:

  • Загрузите скетч на ардуино, который просто считывает датчик и передает показания на ваш компьютер по последовательномуканалу.

  • Запишите длинный цикл таких показаний в файл.

  • Составьте график показаний и внимательно посмотрите на графики: что бы вы сочли существенным изменением? Какие критерии вы могли бы использовать, чтобы решить , что изменение является значительным? Разработайте алгоритм принятия этого решения.

  • Реализуйте и протестируйте алгоритм на своем компьютере, используя записанные данные.

  • Перенесите код на 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