/* * 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 . */ #include #include #include #include "dspl.h" #ifdef DOXYGEN_ENGLISH /*! **************************************************************************** \ingroup FILTER_ANALYSIS_GROUP \fn int DSPL_API group_delay(double* b, double* a, int ord, int flag, double* w, int n, double* tau) \brief Group delay calculation for digital or analog filter corresponds to \f$H(s)\f$, or \f$H(z)\f$ transfer function. Group delay is describes as: \f[ \tau_g(\omega) = - \frac{d\Phi(\omega)}{d\omega}, \f] here \f$\Phi(\omega)\f$ -- filter phase response, \f$\omega\f$ is angular frequency for analog filter, or normalized frequency for digital filter. \param[in] b Pointer to the \f$ H(s) \f$ or \f$H(z)\f$ transfer function numerator coefficients vector. \n Vector size is `[ord+1 x 1]`. \n \n \param[in] a Pointer to the \f$ H(s) \f$ or \f$H(z)\f$ transfer function denominator coefficients vector. \n Vector size is `[ord+1 x 1]`. \n \n \param[in] ord Filter order. \n Transfer function \f$ H(s) \f$ or \f$H(z)\f$ numerator and denominator coefficients number equals `ord+1`. \n \n \param[in] flag Binary flags to set calculation rules: \n \verbatim DSPL_FLAG_ANALOG Coefficients corresponds to analog filter DSPL_FLAG_DIGITAL Coefficients corresponds to digital filter \endverbatim \n \n \param[in] w Pointer to the angular frequency \f$ \omega \f$ (rad/s), which used for analog filter characteristics calculation (flag sets as `DSPL_FLAG_ANALOG`). \n For digital filter (flag sets as `DSPL_FLAG_DIGITAL`), parameter `w` describes normalized frequency of frequency response \f$ H \left(\mathrm{e}^{j\omega} \right) \f$. Digital filter frequency response is \f$ 2\pi \f$-periodic function, and vector `w` advisable to set from 0 to \f$ \pi \f$, or from 0 to \f$ 2\pi \f$, or from \f$ -\pi \f$ to \f$ \pi \f$. Vector size is `[n x 1]`. \n \n \param[in] n Size of frequency vector `w`. \n \n \param[out] tau Pointer to the group delay vector. \n Vector size is `[n x 1]`. \n Memory must be allocated. \n \n \return \return `RES_OK` if function is calculated successfully. \n Else \ref ERROR_CODE_GROUP "code error". \author Sergey Bakhurin www.dsplib.org ***************************************************************************** */ #endif #ifdef DOXYGEN_RUSSIAN /*! **************************************************************************** \ingroup FILTER_ANALYSIS_GROUP \fn int DSPL_API group_delay(double* b, double* a, int ord, int flag, double* w, int n, double* tau) \brief Расчет группового времени запаздывания цифрового или аналогового фильтра. Групповое время запаздывания определяется как: \f[ \tau_g(\omega) = - \frac{d\Phi(\omega)}{d\omega}, \f] где \f$\Phi(\omega)\f$ -- ФЧХ фильтра, \f$\omega\f$ циктическая частот в случае аналогового фильтра, или нормированная частота цифрового фильтра. \param[in] b Указатель на вектор коэффициентов числителя передаточной функции аналогового фильтра \f$ H(s) \f$ или цифрового фильтра \f$ H(z) \f$. \n Размер вектора `[ord+1 x 1]`. \n \n \param[in] a Указатель на вектор коэффициентов числителя передаточной функции аналогового фильтра \f$ H(s) \f$ или цифрового фильтра \f$ H(z) \f$. \n Размер вектора `[ord+1 x 1]`. \n Параметр может быть `NULL`. В этом случае расчет производится для цифрового КИХ-фильтра с коэффициентами, заданными вектором `b`. \n\n \param[in] ord Порядок фильтра. Количество коэффициентов числителя и знаменателя передаточной функции \f$ H(s) \f$ или \f$ H(z) \f$ равно `ord+1`. \n \n \param[in] flag Флаг который задает тип фильтра: \n \verbatim DSPL_FLAG_ANALOG Коэффициенты относятся к аналоговому фильтру DSPL_FLAG_DIGITAL Коэффициенты относятся к цифровому фильтру \endverbatim \param[in] w Указатель на вектор значений циклической частоты \f$ \omega \f$ (рад/с), для которого будет рассчитаны АЧХ, ФЧХ и ГВЗ аналогового фильтра, если установлен флаг `DSPL_FLAG_ANALOG`. \n В случае если флаг `DSPL_FLAG_ANALOG` не установлен, то вектор частоты `w` используется как нормированная частота комплексного коэффициента передачи \f$ H \left(\mathrm{e}^{j\omega} \right) \f$ цифрового фильтра. \n В этом случае характеристика цифрового фильтра является \f$ 2\pi \f$-периодической, и вектор частоты может содержать произвольные значения, однако целесообразно задавать его от 0 до \f$ \pi \f$, а такжет от 0 до \f$ 2\pi \f$, или от \f$ -\pi \f$ до \f$ \pi \f$. \n Размер вектора `[n x 1]`. \n \n \param[in] n Размер вектора циклической частоты `w`. \n \n \param[out] tau Указатель на вектор групповой задержки. \n Размер вектора `[n x 1]`. \n Память должна быть выделена. \n \return `RES_OK` групповая задержка фильтра рассчитана успешно. \n В противном случае \ref ERROR_CODE_GROUP "код ошибки". \n \author Бахурин Сергей www.dsplib.org ***************************************************************************** */ #endif int DSPL_API group_delay(double* pb, double* pa, int ord, int flag, double* w, int n, double* tau) { double a, b, c, d, da, db, dc, dd, f, e; int t, m; double *qa = NULL; if(!pb || !w || !tau || (!pa && (flag & DSPL_FLAG_ANALOG))) return ERROR_PTR; if(ord < 1) return ERROR_FILTER_ORD; if(n < 1) return ERROR_SIZE; if(pa) qa = pa; else { qa = (double*)malloc((ord+1) * sizeof(double)); memset(qa, 0, (ord+1) * sizeof(double)); qa[0] = 1.0; } for(t = 0; t < n; t++) { a = b = c = d = da = db = dc = dd = 0.0; if(flag & DSPL_FLAG_ANALOG) { for(m = 0; m < ord+1; m+=4) { a += pb[m] * pow(w[t], (double)m); c += qa[m] * pow(w[t], (double)m); da += pb[m] * (double) m * pow(w[t], (double)(m-1)); dc += qa[m] * (double) m * pow(w[t], (double)(m-1)); } for(m = 2; m < ord+1; m+=4) { a -= pb[m] * pow(w[t], (double)m); c -= qa[m] * pow(w[t], (double)m); da -= pb[m] * (double) m * pow(w[t], (double)(m-1)); dc -= qa[m] * (double) m * pow(w[t], (double)(m-1)); } for(m = 1; m < ord+1; m+=4) { b += pb[m] * pow(w[t], (double)m) ; d += qa[m] * pow(w[t], (double)m) ; db += pb[m] * (double) m * pow(w[t], (double)(m-1)) ; dd += qa[m] * (double) m * pow(w[t], (double)(m-1)) ; } for(m = 3; m < ord+1; m+=4) { b -= pb[m] * pow(w[t], (double)m) ; d -= qa[m] * pow(w[t], (double)m) ; db -= pb[m] * (double) m * pow(w[t], (double)(m-1)) ; dd -= qa[m] * (double) m * pow(w[t], (double)(m-1)) ; } } else { for(m = 0; m < ord+1; m++) { a += pb[m] * cos(w[t]*(double)m); b -= pb[m] * sin(w[t]*(double)m); c += qa[m] * cos(w[t]*(double)m); d -= qa[m] * sin(w[t]*(double)m); da -= pb[m] *(double)m * sin(w[t]*(double)m); db -= pb[m] *(double)m * cos(w[t]*(double)m); dc -= qa[m] *(double)m * sin(w[t]*(double)m); dd -= qa[m] *(double)m * cos(w[t]*(double)m); } } f = da * c + a * dc + db * d + b * dd; e = db * c + b * dc - da * d - a * dd; tau[t] = (f * (b * c - a * d) - e * (a * c + b * d)) / ((a * a + b * b) * (c * c + d * d)); } if(qa != pa) free(qa); return RES_OK; } #ifdef DOXYGEN_ENGLISH /*! **************************************************************************** \ingroup FILTER_ANALYSIS_GROUP \fn int filter_freq_resp(double* b, double* a, int ord, double* w, int n, int flag, double* mag, double* phi, double* tau) \brief Magnitude, phase response and group delay vectors calculation for digital or analog filter corresponds to \f$H(s)\f$, or \f$H(z)\f$ transfer function. \param[in] b Pointer to the \f$ H(s) \f$ or \f$H(z)\f$ transfer function numerator coefficients vector. \n Vector size is `[ord+1 x 1]`. \n \n \param[in] a Pointer to the \f$ H(s) \f$ or \f$H(z)\f$ transfer function denominator coefficients vector. \n Vector size is `[ord+1 x 1]`. \n \n \param[in] ord Filter order. \n Transfer function \f$ H(s) \f$ or \f$H(z)\f$ numerator and denominator coefficients number equals `ord+1`. \n \n \param[in] w Pointer to the angular frequency \f$ \omega \f$ (rad/s), which used for analog filter characteristics calculation (flag sets as `DSPL_FLAG_ANALOG`). \n For digital filter (flag sets as `DSPL_FLAG_DIGITAL`), parameter `w` describes normalized frequency of frequency response \f$ H \left(\mathrm{e}^{j\omega} \right) \f$. Digital filter frequency response is \f$ 2\pi \f$-periodic function, and vector `w` advisable to set from 0 to \f$ \pi \f$, or from 0 to \f$ 2\pi \f$, or from \f$ -\pi \f$ to \f$ \pi \f$. Vector size is `[n x 1]`. \n \n \param[in] n Size of frequency vector `w`. \n \n \param[in] flag Binary flags to set calculation rules: \n \verbatim DSPL_FLAG_ANALOG Coefficients corresponds to analog filter DSPL_FLAG_DIGITAL Coefficients corresponds to digital filter DSPL_FLAG_LOGMAG Calculate magnitude in logarithmic scale (in dB) DSPL_FLAG_UNWRAP Unwrap radian phases by adding multiples of 2*pi \endverbatim \param[out] mag Pointer to the filter magnitude vector. \n Vector size is `[n x 1]`. \n If pointer is `NULL`, then magnitude will not calculted. \n \n \param[out] phi Pointer to the phase response vector. \n Vector size is `[n x 1]`. \n If pointer is `NULL`, then phase response will not calculted. \n \n \param[out] tau Pointer to the group delay vector. \n Vector size is `[n x 1]`. \n If pointer is `NULL`, then group delay will not calculted. \n \n \return \return `RES_OK` if function is calculated successfully. \n Else \ref ERROR_CODE_GROUP "code error". Example: \include butter_ap_test.c Result: \verbatim b[ 0] = 1.002 a[ 0] = 1.002 b[ 1] = 0.000 a[ 1] = 2.618 b[ 2] = 0.000 a[ 2] = 3.418 b[ 3] = 0.000 a[ 3] = 2.615 b[ 4] = 0.000 a[ 4] = 1.000 \endverbatim \n In `dat` folder will be created 3 files: \n \verbatim butter_ap_test_mag.txt magnitude butter_ap_test_phi.txt phase response butter_ap_test_tau.txt group delay \endverbatim In addition, GNUPLOT will build the following graphs from data stored in files: \image html butter_ap_test.png \author Sergey Bakhurin www.dsplib.org ***************************************************************************** */ #endif #ifdef DOXYGEN_RUSSIAN /*! **************************************************************************** \ingroup FILTER_ANALYSIS_GROUP \fn int filter_freq_resp(double* b, double* a, int ord, double* w, int n, int flag, double* mag, double* phi, double* tau) \brief Расчет амплитудно-частотной (АЧХ), фазочастотной характеристик (ФЧХ), а также группового времени запаздывания (ГВЗ) цифрового или аналогового или фильтра. Функция рассчитывает АЧХ, ФЧХ и ГВЗ аналогового или цифрового фильтра, заданного передаточной характеристикой \f$H(s)\f$, или \f$H(z)\f$ соответственно \param[in] b Указатель на вектор коэффициентов числителя передаточной функции \f$ H(s) \f$. \n Размер вектора `[ord+1 x 1]`. \n \n \param[in] a Указатель на вектор коэффициентов знаменателя передаточной функции \f$ H(s) \f$. \n Размер вектора `[ord+1 x 1]`. \n \n \param[in] ord Порядок фильтра. Количество коэффициентов числителя и знаменателя передаточной функции \f$ H(s) \f$ равно `ord+1`. \n \n \param[in] w Указатель на вектор значений циклической частоты \f$ \omega \f$ (рад/с), для которого будет рассчитаны АЧХ, ФЧХ и ГВЗ аналогового фильтра, если установлен флаг `DSPL_FLAG_ANALOG`. \n В случае если флаг `DSPL_FLAG_ANALOG` не установлен, то вектор частоты `w` используется как нормированная частота комплексного коэффициента передачи \f$ H \left(\mathrm{e}^{j\omega} \right) \f$ цифрового фильтра. \n В этом случае характеристика цифрового фильтра является \f$ 2\pi \f$-периодической, и вектор частоты может содержать произвольные значения, однако целесообразно задавать его от 0 до \f$ \pi \f$, а такжет от 0 до \f$ 2\pi \f$, или от \f$ -\pi \f$ до \f$ \pi \f$. \n Размер вектора `[n x 1]`. \n \n \param[in] n Размер вектора циклической частоты `w`. \n \n \param[in] flag Комбинация флагов, которые задают расчет параметров: \n \verbatim DSPL_FLAG_ANALOG Коэффициенты относятся к аналоговому фильтру DSPL_FLAG_LOGMAG АЧХ рассчитывать в логарифмическом масштабе DSPL_FLAG_UNWRAP раскрывать периодичность ФЧХ \endverbatim \param[out] mag Указатель на вектор АЧХ. \n Размер вектора `[n x 1]`. \n Память должна быть выделена. \n Если указатель `NULL`, то расчет АЧХ не производится. \n \n \param[out] phi Указатель на вектор ФЧХ. \n Размер вектора `[n x 1]`. \n Память должна быть выделена. \n Если указатель `NULL`, то расчет ФЧХ не производится. \n \n \param[out] tau Указатель на вектор ГВЗ. \n Размер вектора `[n x 1]`. \n Память должна быть выделена. \n Если указатель `NULL`, то расчет ГВЗ не производится. \n \n \return `RES_OK` Параметры фильтра рассчитаны успешно. \n В противном случае \ref ERROR_CODE_GROUP "код ошибки". \n Пример использования функции `filter_freq_resp`: \include butter_ap_test.c Результат работы программы: \verbatim b[ 0] = 1.002 a[ 0] = 1.002 b[ 1] = 0.000 a[ 1] = 2.618 b[ 2] = 0.000 a[ 2] = 3.418 b[ 3] = 0.000 a[ 3] = 2.615 b[ 4] = 0.000 a[ 4] = 1.000 \endverbatim \n В каталоге `dat` будут созданы три файла: \n \verbatim butter_ap_test_mag.txt АЧХ фильтра butter_ap_test_phi.txt ФЧХ фильтра butter_ap_test_tau.txt ГВЗ фильтра \endverbatim Кроме того программа GNUPLOT произведет построение следующих графиков по сохраненным в файлах данным: \image html butter_ap_test.png \author Бахурин Сергей www.dsplib.org ***************************************************************************** */ #endif int DSPL_API filter_freq_resp(double* b, double* a, int ord, double* w, int n, int flag, double* mag, double* phi, double* tau) { int res, k, flag_analog; complex_t *hc = NULL; double *phi0 = NULL; double *phi1 = NULL; double *w0 = NULL; double *w1 = NULL; if(!b || !w) return ERROR_PTR; if(ord < 1) return ERROR_FILTER_ORD; if(n < 1) return ERROR_SIZE; flag_analog = flag & DSPL_FLAG_ANALOG; hc = (complex_t*) malloc (n*sizeof(complex_t)); res = flag_analog ? freqs(b, a, ord, w, n, hc) : freqz(b, a, ord, w, n, hc); if(res != RES_OK) goto exit_label; if(mag) { if(flag & DSPL_FLAG_LOGMAG) { for(k = 0; k < n; k++) mag[k] = 10.0 * log10(ABSSQR(hc[k])); } else { for(k = 0; k < n; k++) mag[k] = sqrt(ABSSQR(hc[k])); } } if(phi) { for(k = 0; k < n; k++) phi[k] = atan2(IM(hc[k]), RE(hc[k])); if(flag & DSPL_FLAG_UNWRAP) { res = unwrap(phi, n, M_2PI, 0.8); if(res != RES_OK) goto exit_label; } } if(tau) res = group_delay(b, a, ord, flag, w, n, tau); exit_label: if(hc) free(hc); if(phi0) free(phi0); if(phi1) free(phi1); if(w0) free(w0); if(w1) free(w1); return res; } #ifdef DOXYGEN_ENGLISH /*! **************************************************************************** \ingroup FILTER_ANALYSIS_GROUP \fn int freqs(double* b, double* a, int ord, double* w, int n, complex_t *h) \brief Analog filter frequency response \f$ H(j \omega) \f$ calculation Function calculates analog filter frequency response \f$ H(j \omega)\f$ corresponds to transfer function \f$ H(s) \f$: \f[ H(s) = \frac {\sum_{k = 0}^{N} b_k s^k} {\sum_{m = 0}^{N} a_m s^m}, \f] here \f$ N \f$ - filter order (equals to `ord`). \param[in] b Pointer to the transfer function \f$ H(s) \f$ numerator coefficients vector. \n Vector size is `[ord+1 x 1]`. \n \n \param[in] a Pointer to the transfer function \f$ H(s) \f$ denominator coefficients vector. \n Vector size is `[ord+1 x 1]`. \n \n \param[in] ord Filter order. \n Transfer function \f$ H(s) \f$ numerator and denominator coefficients number equals `ord+1`. \n \n \param[in] w Pointer to the angular frequency \f$ \omega \f$ (rad/s), which used for frequency response \f$ H(j \omega) \f$ calculation. \n Vector size is `[n x 1]`. \n \n \param[in] n The size of the angular frequency vector `w`. \n \n \param[out] h Pointer to the frequency response vector \f$ H(j \omega) \f$, corresponds to angular frequency `w`. \n Vector size is `[n x 1]`. \n Memory must be allocated. \n \n \return `RES_OK` if frequency response vector is calculated successfully. \n Else \ref ERROR_CODE_GROUP "code error". \author Sergey Bakhurin www.dsplib.org ***************************************************************************** */ #endif #ifdef DOXYGEN_RUSSIAN /*! **************************************************************************** \ingroup FILTER_ANALYSIS_GROUP \fn int freqs(double* b, double* a, int ord, double* w, int n, complex_t *h) \brief Расчет комплексного коэффициента передачи \f$ H(j \omega) \f$ аналогового фильтра. Функция рассчитывает значения комплексного коэффициента передачи \f$ H(j \omega)\f$ аналогового фильтра, заданного коэффициентами передаточной функции \f$ H(s) \f$: \f[ H(s) = \frac {\sum_{k = 0}^{N} b_k s^k} {\sum_{m = 0}^{N} a_m s^m}, \f] где \f$ N \f$ - порядок фильтра (параметр `ord`). Комплексный коэффициент передачи рассчитывается путем подстановки \f$ s = j \omega \f$. \param[in] b Указатель на вектор коэффициентов числителя передаточной функции \f$ H(s) \f$. \n Размер вектора `[ord+1 x 1]`. \n \n \param[in] a Указатель на вектор коэффициентов знаменателя передаточной функции \f$ H(s) \f$. \n Размер вектора `[ord+1 x 1]`. \n \n \param[in] ord Порядок фильтра. Количество коэффициентов числителя и знаменателя передаточной функции \f$ H(s) \f$ равно `ord+1`. \n \n \param[in] w Указатель на вектор значений циклической частоты \f$ \omega \f$ (рад/с), для которого будет рассчитан комплексный коэффициент передачи \f$ H(j \omega) \f$. \n Размер вектора `[n x 1]`. \n \n \param[in] n Размер вектора циклической частоты `w`. \n \n \param[out] h Указатель на вектор комплексного коэффициента передачи \f$ H(j \omega) \f$, рассчитанного для циклической частоты `w`. \n Размер вектора `[n x 1]`. \n Память должна быть выделена. \n \n \return `RES_OK` Комплексный коэффициент передачи рассчитан успешно. \n В противном случае \ref ERROR_CODE_GROUP "код ошибки". \n \author Бахурин Сергей www.dsplib.org ***************************************************************************** */ #endif int DSPL_API freqs(double* b, double* a, int ord, double* w, int n, complex_t *h) { complex_t jw; complex_t *bc = NULL; complex_t *ac = NULL; complex_t num, den; double mag; int k; int res; if(!b || !a || !w || !h) return ERROR_PTR; if(ord<0) return ERROR_FILTER_ORD; if(n<1) return ERROR_SIZE; RE(jw) = 0.0; bc = (complex_t*) malloc((ord+1) * sizeof(complex_t)); res = re2cmplx(b, ord+1, bc); if( res!=RES_OK ) goto exit_label; ac = (complex_t*) malloc((ord+1) * sizeof(complex_t)); res = re2cmplx(a, ord+1, ac); if( res!=RES_OK ) goto exit_label; for(k = 0; k < n; k++) { IM(jw) = w[k]; res = polyval_cmplx(bc, ord, &jw, 1, &num); if(res != RES_OK) goto exit_label; res = polyval_cmplx(ac, ord, &jw, 1, &den); if(res != RES_OK) goto exit_label; mag = ABSSQR(den); if(mag == 0.0) { res = ERROR_DIV_ZERO; goto exit_label; } mag = 1.0 / mag; RE(h[k]) = CMCONJRE(num, den) * mag; IM(h[k]) = CMCONJIM(num, den) * mag; } res = RES_OK; exit_label: if(bc) free(bc); if(ac) free(ac); return res; } #ifdef DOXYGEN_ENGLISH #endif #ifdef DOXYGEN_RUSSIAN #endif int DSPL_API freqs_cmplx(double* b, double* a, int ord, complex_t* s, int n, complex_t *h) { complex_t *bc = NULL; complex_t *ac = NULL; complex_t num, den; double mag; int k; int res; if(!b || !a || !s || !h) return ERROR_PTR; if(ord<0) return ERROR_FILTER_ORD; if(n<1) return ERROR_SIZE; bc = (complex_t*) malloc((ord+1) * sizeof(complex_t)); res = re2cmplx(b, ord+1, bc); if( res!=RES_OK ) goto exit_label; ac = (complex_t*) malloc((ord+1) * sizeof(complex_t)); res = re2cmplx(a, ord+1, ac); if( res!=RES_OK ) goto exit_label; for(k = 0; k < n; k++) { res = polyval_cmplx(bc, ord, s+k, 1, &num); if(res != RES_OK) goto exit_label; res = polyval_cmplx(ac, ord, s+k, 1, &den); if(res != RES_OK) goto exit_label; mag = ABSSQR(den); if(mag == 0.0) { res = ERROR_DIV_ZERO; goto exit_label; } mag = 1.0 / mag; RE(h[k]) = CMCONJRE(num, den) * mag; IM(h[k]) = CMCONJIM(num, den) * mag; } res = RES_OK; exit_label: if(bc) free(bc); if(ac) free(ac); return res; } #ifdef DOXYGEN_ENGLISH #endif #ifdef DOXYGEN_RUSSIAN #endif int DSPL_API freqs2time(double* b, double* a, int ord, double fs, int n, fft_t* pfft, double *t, double *h) { double *w = NULL; complex_t *hs = NULL; complex_t *ht = NULL; int err, k; if(!b || !a || !t || !h) return ERROR_PTR; if(ord<1) return ERROR_FILTER_ORD; if(n<1) return ERROR_SIZE; w = (double*)malloc(n*sizeof(double)); hs = (complex_t*)malloc(n*sizeof(complex_t)); err = linspace(-fs*0.5, fs*0.5, n, DSPL_PERIODIC, w); if(err != RES_OK) goto exit_label; err = freqs(b, a, ord, w, n, hs); if(err != RES_OK) goto exit_label; err = fft_shift_cmplx(hs, n, hs); if(err != RES_OK) goto exit_label; ht = (complex_t*)malloc(n*sizeof(complex_t)); err = ifft_cmplx(hs, n, pfft, ht); if(err != RES_OK) { err = idft_cmplx(hs, n, ht); if(err != RES_OK) goto exit_label; } for(k = 0; k < n; k++) { t[k] = (double)k/fs; h[k] = RE(ht[k]) * fs; } exit_label: if(w) free(w); if(hs) free(hs); if(ht) free(ht); return err; } #ifdef DOXYGEN_ENGLISH /*! **************************************************************************** \ingroup FILTER_ANALYSIS_GROUP \fn int freqz(double* b, double* a, int ord, double* w, int n, complex_t *h) \brief Function calculates the digital filter frequency response \f$ H \left(e^{j \omega} \right)\f$ corresponds to transfer function \f$H(z)\f$. Digital filter transfer function: \f[ H(z) = \frac{\sum\limits_{k = 0}^{N} b_k z^{-k}} {\sum\limits_{m = 0}^{N} a_m z^{-m}}, \f] here \f$N\f$ --- filter order (parameter `ord`). \n Frequency response \f$ H \left(e^{j \omega} \right)\f$ we can get if substitute \f$z = e^{j \omega} \f$. \n \param[in] b Pointer to the \f$ H(z) \f$ transfer function numerator coefficients vector. \n Vector size is `[ord+1 x 1]`. \n \n \param[in] a Pointer to the \f$H(z)\f$ transfer function denominator coefficients vector. \n Vector size is `[ord+1 x 1]`. \n \n \param[in] ord Filter order. \n Transfer function \f$H(z)\f$ numerator and denominator coefficients number equals `ord+1`. \n \n \param[in] w Pointer to the normalized frequency of digital filter frequency response \f$ H \left(\mathrm{e}^{j\omega} \right) \f$. \n Digital filter frequency response is \f$ 2\pi \f$-periodic function, and vector `w` advisable to set from 0 to \f$ \pi \f$, or from 0 to \f$ 2\pi \f$, or from \f$ -\pi \f$ to \f$ \pi \f$. Vector size is `[n x 1]`. \n \n \param[in] n Size of frequency vector `w`. \n \n \param[out] h Pointer to the frequency response vector \f$ H \left(\mathrm{e}^{j\omega} \right) \f$, corresponds to normalized frequency `w`. \n Vector size is `[n x 1]`. \n Memory must be allocated. \n \n \return `RES_OK` if frequency response vector is calculated successfully. \n Else \ref ERROR_CODE_GROUP "code error". \author Sergey Bakhurin www.dsplib.org ***************************************************************************** */ #endif #ifdef DOXYGEN_RUSSIAN /*! **************************************************************************** \ingroup FILTER_ANALYSIS_GROUP \fn int freqz(double* b, double* a, int ord, double* w, int n, complex_t *h) \brief Расчет комплексного коэффициента передачи \f$ H \left(e^{j \omega} \right)\f$ цифрового фильтра. Функция рассчитывает значения комплексного коэффициента передачи \f$ H \left(e^{j \omega} \right)\f$ цифрового фильтра, заданного коэффициентами передаточной функции \f$H(z)\f$: \f[ H(z) = \frac {\sum_{k = 0}^{N} b_k z^{-k}} {\sum_{m = 0}^{N} a_m z^{-m}}, \f] где \f$N\f$ --- порядок фильтра (параметр `ord`). \n Комплексный коэффициент передачи рассчитывается путем подстановки \f$z = e^{j \omega} \f$. \n \param[in] b Указатель на вектор коэффициентов числителя передаточной функции \f$H(z)\f$. \n Размер вектора `[ord+1 x 1]`. \n \n \param[in] a Указатель на вектор коэффициентов знаменателя передаточной функции \f$H(z)\f$. \n Размер вектора `[ord+1 x 1]`. \n \n \param[in] ord Порядок фильтра. Количество коэффициентов числителя и знаменателя передаточной функции \f$H(z)\f$ равно `ord+1`. \n \n \param[in] w Указатель на вектор значений нормированной циклической частоты \f$\omega\f$, для которого будет рассчитан комплексный коэффициент передачи \f$ H \left(e^{j \omega} \right)\f$. \n Размер вектора `[n x 1]`. \n \n \param[in] n Размер вектора нормированной циклической частоты `w`. \n \n \param[out] h Указатель на вектор комплексного коэффициента передачи \f$ H \left(e^{j \omega} \right)\f$, рассчитанного для циклической частоты `w`. \n Размер вектора `[n x 1]`. \n Память должна быть выделена. \n \n \return `RES_OK` Комплексный коэффициент передачи рассчитан успешно. \n В противном случае \ref ERROR_CODE_GROUP "код ошибки". \n \note Комплексный коэффициент передачи \f$ H \left(e^{j \omega} \right)\f$ цифрового фильтра представляет собой \f$ 2 \pi-\f$периодическую функцию нормированной циклической частоты \f$\omega\f$. Поэтому анализ цифровых фильтров целесообразно вести на одном периоде повторения \f$ H \left(e^{j \omega} \right)\f$, т.е. в интервале \f$\omega\f$ от 0 до \f$2 \pi\f$, или от \f$-\pi\f$ до \f$ \pi\f$. \n Кроме того известно, что для фильтра с вещественными коэффициентами \f$ H \left(e^{j \omega} \right) = H^* \left(e^{-j \omega} \right)\f$, а значит, анализ цифрового фильтра с вещественными коэффициентами достаточно вести для нормированной частоты \f$\omega\f$ от 0 до \f$\pi\f$. \author Бахурин Сергей www.dsplib.org ***************************************************************************** */ #endif int DSPL_API freqz(double* b, double* a, int ord, double* w, int n, complex_t *h) { complex_t jw; complex_t *bc = NULL; complex_t *ac = NULL; complex_t num, den; double mag; int k; int res; if(!b || !w || !h) return ERROR_PTR; if(ord<0) return ERROR_FILTER_ORD; if(n<1) return ERROR_SIZE; bc = (complex_t*) malloc((ord+1) * sizeof(complex_t)); res = re2cmplx(b, ord+1, bc); if( res!=RES_OK ) goto exit_label; if(a) { /* IIR filter if a != NULL */ ac = (complex_t*) malloc((ord+1) * sizeof(complex_t)); res = re2cmplx(a, ord+1, ac); if( res!=RES_OK ) goto exit_label; for(k = 0; k < n; k++) { RE(jw) = cos(w[k]); IM(jw) = -sin(w[k]); res = polyval_cmplx(bc, ord, &jw, 1, &num); if(res != RES_OK) goto exit_label; res = polyval_cmplx(ac, ord, &jw, 1, &den); if(res != RES_OK) goto exit_label; mag = ABSSQR(den); if(mag == 0.0) { res = ERROR_DIV_ZERO; goto exit_label; } mag = 1.0 / mag; RE(h[k]) = CMCONJRE(num, den) * mag; IM(h[k]) = CMCONJIM(num, den) * mag; } } else { /* FIR filter if a == NULL */ for(k = 0; k < n; k++) { RE(jw) = cos(w[k]); IM(jw) = -sin(w[k]); res = polyval_cmplx(bc, ord, &jw, 1, h+k); if(res != RES_OK) goto exit_label; } } res = RES_OK; exit_label: if(bc) free(bc); if(ac) free(ac); return res; } #ifdef DOXYGEN_ENGLISH /*! **************************************************************************** \ingroup FILTER_ANALYSIS_GROUP \fn int DSPL_API phase_delay(double* b, double* a, int ord, int flag, double* w, int n, double* tau) \brief Phase delay calculation for digital or analog filter corresponds to \f$H(s)\f$, or \f$H(z)\f$ transfer function. Group delay is describes as: \f[ \tau_{\varphi}(\omega) = - \frac{\Phi(\omega)}{\omega}, \f] here \f$\Phi(\omega)\f$ -- filter phase response, \f$\omega\f$ is angular frequency for analog filter, or normalized frequency for digital filter. \param[in] b Pointer to the \f$ H(s) \f$ or \f$H(z)\f$ transfer function numerator coefficients vector. \n Vector size is `[ord+1 x 1]`. \n \n \param[in] a Pointer to the \f$ H(s) \f$ or \f$H(z)\f$ transfer function denominator coefficients vector. \n Vector size is `[ord+1 x 1]`. \n \n \param[in] ord Filter order. \n Transfer function \f$ H(s) \f$ or \f$H(z)\f$ numerator and denominator coefficients number equals `ord+1`. \n \n \param[in] flag Binary flags to set calculation rules: \n \verbatim DSPL_FLAG_ANALOG Coefficients corresponds to analog filter DSPL_FLAG_DIGITAL Coefficients corresponds to digital filter \endverbatim \n \n \param[in] w Pointer to the angular frequency \f$ \omega \f$ (rad/s), which used for analog filter characteristics calculation (flag sets as `DSPL_FLAG_ANALOG`). \n For digital filter (flag sets as `DSPL_FLAG_DIGITAL`), parameter `w` describes normalized frequency of frequency response \f$ H \left(\mathrm{e}^{j\omega} \right) \f$. Digital filter frequency response is \f$ 2\pi \f$-periodic function, and vector `w` advisable to set from 0 to \f$ \pi \f$, or from 0 to \f$ 2\pi \f$, or from \f$ -\pi \f$ to \f$ \pi \f$. Vector size is `[n x 1]`. \n \n \param[in] n Size of frequency vector `w`. \n \n \param[out] tau Pointer to the phase delay vector. \n Vector size is `[n x 1]`. \n Memory must be allocated. \n \n \return \return `RES_OK` if function is calculated successfully. \n Else \ref ERROR_CODE_GROUP "code error". \author Sergey Bakhurin www.dsplib.org ***************************************************************************** */ #endif #ifdef DOXYGEN_RUSSIAN /*! **************************************************************************** \ingroup FILTER_ANALYSIS_GROUP \fn int DSPL_API phase_delay(double* b, double* a, int ord, int flag, double* w, int n, double* tau) \brief Расчет фазовой задержки цифрового или аналогового фильтра. Фазовая задержка определяется как: \f[ \tau_{\varphi}(\omega) = - \frac{\Phi(\omega)}{\omega}, \f] где \f$\Phi(\omega)\f$ -- ФЧХ фильтра, \f$\omega\f$ циктическая частот в случае аналогового фильтра, или нормированная частота цифрового фильтра. \param[in] b Указатель на вектор коэффициентов числителя передаточной функции аналогового фильтра \f$ H(s) \f$ или цифрового фильтра \f$ H(z) \f$. \n Размер вектора `[ord+1 x 1]`. \n \n \param[in] a Указатель на вектор коэффициентов числителя передаточной функции аналогового фильтра \f$ H(s) \f$ или цифрового фильтра \f$ H(z) \f$. \n Размер вектора `[ord+1 x 1]`. \n Параметр может быть `NULL`. В этом случае расчет производится для цифрового КИХ-фильтра с коэффициентами, заданными вектором `b`. \n\n \param[in] ord Порядок фильтра. Количество коэффициентов числителя и знаменателя передаточной функции \f$ H(s) \f$ или \f$ H(z) \f$ равно `ord+1`. \n \n \param[in] flag Флаг который задает тип фильтра: \n \verbatim DSPL_FLAG_ANALOG Коэффициенты относятся к аналоговому фильтру DSPL_FLAG_DIGITAL Коэффициенты относятся к цифровому фильтру \endverbatim \param[in] w Указатель на вектор значений циклической частоты \f$ \omega \f$ (рад/с), для которого будет рассчитаны АЧХ, ФЧХ и ГВЗ аналогового фильтра, если установлен флаг `DSPL_FLAG_ANALOG`. \n В случае если флаг `DSPL_FLAG_ANALOG` не установлен, то вектор частоты `w` используется как нормированная частота комплексного коэффициента передачи \f$ H \left(\mathrm{e}^{j\omega} \right) \f$ цифрового фильтра. \n В этом случае характеристика цифрового фильтра является \f$ 2\pi \f$-периодической, и вектор частоты может содержать произвольные значения, однако целесообразно задавать его от 0 до \f$ \pi \f$, а такжет от 0 до \f$ 2\pi \f$, или от \f$ -\pi \f$ до \f$ \pi \f$. \n Размер вектора `[n x 1]`. \n \n \param[in] n Размер вектора циклической частоты `w`. \n \n \param[out] tau Указатель на вектор фазовой задержки. \n Размер вектора `[n x 1]`. \n Память должна быть выделена. \n \return `RES_OK` фазовая задержка фильтра рассчитана успешно. \n В противном случае \ref ERROR_CODE_GROUP "код ошибки". \n \author Бахурин Сергей www.dsplib.org ***************************************************************************** */ #endif int DSPL_API phase_delay(double* b, double* a, int ord, int flag, double* w, int n, double* tau) { int err, i; double *phi = NULL; if(n > 0) phi = (double*)malloc(n*sizeof(double)); else return ERROR_SIZE; err = filter_freq_resp(b, a, ord, w, n, flag | DSPL_FLAG_UNWRAP, NULL, phi, NULL); if(err!=RES_OK) goto exit_label; for(i = 0; i < n; i++) { tau[i] = w[i] ? ( - phi[i] / w[i]) : ( - phi[i] / (w[i] + 1E-9) ); } exit_label: if(phi) free(phi); return err; } #ifdef DOXYGEN_ENGLISH #endif #ifdef DOXYGEN_RUSSIAN #endif int DSPL_API unwrap(double* phi, int n, double lev, double mar) { double a[2] = {0.0, 0.0}; double d; double th; int k; int flag = 1; if(!phi) return ERROR_PTR; if(n<1) return ERROR_SIZE; if(lev<=0 || mar <=0) return ERROR_UNWRAP; th = mar*lev; while(flag) { flag = 0; a[0] = a[1] = 0.0; for(k = 0; k th) { a[0] -= lev; flag = 1; } if( d < -th) { a[0] += lev; flag = 1; } phi[k]+=a[1]; a[1] = a[0]; } phi[n-1]+=a[1]; } return RES_OK; }