Помощь - Поиск - Пользователи - Календарь
Полная версия этой страницы: Реализация БИХ фильтра
Форум разработчиков электроники ELECTRONIX.ru > Цифровая обработка сигналов - ЦОС (DSP) > Алгоритмы ЦОС (DSP)
sysel
Здравсвуйте!
Столкнулся со следующей проблемой:
Разрабатываю IIR (БИХ) фильтр в MATLAB (fdatool), получаю коэффиециенты фильтра (Direct-Form II, Second-Order Sections), (Order = 6, Sections = 3).
Делаю С-header с этими самыми коэффиециентами (Targets -> Generate C header).
Получаю некие массивы.

Как мне теперь реализовать этот фильтр на языке C ?

Следую принципу каскадной реализации и реализации Direct Form II - но фигня какая-то выходит.

Поделитесь, пожалуйста, рабочим кодом.
bahurin
Цитата(sysel @ Apr 26 2010, 11:49) *
Поделитесь, пожалуйста, рабочим кодом.


Код
typedef struct structIIR{    
    double*    b;
    int        lb;
    double* a;
    int        la;
}IIR, *PIIR;


int conv(double *a, int la, double *b, int lb, double *c){
    if((!a)||(!b)||(!c)||(!la)||(!lb))
        return 0;
    memset(c, 0, (la+lb-1)*sizeof(double));
    for(int i = 0; i < la; i++){
        for(int j = 0; j < lb; j++)
            c[i+j] += a[i]*b[j];
    }
    return 1;
}

int iir_filter(PIIR piir, double *s, int n){
    double* c = (double*)malloc(piir->la*sizeof(double));
    double* d = (double*)malloc(piir->lb*sizeof(double));
    double* v = (double*)malloc((piir->lb+n-1)*sizeof(double));

    for(int i =0; i<piir->la; i++)
        c[i] = piir->a[i]/piir->a[0];
    for(int i =0; i<piir->lb; i++)
        d[i] = piir->b[i]/piir->a[0];
    conv(d,piir->lb,s,n,v);
    s[0] = v[0];
    
    for(int i = 1; i<n; i++){
        int k = 1;
        s[i] = v[i];
        while(((i-k)>=0)&&(k<piir->la)){
            s[i]-=c[k]*s[i-k];
            k++;
        }
    }
    free(c);
    free(d);
    free(v);
    return 1;
}


Коэффициенты пишем в структуру IIR и указатель на нее в функцию фильтрации. А вообще вот dll весит 20 кБ умеет считать фильтры аналогично матлабу. Есть документация с примерами.
sysel
Разобрался сам.
Добавлю свои результаты в фонд будущих поколений:

Пусть нам FDATOOL выдала следующий C-header:
Код
/*
* Filter Coefficients (C Source) generated by the Filter Design and Analysis Tool
*
* Generated by MATLAB(R) 7.8 and the Signal Processing Toolbox 6.11.
*
* Generated on: 26-Apr-2010 15:26:51
*
*/

/*
* Discrete-Time IIR Filter (real)
* -------------------------------
* Filter Structure    : Direct-Form II, Second-Order Sections
* Number of Sections  : 3
* Stable              : Yes
* Linear Phase        : No
*/

/* General type conversion for MATLAB generated C-code  */
#include "tmwtypes.h"
/*
* Expected path to tmwtypes.h
* C:\Program Files\MATLAB\R2009a\extern\include\tmwtypes.h
*/
#define MWSPT_NSEC 7
const int NL[MWSPT_NSEC] = { 1,3,1,3,1,2,1 };
const real64_T NUM[MWSPT_NSEC][3] = {
  {
   0.001582012905215,                 0,                 0
  },
  {
                   1,   -1.997425031815,                 1
  },
  {
    0.06078064837324,                 0,                 0
  },
  {
                   1,   -1.998996713475,                 1
  },
  {
   0.007688806860118,                 0,                 0
  },
  {
                   1,                 1,                 0
  },
  {
                   1,                 0,                 0
  }
};
const int DL[MWSPT_NSEC] = { 1,3,1,3,1,2,1 };
const real64_T DEN[MWSPT_NSEC][3] = {
  {
                   1,                 0,                 0
  },
  {
                   1,   -1.996305874613,   0.9963329403565
  },
  {
                   1,                 0,                 0
  },
  {
                   1,   -1.998581806418,   0.9986427868237
  },
  {
                   1,                 0,                 0
  },
  {
                   1,  -0.9976855336623,                 0
  },
  {
                   1,                 0,                 0
  }
};


Прячем #include "tmwtypes.h" :
// #include "tmwtypes.h"
И заменяем "real64_T" на "double".

Для получения одного отфильтрованного отсчета сигнала надо вызвать функцию IIR_filt (X), где X - входной отсчет.
Функция возвращает отсчет отфильтрованного сигнала.
Предварительно надо задать начальные значения для массива "ячеек памяти" WHistory. Ну или просто обнулить их.

Код
#include "fdacoefs.h"

double WHistory[MWSPT_NSEC][2];

double IIR_filt (double X){
    for (int i=0; i<MWSPT_NSEC; i++){
        double W;
        W = X;
        for (int j=1; j<DL[i]; j++){
            W-= DEN[i][j]*WHistory[i][j-1];
        };
        W*=1/DEN[i][0];

        X = W * NUM[i][0];
        for (int j=1; j<NL[i]; j++){
            X+=NUM[i][j]*WHistory[i][j-1];
        };
        WHistory[i][1] = WHistory[i][0];
        WHistory[i][0] = W;
    };
    return X;
};


Код не оптимизирован, зато даёт хорошее представление о том, чиго надо делать с хедером из FDATOOL.

Вот схематичное описание того, что далает этот код:
http://ftp.math.hkbu.edu.hk/help/toolbox/s...ilt.df2sos.html
sysel
Приведу оптимизированную версию кода, которая "хавает" как floating-point, так и fixed-point IIR из С-Header-ов, сгенерированных FDATOOL из MATLABa

Код
#include "fdacoefs.h"

typedef double    real;

#define Fs        3600    // Частота сэмплирования

#define IIR_hist_size        5    // Кол-во ячеек памяти в реализации фильтра

real History[IIR_hist_size];

real IIR_filter (real X, real* Hist){
    for (int i=0; i<MWSPT_NSEC; i++){
        int jmax = ((NL[i]>DL[i])?(NL[i]):(DL[i]))-1;
        if (jmax>0){
            // Блок фильтра из каскада
            real W = 0;
            for (int j=0; j<jmax; j++){
                W += DEN[i][j+1] * Hist[j];
            };
            W = X - W;
            W *= (1/DEN[i][0]);
    
            X = W * NUM[i][0];
            for (int j=0; j<jmax; j++){
                X += NUM[i][j+1] * Hist[j];
            };
            
            for (int j=1; j<jmax; j++){
                Hist[j] = Hist[j-1];
            };
            Hist[0] = W;
            Hist += jmax;
        } else if (jmax==0){
            // Блок "Gain" между каскадами фильтра
            X *= NUM[i][0] * (1/DEN[i][0]);
        };
    };
    return X;
};

int main(){
    // Обнуляем ячейки памяти
    for (int i=0; i<IIR_hist_size; i++){
        History[i]=0;
    };
    
    real X,Y,F;

    F = 10.0; // 10 Гц

    F=2*CONST_PI*F/(real)Fs;

    for (int i=0; i<1000000; i++){
        X=cos(F*(real)i);
        Y=IIR_filter (X,History);
    };

    return 0;
}
baralgin
Цитата(sysel @ Apr 27 2010, 12:21) *
Код
// Блок "Gain" между каскадами фильтра
X *= NUM[i][0] * (1/DEN[i][0]);

Этот участок кода вызывает подозрение. На fixed-point'е веротно не будет работать(как надо). Наверное лучше разделить: сначала умножение, потом деление.
Да и в целом код не выглядит ни оптимальным ни красивым. Сам начал разбираться этим вопросом в последнии дни. Ваши приведённые примеры значительно помогли(мне smile.gif ). Странно, но в дебрях матлабовского хэлпа ничего не находится по алгоритму вычисления. А в широком поле интернета только стандартная формула (типа y = w-1*y-1+w-2*y-2, wi = ... ), в которой коэффициентов много меньше чем в сабжевом хидере.
sysel
Цитата(baralgin @ Apr 27 2010, 21:35) *
Этот участок кода вызывает подозрение. На fixed-point'е веротно не будет работать(как надо). Наверное лучше разделить: сначала умножение, потом деление.

Да, флагом махать я начал раньше времени насчет "fixed-point". В общем, приведённый выше фрагмент кода работает с fixed-point коеффицентами, если в объявлении матриц коэффиециентов изменить тип на "double".
С fixed-point всё не так просто, как мне казалось. FDATOOL выкидывает форматы представления с фиксированной запятой в комментарии, так что породить код, который бы с ходу хавал бы хедер не выйдет.
Цитата(baralgin @ Apr 27 2010, 21:35) *
Да и в целом код не выглядит ни оптимальным ни красивым.

Согласен. Но, думаю, более оптимальный и красивый код можно породить только если вычленить коэффиециенты из матриц NUM и DEN в какие-то другие структуры. И что самое главное, разделить на этапе написания кода блоки "gain" и фильтров.
Цитата(baralgin @ Apr 27 2010, 21:35) *
Сам начал разбираться этим вопросом в последнии дни. Ваши приведённые примеры значительно помогли(мне smile.gif ). Странно, но в дебрях матлабовского хэлпа ничего не находится по алгоритму вычисления. А в широком поле интернета только стандартная формула (типа y = w-1*y-1+w-2*y-2, wi = ... ), в которой коэффициентов много меньше чем в сабжевом хидере.

Была та же проблема. Формул куча, кода шиш. Породил какой-никакой код и выложил тут.
У приведённого выше кода есть большой плюс: он опирается на порождённый fdatool хедером с минимальными изменениями в нём.
bahurin
Цитата(sysel @ Apr 28 2010, 09:21) *
Была та же проблема. Формул куча, кода шиш. Породил какой-никакой код и выложил тут.
У приведённого выше кода есть большой плюс: он опирается на порождённый fdatool хедером с минимальными изменениями в нём.


вот есть такая pdf-ка еще как фильтры считать и куча матлабовского кода к ней. Кому инетересно можете поглядеть. Я по этой доке писал фильтры разные
Нажмите для просмотра прикрепленного файла
avmsystem
Цитата(sysel @ Apr 26 2010, 16:46) *
Разобрался сам.
Добавлю свои результаты в фонд будущих поколений:

Пусть нам FDATOOL выдала следующий C-header:
[code]/*


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

Подскажите плиз где глянуть наглядный алгоритм использования коэф-тов из fdatool.


Vl4ever
столкнулся с похожей проблемой.Нужно реализовать филтер чебишева с данными параметрами на процессоре stm32f101 ( arm cortex m3) .Имеются библиотеки расчёта IIR (ili FIR) филтеров от производителей ARMa (CMSIS - DSP http://www.onarm.com/cmsis/download/).Если кому-то удалось реализовать филтер,используя Матлаб fdatool и исползуя эти библиотеки,поделитесь пожалуста опытом.Спасибо sm.gif
skyv
Цитата(Vl4ever @ Jan 13 2012, 21:15) *
столкнулся с похожей проблемой.Нужно реализовать филтер чебишева с данными параметрами на процессоре stm32f101 ( arm cortex m3) .Имеются библиотеки расчёта IIR (ili FIR) филтеров от производителей ARMa (CMSIS - DSP http://www.onarm.com/cmsis/download/).Если кому-то удалось реализовать филтер,используя Матлаб fdatool и исползуя эти библиотеки,поделитесь пожалуста опытом.Спасибо sm.gif


Посмотрите документ "The Scientist and Engineer's Guide to Digital Signal Processing".
Там есть алгоритм расчета коэффициентов фильтра.
Для просмотра полной версии этой страницы, пожалуйста, пройдите по ссылке.
Invision Power Board © 2001-2025 Invision Power Services, Inc.