• Без рубрики

Есть тут программисты

Собственно тоже спрошу, есть тут программисты? Есть переменный резистор, скармливаю его показания через аналоговый порт на микроконтроллер. В итоге при парсинге данных с резистора я получаю кучу скачущих значений. Мне как то их надо сгладить. догадываюсь что нужно брать значения пачками, высчитывать среднее арифметическое и возвращать уже скругленное значение, но что-то на ночь глядя не могу придумать подходящий алгоритм.

You may also like...

24 комментария

  1. Роман:

    Порт зашунтируй кондером 0,1мкф

  2. Константин:

    цикл из N захватов данных (вруби АЦП в разовом режиме и при каждом следующем запуске делай инкремент счетчика)
    В конце цикла расчет среднего и обнуление.
    Можно эту тему через прерывания завязать, забить цикл внутри тела прерывания. Так даже рациональнее будет.

  3. Константин:

    Но вообще не должно быть такого.
    У меня на AVRках всё четко работает, значения не скачут.

  4. Михаил:

    Константин, На олдскульном килоомнике все отлично, а вот грибок от геймпада дребезжит нехило(((

  5. Роман:

    Константин, ды он просто порнографию ловит на порт из эфира, вот и все….

  6. Константин:

    Роман, да тоже так думаю. Хотя всякое может быть

  7. Константин:

    Михаил, страннота. Ну тогда только аппроксимация поможет.

  8. Михаил:

    Константин, Вот выручил!! Зафигачу массив буду скармливать ему по 10 значений, выводить среднее арифметическое а массив сдвигать каждый раз!! Юхххуууу!

  9. Михаил:

    Роман, И кондер кстате попробую, Тож на дребезг грешил

  10. Константин:

    Михаил, ты опять усложняешь.
    Зачем расходовать лишнюю память, если можно взять 1 переменную, вначале ее обнулить, затем суммировать в нее все, скажем, 10 значений, а потом в конце цикла (или при значении счетчика == 10) разделить ее на 10 и получить среднее?
    С таким подходом тебе памяти не хватит

  11. Михаил:

    Константин, но смотри тогда хреновый антиалисинг получится, считай ты берешь каждый раз новую пачку данных, а так, просто сдвигаешь регистр беря уже имеющиеся данные добавляя каждый раз по новому значению и подтирая старое. надо и так и так протестировать. Сейчас задача стоит в получении чистейших значений. Но в погоне за каждым байтом твой алгоритм лучше.

  12. Константин:

    Михаил, мм
    про сдвиг я не думал.
    идея прикольная

  13. Евгений:

    Михаил, всё правильно, называется скользящее среднее.
    А еще перед АЦП нужен аналоговый антиалиасинговый фильтр с частотой среза 2Fs, чтобы спектр более высоких частот не лез в рабочую область.

  14. Юрий:

    Фильтр. Фильтр низких частот тебе нужен. Передаточная простейший первого порядка (апериодический фильтр) выглядит следующим образом:
    W(p) = 1/(T1*p+1),
    где T1 = 1/(2*pi*f) — постоянная времени фильтра, а f, Гц — частота среза. Ослабление сигнала у этого фильтра составляет 20 дБ/дек. При переходе к дискретной форме через билинейное преобразование (p = 2/T (1 — z^-1)/(1 + z^-1)), получим:
    W(z) = (1 + z^-1)/((T1*2/T + 1) — (T1*2/T — 1) z^-1),
    где T — период дискретизации сигнала. При переходе к разностным уравнениям, получим:
    Out[k] = 1/(T1*2/T + 1) ( In[k] + In[k-1] + (T1*2/T — 1) Out[k-1] );
    Out[k] = K * ( In[k] + In[k-1] + A*Out[k-1] ),
    где In[k] — входной сигнал, Out[k] — выходной сигнал,
    K = 1/(T1*2/T + 1); A = T1*2/T — 1; — константы.
    Это простое рекуррентное выражение, в котором необходимо запоминать предыдущие значения входа (In[k-1]) и выхода после фильтра (Out[k-1]). Эта штука при этом будет описывать обычный фильтр НЧ первого порядка.
    Можно ещё использовать простой переход по Эйлеру 1-го порядка:
    W(p) = 1/(T1*p+1);
    Out'(t) = 1/T1 (In(t) — Out(t));
    Out[k] = Out[k-1] + Out'[k]*T = Out[k-1] + T/T1 (In[k] — Out[k]);
    Out[k] = 1/(1+T1/T) (In[k] + T1/T*Out[k-1]) ;
    Тут требуется запомнить только предыдущее состояние выхода фильтра. Будет работать примерно так же, но более грубо.

  15. Юрий:

    О так можно взять ещё и фильтр n-го порядка, с ослаблением ВЧ составляющей n*20 дБ/дек. В общем-то, он составляется из n соединённых последовательно одинаковых фильтров НЧ 1-го порядка по тому же самому рекуррентному выражению. При этом получается эдакая конвейерная обработка сигнала. Но при желании можно всё это свести в одно большое выражение. В любом случае на каждый порядок фильтра необходимо запоминать соответствующую долю информации о предыдущих состояниях сигналов.
    Кстати, частоту среза фильтра, соответственно, необходимо взять на менее чем в 2 раза большей, чем максимальная частота вращения ручки потенциометра. а лучше в 10 раз больше. Думаю, f = 5 Гц достаточно.

  16. Михаил:

    Юрий, Охх я не думал что настолько глубокая кроличья нора))))

  17. Юрий:

    Михаил, ну вообще есть целая теория обработки сигналов, но тебе достаточно лишь заставить контроллер считать выражение:
    get(I);
    F = k1 * ( I + Iold + k2*Fold);
    lold = l;
    Fold = F;
    send(F);
    🙂

  18. Михаил:

    Юрий, Спасибо огромное!

  19. Максим:

    Делить лучше на 8, 16, 32 итд… Тогда быстрее будет

  20. Юрий:

    Вообще, то что вы предлагали выше со средним значением, называется фильтром с конечной импульсной характеристикой (или КИХ, или FIR). Т.е. их значение, при подаче постоянного сигнала, устанавливается за конечное фиксированное количество тактов, потому что в них нет обратных связей. Их, вообще говоря, любят использовать, потому что они всегда устойчивы, ну и из-за их конечного переходного процесса и отсутствия обратных связей. Но они и требуют запоминания большего множества данных для работы.
    То что я привёл — это фильтр с бесконечной импульсной характеристикой (БИХ, IIR). Такие фильтры более гибкие ввиду присутствия обратных связей, но и требуют от разработчика больше усилий, т.к. нужно исследовать их ещё и на устойчивость.

  21. Юрий:

    Максим, это, кстати, верно. Но вообще говоря, при делении даже на степени 2-ки по хорошему нельзя забывать об округлении. Т.е. если у нас в результате деления после запятой осталась 1-ца, то её необходимо добавить к целому результату. А вообще, с учётом, что умножение на дробную константу не представляет особых проблем, лучше оставить это дело на совесть компилятора.

  22. Юрий:

    Да, кстати. Как сказал Роман, возможно проблема и в железной части. Может быть переменник обладает слишком большим сопротивлением и из-за этого АЦП не может нормально буфферизировать входное напряжение. Если есть возможность, то лучше доработать аппаратную часть, добавив усилитель или тем же конденсатором.

  23. Михаил:

    Юрий, ага, это только опытным путём можно выяснить, к сожалению осциллографа нет чтоб узнать наверняка)

  24. Юрий:

    Михаил, ещё, как вариант — снизить частоту дискретизации АЦП (увеличив время преобразования), добавив дополнительно время на семплинг. Но с этим я никогда не возился, по этому это как экспериментально. )

Добавить комментарий для Юрий Отменить ответ

Ваш e-mail не будет опубликован. Обязательные поля помечены *