Эффективные пороговые проверки абсолютного значения во встроенном С - PullRequest
3 голосов
/ 27 сентября 2019

Я думаю об эффективном способе реализации проверки порога (с необязательным гистерезисом и задержкой).

Требование / ситуация:

Я хочу проверить, например,неотрицательное значение (например, абсолютное давление) относительно верхнего порога и нижнего порога, приводящее к биту ошибки избыточного давления или биту ошибки пониженного давления соответственно.Будет несколько установленных и сбрасываемых пороговых значений.(Я хочу организовать в массив)

Учитывая гистерезис, должны быть разные значения установки и сброса: например, для случая избыточного давления установлен порог давления p_set (устанавливается бит ошибки) и сброспорог p_reset <= p_set.То же самое относится и к давлению отмены, но здесь p_reset >= p_set, что заставляет оператор сравнения инвертировать:

// Over pressure detection
if (pressure > overPressureSetThld){
  // Over pressure -> set error bit
else if (pressure < overPressureResetThld){
  // Reset over pressure error bit
}

// Under pressure detection
if (pressure < underPressureSetThld){              // Inverted comparison operator
  // Under pressure -> set error bit
else if (pressure > underPressureResetThld){       // Inverted comparison operator
  // Reset under pressure error bit

Альтернативы:

Думая об этом, я вижу дваальтернативы:

  1. Реализуйте его прямо вперед, как указано выше -> больший размер кода / «дублирующий» код (особенно с учетом задержки)
  2. Сравните относительные значения (вычитание и абс, требует опорного давления) -> уменьшить размер кода, потому что только один, если-ElseIf требуется, но выше во время выполнения нагрузки, например:

    1026 *if (abs(pressure - REFRENCE_PRESSURE) > relSetThld){ // Threshold relative to reference and positive // Set over/under pressure error bit else if (abs(pressure - REFRENCE_PRESSURE) < relResetThld){ // Threshold relative to reference and positive // Reset over/under pressure error bit

Вопрос:

Я склонен использовать альтернативу 2, но я спрашиваю себя (и вас), есть ли лучший способ сделать это.Предложения приветствуются!

Лучший Кристоф

1 Ответ

2 голосов
/ 27 сентября 2019

Самый эффективный способ реализовать что-то вроде проверки нескольких уровней с учетом скорости выполнения - это сформировать «бинарный поиск» / BST из различных уровней.Что на практике означает написание цепочки if-else:

if(val < level_mid)
  if(val < level_low)
    // ...
  else
    // ...
else
  if(val < level_high)
    // ...
  else
    // ...

Вы не можете превзойти вышесказанное с точки зрения производительности и веток.С точки зрения читабельности / обслуживания оптимальный код будет выглядеть примерно так:

if(val < level_lowest)
  // ...
else if(val < level_low)
  // ...
else if(val < level_mid)
  // ...
else if(val < level_high)
  // ...

Этот код также довольно эффективен, но гораздо более читабелен / удобен в обслуживании, чем альтернатива "двоичного поиска".Как всегда, разберите и убедитесь сами.

Но, конечно, оптимизация кода вручную без учета конкретной системы не очень разумна.Предположим, например, что вы используете 8 или 16-битный процессор.Все, что будет иметь значение с точки зрения производительности в этом случае, - это размер целочисленных типов.Точно так же использование типов с плавающей запятой в MCU без FPU приведет к крайне неэффективному коду.

Если вы оптимизируете размер кода, вам следует обратить внимание на совершенно другие аспекты, чем количество ветвей.Избавление от раздутых библиотечных вызовов - вещь №1 (я смотрю на вас, stdio.h).

Делать что-то вроде взятия абсолютных значений просто ради уменьшения размера кода бессмысленно - это не так.Совершенно очевидно, что это уменьшит размер кода.Что он, безусловно, сделает, так это увеличит сложность.Что, в свою очередь, приводит к увеличению кода и появлению новых ошибок.Примените принцип KISS .

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...