可编程逻辑
众所周知,小波变换的双正交基就来自与小波函数和尺度函数,而他们通过scale和平移来得到的小波函数族和尺度函数族表示了不同小波(尺度)函数的分辨率,下面来用公式回顾一下:
事实上,尺度函数族中的尺度 j 决定着不同的时间分辨率
而实际上(证明请看参考资料),高时间分辨率的尺度函数必然可以代表低时间分辨率的尺度函数,如上图的三角尺度函数可以表示为:
有了上面的铺垫,这里就比较简单了,因为我们知道,低分辨率信号可以由高分辨率信号线性表达,所以我们可以看出,高分辨率信号所张成的空间必然包含低分辨率张成的空间:
讲小波函数的MRA方程之前,我们不妨来回顾一下IDWT的定义:
自然而然,我们可以知道小波函数的MRA方程的递归意义是更为重要的,所以有:
所以多级的大家也会求了吧...
可以简单地看出,信号经过小波函数系数(尺度函数系数)之后还需要经过一个抽取的过程,这个的话自己看看小波函数和尺度函数的定义式就可以了
这里是相似的,而且由于懒的原因我没有做重构,所以也直接放图:
可以简单地看出,信号经过小波函数系数(尺度函数系数)之后还需要经过一个内插的过程,这个的话自己看看小波函数和尺度函数的定义式就可以了.
需要注意的是,可以先抽取再滤波,但是不能先滤波后内插,见上图,(常识)
众所周知,这次我们要实现的算法框图是这个:
本来我是直接按照算法流程实现了DWT,然后讲抽取和滤波对调了位置(为了提高系统的性能)
后来从网上仅有的资料中查看到别人做了多相分解,后面我想了想,如果不用多相结构的话,相当于原信号的先经过了一次抽取,也是极大地浪费了信号. 又有:
所以我们将信号和滤波器系数都进行奇偶分解,分别进行滤波,得到整体FPGA框图:
接下来我们简单地理一下过程
这个模块比较简单,但是想设计好需要一点小心思,思路就是做一个二分频时钟,上升沿将数据写入偶数部分,下降沿将数据写入奇数部分,这里不给出代码
代码很简单,先生成,再量化:
wn='db4';
[Ld,Hd,Lr,Hr] = wfilters(wn);
k=0:length(Ld)-1;
subplot(221);stem(k,Ld);
title('低通分解滤波器Ld');
subplot(222);stem(k,Lr);
title('低通重建滤波器Lr');
subplot(223);stem(k,Hd);
title('高通分解滤波器Hd');
subplot(224);stem(k,Hd);
title('高通重建滤波器Hr');
qua_ld = round(Ld*2^8);
qua_hd = round(Hd*2^8);
qua_lr = round(Lr*2^8);
qua_hr = round(Hr*2^8);
disp(qua_ld);
disp(qua_hd);
disp(qua_lr);
disp(qua_hr);
这里的流程跟我上一篇博客,FPGA/Verilog 设计FIR滤波器 ^[2]^ 是相似的,这里不多说,给出一个滤波器的源码:
module filter_hd_e(
//clock and reset
input CLK_50M,RST_N,
//filter in out
input signed [15:0] data_in_hd_e,
output signed [19:0] hd_out_e
);
localparam COEFF1,COEFF3,COEFF5,COEFF7; //过长省略
wire signed [19:0] add_result;
reg signed [15:0] data_shift[3:0];
wire signed [23:0] mul_data[3:0];
add_final add_inst(
.clock (CLK_50M),
.data0x (mul_data[0][23:8]),
.data1x (mul_data[1][23:8]),
.data2x (mul_data[2][23:8]),
.data3x (mul_data[3][23:8]),
.result (add_result)
);
always @ (posedge CLK_50M or negedge RST_N)
begin
if(!RST_N)begin
data_shift[0] <= 0;
data_shift[1] <= 0;
data_shift[2] <= 0;
data_shift[3] <= 0;
end
else begin
data_shift[3] <= data_shift[2];
data_shift[2] <= data_shift[1];
data_shift[1] <= data_shift[0];
data_shift[0] <= data_in_hd_e;
end
end
mult mult_inst_1 ( data_shift[0] *COEFF1 //下同
mult mult_inst_2 (
mult mult_inst_3 (
mult mult_inst_4 ( //过长省略
assign hd_out_e = add_result;
endmodule
大家对应这框图可能会说我怎么没有把滤波器系数给翻转,这个问题的话,大家可以看看那个获取系数的函数描述,他本来就帮我们翻转了.
加法器就算了,过于简单
这个在上一篇博客中也有提及,但是这次我们不是直接产生mif文件,而是选择在仿真的时候读入数据,所以代码就是:
depth = 1024;
width = 16;
x = 0 : 2*pi/(depth-1) :2*pi;
y = sin(x)+sin(8*x);
y = (y/2) * 32768;%将信号放大32768倍
y(360:400) = 32767; //为了小波变换的戏剧性效果设置
b = signed2unsigned(y,width);
fid = fopen('sinx.txt','wt'); %将信号写入一个.txt文件中
for num=0 : (depth-1)
fprintf(fid,'%x\\n',round(b(num+1)));
end
fclose(fid);
用tb读入数据:
integer i; //数组坐标
reg signed [15:0] stimulus[1:data_num]; //数组形式存储读出的数据
initial
begin
RST_N = 1'b1;
#60 RST_N = 1'b0;
#60 RST_N = 1'b1;
$readmemh("sinx.txt", stimulus); //将txt文件中的数据存储在数组中
i = 0;
repeat(data_num) begin //重复读取数组中的数据
i = i + 1;
data_in = stimulus[i];
#PERIOD; //每个时钟读取一次
end
$stop;
end
那么又到了紧张刺激的,看波形环节: matlab计算:
fpga计算:
全部0条评论
快来发表一下你的评论吧 !