MATLAB代码仿真

1

g=100;    %蒙特-卡罗仿真统计次数
N=1024;   % 输入信号序列长度
k=128;     %fir滤波器长度
pp=zeros(g,N-k);   %每次循环仿真的误差信号存于矩阵pp中  zero用于生成矩阵
u=1/256;   %步长因子
snr=[3,-3];  %输入信号信噪比参数 一个3db,一个-3db

t=1:N;

s=sin(0.1*pi*t);  %生成正弦波信号
xn=zeros(1,N);   %存放输入信号
y=zeros(1,N);   %存放输出信号
w=zeros(1,k);    %存放权值信号
e=zeros(1,N);   %存放误差信号

for type=1:4
    for q=1:g
        noise=rand(1,length(s)); %随机噪声
        if type==1
            SNR=snr(1);d=s;    % 场景1:期望信号为正弦波,SNR=3dB
        elseif type==2
            SNR=snr(1);d=sqrt(10^(-SNR/10))*noise;  % 场景2:期望信号为噪声,SNR=3dB
        elseif type==3
            SNR=snr(2);d=s;    % 场景3:期望信号为正弦波,SNR=-3dB
        else
            SNR=snr(2);d=sqrt(10^(-SNR/10))*noise;  % 场景4:期望信号为噪声,SNR=-3dB
        end
        xn=sqrt(10^(-SNR/10))*noise+s;
        y(1:k)=xn(1:k);  % 初始化滤波器输出
        %LMS
        for i=(k+1):N
            XN=xn((i-k+1):(i));
            y(i)=w*XN';     %注意'是矩阵行列转置
            e(i)=d(i)-y(i);    %误差
            w=w+u*e(i)'*XN;   % 更新权值
        end
        pp(q,:)=(e(k+1:N)).^2;   %求每次仿真后误差信号的平方值
    end

    figure(1);
    subplot(311);
    plot(s(300:450));   %截取一段信号绘图
    title('信号s时域波形');
    if type==1
        subplot(312);plot(xn(300:450));
        title('信号s加噪声后(snr=3db)');
    elseif type==3
        subplot(313);plot(xn(300:450));
        title('信号s加噪声后(snr=-3db)');        
    end

    %求取各次循环仿真的误差统计均值
    for b=1:N-k
        bi(b)=sum(pp(:,b))/g;
    end

    %绘制自适应滤波后的输出信号
    figure(2);
    if type==1
        subplot(311);
        plot(y(300:450));title('自适应滤波输出,期望为sin,snr=3db');
    elseif type==3
        subplot(312);
        plot(y(300:450));title('自适应滤波输出,期望为sin,snr=-3db');        
    elseif type==4
        subplot(313);y=xn-y; %期望信号为噪声,系统相当于干扰抵消系统
        plot(y(300:450));title('自适应滤波输出,期望为噪声,snr=3db');
    end


    %绘制误差信号
    figure(3);
    if type==1
        subplot(311);
        plot(bi(1:100));title('误差均方信号,snr=3db,期望为sin');
    elseif type==3
        subplot(312);
        plot(bi(1:100));title('误差均方信号,snr=-3db,期望为sin');        
    elseif type==4
        subplot(313);
        plot(bi(1:100));title('误差均方信号,snr=3db,期望为噪声');
    end
end


 仿真结果

从图中可以看出:期望信号选择噪声信号或者正弦波信号均可得到较好结果

2 

将输入的信号改一下,改成s=sin(0.1*pi*t)+sin(0.3*pi*t);,参考信号改成s0=sin(0.1*pi*t);


g=100;    %蒙特-卡罗仿真统计次数
N=1024;   % 输入信号序列长度
k=128;     %fir滤波器长度
pp=zeros(g,N-k);   %每次循环仿真的误差信号存于矩阵pp中  zero用于生成矩阵
u=1/256;   %步长因子
snr=[3,-3];  %输入信号信噪比参数 一个3db,一个-3db

t=1:N;
s0=sin(0.1*pi*t);  %参考信号
s=sin(0.1*pi*t)+sin(0.3*pi*t);  %生成正弦波信号
xn=zeros(1,N);   %存放输入信号
y=zeros(1,N);   %存放输出信号
w=zeros(1,k);    %存放权值信号
e=zeros(1,N);   %存放误差信号

for type=1:4
    for q=1:g
        noise=rand(1,length(s)); %随机噪声
        if type==1
            SNR=snr(1);d=s0;    % 场景1:期望信号为正弦波,SNR=3dB
        elseif type==2
            SNR=snr(1);d=sqrt(10^(-SNR/10))*noise;  % 场景2:期望信号为噪声,SNR=3dB
        elseif type==3
            SNR=snr(2);d=s0;    % 场景3:期望信号为正弦波,SNR=-3dB
        else
            SNR=snr(2);d=sqrt(10^(-SNR/10))*noise;  % 场景4:期望信号为噪声,SNR=-3dB
        end
        xn=sqrt(10^(-SNR/10))*noise+s;
        y(1:k)=xn(1:k);  % 初始化滤波器输出
        %LMS
        for i=(k+1):N
            XN=xn((i-k+1):(i));
            y(i)=w*XN';     %注意'是矩阵行列转置
            e(i)=d(i)-y(i);    %误差
            w=w+u*e(i)'*XN;   % 更新权值
        end
        pp(q,:)=(e(k+1:N)).^2;   %求每次仿真后误差信号的平方值
    end

    figure(1);
    subplot(311);
    plot(s(300:450));   %截取一段信号绘图
    title('信号s时域波形');
    if type==1
        subplot(312);plot(xn(300:450));
        title('信号s加噪声后(snr=3db)');
    elseif type==3
        subplot(313);plot(xn(300:450));
        title('信号s加噪声后(snr=-3db)');        
    end

    %求取各次循环仿真的误差统计均值
    for b=1:N-k
        bi(b)=sum(pp(:,b))/g;
    end

    %绘制自适应滤波后的输出信号
    figure(2);
    if type==1
        subplot(311);
        plot(y(300:450));title('自适应滤波输出,期望为sin,snr=3db');
    elseif type==3
        subplot(312);
        plot(y(300:450));title('自适应滤波输出,期望为sin,snr=-3db');        
    elseif type==4
        subplot(313);y=xn-y; %期望信号为噪声,系统相当于干扰抵消系统
        plot(y(300:450));title('自适应滤波输出,期望为噪声,snr=3db');
    end


    %绘制误差信号
    figure(3);
    if type==1
        subplot(311);
        plot(bi(1:100));title('误差均方信号,snr=3db,期望为sin');
    elseif type==3
        subplot(312);
        plot(bi(1:100));title('误差均方信号,snr=-3db,期望为sin');        
    elseif type==4
        subplot(313);
        plot(bi(1:100));title('误差均方信号,snr=3db,期望为噪声');
    end
end


仿真结果

 3自适应陷滤波器

clear all;
len=4000;    %数据长度
fs=12.5*10^6;    %采样频率
u=1/128;   %步长因子

t=1:len;
t=t/fs;

f0=500*10^3;    %500khz
%
f1=200*10^3;    %200khz
f2=50*10^3;     %50khz
%生成4路参考信号 两两正交
x1=cos(2*pi*f1.*t);
x2=sin(2*pi*f1.*t);
%x3=cos(2*pi*f2.*t);
%x4=sin(2*pi*f2.*t);
x=[x1;x2];

%生成干扰信号
j1=2*cos(2*pi*f1.*t+pi/3);
j2=2*sin(2*pi*f2.*t+pi/6);

%生成有用信号
s=cos(2*pi*f0.*t);  %500khz
%将干扰信号混入有用信号
d=j1+s;

%LMS算法中间变量初始化
w=zeros(2,len+1);
w(:,1)=ones(2,1)/2;
e=zeros(1,len);
aw=zeros(2,len);

%LMS
for k=1:len
    y(k)=w(:,k)'*x(:,k);
    e(k)=d(k)-y(k);
    %aw(:,k)=2*u*x(:,k)*conj(e(k));  %LMS算法
    aw(:,k)=2*u*sign(x(:,k))*conj(e(k));  %符号LMS算法
    w(:,k+1)=w(:,k)+aw(:,k);
end



%绘图
disp_len=1000;  %显示1000个数据点
ax=1:disp_len+1;
subplot(611);
plot(ax,s(len-disp_len:len));legend('有用信号');
subplot(612);
plot(ax,j1(len-disp_len:len));legend('200khz干扰信号');
subplot(613);
plot(ax,j2(len-disp_len:len));legend('50khz干扰信号');
subplot(614);
plot(ax,d(len-disp_len:len));legend('叠加干扰信号');
subplot(615);
plot(ax,e(len-disp_len:len));legend('滤除干扰后的信号eout');
subplot(616);
plot(ax,y(len-disp_len:len));legend('滤除干扰后的信号yout');



仿真结果

 

选择eout可能会有问题,特定情境下 

lfsr模块,用于仿真时的噪声模拟

module lfsr(
    input clk,
    input en,
    input rst_n,
    output [15:0] lfsr_out
);
    
    //Create a 16-bit linear feedback shift register with
    //maximal polynomial x^16 + x^14 + x^13 + x^11 + 1.
    reg [15:0]lfsr = 16'd1;
    wire feedback;
    
    assign feedback = ((lfsr[15] ^ lfsr[13]) ^ lfsr[12]) ^ lfsr[10];
    assign lfsr_out = lfsr;
        
    //Update the linear feedback shift register.
    always @(posedge clk) begin
        if(!rst_n) 
            lfsr <= 16'd1;
        else if(en) 
            lfsr <= {lfsr[14:0], feedback};
    end
endmodule

verilog代码

此处是一个示例,输入一个方波或是三角波,输出基波的正弦波

notch_filter自适应滤波器


//////////////////////////////////////////////////////////////////////////////////
// Company: HDU
// Engineer: Aqua
// Create Date: 2025/04/24 21:38:31
// Design Name: 
// Module Name: notch_filter 自适应陷滤波器
//////////////////////////////////////////////////////////////////////////////////


module notch_filter(
    input clk,             // fpga系统时钟信号,速率为数据速率的6倍     75Mhz
    input clk_50,  // ila
    input rst_n,
    input [23:0] amp,     // 分频系数
    input signed [15:0] din,
    input [33:0] freq,   // 想要滤出的信号频率
    output reg signed [34:0] e_out,  //  误差信号e_out
    output reg signed [34:0] y_out,  //  滤波器输出yout
    output reg signed [15:0] dout      // 输出滤波器输出
);





// ---------------------基准信号生成----------------------
// 例化dds ip ,产生2路基准信号
wire signed [15:0] xin_reg[1:0]; 
wire [31:0] sin200k,sin50k;
// f = data*fclk/2^B
// f为dds出波频率,fclk为dds驱动时钟,B为相位累加字位宽
// 例如此处,fclk = 75Mhz,B = 16,f = 200k 计算出data为174.7取175

// 期望信号
dds_0 dds_0_inst(
    .aclk(clk_50),
    .s_axis_config_tvalid(1'b1),
    .s_axis_config_tdata(('d65536*freq)/50_000_000),  
    .m_axis_data_tdata({xin_reg[1],xin_reg[0]})
);






// // 50kHz的正弦波
// dds_0 dds_0_inst_1(
//     .aclk(clk),
//     .s_axis_config_tvalid(1'b1),
//     .s_axis_config_tdata(16'd44),
//     .m_axis_data_tdata({xin_reg[3],xin_reg[2]})
// );






// 3位计数器,计数周期为6
reg [2:0] cnt;
reg signed [15:0] rin;
always@(posedge clk or negedge rst_n) begin
    if(!rst_n)
        cnt <= 3'd0;
    else begin
        if(cnt == 3'd5) begin
            cnt <= 3'd0;
            rin <= din;       // 每6个时钟周期取一次采集的波形数据
        end
        else
            cnt <= cnt + 1'b1;
    end
end


// 权值数据
reg signed [15:0] w_reg[1:0];    // 这是一个数组,包含4个16位的有符号数
reg signed [15:0] dw_reg[1:0];

reg [2:0] k;
reg [2:0] k1;
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        //初始化位移寄存器的值为0
        k1 <= 3'd0;
        for(k1=0;k1<2;k1=k1+1) begin
            // 初始化权值为1
            w_reg[k1] <= 16'b0011111111111111111;
        end
    end
    else begin
        if(cnt == 3'd5) begin
            k1 <= 3'd0;
            for(k1=0;k1<2;k1=k1+1) begin
                w_reg[k1] <= w_reg[k1] + dw_reg[k1];
            end
        end
    end
end

// 4个乘法器,2级流水线,并行完成 权值与基准信号的乘法运算
wire signed [31:0] y_reg[1:0];

mult mult_0(
    .SCLR(!rst_n),
    .CLK(clk),
    .A(xin_reg[0]),
    .B(w_reg[0]),
    .P(y_reg[0])
);

mult mult_1(
    .SCLR(!rst_n),
    .CLK(clk),
    .A(xin_reg[1]),
    .B(w_reg[1]),
    .P(y_reg[1])
);

// mult mult_2(
//     .SCLR(!rst_n),
//     .CLK(clk),
//     .A(xin_reg[2]),
//     .B(w_reg[2]),
//     .P(y_reg[2])
// );

// mult mult_3(
//     .SCLR(!rst_n),
//     .CLK(clk),
//     .A(xin_reg[3]),
//     .B(w_reg[3]),
//     .P(y_reg[3])
// );




always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        // 初始化移位寄存器的值为0
        y_out <= 35'd0;
        e_out <= 35'd0;
    end
    else begin
        // yout 在一个时钟周期内完成更新
        y_out <= {{3{y_reg[0][31]}},y_reg[0]} + {{3{y_reg[1][31]}},y_reg[1]} ; //+ {{3{y_reg[2][31]}},y_reg[2]} + {{3{y_reg[3][31]}},y_reg[3]}
        // eout 在二个时钟周期内完成更新
        e_out <= {{4{rin[15]}},rin,15'd0} - y_out;  // 误差
    end
end

always@(posedge clk) begin
    if(cnt == 3'd4)
        dout <= y_out[30:15]; // 取高位输出
end

// 根据误差信号e_out的符号,求dw的值,延时一个时钟周期
always@(posedge clk or negedge rst_n) begin
    if(!rst_n) begin
        // 初始化移位寄存器的值为0
        k <= 3'd0;
        for(k=0;k<2;k=k+1) begin
            dw_reg[k] <= 16'd0;
        end
    end
    else begin
        k <= 3'd0;
        for(k=0;k<2;k=k+1) begin
            if(e_out[34])
                dw_reg[k] <= -{{7{xin_reg[k][15]}},xin_reg[k][15:7]};
            else
                dw_reg[k] <= {{7{xin_reg[k][15]}},xin_reg[k][15:7]};
        end
    end
end







ila_0 ila_0_inst(
    .clk(clk_50),
    .probe0(din), // 16bit
    .probe1(e_out), // 34bit
    .probe2(y_out), // 34bit
    .probe3(dout), // 16bit
    .probe4(xin_reg[1]),   // 16bit
    .probe5(freq)   // 34bit
);







endmodule

div

时钟分频模块,奇偶分频占空比50%,此处主要是用于产生PLL产生不了的一些比较低的时钟频率,并且比较方便去修改notch_filter的工作频率,因为这个的工作的频率和adc采样频率都得根据需要处理信号的频率来一点一点尝试

 
// 对于奇数倍和偶数倍分频,且保证占空比为50%
 
 
module div 
(
    input       clk,
    input       rst_n,
    input       [23:0]amp,    //分频系数
    output      clk_div
);
    
// 奇数分频    
reg     [15:0]  cnt;
reg             clk_pos,clk_neg;
wire       clk_div_j;   
assign clk_div_j = clk_pos ^ clk_neg;
// 偶数分频
reg        clk_div_o;
// 输出
assign clk_div = (amp%2 == 1)?clk_div_j:clk_div_o;  //奇数偶数分频选择输出


// 奇数分频

always @(posedge clk or negedge rst_n)begin
  if(!rst_n)
    cnt <= 0;
  else if(cnt==amp-1)
    cnt <= 0;
  else 
    cnt <= cnt + 1;
end         
    
always @(posedge clk or negedge rst_n)begin
    if(!rst_n)
        clk_pos <= 0;
    else if(cnt==amp-1)
        clk_pos <= ~clk_pos;
end
 
always @(negedge clk or negedge rst_n)begin
    if(!rst_n)
        clk_neg <= 0;
    else if(cnt==(amp>>1))
        clk_neg <= ~clk_neg;
end 
 
 



// 偶数分频
reg [23:0] cnt_o;
 
always@(posedge clk or negedge rst_n) begin
    if(!rst_n)
        cnt_o <= 24'd0;
    // else if(amp == 4 && cnt_o == 1)
    else if((amp%2==0) && (cnt_o == amp/2-1))
        cnt_o <= 24'd0;
    else 
        cnt_o <= cnt_o + 1'b1;
end
 
always@(posedge clk or negedge rst_n) begin
    if(!rst_n)
        clk_div_o <= 1'b0;
    // else if(amp == 4 && cnt_o == 1)
    //     clk_div_o <= ~clk_div_o;
    else if(amp ==2)               // 2分频比较特殊
        clk_div_o <= ~clk_div_o;
    else if((amp%2==0) && (cnt_o == amp/2-1))      // 其余偶数分频
        clk_div_o <= ~clk_div_o;
    else
        clk_div_o <= clk_div_o;
end  
 
endmodule

main顶层模块


module main(
    input clk,
    input rst_n,

    input [11:0] adc_data,  // adc采集数据
    output adc_clk,  //时钟为LMS的1/6
    
    output [13:0] dac_data,  // dac输出数据
    output dac_clk
);

wire clk_75m,clk_12m5,clk_100m,clk_5m,clk_30m;
wire clk_lms;

// assign adc_clk = ~clk;
assign dac_clk = clk;
// 仿真时添加随机噪声
//wire [15:0] lfsr_out;  // 随机噪声
wire [33:0] freq;
wire signed [15:0] din;  
wire signed [15:0] dout; // 滤波器输出
wire signed [15:0] adc_data1; 
wire signed [15:0] adc_data2;
//assign din = adc_data1/2 + adc_data2/2;  
// adc数据转化成有符号数
assign din = {adc_data,4'b0}-16'd32768;  
// 转化成无符号数给DAC
assign dac_data = dout[15:2] + 14'd8192;
wire signed [15:0] useless_data1;
wire signed [15:0] useless_data2;


// f = data*fclk/2^B
// f为dds出波频率,fclk为dds驱动时钟,B为相位累加字位宽
// 例如此处,fclk = 75Mhz,B = 16,f = 200k 计算出data为174.7取175


// // 200kHz的正弦波
// dds_0 dds_0_inst(
//     .aclk(clk_12m5),
//     .s_axis_config_tvalid(1'b1),
//     .s_axis_config_tdata(16'd1049),
//     .m_axis_data_tdata({adc_data1,useless_data1})
// );
// dds_0 dds_0_inst1(
//     .aclk(clk_12m5),
//     .s_axis_config_tvalid(1'b1),
//     .s_axis_config_tdata(16'd264),
//     .m_axis_data_tdata({adc_data2,useless_data2})
// );







wire locked;
clock0 clock0_inst(
    .clk_75m(clk_75m),
    .clk_12m5(clk_12m5),
    .clk_100m(clk_100m),
    .clk_out4(clk_5m),
    .clk_out5(clk_30m),
    .resetn(rst_n),
    .clk_in1(clk),
    .locked(locked)
);

reg [23:0] amp = 24'd5;

div div_inst1(
    .clk(clk_30m),
    .rst_n(rst_n),
    .amp(amp),
    .clk_div(clk_lms)
);

div div_inst2(
    .clk(clk_5m),
    .rst_n(rst_n),
    .amp(amp),
    .clk_div(adc_clk)
);

notch_filter notch_filter_inst(
    .clk(clk_lms),
    .clk_50(clk),
    .rst_n(rst_n),
    .amp(amp),
    .freq(freq),
    .din(din),
    .dout(dout)
);

// 测量基波的频率,以此生成该频率正弦波的基准信号
freq_meter_calc freq_meter_calc_inst(
    .sys_clk(clk),
    .clk_stand(clk_100m),
    .sys_rst_n(rst_n),
    .clk_test(din[15]),
    .freq(freq)
);





endmodule

效果:

显然这不是一个合格的正弦波,因此还需要过一个低通滤波器,此处的高频分量正好是notch_filter的工作时钟频率的6分频(这个模块处理过程需要6个时钟周期),

更多推荐