这个东西是2017年全国电子设计大赛E题,题目要求如下:
题目要求做一个自适应滤波器,开始看了一个星期的自适应滤波器,,无奈有点晕头晕脑,,没看太明白,仿真结果也不太理想,于是决定用模拟方案(最后还是用数字方案完整的实现了所有功能),输入为混有噪声信号的D与纯噪声信号B,输出为有用信号,其中D中的噪声与纯噪声信号B频谱相同,噪声信号被限定为正弦波、三角波、或者方波,但相位差未知,因为过了一个移相器,所以单纯用减法器减掉噪声是不行的,既然相位差未知,所以我们第一个想法是测出相位差,于是有了下面的方案:
图1:利用乘法器检测相位
信号D中除了噪声,还包含有用信号,所以通过比较器然后测相位差是行不通的,所以我们打算用模拟乘法器,将信号B不断移相得到信号F,然后与D相乘,再过低通滤波器(同频信号相乘会得到直流和和频,不同频信号相乘得到差频和和频,低通是为了滤掉除直流以外的信号),当低通滤波器输出直流电压最大时,此时F的相位与D中噪声信号相位相同,从而根据移相器移相的角度得到相位差,然后用另外一路移相器移到该相位得到信号G,再用减法器相减,得到有用信号E。
理想很丰满,现实确总让人失望,这个方案里有几个不好弄的问题。
对于问题1,FPGA+FIFO+A/D+D/A解决了
对于问题2,我们换了种思路,如图2,我们先对噪声信号B移相,得到信号F,然后先用信号D减去信号F,由于噪声信号频率可以测出来,我们用FPGA产生两路与由于信号噪声同频,但两路信号间相位差为90°的正交方波信号,做一个锁定放大器,检测信号相减后剩余的噪声信号,当剩余噪声信号最小时,记录相位,然后控制另外一路移相器以到那个相位与信号D相减得到有用信号E,这样做之后效果好很多,相位误差±1°左右,噪声信号为正弦波和三角波时,基本可以满足题目要求,但方波还是不行。。
对于问题3,可能把运放换成高速运放,或者限制输入信号带宽应该会好一点吧,由于时间有限和有了更好的方案,就没管这个问题了。。
对于问题4,,放弃了这个要求了,,不过我们又做了个数字方案,这个要求也满足了。
图4:最后滤出来的波形,忘记拍滤之前的了,,,大致就是两个不同频率、1Vpp的正弦波叠加。
做了两个多星期,,总算出了点结果,,好在还没有结束
在书上看到了自适应陷波器,相当于一个窄带陷波器,可以做成多路构成多路窄带滤波器,,然后matlab仿真,,效果不错,C语言仿真,效果不过,Verilog写完modelsim仿真,效果不错,,signTab仿真,,效果不错,,然后上A/D,D/A,完美。。。
迭代公式很简单,,怎么推到出来的,,迷迷糊糊看了个大概,,,这里面印象最深的是第一次在FPGA里面用到了流水线,,以前一直是状态机模拟C语言的,,这次用流水线大大提高了时间效率,一环扣一环,,一点多余都没有。
最后系统大致结构为:首先FPGA测量噪声频率,然后单片机算出噪声基波及各次谐波所对应的频率控制字,然后写入到FPGA,控制FPGA内部DDS产生不同频率的参考信号,从而滤除掉噪声的基波和各次谐波,,本来打算再做一路AD采样,通过频谱检测当前是否为正弦波,如果是正弦波,就只抑制基波,避免伤及无辜,但由于时间有限,,还是没有做。。
图5:自适应陷波器结果图。。网上截图的,,这里只有一路陷波,实际上我们做了16路。
图6:状态机流水
图7:流水线代码截图,一环扣一环,,没有任何多余。。。
图8:matlab仿真
最后实测的图忘记拍了,,效果不错,,完全满足题目所有要求。
这个题做了快一个月,做了一个模拟方案,一个数字方案,也算是收获不少吧。
最后附matlab仿真代码:
clear;clc;
close all;
%采样信息
fs=1e6;
t=0:1/fs:1;
%噪声信息
noiseInfo=[
10.01e3 pi/2;
39.99e3 pi/2;
99.99e3 pi/2;
69.99e3 pi/2;
29.99e3 pi/2;
];
%有用信号信息
sourceInfo=[
10e3 0;
30e3 0;
];noise=zeros(16,length(t));
source=zeros(16,length(t));
ref_s=zeros(16,length(t));
ref_c=zeros(16,length(t));dn=zeros(1,length(t));
wn=zeros(16,2);
en=zeros(1,length(t));%生成噪声
for i=1:1:length(noiseInfo(1:end,1))
noise(i,:)=sin(2*pi*t*noiseInfo(i,1)+noiseInfo(i,2))*10;
ref_s(i,:)=sin(2*pi*t*(noiseInfo(i,1)+0.000));
ref_c(i,:)=cos(2*pi*t*(noiseInfo(i,1)+0.000));
end
%生成有用信号
for i=1:1:length(sourceInfo(1:end,1))
source(i,:)=sin(2*pi*t*sourceInfo(i,1)+sourceInfo(i,2))*10;
end
%将噪声累加
for i=1:1:length(noiseInfo(1:end,1))
dn=dn+noise(i,:);
end
%将有用信号累加
for i=1:1:length(sourceInfo(1:end,1))
dn=dn+source(i,:);
end
%滤波
for i=1:1:length(t)
sum=0;
for j=1:1:length(noiseInfo(1:end,1))
sum=sum+wn(j,1)*ref_s(j,i)+wn(j,2)*ref_c(j,i);
end
en(i)=dn(i)-sum;
for j=1:1:length(noiseInfo(1:end,1))
wn(j,1)=wn(j,1)+2*0.00002*en(i)*ref_s(j,i);
wn(j,2)=wn(j,2)+2*0.00002*en(i)*ref_c(j,i);
end
end
figure;
plot(dn);
figure;
plot(en);
figure;
plot(abs(fft(dn(6e5:1e6))));
figure;
plot(abs(fft(en(6e5:1e6))));