libdspl-2.0/dspl/src/filter_iir.c

539 wiersze
17 KiB
C
Czysty Wina Historia

This file contains ambiguous Unicode characters!

This file contains ambiguous Unicode characters that may be confused with others in your current locale. If your use case is intentional and legitimate, you can safely ignore this warning. Use the Escape button to highlight these characters.

/*
* Copyright (c) 2015-2019 Sergey Bakhurin
* Digital Signal Processing Library [http://dsplib.org]
*
* This file is part of libdspl-2.0.
*
* is free software: you can redistribute it and/or modify
* it under the terms of the GNU Lesser General Public License as published by
* the Free Software Foundation, either version 3 of the License, or
* (at your option) any later version.
*
* DSPL is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU Lesser General Public License
* along with Foobar. If not, see <http://www.gnu.org/licenses/>.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include "dspl.h"
#include "dspl_internal.h"
#ifdef DOXYGEN_ENGLISH
/*! ****************************************************************************
\ingroup IIR_FILTER_DESIGN_GROUP
\fn int bilinear(double* bs, double* as, int ord, double* bz, double* az)
\brief
Transform a s-plane analog filter transfer function \f$H(s)\f$ to the
digital filter transfer function \f$H(z)\f$.
Bilinear transform is rational composition:
\f[
s \leftarrow \frac{1 - z^{-1}}{1 - z^{-1}}.
\f]
Digital filter order, passband magnitude ripple and stopband suppression
still the same after bilinear transform as analog filter.
Frequency \f$\Omega\f$ of analog filter and frequency
\f$\omega\f$ of digital filter relations:
\f[
\Omega = \tan(\omega / 2).
\f]
\param[in] bs
Pointer to the vector of analog filter \f$H(s)\f$
numerator coefficients.
Vector size is `[ord+1 x 1]`. \n
\n
\param[in] as
Pointer to the vector of analog filter \f$H(s)\f$
denominator coefficients vector.
Vector size is `[ord+1 x 1]`. \n
\n
\param[in] ord
Analog and digital filters order. \n
\n
\param[out] bz
Pointer to the vector of digital filter \f$H(z)\f$
numerator coefficients after bilinear transform.
Vector size is `[ord+1 x 1]`. \n
Memory must be allocated. \n
\n
\param[out] az
Pointer to the vector of digital filter \f$H(z)\f$
denominator coefficients after bilinear transform.
Vector size is `[ord+1 x 1]`. \n
Memory must be allocated. \n
\n
\return
`RES_OK` if bilinear transform is calculated successfully. \n
Else \ref ERROR_CODE_GROUP "code error".
Example:
\include bilinear_test.c
This program calculates the transfer function \f$H(s)\f$ of analog
Chebyshev filter of the first kind, with a cutoff frequency of 1 rad/s,
and produces bilinear trandform to digital filter,
with a normilized cutoff frequency equals 0.5.
Result:
\verbatim
bz[0] = 0.246 az[0] = 4.425
bz[1] = 0.983 az[1] = -3.318
bz[2] = 1.474 az[2] = 4.746
bz[3] = 0.983 az[3] = -2.477
bz[4] = 0.246 az[4] = 1.034
err = 0
\endverbatim
In addition, the frequency response of the resulting digital filter
is calculated and plotted by GNUPLOT package.
\image html bilinear.png
\author Sergey Bakhurin www.dsplib.org
***************************************************************************** */
#endif
#ifdef DOXYGEN_RUSSIAN
/*! ****************************************************************************
\ingroup IIR_FILTER_DESIGN_GROUP
\fn int bilinear(double* bs, double* as, int ord, double* bz, double* az)
\brief
Билинейное преобразование передаточной характеристики аналогового
фильтра \f$H(s)\f$, в передаточную характеристику цифрового фильтра \f$H(z)\f$.
Функция рассчитывает коэффициенты передаточной характеристики \f$H(z)\f$
цифрового фильтра путем дробно-рациональной подстановки вида
\f[
s \leftarrow \frac{1 - z^{-1}}{1 - z^{-1}}.
\f]
Порядок цифрового фильтра при этом остается равным порядку аналогового фильтра,
а ось частот \f$\Omega\f$ аналогового фильтра связана c осью частот
\f$\omega\f$ цифрового фильтра соотношением:
\f[
\Omega = \tan(\omega / 2).
\f]
\param[in] bs
Указатель на вектор коэффициентов числителя передаточной функции \f$H(s)\f$
исходного аналогового фильтра. \n
Размер вектора `[ord+1 x 1]`. \n
Память должна быть выделена. \n
\n
\param[in] as
Указатель на вектор коэффициентов знаменателя передаточной функции \f$H(s)\f$
исходного аналогового фильтра. \n
Размер вектора `[ord+1 x 1]`. \n
Память должна быть выделена. \n
\n
\param[in] ord
Порядок фильтра. \n
Количество коэффициентов числителя и знаменателя передаточных функций
\f$H(s)\f$ и \f$H(z)\f$ аналогового и цифрового фильтров равно `ord+1`. \n
\n
\param[out] bz
Указатель на вектор коэффициентов числителя передаточной функции \f$H(z)\f$
полученного цифрового фильтра. \n
Размер вектора `[ord+1 x 1]`. \n
Память должна быть выделена. \n
\n
\param[out] az
Указатель на вектор коэффициентов знаменателя передаточной функции \f$H(z)\f$
полученного цифрового фильтра. \n
Размер вектора `[ord+1 x 1]`. \n
Память должна быть выделена. \n
\n
\return
`RES_OK` --- фильтр рассчитан успешно. \n
В противном случае \ref ERROR_CODE_GROUP "код ошибки". \n
Пример использования функции `bilinear`:
\include bilinear_test.c
Данная программа производит расчет передаточной характеристики аналогового
фильтра Чебышева первого рода, с частотой среза равной 1 рад/с, и производит
билинейное преобразование в цифровой, с частотой среза равной 0.5.
Результат работы программы:
\verbatim
bz[0] = 0.246 az[0] = 4.425
bz[1] = 0.983 az[1] = -3.318
bz[2] = 1.474 az[2] = 4.746
bz[3] = 0.983 az[3] = -2.477
bz[4] = 0.246 az[4] = 1.034
err = 0
\endverbatim
Кроме этого производится расчет АЧХ полученного цифрового фильтра и строится
график АЧХ пакетом GNUPLOT
\image html bilinear.png
\author Бахурин Сергей www.dsplib.org
***************************************************************************** */
#endif
int DSPL_API bilinear(double* bs, double* as, int ord, double* bz, double* az)
{
double c[2] = {1.0, -1.0};
double d[2] = {1.0, 1.0};
return ratcompos(bs, as, ord, c, d, 1, bz, az);
}
#ifdef DOXYGEN_ENGLISH
/*! ****************************************************************************
\ingroup IIR_FILTER_DESIGN_GROUP
\fn int iir(double rp, double rs, int ord, double w0, double w1,
int type, double* b, double* a)
\brief
Digital IIR filter design.
The function calculates the coefficients of the digital IIR filter
transfer fucntion \f$ H(z) \f$.
Filter coeffitients can be used in \ref filter_iir function
\param[in] rp
Magnitude ripple in passband (dB). \n
\n
\param[in] rs
Suppression level in stopband (dB). \n
\n
\param[in] ord
Filter order. \n
Number of \f$H(z)\f$ numerator and denominator coefficients is `ord+1`. \n
For bandpass and bandstop filters `ord` must be even. \n
\n
\param[in] w0
Normalized cutoff frequency (from 0 to 1) for lowpass or highpass filter. \n
Or left normalized cutoff frequency (from 0 to 1) for
bandpass and bandstop filter. \n
\n
\param[in] w1
Right normalized cutoff frequency (from 0 to 1) for
bandpass and bandstop filter. \n
This parameter is ingnored for lowpass and highpass filters.
\n
\param[in] type
Filter type. \n
This patameter sets combination of filter type (one of follow): \n
\verbatim
DSPL_FILTER_LPF - lowpass filter;
DSPL_FILTER_HPF - highpass filter;
DSPL_FILTER_BPASS - bandpass filter;
DSPL_FILTER_BSTOP - bandstop filter,
\endverbatim
and of filter approximation type (one of follow):
\verbatim
DSPL_FILTER_BUTTER - Butterworth filter;
DSPL_FILTER_CHEBY1 - Chebyshev of the first kind filter;
DSPL_FILTER_CHEBY2 - Chebyshev of the second kind filter;
DSPL_FILTER_ELLIP - Elliptic filter.
\endverbatim
\n
\n
\param[out] b
Pointer to the transfer function \f$H(z)\f$
numerator coefficients vector. \n
Vector size is `ord+1`. \n
Memory must be allocated. \n
\n
\param[out] a
Pointer to the transfer function \f$H(z)\f$
denominator coefficients vector. \n
Vector size is `ord+1`. \n
\n
\return
`RES_OK` if filter is calculated successfully. \n
Else \ref ERROR_CODE_GROUP "code error".
Example:
\include iir_test.c
This program calcultes filter coefficients for different flags `type`.
In addition, the filters magnitudes
is calculated and plotted by GNUPLOT package.
\image html iir_test.png
\author Sergey Bakhurin www.dsplib.org
***************************************************************************** */
#endif
#ifdef DOXYGEN_RUSSIAN
/*! ****************************************************************************
\ingroup IIR_FILTER_DESIGN_GROUP
\fn int iir(double rp, double rs, int ord, double w0, double w1,
int type, double* b, double* a)
\brief
Функция расчета коэффициентов передаточной характеристики \f$H(z)\f$
цифрового фильтра БИХ.
Функция рассчитывает коэффициенты передаточной характеристики \f$H(z)\f$
цифрового фильтра, которые могут быть использованы в функции \ref filter_iir
\param[in] rp
Уровень неравномерности квадрата АЧХ в полосе пропускания фильтра (дБ). \n
Размер вектора `[ord+1 x 1]`. \n
\n
\param[in] rs
Уровень подавления в полосе заграждения фильтра (дБ).\n
\n
\param[in] ord
Порядок фильтра. \n
Количество коэффициентов числителя и знаменателя передаточной
функции \f$H(z)\f$ цифрового фильтров равно `ord+1`. \n
Для полосовых и режекторных фильтров параметр `ord` должен быть чётным. \n
\n
\param[in] w0
Нормированная частота среза ФНЧ или ФВЧ, или левая частота среза для
полосового и режекторного фильтра.\n
\n
\param[in] w1
Правая частота среза полосового и режекторного фильтра. \n
Данный параметр игнорируется для ФНЧ и ФВЧ. \n
\n
\param[in] type
Тип фильтра. \n
Данный параметр определяет тип фильтра и образуется
набором флагов типа фильтра: \n
\verbatim
DSPL_FILTER_LPF - фильтр нижних частот;
DSPL_FILTER_HPF - фильтр верхних частот;
DSPL_FILTER_BPASS - полосовой фильтр;
DSPL_FILTER_BSTOP - режекторный фильтр,
\endverbatim
а также флагов типа аппроксимации АЧХ фильтра:
\verbatim
DSPL_FILTER_BUTTER - фильтр Баттерворта;
DSPL_FILTER_CHEBY1 - фильтр Чебышева первого рода;
DSPL_FILTER_CHEBY2 - фильтр Чебышева второго рода;
DSPL_FILTER_ELLIP - эллиптический фильтр.
\endverbatim
\n
\n
\param[out] b
Указатель на вектор коэффициентов
числителя передаточной функции \f$H(z)\f$. \n
Размер вектора `ord+1`. \n
Память должна быть выделена. \n
\n
\param[out] a
Указатель на вектор коэффициентов знаменателя передаточной
функции \f$H(z)\f$. \n
Размер вектора `ord+1`. \n
Память должна быть выделена. \n
\n
\return
`RES_OK` --- Фильтр рассчитан успешно. \n
В противном случае \ref ERROR_CODE_GROUP "код ошибки". \n
Пример использования функции:
\include iir_test.c
Данная программа производит расчет коэффициентов фильтров
при различном сочетании флагов параметра `type`.
Кроме этого производится расчет АЧХ полученных цифровых фильтров и выводится на
график АЧХ пакетом GNUPLOT
\image html iir_test.png
\author Бахурин Сергей www.dsplib.org
***************************************************************************** */
#endif
int DSPL_API iir(double rp, double rs, int ord, double w0, double w1,
int type, double* b, double* a)
{
double *bs = NULL;
double *as = NULL;
double *bt = NULL;
double *at = NULL;
double wa0, wa1, ws;
int err, ord_ap = ord;
int i;
if(((type & DSPL_FILTER_TYPE_MASK) == DSPL_FILTER_LPF) ||
((type & DSPL_FILTER_TYPE_MASK) == DSPL_FILTER_HPF))
{
bs = (double*)malloc((ord_ap+1)*sizeof(double));
as = (double*)malloc((ord_ap+1)*sizeof(double));
bt = (double*)malloc((ord_ap+1)*sizeof(double));
at = (double*)malloc((ord_ap+1)*sizeof(double));
}
if(((type & DSPL_FILTER_TYPE_MASK) == DSPL_FILTER_BPASS) ||
((type & DSPL_FILTER_TYPE_MASK) == DSPL_FILTER_BSTOP))
{
if(ord % 2)
return ERROR_FILTER_ORD_BP;
else
{
ord_ap = ord / 2;
bs = (double*)malloc((ord_ap + 1)*sizeof(double));
as = (double*)malloc((ord_ap + 1)*sizeof(double));
bt = (double*)malloc((ord + 1)*sizeof(double));
at = (double*)malloc((ord + 1)*sizeof(double));
}
}
err = iir_ap(rp, rs, ord_ap, type, bs, as);
if(err != RES_OK)
goto error_proc;
/* frequency transformation */
wa0 = tan(w0 * M_PI * 0.5);
wa1 = tan(w1 * M_PI * 0.5);
switch(type & DSPL_FILTER_TYPE_MASK)
{
case DSPL_FILTER_LPF:
err = low2low(bs, as, ord_ap, 1.0, wa0, bt, at);
break;
case DSPL_FILTER_HPF:
ws = filter_ws1(ord_ap, rp, rs, type);
err = low2low( bs, as, ord_ap, 1.0, 1.0 / ws, bs, as);
err = low2high(bs, as, ord_ap, 1.0, wa0, bt, at);
break;
case DSPL_FILTER_BPASS:
err = low2bp(bs, as, ord_ap, 1.0, wa0, wa1, bt, at);
break;
case DSPL_FILTER_BSTOP:
/* need frequency transform ws -> 1 rad/s */
ws = filter_ws1(ord_ap, rp, rs, type);
err = low2low( bs, as, ord_ap, 1.0, 1.0 / ws, bs, as);
err = low2bs(bs, as, ord_ap, 1.0, wa0, wa1, bt, at);
break;
default:
err = ERROR_FILTER_TYPE;
break;
}
if(err != RES_OK)
goto error_proc;
err = bilinear(bt, at, ord, b, a);
for(i = 1; i <= ord; i++)
{
a[i] /= a[0];
b[i] /= a[0];
}
b[0] /= a[0];
a[0] = 1.0;
error_proc:
if(bs)
free(bs);
if(as)
free(as);
if(bt)
free(bt);
if(at)
free(at);
return err;
}
/******************************************************************************
Analog prototype for IIR
*******************************************************************************/
int iir_ap(double rp, double rs, int ord, int type, double* b, double* a)
{
int err;
switch(type & DSPL_FILTER_APPROX_MASK)
{
case DSPL_FILTER_BUTTER:
err = butter_ap(rp, ord, b, a);
break;
case DSPL_FILTER_CHEBY1:
err = cheby1_ap(rp, ord, b, a);
break;
case DSPL_FILTER_CHEBY2:
err = cheby2_ap_wp1(rp, rs, ord, b, a);
break;
case DSPL_FILTER_ELLIP:
err = ellip_ap(rp, rs, ord, b, a);
break;
default:
err = ERROR_FILTER_APPROX;
}
return err;
}