巴特沃斯(Butterworth)滤波器的设计和幅频特性曲线绘制

大佬的一些文章
设计滤波器的参考链接
绘制伯德图的源码参考链接

一、设计Butterworth滤波器

设计滤波器,其实就是设计传递函数,butterworth低通滤波器的传递函数如下:
在这里插入图片描述
对于butterworth高通滤波器,唯一的区别是分子项,从1变为s^N。
高低通Butterworth滤波器归一化后的系数如下:
所谓归一化,就是只按照阶数来定系数,不考虑截止频率
在这里插入图片描述

反归一化过程(考虑截止频率):将s用以下公式代替,wc为截止频率,单位rad/s。
在这里插入图片描述
就得到考虑了阶数以及截至频率的Butterworth滤波器的传递函数。

1.1 利用matlab获取滤波器的归一化系数

在Matlab中,通过改变下面代码的N值(阶数),可以得到任意阶的归一化系数,(上面只给出了10阶的,你可以对比看看对不对)。

clc;clear
N = 10;%阶数
wc = 1;%截至频率设置为1rad/s,这样相当于归一化

[B,A]= butter(N,wc,'s')  %代入N和wn设计低通巴特沃斯模拟滤波器
%[B,A]= butter(N,wc,'high','s')  %代入N和wn设计高通巴特沃斯模拟滤波器
B=B./B(N);
A=A./B(N);

1.2 设计低通Butterworth滤波器

还记得上面说的吗?设计滤波器就是设计传递函数的分子项和分母项的系数

 %% butterworth滤波器的归一化系数,共7阶
    coff=[1 1 0 0 0 0 0 0;
          1 sqrt(2) 1 0 0 0 0 0;
          1 2 2 1 0 0 0 0;
          1 2.6131 3.4142 2.6131 1 0 0 0;
          1 3.2361 5.2361 5.2361 3.2361 1 0 0;
          1 3.8637 7.4641 9.1416 7.4641 3.8637 1 0;
          1 4.4940 10.0978 14.5918 14.5918 10.0978 4.4940 1];
    N=4;%滤波器的阶数
    wc=90;%单位Hz
    wc=2*pi*wc;%转换为rad/s
    
    num1=[0 0 0 0 1];	%分子系数
    for i=1:(N+1)
        den1(i)=coff(N,i)*(1/wc)^(N-i+1);%分母系数
    end
    
    %整理系数
    num1=num1/den1(1);
    den1=den1/den1(1);

1.3 设计高通Butterworth滤波器

高低通的区别,仅仅只是分子项的区别。
对于低通,分子项为1;——以5阶为例为[0 0 0 0 1]
对于高通,分子项为s^n;——以5阶为例为[1 0 0 0 0]

 %% butterworth滤波器的归一化系数,共7阶
    coff=[1 1 0 0 0 0 0 0;
          1 sqrt(2) 1 0 0 0 0 0;
          1 2 2 1 0 0 0 0;
          1 2.6131 3.4142 2.6131 1 0 0 0;
          1 3.2361 5.2361 5.2361 3.2361 1 0 0;
          1 3.8637 7.4641 9.1416 7.4641 3.8637 1 0;
          1 4.4940 10.0978 14.5918 14.5918 10.0978 4.4940 1];
    N=4;%滤波器的阶数
    wc=90;%单位Hz
    wc=2*pi*wc;%转换为rad/s
    
    num1=[1 0 0 0 0];	%分子系数
    for i=1:(N+1)
        den1(i)=coff(N,i)*(1/wc)^(N-i+1);%分母系数
    end
    
    %整理系数
    num1=num1/den1(1);
    den1=den1/den1(1);

二、C++源码——绘制伯德图

头文件和cpp文件见最末尾,具体使用方法如下:

//在应用的头文件类中
#include "bode.h"

Bode HighPassCurveData;//高通滤波器数据

//在应用的cpp文件中
//butterworth滤波器的归一化系数,共8阶
double coff[8][9]={1,1,0,0,0,0,0,0,0,
               1,1.4142,1,0,0,0,0,0,0,
               1,2,2,1,0,0,0,0,0,
               1,2.6131,3.4142,2.6131,1,0,0,0,0,
               1,3.2361,5.2361,5.2361,3.2361,1,0,0,0,
               1,3.8637,7.4641,9.1416,7.4641,3.8637,1,0,0,
               1,4.4940,10.0978,14.5918,14.5918,10.0978,4.4940,1,0,
               1,5.1258309,13.1370712,21.846151,25.6883559,21.846151,13.1370712,5.1258309,1};

//更新高通滤波器的幅频曲线
HighPassCurveData._TF.n=OrderHighPass+1;
HighPassCurveData._TF.d=OrderHighPass+1;

//定义分子项系数
double tempvalue=1.0/(2*PI*CutOffFreqHighPass);
HighPassCurveData._TF.num[0]=pow(tempvalue,OrderHighPass);;
for(int i=1;i<HighPassCurveData._TF.n;++i)
{
     HighPassCurveData._TF.num[i]=0;
}

//定义分母项系数
for(int i=0;i<HighPassCurveData._TF.d;++i)
{
     HighPassCurveData._TF.den[i]=coff[OrderHighPass-1][i]*pow(tempvalue,OrderHighPass-i);
}

HighPassCurveData._wlen=LEN;//幅频特性曲线的数据长度
HighPassCurveData.freData  = new struct fre[LEN];
HighPassCurveData.BodeData =new struct BodeNum[LEN];
for(int i=0;i<LEN;i++)
{
     HighPassCurveData.freData[i].f=Xaxisdata[i];//幅频特性曲线的X轴坐标,单位Hz
     HighPassCurveData.freData[i].w=HighPassCurveData.freData[i].f*2*PI;//转换单位为rad/s
}
//计算幅频特性曲线各频点的幅度值
HighPassCurveData.compute();

头文件如下:

#ifndef BODE_H
#define BODE_H
/******************************************************************************
* 文件       :    bode.h
* 作者       :     dhs 746769845@qq.com
* 版本       :    V1.0
* 日期       :    2020-7-31
* 描述       :    给定传递函数绘制,计算对应的波特图坐标的数据(幅值、相角)
*
******************************************************************************/
#include <complex>
#include <cmath>
using namespace std;
 
#define PI 3.1415926535
/*传递函数结构体*/
struct TransferFunction
{
   double num[10]; //传递函数分子项
   double den[10]; //传递函数分母项
   char  n;       //分子个数
   char  d;       //分母个数
};
/*幅值、相角结构体*/
struct BodeNum
{
   double mag;      //幅值 db
   double phase;    //相角 度(角度)
};
/*频率、角频率结构体*/
struct fre
{
   double f;       //频率 Hz
   double w;       //角频率 rad/s
};
class Bode
{
public:
   Bode(struct TransferFunction TF);  //传入传递函数
   ~Bode();
   struct BodeNum *compute();         //完成计算
   struct fre *logspace(int start, int stop, int num=50, int base=10.0);//产生输入的频率数组
   int getWlen(){return _wlen;}      //获取数组长度
 
private:
   struct TransferFunction _TF;      //传递函数
   double *_w;                        //频率指针
   int _wlen;                        //频率长度
   struct fre *freData;              //频率、角频率
   struct BodeNum *BodeData;         //幅值、相角
};
 
#endif // BODE_H

cpp文件如下:

 
/******************************************************************************
* 文件       :    bode.h
* 作者       :     dhs 746769845@qq.com
* 版本       :    V1.0
* 日期       :    2020-7-31
* 描述       :    给定传递函数绘制,计算对应的波特图坐标的数据(幅值、相角)
*
******************************************************************************/
#include "bode.h"
 
 
/*******************************************************************************
* 函 数 名         : Bode
* 函数功能         : bode类,构造函数
* 输入参数         : TF          --> 传入传递函数
* 返 回 值         : 无
*******************************************************************************/
Bode::Bode(struct TransferFunction TF)
   :_TF(TF)
{
   freData  = 0;
   BodeData = 0;
}
/*******************************************************************************
* 函 数 名         : compute()
* 函数功能         : bode图数据计算
* 输入参数         : 无
* 返 回 值         : bode图计算后的数据(数组指针)
*******************************************************************************/
struct BodeNum *Bode::compute()
{
   int i=0;
   int j=0;
   complex<double> ds,ms,s,j1;
   if(freData ==0)
   {
       return 0;
   }
   ds=ms={0,0};
   j1={0,1};                //虚数单位
   for (i=0; i<_wlen; i++)
   {
       s=j1*freData[i].w; //传递函数中的 s用jw代入
       ms ={0,0};         //保存分子项
       ds ={0,0};         //保存分母项
       for (j=0; j<_TF.n; j++)
       {
           ms= ms * s + _TF.num[j];
       }
       for (j=0; j<_TF.d; j++)
       {
           ds= ds * s + _TF.den[j];
       }
       s = ms/ds;
       BodeData[i].mag = 20.0 * log10(abs(s));       //20倍 log10幅度值
       BodeData[i].phase = atan2(s.imag(),s.real()) * 180.0 / PI;  //相角值
   }
   return BodeData;
}
/*******************************************************************************
* 函 数 名         : logspace
* 函数功能         : 生成频率
* 输入参数         : start-->对数开始的冥
*                   stop -->对数结束的冥
*                   num  --> 生成频率的个数 默认50
*                   base --> 对数的底  默认为10
*                  例:logspace(-2, 5, 200, 10)  //表示从0.01Hz~0.1MHz按照10倍频的间距 生成200个频率
* 返 回 值         : 返回生成的频率(数组指针)
*******************************************************************************/
struct fre *Bode::logspace(int start, int stop, int num, int base)
{
   double step=0;
   int i =0;
   _wlen = num;
   freData  = new struct fre[num];
   BodeData =new struct BodeNum[num];
   step =(stop-start)/(num-1.0);
   for(i=0;i<num; i++)
   {
       freData[i].f=pow(base, start+step*i);
       freData[i].w=freData[i].f*2*PI;
   }
 
   return freData;
 
}
/*******************************************************************************
* 函 数 名         : ~Bode
* 函数功能         : 析构
* 输入参数         :
* 返 回 值         :
*******************************************************************************/
Bode::~Bode()
{
   delete BodeData;
   delete freData;
 
}
 
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

kissgoodbye2012

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值