FIR数字滤波器设计方法的C++实现

头文件:

/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program 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. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                                  dfd.h
 *
 * Digital Filter Design.
 *
 * This is a base class for FIR and IIR filter design. It contains the design
 * specifies and some universal parameters of filter.
 *
 * Zhang Ming, 2010-03, Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef DFD_H
#define DFD_H


#include <string>
#include <vector.h>


namespace splab
{

    const double    FREQ_MIN    =   1.0E-3;     // min freqency
    const double    FREQ_MAX    =   1.0E12;     // max freqency
    const double    GAIN_PASS   =   -1.0E-2;    // max passband gain
    const double    GAIN_TRAN   =   -3.0103;    // min pb, max sb gain
    const double    GAIN_STOP   =   -1.0E02;    // min stopband gain

    class DFD
    {

     public:

        DFD( const string &select );
        virtual ~DFD();

        void setParams( double fs, double f1, double a1,
                        double f2, double a2 );
        void setParams( double fs, double f1, double a1, double f2,
                        double f3, double a2, double f4, double a3 );

        virtual void design() = 0;
        virtual void dispInfo() const = 0;

    protected:

        double  fsamp;              // sampling frequency
        double  wpass1, wpass2;     // passband edge frequency
        double  wstop1, wstop2;     // stopband edge frequency

        double  apass1, apass2;     // passband gain
        double  astop1, astop2;     // stopband gain

        string  filtType;           // filter type
        int     order;              // length of filter

        inline double getValue( double x, double min, double max );

    };
    // class DFD


    #include <dfd-impl.h>

}
// namespace splab


#endif
// DFD_H
/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program 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. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                                  fir.h
 *
 * Finite Impulse Response Digital Filter.
 *
 * This class is designed for designing the FIR filter using window function
 * method. The unit of frequency and gain parameters are "Hz" and "dB",
 * respectively.
 *
 * The valid filter types are:
 *      lowpass     highpass    bandpass    bandstop
 * and the valid windows are:
 *      Rectangle   Bartlett    Blackman    Hanning     Hamming
 *      Gauss       Kaiser
 *
 * The length of filter( filter's order plus one ) are multiples of 4, which
 * is the least number(L=4n) satisfying the design specifies.
 *
 * Zhang Ming, 2010-03, Xi'an Jiaotong University.
 *****************************************************************************/


#ifndef FIR_H
#define FIR_H


#include <iomanip>
#include <window.h>
#include <dfd.h>


namespace splab
{

    using std::setw;
    using std::ios;
    using std::setiosflags;
    using std::setprecision;


    class FIR : public DFD
    {

     public:

        FIR( const string &select, const string &win );
        FIR( const string &select, const string &win, double a );
        ~FIR();

        void    design();
        void    dispInfo() const;
        Vector<double> getCoefs() const;

    private:

        void    orderEst();
        void    idealCoef();
        void    calcCoef();
        double  frqeResp( double freq );
        void    calcGain();
        bool    isSatisfy();

        string  windType;           // window type

        Vector<double>  wind,       // window function
                        coefs,      // coefficients
                        edgeGain;   // gain at edge frquency
        double  alpha;              // window parameter

    };
    // class FIR


    #include <fir-impl.h>

}
// namespace splab


#endif
// FIR_H

实现文件:

/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program 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. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                               dfd-impl.h
 *
 * Implementation for DFD class.
 *
 * Zhang Ming, 2010-03, Xi'an Jiaotong University.
 *****************************************************************************/


/**
 * constructors and destructor
 */
DFD::DFD( const string &select ) : filtType(select)
{
}

DFD::~DFD()
{
}


/**
 * Get a number which falls between min and max.
 */
double DFD::getValue( double x, double min, double max )
{

    if( (x > min) && (x < max) )
        return x;
    else
    {
        cerr << "The parameter is out of range!" << endl;
        return 0;
    }
}


/**
 * Set filter's parameters
 */
void DFD::setParams( double fs, double f1, double a1, double f2, double a2 )
{
    fsamp = getValue( fs, FREQ_MIN, FREQ_MAX );
    double maxFreq = fsamp / 2;

    if( filtType == "lowpass" )
    {
        wpass1 = getValue( f1, FREQ_MIN, maxFreq );
        apass1 = getValue( a1, GAIN_TRAN, GAIN_PASS );
        wstop1 = getValue( f2, wpass1, maxFreq );
        astop1 = getValue( a2, GAIN_STOP, GAIN_TRAN );
    }
    else if( filtType == "highpass" )
    {
        wstop1 = getValue( f1, FREQ_MIN, maxFreq );
        astop1 = getValue( a1, GAIN_STOP, GAIN_TRAN );
        wpass1 = getValue( f2, wstop1, maxFreq );
        apass1 = getValue( a2, GAIN_TRAN, GAIN_PASS );
    }
    else
        cerr << "Parameters setting has failed!" << endl;

    // Convert all edge frequencies to rad/sec
    wpass1 *= TWOPI;
    wstop1 *= TWOPI;

}

void DFD::setParams( double fs, double f1, double a1, double f2,
                     double f3, double a2, double f4, double a3 )
{
    fsamp = getValue( fs, FREQ_MIN, FREQ_MAX );
    double maxFreq = fsamp / 2;

    if( filtType == "bandpass" )
    {
        wstop1 = getValue( f1, FREQ_MIN, maxFreq );
        astop1 = getValue( a1, GAIN_STOP, GAIN_TRAN );
        wpass1 = getValue( f2, wstop1, maxFreq );
        wpass2 = getValue( f3, wpass1, maxFreq );
        apass1 = getValue( a2, GAIN_TRAN, GAIN_PASS );
        wstop2 = getValue( f4, wpass2, maxFreq );
        astop2 = getValue( a3, GAIN_STOP, GAIN_TRAN );
        apass2 = apass1;
        if( astop1 < astop2 )
            astop2 = astop1;
        else
            astop1 = astop2;
    }
    else if( filtType == "bandstop" )
    {
        wpass1 = getValue( f1, FREQ_MIN, maxFreq );
        apass1 = getValue( a1, GAIN_TRAN, GAIN_PASS );
        wstop1 = getValue( f2, wpass1, maxFreq );
        wstop2 = getValue( f3, wstop1, maxFreq );
        astop1 = getValue( a2, GAIN_STOP, GAIN_TRAN );
        wpass2 = getValue( f4, wstop2, maxFreq );
        apass2 = getValue( a3, GAIN_TRAN, GAIN_PASS );
        astop2 = astop1;
        if( apass1 < apass2 )
            apass1 = apass2;
        else
            apass2 = apass1;
    }
    else
        cerr << "Parameters setting has failed!" << endl;

    // Convert all edge frequencies to rad/sec
    wpass1 *= TWOPI;
    wpass2 *= TWOPI;
    wstop1 *= TWOPI;
    wstop2 *= TWOPI;
}
/*
 * Copyright (c) 2008-2011 Zhang Ming (M. Zhang), [email protected]
 *
 * This program is free software; you can redistribute it and/or modify it
 * under the terms of the GNU General Public License as published by the
 * Free Software Foundation, either version 2 or any later version.
 *
 * Redistribution and use in source and binary forms, with or without
 * modification, are permitted provided that the following conditions are met:
 *
 * 1. Redistributions of source code must retain the above copyright notice,
 *    this list of conditions and the following disclaimer.
 *
 * 2. Redistributions in binary form must reproduce the above copyright
 *    notice, this list of conditions and the following disclaimer in the
 *    documentation and/or other materials provided with the distribution.
 *
 * This program 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. A copy of the GNU General Public License is available at:
 * http://www.fsf.org/licensing/licenses
 */


/*****************************************************************************
 *                               fir-impl.h
 *
 * Implementation for FIR class.
 *
 * Zhang Ming, 2010-03, Xi'an Jiaotong University.
 *****************************************************************************/


/**
 * constructors and destructor
 */
FIR::FIR( const string &select, const string &win )
        : DFD( select ), windType(win)
{
    bool cond = ( filtType=="lowpass" || filtType=="highpass" ||
                  filtType=="bandpass" || filtType=="bandstop" );
    assert(cond);

    cond = ( windType=="Rectangle" || windType=="Bartlett" ||
             windType=="Blackman" || windType=="Hanning" ||
             windType=="Hamming" || windType=="Gauss" );
    assert(cond);
}

FIR::FIR( const string &select, const string &win, double a )
        : DFD( select ), windType(win), alpha(a)
{
    bool cond = ( filtType=="lowpass" || filtType=="highpass" ||
                  filtType=="bandpass" || filtType=="bandstop" );
    assert(cond);

    cond = ( windType=="Kaiser" || windType=="Gauss" );
    assert(cond);
}

FIR::~FIR()
{
}


/**
 * Design digital FIR filter.
 */
void FIR::design()
{
    // Estimate the length of filter.
    orderEst();
    calcCoef();
    calcGain();

    while( !isSatisfy() )
    {
        order += 4;
        calcCoef();
        calcGain();
    }
}


/**
 * Displays the design result of filter.
 */
void FIR::dispInfo() const
{
    int i, j, k;

    cout << endl;
    cout << "\t\t    Filter selectivity      :  " << filtType << endl;
    cout << "\t\t    Window type             :  " << windType << endl;
    cout << "\t\t    Sampling Frequency (Hz) :  " << fsamp << endl;

    //  gains and edge frequency
    if( filtType=="lowpass" )
    {
        cout << "\t\t    Passband frequency (Hz) :  "
             << wpass1/TWOPI << endl;
        cout << "\t\t    Passband gain      (dB) :  "
             << apass1 << endl;
        cout << "\t\t    Stopband frequency (Hz) :  "
             << wstop1/TWOPI << endl;
        cout << "\t\t    Stopband gain      (dB) :  "
             << astop1 << endl;
    }
    else if( filtType=="highpass" )
    {
        cout << "\t\t    Stopband frequency (Hz) :  "
             << wstop1/TWOPI << endl;
        cout << "\t\t    Stopband gain      (dB) :  "
             << astop1 << endl;
        cout << "\t\t    Passband frequency (Hz) :  "
             << wpass1/TWOPI << endl;
        cout << "\t\t    Passband gain      (dB) :  "
             << apass1 << endl;
    }
    else if( filtType=="bandpass" )
    {
        cout << "\t\t    Lower stopband frequency (Hz) :  "
             << wstop1/TWOPI << endl;
        cout << "\t\t    Lower stopband gain      (dB) :  "
             << astop1 << endl;
        cout << "\t\t    Lower passband frequency (Hz) :  "
             << wpass1/TWOPI << endl;
        cout << "\t\t    Upper passband frequency (Hz) :  "
             << wpass2/TWOPI << endl;
        cout << "\t\t    Passband gain            (dB) :  "
             << apass1 << endl;
        cout << "\t\t    Upper stopband frequency (Hz) :  "
             << wstop2/TWOPI << endl;
        cout << "\t\t    Upper stopband gain      (dB) :  "
             << astop2 << endl;
    }
    else
    {
        cout << "\t\t    Lower passband frequency (Hz) :  "
             << wpass1/TWOPI << endl;
        cout << "\t\t    Lower passband gain      (dB) :  "
             << apass1 << endl;
        cout << "\t\t    Lower stopband frequency (Hz) :  "
             << wstop1/TWOPI << endl;
        cout << "\t\t    Upper stopband frequency (Hz) :  "
             << wstop2/TWOPI << endl;
        cout << "\t\t    Stopband gain            (dB) :  "
             << astop1 << endl;
        cout << "\t\t    Upper passband frequency (Hz) :  "
             << wpass2/TWOPI << endl;
        cout << "\t\t    Upper passband gain      (dB) :  "
             << apass2 << endl;
    }

    // display coefficients
    cout << endl << endl;
    cout << "\t\t\t\t  Filter Coefficients" << endl << endl;
    cout << "   N    [     N + 0            N + 1" ;
    cout << "            N + 2            N + 3     ]" << endl;
    cout << "  ===   ============================" ;
    cout << "========================================" ;
    for( i=0; i<order/4; ++i )
    {
        j = i * 4;
        cout << endl << setw(4) << j << "    ";

        cout << setiosflags(ios::scientific) << setprecision(8);
        for( k=0; k<4; ++k )
            cout << setw(16) << coefs[j+k] << " " ;
    }

    cout << endl << endl << endl
         << "\t ==================== Edge Frequency Response";
    cout << " ====================" << endl;
    cout << setiosflags(ios::fixed);
	if( edgeGain.size() == 2 )
    {
        cout << "\t     Mag(fp) = " << edgeGain[0] << "(dB)";
        cout << "       Mag(fs) = " << edgeGain[1] << "(dB)" << endl;
    }
    else
    {
        cout << "\t     Mag(fp1) = " << edgeGain[0] << "(dB)";
        cout << "       Mag(fp2) = " << edgeGain[1] << "(dB)" << endl;
        cout << "\t     Mag(fs1) = " << edgeGain[2] << "(dB)";
        cout << "       Mag(fs2) = " << edgeGain[3] << "(dB)" << endl;
    }
}


/**
 * Get the FIR filter's coefficients.
 */
inline Vector<double> FIR::getCoefs() const
{
    return coefs;
}


/**
 * Estimates the length of FIR filter.
 */
void FIR::orderEst()
{
    double  deltaFreq,  // delta frequency
            lowerDF,    // delta freq of lower band
            upperDF,    // delta freq of upper band
            errSB,      // stopband error
            errPB,      // passband error
            errMin,     // minimum of sb/pb errors
            errDB;      // minimum error in dB

    // Determine frequency delta
    if( filtType=="lowpass" || filtType=="highpass" )
        deltaFreq = abs(wstop1-wpass1) / fsamp;
    else
    {
        lowerDF = abs(wstop1-wpass1) / fsamp;
        upperDF = abs(wstop2-wpass2) / fsamp;

        if( lowerDF > upperDF )
            deltaFreq = upperDF;
        else
            deltaFreq = lowerDF;
    }

    // Determine stopband and passband errors
    errPB = 1 - pow( 10, 0.05*apass1 );
    errSB = pow( 10, 0.05*astop1 );

    if( errSB < errPB )
        errMin = errSB;
    else
        errMin = errPB;
    errDB = -20 * log10(errMin);

    // Store filter length in pFilt and return beta.
    if( errDB > 21 )
        order = int( ceil( 1 + (errDB-7.95) / (2.285*deltaFreq) ) );
    else
        order = int( ceil( 1 + (5.794/deltaFreq) ) );

    order += 4 - order%4;
}


/**
 * Calculates ideal FIR coefficients.
 */
void FIR::idealCoef()
{
    int     i;
    double  t,
            tau,
            Wc1,
            Wc2;

    // Calculate tau as non-integer if order is even.
    tau =  ( order - 1 ) / 2.0;

    // Adjust cutoff frequency to midway point between stop
    // and pass edge frequency and convert to digital frequency.
    Wc1 = (wstop1 + wpass1) / (2*fsamp);
    Wc2 = (wstop2 + wpass2) / (2*fsamp);

    // Calc coefs based on selectivity of filter.
    if( filtType == "lowpass" )
        for( i=0; i<order; ++i )
        {
            if( i == tau )
                coefs[i] = Wc1/PI;
            else
            {
                t = i - tau;
                coefs[i] = sin(Wc1*t) / (PI*t);
            }
        }
    else if( filtType == "highpass" )
        for( i=0; i<order; ++i )
        {
            if( i == tau )
                coefs[i] = (PI-Wc1) / PI;
            else
            {
                t = i - tau;
                coefs[i] = ( sin(PI*t) - sin(Wc1*t) ) / (PI*t);
            }
        }
    else if( filtType == "bandpass" )
        for( i=0; i<order; ++i )
        {
            if( i == tau )
                coefs[i] = ( Wc2-Wc1 ) / PI;
            else
            {
                t = i - tau;
                coefs[i] = ( sin(Wc2*t) - sin(Wc1*t) ) / (PI*t);
            }
        }
    else
        for( i=0; i<order; ++i )
        {
            if( i == tau )
                coefs[i] = ( PI+Wc1-Wc2 ) / PI;
            else
            {
                t = i - tau;
                coefs[i] = ( sin(PI*t)-sin(Wc2*t)+sin(Wc1*t) ) / (PI*t);
            }
        }
}


/**
 * Calculates the digital FIR coefficients.
 */
void FIR::calcCoef()
{
    coefs.resize(order);
    wind.resize(order);

    //  Calculate the ideal FIR coefficients.
    idealCoef();

    // Get window function.
    if( windType=="Kaiser" || windType=="Gauss" )
        wind = window( windType, order, alpha, 1.0 );
    else
        wind = window( windType, order, 1.0 );

    //  Multiply window and ideal coefficients.
    coefs *= wind;
}


/**
 * Calculate the response at edge freqency.
 */
double FIR::frqeResp( double freq )
{
    double  mag = 1.0,
            rea = 0.0,
            img = 0.0,
            omega = TWOPI*freq / fsamp;

    // Loop through all the coefficients.
    for( int i=0; i<order; ++i )
    {
        double  domega = i * omega;
        rea += coefs[i] * cos(domega);
        img += coefs[i] * sin(domega);
    }

    // Calculate final result and convert to degrees.
    mag = sqrt( rea*rea + img*img );
    if( mag < EPS )
        mag = EPS;
    mag = 20 * log10( mag );

    return mag;
}


/**
 * Calculate the response at edge freqency.
 */
void FIR::calcGain()
{
    // Determine the edge freqency.
    if( filtType=="lowpass" || filtType=="highpass" )
    {
        double  f1 = wpass1 / TWOPI,
                f2 = wstop1 / TWOPI;

        edgeGain.resize(2);
        edgeGain(1) = frqeResp( f1 );
        edgeGain(2) = frqeResp( f2 );
    }
    else
    {
        double  f1 = wpass1 / TWOPI,
                f2 = wpass2 / TWOPI,
                f3 = wstop1 / TWOPI,
                f4 = wstop2 / TWOPI;

        edgeGain.resize(4);
        edgeGain(1) = frqeResp( f1 );
        edgeGain(2) = frqeResp( f2 );
        edgeGain(3) = frqeResp( f3 );
        edgeGain(4) = frqeResp( f4 );
    }
}


/**
 * Design digital FIR filter.
 */
bool FIR::isSatisfy()
{
    if( edgeGain.size() == 2 )
    {
        if( edgeGain(1)<apass1 || edgeGain(2)>astop1 )
            return false;
    }
    else
    {
        if( edgeGain(1)<apass1 || edgeGain(2)<apass2 ||
            edgeGain(3)>astop1 || edgeGain(4)>astop2 )
            return false;
    }

    return true;
}

测试代码:

/*****************************************************************************
 *                               fir_test.cpp
 *
 * FIR class testing.
 *
 * Zhang Ming, 2010-03, Xi'an Jiaotong University.
 *****************************************************************************/


#define BOUNDS_CHECK

#include <iostream>
#include <fir.h>


using namespace std;
using namespace splab;


int main()
{
    string  wType = "Hamming";

//    string  fType = "lowpass";
//    double  fs = 1000,
//            fpass = 200,
//            apass = -3,
//            fstop = 300,
//            astop = -20;
//    FIR fir( fType, wType );
//    fir.setParams( fs, fpass, apass, fstop, astop );

//    string  fType = "highpass";
//    double  fs = 1000,
//            fstop = 200,
//            astop = -20,
//            fpass = 300,
//            apass = -3;
//    FIR fir( fType, wType );
//    fir.setParams( fs, fstop, astop, fpass, apass );

//    string  fType = "bandpass";
//    double  fs = 1000,
//            fstop1 = 100,
//            astop1 = -20,
//            fpass1 = 200,
//            fpass2 = 300,
//            apass1 = -3,
//            fstop2 = 400,
//            astop2 = -20;
//    FIR fir( fType, wType );
//    fir.setParams( fs, fstop1, astop1, fpass1, fpass2, apass1, fstop2, astop2 );

    string  fType = "bandstop";
    double  fs = 1000,
            fpass1 = 100,
            apass1 = -3,
            fstop1 = 200,
            fstop2 = 300,
            astop1 = -20,
            fpass2 = 400,
            apass2 = -3;
    FIR fir( fType, wType );
    fir.setParams( fs, fpass1, apass1, fstop1, fstop2, astop1, fpass2, apass2 );

    fir.design();
    fir.dispInfo();

    cout << endl;
    return 0;
}
运行结果:
                    Filter selectivity      :  bandstop
                    Window type             :  Hamming
                    Sampling Frequency (Hz) :  1000
                    Lower passband frequency (Hz) :  100
                    Lower passband gain      (dB) :  -3
                    Lower stopband frequency (Hz) :  200
                    Upper stopband frequency (Hz) :  300
                    Stopband gain            (dB) :  -20
                    Upper passband frequency (Hz) :  400
                    Upper passband gain      (dB) :  -3


                                  Filter Coefficients

   N    [     N + 0            N + 1            N + 2            N + 3     ]
  ===   ====================================================================
   0    -3.85192764e-003  8.42472981e-003  3.11153775e-003 -2.03549729e-003
   4    -3.55185234e-002  2.30171390e-002 -1.41331145e-001  2.61755439e-001
   8     2.88881794e-002  3.56158158e-001  3.56158158e-001  2.88881794e-002
  12     2.61755439e-001 -1.41331145e-001  2.30171390e-002 -3.55185234e-002
  16    -2.03549729e-003  3.11153775e-003  8.42472981e-003 -3.85192764e-003


         ==================== Edge Frequency Response ====================
             Mag(fp1) = -0.85449456(dB)       Mag(fp2) = -0.80635855(dB)
             Mag(fs1) = -21.347821(dB)       Mag(fs2) = -21.392825(dB)


Process returned 0 (0x0)   execution time : 0.078 s
Press any key to continue.
 

你可能感兴趣的:(FIR数字滤波器设计方法的C++实现)