呜呜祖啦滤波器,初步设计数字信号处理,所做的一个题目,望高手指点
本人是FPGA的初学者,花了一个月时间来学习数字信号处理的知识,现在有一点点成效了,跟大家一起分享,对于初学者也许有帮助,但更希望高手们来指点,我想听取大家的建议进一步改善该方案。以下是自己整理的一个文档,内容就是下面粘贴出来的那些和设计过程的一些感触而已,只是为了方便初学者,而整理的
点击此处下载 ourdev_573514.pdf(文件大小:337K) (原文件名:呜呜祖啦滤波器FPGA实现.pdf)
摘要:研究一种采用FPGA实现128阶FIR音频滤波器,在满足滤波要求的情况下,所耗资源最少;讨论窗函数的选择、滤波器的结构、系数的量化问题;重点在于如何去实现和如何去仿真验证,而不仅仅是理论讨论,涉及到MATLAB与Modelsim联合仿真验证。
1、引言
2010南非世界杯,球迷们的豪华盛宴,但遗憾的是南非球迷们在现场吹起了呜呜祖啦,这种声音不仅很刺耳,还覆盖掉了足球场上的一切声音,使得在呜呜祖啦滤波器FPGA实现.doc司迅速的推出了一款呜呜祖啦滤波器,但为什么转播的时候没有采用这款滤波器先滤除呜呜祖啦声音后再传送到电视机呢?一个很重要的原因是,这款滤波器是纯软件制作,速度无法达到直播所需的高速,而基于硬件实现的FPGA方案却能很好的满足这一要求,所以研究这种方案很既有吸引力。
2、MATLAB计算出滤波器系数
本设计采用的是有限脉冲响应滤波器(FIR),汉宁窗,高通,具体设计如下:
wp=0.17*pi; ws=0.12*pi; % 输入设计指标
deltaw=wp-ws; % 计算过渡带的宽度
N0=ceil(6.2*pi/deltaw); % 按汉宁窗窗计算滤波器长度N0
N=N0+mod(N0+1,2) % 为实现FIR类型I偶对称滤波器,应确保N为奇数
windows=(hanning(N))'; % 使用汉宁窗,并将列向量变为行向量
wc=(ws+wp)/2; % 截止频率取通阻带频率的平均值
hd=ideal_lp(pi,N)-ideal_lp(wc,N); % 建立理想高通滤波器
b=hd.*windows; % 求FIR系统函数系数
=freqz_m(b,1); % 求解频率特性
n=0:N-1; dw=2*pi/1000; % dw为频率分辨率,将0—2π 分成为1000份
Rp=-(min(db(wp/dw+1:501))) % 检验通带波动
As=-round(max(db(1:ws/dw+1))) % 检验最小阻带衰减
滤波器参数初步设定了之后,导入音频数据,实现滤波,进行快速傅里叶变换,观察滤波前与滤波后的频谱,试听滤波前与滤波后的音频,反复调整参数,直到达到所需效果,但有一点必须要考虑,那就是抽头系数N越大,滤波效果越好,但所耗资源越多。折合这两个因数,综合考虑,本设计决定采用125点对称抽头系数,125点既可以达到很好的效果,又可以不必消耗过多的资源,具体设计如下:
=wavread('D:\2014.wav'); % 读入音频文件
Y=filter(b,1,y); % 实现数字滤波
t=(0:length(y)-1)/fs; % 计算数据时刻
subplot(3,2,1);plot(t,y); % 绘制原波形图
title('原信号波形图'); % 加标题
subplot(3,2,2);plot(t,Y); % 绘制滤波后波形图
title('滤波后波形图'); % 加标题
xf=fft(y); % 作傅里叶变换求原频谱
yf=fft(Y); % 作傅里叶变换求滤波后频谱
fm=3000*length(xf)/fs; % 确定绘频谱图的上限频率
f=(0:fm)*fs/length(xf); % 确定绘频谱图的频率刻度
subplot(3,2,3);plot(f,abs(xf(1:length(f)))); % 绘制原波形频谱图
title('原信号频谱图'); % 加标题
subplot(3,2,4);plot(f,abs(yf(1:length(f)))); % 绘制滤波后频谱图
title('滤波后信号频谱图'); % 加标题
subplot(3,2,5),plot(w/pi,db);
axis();
title('幅度频率响应');% 加标题
set(gca,'XTickMode','manual','XTick',...
);
set(gca,'YTickMode','manual','YTick',...
[-100,-20,-3,0]);grid
sound(Y,fs,bits); % 播放音频
sound(y,fs,bits);
wavwrite(Y,fs,bits,'D:\4014.wav'); % 读出音频
以上的两段程序可以综合一起,做成一个high_pass_hanning.m文件。运行该程序可以得到125个具有对称性的抽头系数。(系数都是归一化了的,如-1.0023e-007、0.8550)以下是上面调用到的一个小函数:
function hd=ideal_lp(wc,N)
tao=(N-1)/2;
n=;
m=n-tao+eps;
hd=sin(wc*m)./(pi*m);
end
3、MATLAB对系数进行处理
FPGA无法对小数直接进行运算,故需对系数进行处理,转换为FPGA
能直接进行运算的正整数,负数用其补码表示,具体设计如下:
q = quantizer(); % 23代表截取小数点后面的位数,24代表转换之后的位数
b0=num2hex(q,b); % 有符号小数形式,转换为正整数形式,最高位为符号位
经这么一转换后,抽头系数就变成了正整数的形式了,以十六进制表示,位数为24位,最高位为符号位。(MATLAB的一些函数的用法,可以在命令窗口直接输入help+命令,如help num2hex,即可了解该函数的使用,MATLAB很人性化吧!)
4、Verilog HDL 实现24*8的乘法器
上面提到FPGA无法对小数直接进行运算,故转换成了正整数形式,但是我
们在进行运算的时候,时刻要警惕,我们进行运算的是小数,而不是整数,(它们的不同点就是:整数在高位可以补0,而小数则是在低位可以补0,如整数12’h010与8’h10相等,而小数12’h010与8’h01相等),其实就只是一点小小差别而已,至于运算都是一样的,这点得好好思考才行,我为这东西折腾了好几天才理解透。本设计采用的是加法器树乘法器,采用多级流水线技术,具体设计如下:
module signed_mult24_8 (
mul_a,
mul_b,
mul_out,
clk,
rst_n
);
parameter MUL_WIDTH_a= 24;
parameter MUL_WIDTH_b= 8;
parameter MUL_RESULT = 31;
input mul_a;
input mul_b;
input clk;
input rst_n;
output mul_out;
reg mul_out;
reg mul_out_reg;
reg msb;
reg msb_reg_0;
reg msb_reg_1;
reg msb_reg_2;
reg mul_a_reg;
reg mul_b_reg;
reg stored0;
reg stored1;
reg stored2;
reg stored3;
reg stored4;
reg stored5;
reg stored6;
reg add0_0;
reg add0_1;
reg add0_2;
reg add0_3;
reg add1_0;
reg add1_1;
reg add2_0;
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
begin
mul_a_reg <= 24'b0;
mul_b_reg <= 8'b0;
stored0 <= 30'b0;
stored1 <= 30'b0;
stored2 <= 30'b0;
stored3 <= 30'b0;
stored4 <= 30'b0;
stored5 <= 30'b0;
stored6 <= 30'b0;
add0_0 <= 30'b0;
add0_1 <= 30'b0;
add0_2 <= 30'b0;
add0_3 <= 30'b0;
add1_0 <= 30'b0;
add1_1 <= 30'b0;
add2_0 <= 30'b0;
msb <= 1'b0;
msb_reg_0 <= 1'b0;
msb_reg_1 <= 1'b0;
msb_reg_2 <= 1'b0;
mul_out_reg <= 31'b0;
mul_out <= 31'b0;
end
else
begin
mul_a_reg <= (mul_a==0)?mul_a : {mul_a,~mul_a+1'b1};
mul_b_reg <= (mul_b==0)?mul_b : {mul_b,~mul_b+1'b1};
msb_reg_0 <= mul_a_reg ^ mul_b_reg;
msb_reg_1 <= msb_reg_0;
msb_reg_2 <= msb_reg_1;
msb <= msb_reg_2;
stored0 <= mul_b_reg ? {7'b0,mul_a_reg} : 30'b0;
stored1 <= mul_b_reg ? {6'b0,mul_a_reg,1'b0}: 30'b0;
stored2 <= mul_b_reg ? {5'b0,mul_a_reg,2'b0}: 30'b0;
stored3 <= mul_b_reg ? {4'b0,mul_a_reg,3'b0}: 30'b0;
stored4 <= mul_b_reg ? {3'b0,mul_a_reg,4'b0}: 30'b0;
stored5 <= mul_b_reg ? {2'b0,mul_a_reg,5'b0}: 30'b0;
stored6 <= mul_b_reg ? {1'b0,mul_a_reg,6'b0}: 30'b0;
add0_0 <= stored0 + stored1;
add0_1 <= stored2 + stored3;
add0_2 <= stored4 + stored5;
add0_3 <= stored6;
add1_0 <= add0_0 + add0_1;
add1_1 <= add0_2 + add0_3;
add2_0 <= add1_0 + add1_1;
mul_out_reg <= (add2_0==0)? 31'b0 : {msb,add2_0};
mul_out <= (mul_out_reg==0)? 31'b0 : (mul_out_reg==0)? mul_out_reg :
{mul_out_reg,~mul_out_reg+1'b1};
end
end
endmodule
这里面有几个地方需要注意:1、每个二叉树后面需要使用一个流水寄存器,以至达到每个时钟周期完成一次运算。2、对于负数需把其补码还原为原码再进行运算,若运算结果为负数,需转换为补码再输出。3、对于输入的两个数,当一个为0,一个为负数时,需要特别处理,否则结果输出为-1,明显的出错了。4、符号位与数据位需要时钟同步,不然也会出错,因为符号位运算所需时钟周期较少,而数据运算所需周期较多。
5、采用改进的串行结构进行滤波器设计
串行结构所耗资源最少,只需一个乘法器和一些加法器,而速度很慢,据抽头系数个数而定;并行结构所耗资源最多,据抽头系数个数而定,但速度最快,一个时钟周期即可完成一次滤波;分布式结构,耗资源不是很多,而速度也不是很快,基于串行和并行之间,据输入数据的位数来决定。(以上说法不一定正确,但对于大多数情况都是这样的)本设计采用的是改进的串行结构(先加后乘),N=125,系数具有对称性,故只需63个时钟周期,即可完成一次滤波,耗资源很少,只需一个乘法器和62个加法器。本设计是针对音频信号进行滤波,音频信号频率很低,所以即使完成一次滤波需要63个时钟周期,但也能很好的满足要求,且能有效的减少所耗资源,具体设计如下:
module ser_fir (clk,rst_n,fir_in,fir_out );
parameter FIR_TAP = 125;
parameter FIR_TAPHALF = 63;
parameter IDATA_WIDTH = 8;
//parameter PDATA_WIDTH = 9;
parameter COEFF_WIDTH = 24;
parameter OUT_WIDTH = 31;
input clk;
input rst_n;
input fir_in;
output fir_out;
reg fir_out;
reg fir_in_reg;
reg shift_buf;
reg add;
reg cof;
reg cof_reg_maca;
reg add_reg_macb;
wire result;
reg sum;
reg count;
integer i,j,k0,k1;
always @ (posedge clk or negedge rst_n )
begin
if ( !rst_n )
begin
cof = 24'hffffff;
cof = 24'hffffcd;
cof = 24'hffff36;
cof = 24'hfffe46;
cof = 24'hfffd54;
cof = 24'hfffcfe;
cof = 24'hfffdee;
cof = 24'h000095;
cof = 24'h0004de;
cof = 24'h000a03;
cof = 24'h000e99;
cof = 24'h0010cf;
cof = 24'h000ef6;
cof = 24'h000810;
cof = 24'hfffc5d;
cof = 24'hffed9d;
cof = 24'hffdefc;
cof = 24'hffd47f;
cof = 24'hffd220;
cof = 24'hffdaa9;
cof = 24'hffeead;
cof = 24'h000be4;
cof = 24'h002d1d;
cof = 24'h004b00;
cof = 24'h005d7c;
cof = 24'h005dab;
cof = 24'h0047cb;
cof = 24'h001cbe;
cof = 24'hffe2b3;
cof = 24'hffa492;
cof = 24'hff7036;
cof = 24'hff5398;
cof = 24'hff5988;
cof = 24'hff8699;
cof = 24'hffd709;
cof = 24'h003e4f;
cof = 24'h00a893;
cof = 24'h00fe1c;
cof = 24'h01281a;
cof = 24'h0115f7;
cof = 24'h00c208;
cof = 24'h00347c;
cof = 24'hff83b3;
cof = 24'hfed17a;
cof = 24'hfe456e;
cof = 24'hfe0550;
cof = 24'hfe2ca1;
cof = 24'hfec52b;
cof = 24'hffc216;
cof = 24'h00fed6;
cof = 24'h024291;
cof = 24'h0347d1;
cof = 24'h03c777;
cof = 24'h03853a;
cof = 24'h025b72;
cof = 24'h004413;
cof = 24'hfd5cef;
cof = 24'hf9e642;
cof = 24'hf63b5d;
cof = 24'hf2c675;
cof = 24'heff16e;
cof = 24'hee161e;
cof = 24'h6d70a3;
end
end
always @ (posedge clk or negedge rst_n )
begin
if ( !rst_n )
fir_in_reg <= 8'b0;
else
if ( count==6'd63 )
fir_in_reg <= fir_in;
end
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
for ( i=0;i<=FIR_TAP-1;i=i+1 )
shift_buf <= 8'b0;
else
if ( count==6'd63 )
begin
for ( j=0;j<FIR_TAP-1;j=j+1 )
shift_buf <= shift_buf;
shift_buf <= fir_in_reg;
end
end
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
for ( k0=0;k0<=FIR_TAPHALF-1;k0=k0+1 )
add <= 8'b0;
else
if ( count==6'd63 )
begin
for( k1=0;k1<=FIR_TAPHALF-2;k1=k1+1 )
add <= shift_buf + shift_buf;
add <= shift_buf;
end
end
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
count <= 6'b0;
else
if ( count==6'd63 )
count <= 6'b0;
else
count <= count + 1'b1;
end
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
begin
cof_reg_maca <= 24'b0;
add_reg_macb <= 8'b0;
end
else
if ( count <= 6'd62 )
begin
cof_reg_maca <= cof;
add_reg_macb <= add;
end
else if ( count == 6'd63 )
begin
cof_reg_maca <= 24'b0;
add_reg_macb <= 8'b0;
end
end
signed_mult24_8 mul_0 (
.mul_a(cof_reg_maca),
.mul_b(add_reg_macb),
.mul_out(result),
.clk(clk),
.rst_n(rst_n)
);
wire result_out = {result,result};
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
sum <= 32'b0;
else
if ( count==6'b0)
sum <= 32'b0;
else
sum <= sum + result_out;
end
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
fir_out <= 31'b0;
else
if ( count==6'b0 )
fir_out <= sum;
end
endmodule
滤波器的核心程序简单吧!就那么百来行而已。但这里有一个需要注意的地方:在进行先加后乘的时候,由于抽头系数为奇数个,所以对第62个数据,需要特别处理,不需要与任何数相加,不然将会出错。
6、Modelsim对设计好的滤波器进行仿真验证
这里需要用Modelsim 进行仿真验证,而不用FPGA厂商提供的集成软件,Modelsim有很多优点,特别对于数字信号处理方面的仿真,我们可以通过写Testbench进行仿真。通过Testbench对记事本文件数据读入,处理后再读出到记事本文件。这样做的好处是,我们可以结合MATLAB一起进行仿真验证,首先是从MATLAB把未经滤波的音频数据读出到记事本文件,然后送给Modelsim作为数据输入源,经设计好了的滤波器滤波处理之后,把数据输出到另一个记事本文件,最后MATLAB把刚才处理过了的音频数据文件读出数据,进行快速傅里叶变换,观察其频谱,试听其音频,跟直接在MATLAB进行滤波处理的音频比较,这样便可以很清楚的看到自己设计的滤波器滤波效果与直接MATLAB滤波的效果的对比了,这时即可验证FPGA设计的正确性了,这种验证方法,对于数字信号处理非常的有效,所以极力推荐,具体设计如下:
`define auto_init
`timescale 1ns/1ns
`define INPUT_FILE "fir_in8.txt"
`define OUTPUT_FILE "fir_out31.txt"
module test_ser_fir ();
parameter NOOFDATA = 40000;
parameter FIR_TAP = 125;
parameter FIR_TAPHALF = 63;
parameter IDATA_WIDTH = 8;
//parameter PDATA_WIDTH = 9;
parameter COEFF_WIDTH = 24;
parameter OUT_WIDTH = 31;
parameter CLK_CYCLE = 20;
parameter CLK_HCYCLE = 10;
reg clk;
reg rst_n;
reg fir_in;
wire fir_out;
reg memb ;
reg membyte ;
reg write;
integer handle;
reg count_w;
reg regcount;
reg k;
reg k0;
ser_fir dut ( clk,rst_n,fir_in,fir_out );
`ifdef auto_init
initial
begin
$readmemb(`INPUT_FILE,memb);
regcount = 0;
count_w = 0;
handle= 0;
clk = 0;
k =0 ;
k0 = 0;
rst_n = 1'b0;
#(10*CLK_CYCLE + CLK_HCYCLE) rst_n = 1'b1;
end
`endif
always #CLK_HCYCLE clk = ~clk;
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
regcount <= 6'b0;
else
if ( regcount == 6'd63 )
regcount <= 6'b0;
else
regcount <= regcount + 1'b1;
end
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
begin
fir_in <= 10'b0;
k <= 19'd1;
end
else
if ( regcount==6'd63 )
begin
k <= k + 1'b1;
fir_in <= memb;
end
end
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
k0 <= 19'b0;
else
if ( regcount==6'b0 )
begin
k0 <= k0 + 1'b1;
membyte <= fir_out;
end
end
always @ ( posedge clk or negedge rst_n )
begin
if ( !rst_n )
write <= 1'b0;
else
begin
if ( k == NOOFDATA )
write <= 1'b1;
end
end
always @ ( posedge write )
begin
handle = $fopen(`OUTPUT_FILE);
$display("writing results to file...");
for ( count_w=0;count_w<NOOFDATA;count_w=count_w+1 )
begin
$fdisplay(handle,"%d",membyte);
$display("%d",membyte);
end
$fclose(handle);
end
endmodule
测试程序也很简单吧!非常短!但这里有几个需要注意的地方:1、记事本文件的地址是从1开始的,所以赋初值为1,而不是0;2、Testbench对记事本文件数据读取时,只能识别二进制数据,而写入记事本文件时则可写成十六进制、十进制、二进制等。MATLAB对记事本文件的操作,具体设计如下:
function var=txtfile_rt(filename,width,depth)
% filename中的数是10进制的数,负数以补码形式表示, var为定点数
% Created by maqingbiao
% maqingbiao@foxmail.com
% filename --the name of the file to be created,eg,"a.txt",string;
% var ----the data to be writed to the file;
% width --the word size of the data,width>=1,int;
% depth --the number of the data to be writed,int;
fid=fopen(filename,'rt');
for i=1:depth
var_d(i)=fscanf(fid,'%d',1);
end
fclose(fid);
q=quantizer([(width+1) width]);
var_h=dec2hex(var_d);
var=hex2num(q,var_h);
end
我发现在MATLAB把数据写入记事本的时候,不能识别二进制,所以就不能使用直接写入数据的方法,而是手工拷贝的,我要拷贝的是30秒钟的音频数据,数据总量有32万个之多,由于MATLAB显示的原因,一次不能显示完32万个,所以我分8次拷贝,具体设计如下:
q = quantizer(); % 7代表截取小数点后面的位数,8代表转换之后的位数
y=y(:,1); % y为音频数据,为二维的,左右声道,只需取其中一维处理即可
yy=num2hex(q,y); % 小数转十六进制
yyy=hex2dec(yy); %十六进制转十进制
y=yyy;
y1=y(1:40000); %取y的前4万个数据
y2=y(40001:80000);
y3=y(80001:120000);
y4=y(120001:160000);
y5=y(160001:200000);
y6=y(200001:240000);
y7=y(240001:280000);
y8=y(280001:320000);
y11=dec2bin(y1); %十进制转二进制
y12=dec2bin(y2);
y13=dec2bin(y3);
y14=dec2bin(y4);
y15=dec2bin(y5);
y16=dec2bin(y6);
y17=dec2bin(y7);
y18=dec2bin(y8);
MATLAB滤波与FPGA滤波效果对比,wuwuzula.m文件,具体设计如下:
wp=0.17*pi; ws=0.12*pi; % 输入设计指标
deltaw=wp-ws; % 计算过渡带的宽度
N0=ceil(6.2*pi/deltaw); % 按汉宁窗窗计算滤波器长度N0
N=N0+mod(N0+1,2) % 为实现FIR类型I偶对称滤波器,应确保N为奇数
windows=(hanning(N))'; % 使用汉宁窗,并将列向量变为行向量
wc=(ws+wp)/2; % 截止频率取通阻带频率的平均值
hd=ideal_lp(pi,N)-ideal_lp(wc,N); % 建立理想高通滤波器
b=hd.*windows; % 求FIR系统函数系数
=freqz_m(b,1); % 求解频率特性
n=0:N-1; dw=2*pi/1000; % dw为频率分辨率,将0—2π 分成为1000份
Rp=-(min(db(wp/dw+1:501))) % 检验通带波动
As=-round(max(db(1:ws/dw+1))) % 检验最小阻带衰减
=wavread('D:\2014.wav'); % 读入音频文件
Y=filter(b,1,y); % 实现数字滤波
y11=y(:,1);
y11=y(1:40000);
y=y11;
y22=Y(:,1);
y22=y22(1:40000);
Y=y22;
YY=txtfile_rt('fir_out31.txt',30,40000);
t=(0:length(y)-1)/fs; % 计算数据时刻
xf=fft(y); % 作傅里叶变换求原频谱
yf=fft(Y); % 作傅里叶变换求MATLAB滤波后频谱
yyf=fft(YY); %作傅里叶变换求FPGA滤波后频谱
fm=3000*length(xf)/fs; % 确定绘频谱图的上限频率
f=(0:fm)*fs/length(xf); % 确定绘频谱图的频率刻度
subplot(2,2,1);plot(f,abs(xf(1:length(f)))); % 绘制原波形频谱图
title('原信号频谱图'); % 加标题
subplot(2,2,2);plot(f,abs(yf(1:length(f)))); % 绘制MATLAB滤波后频谱图
title('MATLAB滤波后信号频谱图'); % 加标题
subplot(2,2,3);plot(f,abs(yyf(1:length(f)))); % 绘制FPGA滤波后频谱图
title('FPGA滤波后信号频谱图'); % 加标题
subplot(2,2,4);plot(f,abs(yyf(1:length(f)))); % 绘制FPGA滤波后频谱图
title('FPGA滤波后信号频谱图'); % 加标题
运行该程序,得到结果如下,本设计滤波效果还可以吧!哈哈!
http://cache.amobbs.com/bbs_upload782111/files_32/ourdev_573487.JPG
(原文件名:12.JPG)
以上的音频文件,是从互联网上下载一段2010世界杯视频下来,然后经音频提取软件,把这段视频中的音频提取下来,再经截断后得到的一小段含有呜呜祖啦声音的音频文件,需要注意的是音频文件需要转成.WAV格式,因为MATLAB只能识别这种格式的文件。
(设计到此结束)
参考文献:《基于Verilog HDL的数字系统应用设计》王钿、卓兴旺 编著。
《数字信号处理的FPGA实现》第二版 刘凌 译。
《数字信号处理实验》MATLAB版,刘舒帆、费诺、陆辉 编著
本人博客:http://www.cnblogs.com/maqingbiao/archive/2010/08/07/1794672.html 不错! 虽然看不懂,但是还是顶! 人才啊。 其实我很菜鸟的 自己摸索了一个月才做出那么一个小小的东西来 matlab ,伤心事啊 你的sample下载连接在哪里?我想听听。另外,dsp芯片难道处理不了? LZ人才也 mark DSP应该也能处理,延时可能稍大。FPGA应该可以在更小的延时下实现 参考http://www.surfpoeten.de/tube/vuvuzela_filter
德文的,可以用翻译软件弄成英文来看 记号,备用!谢谢楼主! mark 回复【9楼】crom
dsp应该也能处理,延时可能稍大。fpga应该可以在更小的延时下实现
-----------------------------------------------------------------------
STM32都能搞定
96kHz 24bit,如果改用IIR陷波,只需2阶即可 楼主能学以致用,学习 mark mark 不顶不行! mark 回复【13楼】warmonkey
STM32都能搞定
96kHz 24bit,如果改用IIR陷波,只需2阶即可
-----------------------------------------------------------------------
也许STM32真的也能搞定 但应该不会有人能它做数字信号处理吧至于多少阶能做到,这倒不是很要紧,阶数少点,过渡带宽点而已
我做这个东西只是出于一种学习的目的只要做一个滤波器了,再做其他滤波器,应该都不会觉得太难了的 回复【19楼】maqingbiao
回复【13楼】warmonkey
stm32都能搞定
96khz 24bit,如果改用iir陷波,只需2阶即可
-----------------------------------------------------------------------
也许stm32真的也能搞定 但应该不会有人能它做数字信号处理吧至于多少阶能做到,这倒不是很要紧,阶数少点,过渡带宽点而已
我做这个东西只是出于一种学习的目的只要做一个滤波器了,再做其他滤波器,应该都不会觉得太难了的
-----------------------------------------------------------------------
不得不说lz还是做的很棒的,希望lz能够熟悉如何将滤波器实用化 mark 楼主你太有想法了. 从idea到realization,不错 呵呵有了好想法 就要赋予行动 不然就没多大意义了 mark!!!!! 这个项目真的很有趣! 帅啊... mark MARK 你这个延时多少呢 大概就是1/100Mhz*63 而已吧 有没有用自适应滤波试试 恩,很有参考价值 看楼主的图,似乎基本就是高通滤波,把低频段抹平?
这似乎不妥吧……低频段别人有用的声音也抹掉了啊…… 回复【31楼】ggyyll8683
有没有用自适应滤波试试
-----------------------------------------------------------------------
正想尝试一下自适应滤波,但现在准备省的电子设计竞赛
回复【33楼】lileistone 三块石头
看楼主的图,似乎基本就是高通滤波,把低频段抹平?
这似乎不妥吧……低频段别人有用的声音也抹掉了啊……
-----------------------------------------------------------------------
确实是这样,人的声音有小部分已经被滤除掉,当时我也考虑到,但是音频信号属于低频,要做带阻,要做到过渡带很窄,就要阶数很高,这样耗资源很多,改善却很小,因为呜呜组啦声音几乎覆盖了0—800HZ。我用MATLAB仿真了很多次,给导师试听了效果,最后他建议我做成高通的滤波器了 楼主能否把MATLAB和FPGA代码都发上来参考下,在下目前也在接触数字信号处理的东西,很多的不解 mark 回复【35楼】xml2028 收音机
楼主能否把MATLAB和FPGA代码都发上来参考下,在下目前也在接触数字信号处理的东西,很多的不解
-----------------------------------------------------------------------
点击此处下载 ourdev_595364DC3IAU.rar(文件大小:7.66M) (原文件名:ser_fir24_8.rar)
点击此处下载 ourdev_595363S5LFF2.rar(文件大小:1.06M) (原文件名:test_ser_fir24_8.rar) mark mark 在满足滤波要求的情况下,所耗资源最少;
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
要达到这个目的,可以使用单bit乘法算法,省很多资源。
采用matlab是验证算法的正确性,而不是验证算法在特定硬件上是否最优。 mark一下 强人啊
页:
[1]