Zelepuk
Mar 23 2011, 12:18
Собираюсь реализвоать Цифровую фильтрацию на Си.
Смотрю в матлабе модель фильтра. Как и положено наблюдается нектороый переходный процесс.
Мой алгорит фильтрации бцдет работать так:
отсчёты из АЦП поступают в некий буфер, раз в 1 секунду возникает прерывание, в котором, выборки из буфера кидаются в друго буфер, и производится фильтрация.
Боюсь, что возникнет переходный процесс. Так как данные при таком подходе фильтруются не непрерывно.
Какими приёмами можно избежать переходных процессов?
SSerge
Mar 23 2011, 12:29
"некий буфер" должен быть кольцевым.
maugli
Mar 23 2011, 12:32
Сохраняйте полное состояние фильтра в прмежутках фильтрации .
Zelepuk
Mar 23 2011, 13:15
Цитата(SSerge @ Mar 23 2011, 15:29)

"некий буфер" должен быть кольцевым.
да. буфер кольцевой, но фильтрация всё равно осущестлвяется над куском этого буфера...
Цитата(maugli @ Mar 23 2011, 15:32)

Сохраняйте полное состояние фильтра в прмежутках фильтрации .
Можно по подробнее. Что такое полное состояние фильтра?
Мусатов Константин
Mar 23 2011, 13:36
Вы будете использовать какой тип фильтра? КИХ, БИХ, FFT?
Как я понимаю, если вы хотите делать обработку порциями, то это только FFT фильтр. Для отсутствия выбросов на границах блоков с такими фильтрами надо использовать специальный алгоритм сшивки. Точно не скажу, но там вроде подбирается фаза.
Переходные процессы - неотъемлемая часть любых фильтров, придется смириться.
Вам следует лишь обеспечить непрерывность поступления входных данных от АЦП. В этом случае переходный процесс будет только в начале работы. При любых разрывах во ВХОДНЫХ данных (а не в их обработке) будут переходные процессы на разрывах.
А так - пока непонятно, во время прерывания и передачи части данных на обработку у вас входные данные продолжают равномерно поступать?
И что такое полное состояние фильтра вы поймете, когда напишете формулу для цифровой фильтрации.
ЗЫ. Обработку порциями можно реализовать не только в БПФ (FFT), но и в КИХ- и БИХ-фильтрах. В БПФ для "сшивки" используется суммирование с перекрытием.
Zelepuk
Mar 23 2011, 13:55
У меня данные от АЦП полступают всегда, прерывание от АЦП - высокоприоритетное прерывание.
Надо осуществить постоянное поступление данных в фильтр? Бесконечная циклическая фильтрация? а если фильтров несколько?
Алгоритм по сути такой: данные из циклического буфера фильтруются ких фильтром и идут на FFT, в то же время, необходимо раз в секунду фильтровать блок данных БИХ фильтром (в прерывании) и вычислять частоту сигнала.
Вот как-то так.
Мусатов Константин
Mar 23 2011, 15:04
Цитата
Обработку порциями можно реализовать не только в БПФ (FFT), но и в КИХ- и БИХ-фильтрах
Но тогда непонятно как порции результатов сшивать. Если сшивать не надо, то понятно, что можно.
Цитата
Надо осуществить постоянное поступление данных в фильтр? Бесконечная циклическая фильтрация? а если фильтров несколько?
Несколько последовательных фильтров или несколько параллельных каналов фильтров?
bahurin
Mar 23 2011, 15:38
любой фильтр КИХ или БИХ может работать бесконечно. Переходной процесс будет только в начале если данные идут без разрывов. Цифровой фильтр это набор ячеек памяти и коэффициентов нерекурсивной и рекурсивной части (если она есть). Поскольку коэффициенты не изменяются то вам нужно запомнить состояние ячеек памяти на последнем отсчете предыдущего куска и использовать эти значения как начальные условия на следующем куске. Сшивка в этом случае будет автоматической.
Zelepuk
Mar 23 2011, 15:39
Алгоритм обработки данных должен выглядеть как на рисунке ниже.
Как фильтрация по уму делается?
Понимаю что накапливать блок данных, а затем фильтровать не совсем good (это для FFT годится).
как я понимаю фильтрация (как КИХ так и БИХ в моём случае) должна выполнятся непрерывно с приходом новго отсчёта? Соответственно формируются новые буферы циклические (ещё два буфера помимо основного), в которых лежат фильтрованые данные...
а в прерывании (1 раз в секунду для расчёта частоты) уже обработывать фильтрованые данные, а не фильтровать...
Наставтье на путь истиный...
Мусатов Константин
Mar 23 2011, 20:40
Цитата(bahurin @ Mar 23 2011, 18:38)

любой фильтр КИХ или БИХ может работать бесконечно. Переходной процесс будет только в начале если данные идут без разрывов. Цифровой фильтр это набор ячеек памяти и коэффициентов нерекурсивной и рекурсивной части (если она есть). Поскольку коэффициенты не изменяются то вам нужно запомнить состояние ячеек памяти на последнем отсчете предыдущего куска и использовать эти значения как начальные условия на следующем куске. Сшивка в этом случае будет автоматической.
Это все понятно. Выражение блоковая обработка означает, что получили ограниченный блок и с ним возимся. А КИХ или БИХ фильтры потоковые, работающие на FIFO или циклических буферах. В том то и суть, что операция выполняется на каждом отсчете (не важно потом или сразу), в отличие от FFT, где берется блок и операция выполняется над блоком. Хотя, вроде есть алгоритмы непрерывного FFT...
Цитата(Zelepuk @ Mar 23 2011, 18:39)

Алгоритм обработки данных должен выглядеть как на рисунке ниже.
Наставтье на путь истиный...
То, что Вы называете блок компенсации - это так же фильтр, КИХ или БИХ, в зависимости от сложности и требований. Его было бы логично объединить с децимирующим, что бы снизить вычислительные нагрузки. Но это надо смотреть вам исходя из параметров. КИХ фильтр исполняется на каждом отсчете. Имеете циклический буфер, на место самой старой записи пишете новую, сдвигаете курсор начала и выполняете операцию свертки. Полученный результат идет дальше. И так на каждом шаге. Где надо делать FFT, копите буфер. Как заполнился, выполнили FFT и очистили буфер. Может потребоваться два буфера, если FFT не выполнится за цикл оцифровки.
Pavel_SSS
Mar 23 2011, 21:43
Цитата(Zelepuk @ Mar 23 2011, 18:39)

Алгоритм обработки данных должен выглядеть как на рисунке ниже.
Как фильтрация по уму делается?
Понимаю что накапливать блок данных, а затем фильтровать не совсем good (это для FFT годится).
как я понимаю фильтрация (как КИХ так и БИХ в моём случае) должна выполнятся непрерывно с приходом новго отсчёта? Соответственно формируются новые буферы циклические (ещё два буфера помимо основного), в которых лежат фильтрованые данные...
а в прерывании (1 раз в секунду для расчёта частоты) уже обработывать фильтрованые данные, а не фильтровать...
Наставтье на путь истиный...
Какие частоты на входе и на выходе? По идее Вам надо спроектировать, к примеру в Матлабовском FDATool децимирующий фильтр, потом сделайте кольцевой буфер длиннее порядка фильтра и такой длинны, чтобы данные не наползали за время обработки, после чего вычисляйте каждый N-ный отсчет (N - коэффициент децимации, надеюсь у Вас - целый), результат сохраняйте в другой кольцевой буфер и обрабатывайте дальше.
Кстати, а зачем перед измерителем частоты БИХ - фильтр? Частоту можно измерить например путем подсчета переходов через ноль - чтобы не мешал шум переход засчитывайте только если сигнал после перехода пересек также некий пороговый уровень в ту же сторону. Пороговый уровень может быть, например, 1/3 размаха, либо, если сигнал зашумлен, можно сделать ФАПЧ.
Про "сшивку", суммирование с перекрытием и "фильтрацию по уму" в случае FFT.
Сначала выясняете длину импульсной характеристики M. Если имеете только частотную характеристику, делаете обратное ДПФ от нее и выясняете, при каком M отсчеты становятся меньше требуемой точности вычислений.
Потом определеяте потребную длину FFT N.
Входной поток разбиваете на блоки по N-M отсчетов, дополняете M нулями и делаете FFT. При необходимости фильтруете и делаете обратное FFT.
Таким образом, входные блоки имеют длину N-M, выходные N. Непрерывный выходной поток получаете, объединяя выходные блоки с перекрытием M отсчетов. Внутри зоны перекрытия суммируете одновременные отсчеты из разных блоков. От более раннего блока это затухающие отсчеты, от более позднего - начальные отсчеты переходного процесса. В сумме они обеспечивают математически корректную сшивку блоков.
Все, непрерывный выходной поток не имеет переходных процессов внутри себя, только в начале.
Хотя, может, ваша задача и не требует обратного преобразования и суммирования с перекрытием.
Zelepuk
Mar 24 2011, 06:29
Спасибо всем за коментарии. Ситуация проясняется.
Выходит что если меем некий каскад КИХ-фильтров (к примеру), то нужно для каждого этапа (для каждого нового фильтра) делать свой колцевой буфер?
Есть какие-то критерии повыбору длины? иначе говоря как расчитать длину кольцевого буфера чтобы успеть брать и обробатывать по одному тсчёту(фильтрация)?
Итого имеем систему:
АЦП -> кольцевой буфер -> КИХ-фильтр дециматор -> кольцевой буфер -> БИХ-фильтр
Вывод: до каждого фильтра должен стоять кольцевой буфер.
Pavel_SSS
Mar 24 2011, 07:01
Цитата(Zelepuk @ Mar 24 2011, 09:29)

Спасибо всем за коментарии. Ситуация проясняется.
Выходит что если меем некий каскад КИХ-фильтров (к примеру), то нужно для каждого этапа (для каждого нового фильтра) делать свой колцевой буфер?
Есть какие-то критерии повыбору длины? иначе говоря как расчитать длину кольцевого буфера чтобы успеть брать и обробатывать по одному тсчёту(фильтрация)?
Итого имеем систему:
АЦП -> кольцевой буфер -> КИХ-фильтр дециматор -> кольцевой буфер -> БИХ-фильтр
Вывод: до каждого фильтра должен стоять кольцевой буфер.
В принципе да. Входной кольцевой буфер необходим для того, чтобы хранить достаточное для работы фильтра количество входных отсчетов, выходные отсчеты, соответственно, сохраняются в выходном кольцевом буфере.
КИХ - фильтры каскадно практически никогда не включают - их почти всегда можно привести к одному фильтру. БИХ - фильтры наоборот - почти всегда разбивают на звенья второго порядка и эти звенья включают последовательно.
Zelepuk
Mar 24 2011, 07:26
Но как найти глубину этих буферов? Есть критерии?
Pavel_SSS
Mar 24 2011, 07:46
Цитата(Zelepuk @ Mar 24 2011, 10:26)

Но как найти глубину этих буферов? Есть критерии?
Буфер должен содержать данные, необходимые для расчета следующего выходного отсчета КИХ-фильтра, следовательно его размер должен быть никак не меньше порядка КИХ-фильтра, плюс к тому необходим некоторый запас - ведь в буфер с одной стороны поступают данные от АЦП - например по прерываниям от АЦП, и надо чтобы данные от АЦП не наползали на данные , которые Вы считываете при выполнении КИХ - фильтрации. Какой запас - зависит от скоростей обработки и входного потока. Если Вы обрабатываете данные - вычисляете следующий отсчет - в той же процедуре обработки прерывания, которая считывает данные из АЦП, то никакого запаса не надо, лишь бы процедура успевала закончиться до прихода следующего прерывания от АЦП. В Вашем случае Вам целесообразно в процедуре обработки прерывания выполнять сразу и децимацию - например при дцеимации в 8 раз просто пропускать 7 отсчетов и вычислять восьмой с помощью КИХ-фильтра, сохраняя выходные отсчеты в выходном кольцевом буфере - там поток будет в 8 раз меньше чем входной поток данных.
Длина кольцевого буфера равна числу запоминаемых отсчетов. Для КИХ - входных отсчетов, для БИХ - 2 буфера, для входных и выходных отсчетов.
Число отсчетов определяется порядком фильтра. Спроектируйте в Матлабе КИХ-фильтр, к примеру, он (Матлаб) вам выдаст порядок фильтра.
Zelepuk
Mar 24 2011, 08:52
Цитата(V_G @ Mar 24 2011, 11:33)

Длина кольцевого буфера равна числу запоминаемых отсчетов. Для КИХ - входных отсчетов, для БИХ - 2 буфера, для входных и выходных отсчетов.
Число отсчетов определяется порядком фильтра. Спроектируйте в Матлабе КИХ-фильтр, к примеру, он (Матлаб) вам выдаст порядок фильтра.
а как же скорочть оработки? Думаю тут ещё важно за сколько процессор MAC делает...
Pavel_SSS
Mar 24 2011, 09:21
Цитата(Zelepuk @ Mar 24 2011, 11:52)

а как же скорочть оработки? Думаю тут ещё важно за сколько процессор MAC делает...
Допустим у Вас выборки поступают раз в 10 мкс, для децимации необходим фильтр с 50 коэффициентами, для которого надо 30 мкс времени. Также допустим что необходима децимация в 8 раз. Тогда Вы каждые 10 мкс сохраняете выборки в кольцевом буфере(входном) по прерыванию от АЦП, и каждый 8-й отсчет - т.е. 1 раз в 80 мкс запускаете фильтр. (не забудьте разрешить прерывания от АЦП в процедуре фильтра.) Тогда пока выполняется фильтр поступят еще 3 отсчета, которые затрут самые старые данные в буфере. Поэтому Вам надо или организовать процесс фильтрации так, чтобы к моменту прихода нового отсчета старые данные были бы уже не нужны - делать MAC-и от ранних отсчетов к поздним, или добавить 3 ячейки к кольцевому буферу и сделать его размером 53 ячейки. Так поступают если организация счета от ранних отсчетов к поздним занимает больше тактов(на переинициализацию указателей) чем счет от поздних к ранним отсчетам, а памяти не жалко.
bahurin
Mar 24 2011, 10:51
Код
#include < stdio.h >
#include < stdlib.h >
#include < windows.h >
#define _USE_MATH_DEFINES
#include < math.h >
// фильтрация с буфером (функция не оптимальна, но принцип работы правильный)
double filter(double xn, double* b, double* a, double* B, int N){
B[0] = xn;
for(int i = 1; i<N; i++)
B[0]-=a[i]*B[i];
double y = 0.0;
for(int i = 0; i<N; i++)
y+=b[i]*B[i];
memmove(B+1,B,(N-1)*sizeof(double));
return y;
}
int main(){
// к-ты нерекурсивной части
double b[4] = { 1.495242110818999600e-002,
3.165778089032666300e-002,
3.165778089032666300e-002,
1.495242110818999600e-002};
// к-ты рекурсивной части
double a[4] = { 1.000000000000000000e+000,
-2.137206690461268100e+000,
1.770779554588140800e+000,
-5.403524601298397300e-001};
double x[100]; // исходный сигнал
double y[1000]; // фильтрованный сигнал
double B[4]; // кольцевой буфер
memset(B,0,4*sizeof(double)); // обнуляю при старте
for (int n = 0; n<10; n++){
for(int i = 0; i<100; i++){
x[i]=(double)(rand()%1000) / 1000.0; // заполняю очередной кусок
y[i+n*100] = filter(x[i],b,a,B,4); //и фильтрую очредной кусок
}
}
return 0;
}
Вот пример фильтрации с буфером. Фильтрует куски без разрывов, принцип понять можно, хотя программа не оптимальна.
Zelepuk
Mar 24 2011, 11:26
Цитата(bahurin @ Mar 24 2011, 13:51)

Код
#include < stdio.h >
#include < stdlib.h >
#include < windows.h >
#define _USE_MATH_DEFINES
#include < math.h >
// фильтрация с буфером (функция не оптимальна, но принцип работы правильный)
double filter(double xn, double* b, double* a, double* B, int N){
B[0] = xn;
for(int i = 1; i<N; i++)
B[0]-=a[i]*B[i];
double y = 0.0;
for(int i = 0; i<N; i++)
y+=b[i]*B[i];
memmove(B+1,B,(N-1)*sizeof(double));
return y;
}
int main(){
// к-ты нерекурсивной части
double b[4] = { 1.495242110818999600e-002,
3.165778089032666300e-002,
3.165778089032666300e-002,
1.495242110818999600e-002};
// к-ты рекурсивной части
double a[4] = { 1.000000000000000000e+000,
-2.137206690461268100e+000,
1.770779554588140800e+000,
-5.403524601298397300e-001};
double x[100]; // исходный сигнал
double y[1000]; // фильтрованный сигнал
double B[4]; // кольцевой буфер
memset(B,0,4*sizeof(double)); // обнуляю при старте
for (int n = 0; n<10; n++){
for(int i = 0; i<100; i++){
x[i]=(double)(rand()%1000) / 1000.0; // заполняю очередной кусок
y[i+n*100] = filter(x[i],b,a,B,4); //и фильтрую очредной кусок
}
}
return 0;
}
Вот пример фильтрации с буфером. Фильтрует куски без разрывов, принцип понять можно, хотя программа не оптимальна.
Благодарю за код.Как я понимаю здесь БИХ фильтр, так как присутствует рекурсивная часть?
bahurin
Mar 24 2011, 12:31
Цитата(Zelepuk @ Mar 24 2011, 14:26)

Благодарю за код.Как я понимаю здесь БИХ фильтр, так как присутствует рекурсивная часть?
да если надо ких фильтр, то просто все коэффициенты "a" надо обнулить кроме одного
Zelepuk
Mar 24 2011, 21:13
Цитата(bahurin @ Mar 24 2011, 15:31)

да если надо ких фильтр, то просто все коэффициенты "a" надо обнулить кроме одного
Один, я так понимаю, - это как раз коэффициент равняющийся единице?
Для просмотра полной версии этой страницы, пожалуйста,
пройдите по ссылке.