Matlab生成滤波器参数
filterDesigner
命令行输入filterDesigner
设置滤波器参数
编辑可以设置滤波器结构(直接一型/二型等、单节/多节)
目标中选择导出c语言头文件
得到滤波器参数
Simulink验证
matlab simulink仿真的目的主要是提前观测滤波效果,在vitis实现后可以将滤波前后的情况与simulink仿真进行对比,记录一下仿真过程。
添加滤波器到simulink中
添加正弦波生成器200Hz与5000Hz以及示波器模块
滤波前:
带通滤波后:
将200Hz信号成功恢复出来,滤去了5kHz的正弦信号。
代码
filter.h
#ifndef _FILTER_
#define _FILTER_
#define TEMP_BASE_ADDR 0x20000000
#define MWSPT_NSEC 13
extern const int NL_mult[MWSPT_NSEC];
extern const double NUM_mult[MWSPT_NSEC][3];
extern const int DL_mult[MWSPT_NSEC];
extern const double DEN_mult[MWSPT_NSEC][3];
#include <stdio.h>
#include <math.h>
extern const int NL_single;
extern const double NUM_single[13];
extern const int DL_single;
extern const double DEN_single[13];
void filter_single(double* x, double* y, int xlen, double* a, double* b, int nfilt);
void filter_mult(double* RxBufferPtr, double* buffer_temp);
void filter_single_use(double* inaddr, double* outaddr);
void filter_all(double* inaddr, double* outaddr);
#endif
filter_single是直接一型的单节滤波器代码,低通IIR,filter_single_use调用filter_single进行滤波操作,感觉是可以直接去掉filter_single_use这一环的,没试。可以输入一连串double数据,输出滤波后的一串double数据。
filter_mult是直接一型的二阶多节滤波器代码,带通IIR,输入单个double数据,输出滤波后的单个double数据。
两者代码结构是不同的,为什么不写成一样,是因为我copy的时候,两个大佬写的不一样,之后有时间再改。
filter_all是滤波的全过程,主要包含
filter.c
#include "filter.h"
#include <math.h>
#define k 0.2
double xDelay[26] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //初始化x的延迟,(x[n-1]...x[n-2])*13 多节二阶
double yDelay[26] = {0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0}; //初始化y的延迟,(y[n-1]...y[n-2])*13
double xDelay_single[6] = {0,0,0,0,0,0}; //初始化x的延迟,(x[n]...x[n-12]) 单节13阶
double yDelay_single[6] = {0,0,0,0,0,0}; //初始化y的延迟,(y[n]...y[n-12])
int numjoint = 6;
int numStage = 13;
const int NL_mult[MWSPT_NSEC_MULT] = { 1,3,1,3,1,3,1,3,1,3,1,3,1 }; //滤波器分子系数
const double NUM_mult[MWSPT_NSEC_MULT][3] = {
{
0.5834802936154, 0, 0
},
{
1, -0.09583101176903, 1
},
{
0.5834802936154, 0, 0
},
{
1, -1.999802349761, 1
},
{
0.6897246154972, 0, 0
},
{
1, 1.455323776042, 1
},
{
0.6897246154972, 0, 0
},
{
1, -1.999971691646, 1
},
{
0.07983392337156, 0, 0
},
{
1, -0.633411429872, 1
},
{
0.07983392337156, 0, 0
},
{
1, -1.999653971883, 1
},
{
1, 0, 0
}
};
const int DL_mult[MWSPT_NSEC_MULT] = { 1,3,1,3,1,3,1,3,1,3,1,3,1 }; //滤波器分母系数
const double DEN_mult[MWSPT_NSEC_MULT][3] = {
{
1, 0, 0
},
{
1, -1.437641216242, 0.7157935362898
},
{
1, 0, 0
},
{
1, -1.97099085614, 0.9729983069548
},
{
1, 0, 0
},
{
1, -1.89549235219, 0.900976018839
},
{
1, 0, 0
},
{
1, -1.522167636734, 0.6198289328958
},
{
1, 0, 0
},
{
1, -1.460250768155, 0.897554646763
},
{
1, 0, 0
},
{
1, -1.99236891738, 0.9937430534111
},
{
1, 0, 0
}
};
const int NL_single = MWSPT_NSEC_SINGLE; //滤波器分子系数
const double NUM_single[MWSPT_NSEC_SINGLE] = {
3.254338963004e-13,1.627169481502e-12,3.254338963004e-12,3.254338963004e-12,
1.627169481502e-12,3.254338963004e-13
};
const int DL_single = MWSPT_NSEC_SINGLE; //滤波器分母系数
const double DEN_single[MWSPT_NSEC_SINGLE] = {
1, -4.979373082966, 9.917704906665, -9.876874869511,
4.918127356203, -0.979584310381
};
//单节二阶滤波
double filter_double(double DataIn, double a[][3], double b[][3], int indexStage)
{
double a1, a2;
double b0, b1, b2;
double result;
b0 = b[indexStage][0];
b1 = b[indexStage][1];
b2 = b[indexStage][2];
a1 = a[indexStage][1];
a2 = a[indexStage][2];
result = b0 * DataIn + b1 * xDelay[indexStage * 2] + b2 * xDelay[indexStage * 2 + 1] - a1 * yDelay[indexStage * 2] - a2 * yDelay[indexStage * 2 + 1];
//延时因子的移位 不同节之间的滤波器x[n]延迟相互独立,需要申请单独地址
xDelay[indexStage * 2 + 1] = xDelay[indexStage * 2];
xDelay[indexStage * 2] = DataIn;
yDelay[indexStage * 2 + 1] = yDelay[indexStage * 2];
yDelay[indexStage * 2] = result;
return result;
}
//单节13阶滤波调用 (可以删掉
void filter_single_use(double* inaddr, double* outaddr){
int data_len = 1024;
double* input_data = (double*)inaddr;
static double huangemingzi[1024];
// double* output_data = (double*)singlefilter_addr;
filter_single(input_data, huangemingzi, data_len, DEN_single, NUM_single, numjoint);
double* ddr_buffer_temp = (double*)outaddr;
for (int i = 0; i < data_len; i++) {
if(output_data[i] > 0)
ddr_buffer_temp[i] = huangemingzi[i];
else
ddr_buffer_temp[i] = 0;
}
// 释放内存
// free(output_data);
}
//单节13阶滤波
void filter_single(double* x, double* y, int xlen, double* a, double* b, int nfilt)//nfilt为系数数组长度
{
int i, j;
a[0] = 0.0;
// double y_r[xlen];
memset(y,0,xlen*sizeof(double));
for (i = 0; i<xlen; i++)
{
// xDelay_single[12] = xDelay_single[11];
// xDelay_single[11] = xDelay_single[10];
// xDelay_single[10] = xDelay_single[9];
// xDelay_single[9] = xDelay_single[8];
// xDelay_single[8] = xDelay_single[7];
// xDelay_single[7] = xDelay_single[6];
// xDelay_single[6] = xDelay_single[5];
// xDelay_single[5] = xDelay_single[4];
// xDelay_single[4] = xDelay_single[3];
// xDelay_single[3] = xDelay_single[2];
// xDelay_single[2] = xDelay_single[1];
// xDelay_single[1] = xDelay_single[0];
// xDelay_single[0] = x[i];
for(int l = nfilt-1; l > 0; l--){
xDelay_single[l] = xDelay_single[l-1];
}
xDelay_single[0] = x[i];
for (j = 0; j < nfilt; j++)
{
y[i] += (b[j] * xDelay_single[j] - a[j] * yDelay_single[j]);
// xil_printf("b=%ld,a=%ld,j=%d,y=%ld\r\n",b[j],a[j],j,y[i]);
}
// yDelay_single[12] = yDelay_single[11];
// yDelay_single[11] = yDelay_single[10];
// yDelay_single[10] = yDelay_single[9];
// yDelay_single[9] = yDelay_single[8];
// yDelay_single[8] = yDelay_single[7];
// yDelay_single[7] = yDelay_single[6];
// yDelay_single[6] = yDelay_single[5];
// yDelay_single[5] = yDelay_single[4];
// yDelay_single[4] = yDelay_single[3];
// yDelay_single[3] = yDelay_single[2];
// yDelay_single[2] = yDelay_single[1];
// yDelay_single[1] = y[i];
for(int m = nfilt-1; m > 1; m--){
yDelay_single[m] = yDelay_single[m-1];
}
yDelay_single[1] = y[i];
}
}
//cd D:/studydata/chengdu/PL_DMA_PS/data
void filter_all(double* inaddr, double* outaddr){
int data_len = 1024;
double num;
//分配地址
double* input_data = (double*) inaddr; //为中间变量申请储存地址
//mrd -bin -file input.bin 0x001239f0 2048
static double mid_data[1024];
static double multfilter_data[1024];
//mrd -bin -file multfilter.bin 0x00114228 2048
static double sqr_data[1024];
//mrd -bin -file sqr.bin 0x00116228 2048
static double singlefilter_data[1024];
//mrd -bin -file singlefilter.bin 0x00118228 2048
static double sqrt_data[1024];
//mrd -bin -file sqrt.bin 0x0011a228 2048
static double div_data[1024];
//mrd -bin -file div.bin 0x0011c228 2048
static double mult_data[1024];//乘法
//mrd -bin -file mult.bin 0x0011e228 2048
//mrd -bin -file output.bin 0x001219f0 2048
//-----------进行带通滤波-------------
for (int i = 0; i < data_len ; i++){
mid_data[i] = input_data[i];
for(int indexStage = 0 ; indexStage < numStage ; indexStage++){
multfilter_data[i] = filter_double(mid_data[i],DEN_mult,NUM_mult,indexStage);
mid_data[i] = multfilter_data[i];
}
//----------平方----------
sqr_data[i] = multfilter_data[i]*multfilter_data[i];
}
//----------低通----------
filter_single_use(sqr_data, singlefilter_data);
for(int l = 0; l < data_len;l++){ //防止滤波器瞬态响应产生的负值对后续开根号的影响
if(singlefilter_data[l] > 0){
num = singlefilter_data[l];
}
else
singlefilter_data[l] = num;
}
//----------平方根、除法、乘法----------
for(int j = 0; j < data_len; j++){
sqrt_data[j] = sqrt(singlefilter_data[j]);
div_data[j] = k/sqrt_data[j];
mult_data[j] = div_data[j]*multfilter_data[j];
}
// double* ddr_buffer_temp = (double*)outaddr;
for (int i = 0; i < data_len; i++) {
outaddr[i] = mult_data[i];
}
}
数据可视化
(1)connect 【建立连接】
(2)target 【查看可连接目标】
(3)target 2 【连接到目标2】
(4)cd 文件存储路径 【进入到指定目录,生成文件会保存在该目录下,注意路径分隔符用左斜杠】
(5)mrd -bin -file filename.bin startaddr length 【通过该指令拷贝数据并保存在步骤(4)目录中,其中filename为文件名,必须用.bin为后缀,startaddr为拷贝的起始地址,length为拷贝的长度,单位感觉怪怪的,好像是length = data_num*data_len/32 = 1024*64/32
在matlab中运行上述代码,读取bin文件数据。
使用plot函数绘图。
测试
第一帧由于滤波器初始化,刚开始会导致波形的不稳定,但之后的帧滤波就不会产生有这个问题。
采用单步调试对所有滤波步骤进行测试
while(1) //滤波器代码简单测试
{
frame++;
for (i = 0; i < data_len; ++i)
{
datain[i] = 0.5 * (sin(2 * PI * 200 * (frame*data_len + i) / fs) + cos(2 * PI * 5000 * (frame*data_len + i) / fs + PI / 4));
}
// filter_single_use(datain, dataout);
filter_all(datain, dataout);
}
测试1
采样频率为31.25k,产生的200Hz和5000Hz正弦波叠加图样为:
采样频率为31.25k。
带通滤波
平方
低通滤波
平方根
除法
乘法
测试2
采样频率为31.25k,产生的20Hz和5000Hz正弦波叠加图样为:
带通滤波
平方
低通滤波
平方根
除法
乘法
总结
可以看出滤波器功能完美实现。
坑:
1.
分配长串且反复调用的数据地址时时尽量采用静态变量,以保证读取数据的稳定性,之前采用malloc函数分配临时地址或者直接使用double xxx[1024]时都会出现问题。
malloc经常出现返回NULL的情况(分配地址失败
double xxx[1024]则有时候会覆盖其他地址的数据,不知道出现原因,多次重新编译运行也无法解决,采用静态地址后解决。
2.