Verilog并行FIR滤波器设计

设计一个2kHz采样,500Hz截止的15阶低通滤波器(h(n)长度为16),过渡带500~600Hz的FIR滤波器,量化位数为12bit,输入信号位宽也为12bit。

参考如何快速设计一个FIR滤波器(一)
参考如何快速设计一个FIR滤波器(二)

1.Matlab 生成抽头系数

// An highlighted block
function b = lpf
fs = 2000;%采样频率
n = 15;%阶数
qm = 12;%量化位数
f = [500 600];

fc = [0 f(1)*2/fs f(1)*2/fs f(2)*2/fs f(2)*2/fs 1];%过渡带
mag = [1 1 0.2 0.2 0 0];%低通

b = fir2(n,fc,mag);
subplot(211);
freqz(b);

b_pm = round(b/max(abs(b))*(2^(qm-1) -1));%12量化

%生成系数写入文件
fid=fopen('E:\Work\IC\Modem\code\Chapter_4\FIR\coe.txt','w');
for i = 1: length(b_pm)
    B_hex=dec2hex(b_pm(i)+(b_pm(i)<0)*2^qm,qm);
for j = 1:qm
      %k = strcat(B_hex);
      fprintf(fid,'%c',B_hex(j));
end
fprintf(fid,'\r\n');
end
fprintf(fid,';'); 
fclose(fid);
%画图
f_b = 20*log10(abs(fft(b)));%幅频响应 
f_b = f_b-max(f_b); %归一化
f_b_pm = 20*log10(abs(fft(b_pm)));  
f_b_pm = f_b_pm-max(f_b_pm);

x_f = 0:(fs/length(f_b)):fs/2;%正频率部分

f_b = f_b(1:length(x_f));
f_b_pm = f_b_pm(1:length(x_f));

subplot(212);
plot(x_f, f_b,'--',x_f, f_b_pm,'-')
xlabel('frequency(MHz)');ylabel('Magnitude(dB)');
legend('No quantitative','12 bits quantitative');

在这里插入图片描述

抽头系数为:
在这里插入图片描述

2.Matlab生成混频信号

// An highlighted block
var foo = 'bar';

f1 = 200;
f2 = 800;
fs = 2000;
N = 12;
len = 2000;

t = 0:1/fs:(len - 1)/fs;
s1 = sin(2*pi*f1*t);
s2 = sin(2*pi*f2*t);
s = s1 + s2;

hn = lpf;
filter_s = filter(hn,1,s);

%求信号的幅频响应
m_s = 20*log10(abs(fft(s,1024)));
m_s = m_s - max(m_s);
%滤波后的幅频响应
m_filter_s = 20*log10(abs(fft(filter_s,1024)));
m_filter_s = m_filter_s - max(m_filter_s);
%滤波器本身的幅频响应
m_hn = 20*log10(abs(fft(hn,1024)));
m_hn = m_hn - max(m_hn);

%设置幅频响应的横坐标单位为Hz
x_f = 0:(fs/length(m_s)):fs/2; 

%只显示正频率部分的幅频响应
m_s = m_s(1:length(x_f));
m_filter_s = m_filter_s(1:length(x_f));
m_hn = m_hn(1:length(x_f));

%绘制幅频响应曲线
subplot(211)
plot(x_f,m_s,'r-.',x_f,m_filter_s,'b-.',x_f,m_hn,'g-.');
xlabel('频率(Hz)');ylabel('幅度(dB)');title('Matlab仿真合成单频信号滤波前后的频谱');
legend('输入信号频谱','输出信号频谱','滤波器响应');
grid;
%绘制滤波前后的时域波形

%设置显示数据范围,设置横坐标单位s
subplot(212)
x_t =  0:1/fs:80/fs;
t_s=s(1:length(x_t));
t_filter_s=filter_s(1:length(x_t));
plot(x_t,t_s,'--',x_t,t_filter_s,'-');
xlabel('时间(s)');ylabel('幅度');title('FPGA仿真合成单频信号滤波前后的时域波形');
legend('输入信号波形','输出信号波形');
grid;

%对仿真产生的合成单频信号进行量化处理
s=s/max(abs(s));         %归一化处理
Q_s=round(s*(2^(N-1)-1));%12比特量化

%将生成的数据以二进制数据格式写入txt文件中
fid=fopen('E:\Work\IC\Modem\code\Chapter_4\FIR\testdata.txt','w');
for i=1:length(Q_s)
    B_noise=dec2bin(Q_s(i)+(Q_s(i)<0)*2^N,N);
    for j=1:N
       if B_noise(j)=='1'
           tb=1;
       else
           tb=0;
       end
       fprintf(fid,'%d',tb);  
    end
    fprintf(fid,'\r\n');
end
fprintf(fid,';'); 
fclose(fid);

在这里插入图片描述

3.verilog 实现仿真

  • 来源于杜勇老师的数字调制解调技术的MATLAB与FPGA实现 Altera Verilog版一书。
    来源于
  • verilog实现 未考虑时序优化,只是实现了功能。
// An highlighted block
module fir #(
  parameter iwidth = 12,
  parameter owidth = 29 ,
  parameter order = 16
)
( 
input clk,
input rst,
input[iwidth  :0] din,
output reg [owidth  :0] dout
);

reg[iwidth -1 :0] X[0: order-1];
reg[iwidth  :0] add_X[0: order-1];
wire [iwidth -1 :0] coe [0 :7];

assign coe[7] = 12'h7ff;
assign coe[6] = 12'h21e;
assign coe[5] = 12'heb2;
assign coe[4] = 12'hf88;
assign coe[3] = 12'h05a;
assign coe[2] = 12'h018;
assign coe[1] = 12'hff0;
assign coe[0] = 12'hffb;

reg [24: 0] sum[0:7];
reg[owidth -1 :0] sum1,sum2;

genvar i;
generate
for (i = 0; i < order; i = i + 1) begin:shift
 
 always@ (posedge clk or negedge rst) begin
  if (!rst) 
    X[i] <= 1'b0;
  else if (i == 0) X[i] <= din;
  else if (i > 0) X[i] <= X[i-1];
  end
 end
endgenerate

integer j;
always@(posedge clk or negedge rst) begin
  if(!rst) 
    add_X[j] <= 13'b0;
  else begin
    for (j =0; j <8; j = j +1) begin
    add_X[j] <= {{X[j][11]},X[j]} + {{X[15 - j][11]},X[15 -j]};
  end
 end
end

always@ (posedge clk or negedge rst) begin
  if (!rst) begin
    for (j = 0; j < 8; j = j + 1)
      sum[j] <= 25'b0;
  end
  else begin
    for (j =0; j <8; j = j +1) begin
      sum[j] <= {{13{coe[j][11]}},coe[j]} * ({{12{add_X[j][12]}},add_X[j]});
    end
  end
end      

always@ (posedge clk or negedge rst) begin
  if (!rst)  begin
   sum2 <= 29'b0;
   sum1 <= 29'b0;
   dout <= 29'b0;
 end
 else begin
  sum1 <= {{4{sum[0][24]}},sum[0]} + {{4{sum[1][24]}},sum[1]} + {{4{sum[2][24]}},sum[2]} + {{4{sum[3][24]}},sum[3]};
  sum2 <= {{4{sum[4][24]}},sum[4]} + {{4{sum[5][24]}},sum[5]} + {{4{sum[6][24]}},sum[6]} + {{4{sum[7][24]}},sum[7]};
  dout <= {{sum1[28]},sum1} + {{sum2[28]},sum2}; 
 end
end

endmodule
  • 测试
`timescale 1ns/1ps
module test();
reg clk;
reg rst;
reg [11: 0] din;
wire[28: 0] dout;

fir  #
    (
      .iwidth(12),
      .owidth (29),
      .order (16)
    )
    u1
    ( .clk(clk),
      .rst(rst),
      .din(din),
      .dout(dout)
    );

//rst
initial begin
  rst = 1'b1;
  #10 rst = 1'b0;
  #20 rst = 1'b1;
  #400000 $finish;
end

//clk
initial begin
  clk = 1'b1;
  forever #10 clk = ~clk;
end

reg [11: 0] mem [0:1999];
integer i;

initial begin
  $readmemb("/home/IC/Mylearn/FIR/testdata.txt", mem);
  i = 0;
  repeat(1999) begin
    i = i + 1;
    din = mem[i];
    #20;
  end
end

 initial begin
  $fsdbDumpfile("fir.fsdb");
  $fsdbDumpvars;
 end
 endmodule
  • verdi结果,波形不是很完美,但是功能是正确的。
    在这里插入图片描述
  • 3
    点赞
  • 44
    收藏
    觉得还不错? 一键收藏
  • 4
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 4
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值