(完美运行)基于QT的滤波器设计(含信号合成、FFT、FIR滤波、IIR滤波)

QT版本5.9.6,详细代码和完整工程文件见资料,下载即可运行,适合QT新手以及学习IIR、FIR滤波、FFT的C语言算法实现,受益绝对匪浅。
(1)在上位机,使用QT软件编写完成两种或三种频率信号的合成,在图形界面上显示合成的时域波形;
(2)使用FFT计算合成信号的频率,在界面上绘制频谱图;
(3)使用matlab的Filter Designer设计FIR和IIR滤波器,分别完成一种频率成分的去除,并且在界面上显示滤除后的信号时域波形。

1、三种频率信号的合成,正弦信号a、正弦信号b、正弦信号c,并在UI界面上显示合成信号的时域波形:
通过在界面输入三个信号的频率,然后在程序里读取三个频率,转换为角度,生成三个正弦信号,绘制三个波形。下面这段程序实现了从输入框读取频率,生成三个正弦信号,并在图上绘制三个正弦波合成的信号的功能。

//三种频率的正弦波信号合成  
void Widget::on_com_clicked()  
{
    
      
    QLayoutItem *child;  
    while ((child = ui->layout->takeAt(0)) != 0)  
    {
    
      
           if(child->widget())  
           {
    
      
               child->widget()->setParent(NULL);  
           }  
            delete child;  
    }  
    Widget::Chart_Init();  
    series->clear();  
    chart->removeSeries(series);  
series->setName("合成");  

//读取文本框中的频率
    QString fa = ui->fa->toPlainText();  
    double fa1=fa.toDouble();  
    QString fb = ui->fb->toPlainText();  
    double fb1=fb.toDouble();  
    QString fc = ui->fc->toPlainText();  
    double fc1=fc.toDouble();  
  
    for(double i=0.0;i<10.0;i+=0.0001){
    
      
        double angle1 = i * fa1;  
        double angle2 = i * fb1;  
        double angle3 = i * fc1;  
        series->append(i,(sin(2*3.14159265*angle1)+sin(2*3.14159265*angle2)+sin(2*3.14159265*angle3)));  
    }  
    chart->addSeries(series);//把折线添加到图表  
    series->attachAxis(axisX); 
    series->attachAxis(axisY);  
    chart->axisY()->setRange(-3, 3);  
}  

在这里插入图片描述
2、使用FFT计算合成信号的频率,在界面绘制频谱图。
1)下面这段是主程序,调用了FFT.h头文件,头文件中又调用了FFT.c函数进行计算FFT,然后对得到的结果画幅频曲线:

//对合成信号做FFT,绘制幅频曲线  
void Widget::on_FFT_clicked()  
{
    
      
    QLayoutItem *child;  
     while ((child = ui->layout->takeAt(0)) != 0)  
     {
    
      
            if(child->widget())  
            {
    
      
                child->widget()->setParent(NULL);  
            }  
            delete child;  
     }  
   Widget::Chart_Init();  
    series->clear();  
    series->setName("IIR滤波");  
    //获得文本输入框中a波形的频率  
    QString fa = ui->fa->toPlainText();  
    double freq_a=fa.toDouble();  
    double freq_a_radians=freq_a*2*3.1415926;  
    //获得文本输入框中b波形的频率  
    QString fb = ui->fb->toPlainText();  
    double freq_b=fb.toDouble();  
    double freq_b_radians=freq_b*2*3.1415926;  
    QString fc = ui->fc->toPlainText();  
    double freq_c=fc.toDouble();  
    double freq_c_radians=freq_c*2*3.1415926;  
    double max_freq=freq_a;  
    if(max_freq<=freq_b)  
        max_freq=freq_b;  
    else if(max_freq<=freq_c)  
        max_freq=freq_c;  
   //获得FFT数据,用于显示  
    double real_freq[1024];  
    double amp[1024];  
    get_FFT_data(real_freq,amp,freq_a_radians,freq_b_radians,freq_c_radians);  
    //显示FFT变换后计算得到的频谱图  
    for(int i=0;i<max_freq+50;i++)  
    {
    
      
        series->append(real_freq[i],amp[i]);  
    }  
    chart->addSeries(series);//把折线添加到图表  
    series->setName("FFT");  
    chart->createDefaultAxes();  
    chart->axisY()->setRange(-1, 1);  
}  

在这里插入图片描述
在这里插入图片描述
3、FIR滤波
采用了Matlab的Filter Designer设计FIR滤波器,通带频率为100Hz,截止频率为200Hz,通带波纹0.5dB,阻带波纹80dB,信号采样率为800Sa/s,按照奈奎斯特采样定律,所以理论上来说能够处理的信号在400Hz以内,设计出的FIR滤波器阶数为21阶。

在这里插入图片描述

FIR滤波程序:
//FIR滤波  
void Widget::on_FIRfilter_clicked()  
{
    
      
    QLayoutItem *child;  
    while ((child = ui->layout->takeAt(0)) != 0)  
    {
    
      
           if(child->widget())  
           {
    
      
               child->widget()->setParent(NULL);  
           }  
           delete child;  
    }  
    Widget::Chart_Init();  
    series->clear();  
    series->setName("FIR滤波");   //添加波形名字  
    chart->removeSeries(series);  
    double data_in[10000];  
    double data_out[10000];  
    QString fa = ui->fa->toPlainText();  
    double fa1=fa.toDouble();  
    QString fb = ui->fb->toPlainText();  
    double fb1=fb.toDouble();  
    QString fc = ui->fc->toPlainText();  
    double fc1=fc.toDouble();  
    for(double i=0.0;i<10.0;i+=0.001){
    
      
        double angle1 = 2*3.14159*i * fa1;  
        double angle2 = 2*3.14159*i * fb1;  
        double angle3 = 2*3.14159*i * fc1;  
        int j = 1000 * i;  
        data_in[j]=sin(angle1)+sin(angle2)+sin(angle3);  
    }  
    int i=0,j=0,k=0;  
    double state[FIR_FILTER_LENGTH];  
    double temp=0;    
double FIR_COFFES[FIR_FILTER_LENGTH]= {
    
      
      0.000828859699301925110029309884396298003, 0.005491897013585840710281349430488262442,0.014807416606805706704719227673194836825, 0.021389125806650765432292971013339411002,
       0.010554414190420358110600318468641489744, -0.022661508756789315588431321657481021248,  
      -0.053911115172153287189438231052918126807, -0.0357090761579505269751599882965820143,  
       0.061219089267199357229376488476191298105, 0.205966149469584192122084687071037478745,  
       0.31493515071552402595500552706653252244, 0.31493515071552402595500552706653252244 ,  
       0.205966149469584192122084687071037478745, 0.061219089267199357229376488476191298105,  
      -0.0357090761579505269751599882965820143, -0.053911115172153287189438231052918126807,  
       -0.022661508756789315588431321657481021248, 0.010554414190420358110600318468641489744,  
        0.021389125806650765432292971013339411002, 0.014807416606805706704719227673194836825,  
        0.005491897013585840710281349430488262442, 0.000828859699301925110029309884396298003};  
  
    for (k = 0; k < 10000; k++){
    
      
        state[0] = data_in[k];  
        for (i = 0, temp = 0; i < FIR_FILTER_LENGTH-1; i++)  
            temp += FIR_COFFES[i] * state[i];  
        data_out[k] = temp;  
        for (j = FIR_FILTER_LENGTH - 2; j > -1 ; j--)  
        state[j+1] = state[j];  
    }  
    for(double i=0.0;i<10.0;i+=0.001){
    
      
        series->append(i,data_out[int (1000 * i)]);  
    }  
    chart->addSeries(series);//把折线添加到图表  
    series->attachAxis(axisX);  
    series->attachAxis(axisY);  
    chart->axisY()->setRange(-1.5, 1.5);  
}  

在界面分别设置3组三个信号的频率,验证FIR滤波的效果:
在这里插入图片描述
在这里插入图片描述
组2:用50Hz、220Hz和280Hz三个频率的信号波形进行滤波验证:
在这里插入图片描述
组3:用20Hz、220Hz和340Hz三个频率的信号波形进行滤波验证:
在这里插入图片描述
4、IIR滤波
采用了Matlab的Filter Designer工具箱设计IIR滤波器,为了对比和FIR滤波器的滤波效果,大多数参数和FIR滤波器阶数保持一致,所以也设置通带频率为100Hz,截止频率为200Hz,通带波纹0.5dB,阻带波纹80dB,信号采样率为800Sa/s,按照奈奎斯特采样定律,所以理论上来说也能够处理的信号在400Hz以内,设计出的滤波器阶数为12阶。

在这里插入图片描述
下面是IIR滤波的代码部分,调用了IIR参数设置和IIR滤波两个函数,2型的IIR滤波器函数并没有列出,详细的可以看程序。

//点击IIR滤波按钮,进行IIR滤波  
void Widget::on_IIRfilter_clicked()  
{
    
      
    QLayoutItem *child;  
     while ((child = ui->layout->takeAt(0)) != 0)  
     {
    
      
            if(child->widget())  
            {
    
      
                child->widget()->setParent(NULL);  
            }  
            delete child;  
     }  
    Widget::Chart_Init();  
    series->clear();  
    series->setName("IIR滤波");   //添加波形名字    
    int N=13;  
double b[N]={
    
    
3.09525176187779e-06,  3.71430211425335e-05,   0.000204286616283934, 
0.000680955387613114,   0.00153214962212951,    0.00245143939540721,    
0.00286001262797508,    0.00245143939540721,    0.00153214962212951,
0.000680955387613114,   0.000204286616283934,   3.71430211425335e-05,   3.09525176187779e-06};  
double a[N]={
    
    
1, -5.34962036107987,  14.1411241339418,   -23.9072313155838,  
28.4874436778036,   -25.0265817923911,  16.5375193873507,   
8.25031849575782,  3.07476132941233,   -0.832796574455573,
0.155288255056261,  -0.0178681514268133,    0.000958058346940756};  
    IIR_II filter;  
    filter.setPara(b, N-1, a, N-1);//设置IIR滤波器参数,b是分子,a是分母,分母,  
    //N-1是滤波器阶数,由于从0开始,所以是N-1,而不是N  
  
    double data_in[10000];  
    double data_out[10000];  
    //读取三个输入框中的频率数字  
    QString fa = ui->fa->toPlainText();  
    double fa1=fa.toDouble();  
    QString fb = ui->fb->toPlainText();  
    double fb1=fb.toDouble();  
    QString fc = ui->fc->toPlainText();  
    double fc1=fc.toDouble();  
  
    //将频率转换为角度  
    for(double i=0.0;i<10.0;i+=0.001){
    
      
        double angle1 = 2*3.14159*i * fa1;  
        double angle2 = 2*3.14159*i * fb1;  
        double angle3 = 2*3.14159*i * fc1;  
        int j = 1000 * i;  
        data_in[j]=sin(angle1)+sin(angle2)+sin(angle3);  
        }  
  
    //调用IIR滤波器进行滤波  
    //data_in是待滤波信号,data_out是滤波后的信号,10000是信号长度  
    filter.filter(data_in,data_out,10000);  
  
    //在图上画滤波后的波形  
     for(double i=0.0;i<10.0;i+=0.001)  
        {
    
      
            series->append(i,data_out[int (1000 * i)]);  
        }  
        chart->addSeries(series);//把折线添加到图表   
        series->attachAxis(axisX);  
        series->attachAxis(axisY);  
        chart->axisY()->setRange(-1.5, 1.5);  
}  

为了验证设计的IIR滤波器的滤波性能,我们采用了三组信号,这个和FIR滤波部分仍然保持一致。
在这里插入图片描述
组1:用100Hz、250Hz和380Hz三个频率的信号波形进行滤波验证:
在这里插入图片描述
组2:用50Hz、220Hz和280Hz三个频率的信号波形进行滤波验证:
在这里插入图片描述
组3:用20Hz、220Hz和340Hz三个频率的信号波形进行滤波验证:
在这里插入图片描述
IIR和FIR滤波的对比:
由于在本次实验设计滤波器指标阶段时,我刻意将滤波器的滤波指标保持一致,设计出的FIR滤波器阶数为21阶,IIR滤波器阶数为12阶,可见当计算资源非常宝贵时,IIR滤波器非常有用,即以最小的滤波器滤波器阶数实现滤波,另外对比IIR和FIR滤波器的滤波器系数的位数可以发现,IIR的位数比FIR的位数少很多,几乎少一半,这对于处理器如FPGA来说是一大好事,因为处理器的浮点数的位数是固定的,本身容易造成有限字长效应,不得不截断滤波器系数的长度,导致误差积累。单纯的就滤波效果来说,两种滤波器都能有效滤波,滤波效果相差不大,但是需要注意的是设计IIR滤波器一定要保持其稳定性,及分母的极点在单位圆以内。

猜你喜欢

转载自blog.csdn.net/qq_45362665/article/details/128237476