Перейти к содержанию
    

Простейший цифровой ФНЧ

Есть массив, в котором записаны значения с АЦП. Напряжения формируют некую "огибающую"

 

Платформа: STM32, сигнал - массив значений с АЦП в вольтах.

 

1)Подскажите фильтр (алгоритм на Си) чтобы сгладить(усреднить) значения в массиве?

2) Как определить характерные места у огибающей (резкое увеличение значения, резкий спад)

 

post-34798-1295522267_thumb.jpg

Изменено пользователем Ivan Kuznetzov

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть массив, в котором записаны значения с АЦП. Напряжения формируют некую "огибающую"

 

1)Подскажите фильтр чтобы сгладить(усреднить) значения в массиве?

Для каждого элемента массива посчитайте среднее значение от окружающих его элементов.

Это и есть простейший цифровой ФНЧ. Чем шире окрестность, в которой считается среднее - тем сильнее "сглаживание", но и искажение формы исходного сигнала также сильнее.

Если не вдаваться в теорию - вот как-то так.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Demeny, спасибо! функция уже заметно красивей стала!!!

 

for (x=1;x<ARRAYSIZE;x++) Pulsearray[x] = (Pulsearray[x-1] + Pulsearray[x+1])/2;

post-34798-1295524959_thumb.jpg

Изменено пользователем Ivan Kuznetzov

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

for (x=1;x<ARRAYSIZE;x++) Pulsearray[x] = (Pulsearray[x-1] + Pulsearray[x+1])/2;

Наверное лучше

Pulsearray[x] = (Pulsearray[x-1] + Pulsearray[x] + Pulsearray[x+1])/3;

:)

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

AHTOXA, спасибо, действительно красивее! :rolleyes:

 

Вот еще не пойму, как на синем графике найти указанные стрелками точки? дельту измерять какую-нибудь? :wacko:

 

post-34798-1295531703_thumb.jpg

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Есть метод скользящего среднего, считается так:

 

(текущий обработанный результат)=( (предыдущий обработанный результат)*(N-1)/N )+(текущий код АЦП)/N

 

Под кодом АЦП может выступать текущий отсчет необработанной вашей реализации. Собственно точки тогда имеют железную привязку :)

 

N=1....и до бесконечности

 

на практике достаточно N до 32, ну и естественно с ростом N теряются подробности сигнала.

 

 

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

AHTOXA, спасибо, действительно красивее! :rolleyes:

Да, но так всё равно неправильно :) Получается, что для первой точки мы взяли начальные данные, а для остальных - одна из точек (которая x-1) - уже отфильтрованная. Надо либо занычивать её в переменной, либо фильтровать в другой массив.

А лучше сделать скользящее среднее, как написал firstvald. Там можно регулировать степень сглаживания.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

/************************************************************************
*                                                                        *
*                   Библиотека для цифровой фильтрации.                    *
*                            Версия:     1.01.                                *
*                                                                        *
* Файл: fir.c        Дата создания: 08.07.2010г.                            *
*              Последние изменения: 08.07.2010г.                            *
* Сапего Александр Леонидович. ([email protected])                        *
*                                                                        *
************************************************************************/

#include "stdint.h"

// Фильтр 2-го порядка исходя из формулы y0^ = a0*(x0+x2)+a1*x1 + b1*y0 + b2*y1 + c1*y0
// где a и b - коэффициенты, c - целая часть y0
// После выполнения производится сдвиг y.
// y1 -> y2, y0 -> y1, y0^ -> y0;
//
// В процедуру передаётся 2 параметра
// 1 - указатель на значения, в последовательности: x0,x1,x2,y0,y1,y2
// 2 - указатель на значения коэффициентов в последовательности: a0,a1,b1,b2,c1
// По финишу результат делится на 32768

struct    data_s
{
  int16_t        x[3],y[3];                                // Данные фильтра
};

struct    coef_s
{
  int16_t        a0, a1, b1, b2, c1;                        // Коэффициенты фильтра
};

void fir2_16(uint8_t * data, uint8_t * coef)
{
  struct data_s    *d_s;
  struct coef_s    *c_s;
  int32_t        acc;
  
  d_s = (struct data_s *) data;
  c_s = (struct coef_s *) coef;
  acc = (int32_t)(d_s->x[0] + d_s->x[2]) * (int32_t)c_s->a0;
  acc += (int32_t)d_s->x[1] * (int32_t)c_s->a1;
  acc += (int32_t)d_s->y[0] * (int32_t)c_s->b1;
  acc += (int32_t)d_s->y[1] * (int32_t)c_s->b2;
  acc >>= 15;
  acc += d_s->y[0] * c_s->c1;
  d_s->y[2] = d_s->y[1];
  d_s->y[1] = d_s->y[0];
  d_s->y[0] = acc;
}

 

// Фильтр Баттерворта 4 порядка 1000 -> 100; 200  = -30 дб
//
// 1 звено y0 = 0,061885*(x0+x2) + 0,123770*x1 + 1,048600*y1 - 0,296140*y2
// Коэффициенты a0,a1,b1,b2,c1 = 2028, 4056, 1593, -9704, 1 
// 2 звено y0 = 0,077956*(x0+x2) + 0,155913*x1 + 1,320910*y1 - 0,632739*y2
// Коэффициенты a0,a1,b1,b2,c1 = 2554, 5109, 10516, -20734, 1
//
int16_t            fltr_c1[5] = {2028, 4056, 1593, -9704, 1},
                fltr_c2[5] = {2554, 5109, 10516, -20734, 1};

 

    fir2_16((uint8_t *)&lin[cnt_line].x[0],(uint8_t *)fltr_c1);// Первое звено фильтра
    fir2_16((uint8_t *)&lin[cnt_line].y[0],(uint8_t *)fltr_c2);// Второе звено фильтра

 

Так например. ))

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

SasaVitebsk, поясните пожалуйста как пользоваться? Есть массив, 200 точек. Входные параметры фильтра - это data?

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Пробегало давненько:

u16_t Yavg;

for(;;)
{
   Yavg -= Yavg/256;
   Yavg += ADCH;
}

 

Запуск и готовность АЦП за Вами.

Утверждается, что в старшем байте Yavg получим фильтр НЧ с частотой среза = частоте запуска АЦП/256

с погрешностью обработки <0.5 LSB, по АФЧХ эквивалентный RC цепочке с такой же частотой среза.

 

Почему? Хемминг уже рассказал, у меня лучше не получится.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Платформа: STM32, сигнал - массив значений с АЦП в вольтах.

 

1)Подскажите фильтр (алгоритм на Си) чтобы сгладить(усреднить) значения в массиве?

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

1)Подскажите фильтр (алгоритм на Си) чтобы сгладить(усреднить) значения в массиве?

2) Как определить характерные места у огибающей (резкое увеличение значения, резкий спад)

 

1) demiurg_spb и firstvald уже подсказали простейший IIR фильтр:

y[0] = x[0];
for (int i = 1; i < len; i++) y[i] = y[i-1] + (x[i] - y[i-1]) * K

K = 0.0 .. 1.0, временная постоянная фильтра. Ну и конечно можно (и нужно) заменить на целочисленное умножение и битовый сдвиг вправо.

 

Хотя если надо потом точно определять положение "характерных мест", то fir фильтр (скользящее среднее - частный случай) лучше из-за линейной фазовой характеристики. Кстати, то что предложил SasaVitebsk - fir фильтром не является.

 

2) искать локальные максимумы на производной, или, если заранее известно то как именно выглядит то что хочется найти, то максимумы корреляционной функции сигнала с тем, что ищем.

 

разводить плату надо было так, чтобы программисту не пришлось фильтровать результаты АЦП

таким сигнал вполне может быть изначально, и совсем не обязательно вызван шумами на плате.

 

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Если вы работаете в серьезной фирме, а не в кружке "умелые руки" при районном доме пионеров, то разводить плату надо было так, чтобы программисту не пришлось фильтровать результаты АЦП. Как именно разводить - написано в любом учебнике схемотехники.
Ага и всем-всем заказчикам отрубать руки если они датчик (TC или RTD например) подключат проводом без экрана и не дай Бог вблизи силовых кабелей или или или.......... :-)

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

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

В Саратове живут суровые профэссианалы :biggrin:

Увы - не все. Почему-то считается немерянной крутизной развести плату минимального размера, сэкономив на конденсаторах по питанию, землях и размещении элементов - главное упихать их поплотнее, а то, что АЦП шумит на 4 разряда - это фигня, программисты отфильтруют.

Поделиться сообщением


Ссылка на сообщение
Поделиться на другие сайты

Присоединяйтесь к обсуждению

Вы можете написать сейчас и зарегистрироваться позже. Если у вас есть аккаунт, авторизуйтесь, чтобы опубликовать от имени своего аккаунта.

Гость
Ответить в этой теме...

×   Вставлено с форматированием.   Вставить как обычный текст

  Разрешено использовать не более 75 эмодзи.

×   Ваша ссылка была автоматически встроена.   Отображать как обычную ссылку

×   Ваш предыдущий контент был восстановлен.   Очистить редактор

×   Вы не можете вставлять изображения напрямую. Загружайте или вставляйте изображения по ссылке.

×
×
  • Создать...