信号混叠:125kHz滤波器的折返之谜

目录

前言

1.抗混叠滤波器未开启或不起作用时

1.1现象

1.2原因

[为什么会形成"倒 V 字形"?](#为什么会形成“倒 V 字形”?)

[为什么 125 kHz 的低通滤波器没有把它滤掉?](#为什么 125 kHz 的低通滤波器没有把它滤掉?)

如何判断结果是否"正确"?

总结建议

2.当抗混叠滤波器起作用时

2.1现象

3.FPGA滤波器性能和参数生成代码


前言

该笔记是针对 4MHz 采样信号的 250kHz 下采样抗混叠滤波器验证测试及故障排除的记录。

1.抗混叠滤波器未开启或不起作用时

1.1现象

采集的信号是100hz~250khz的信号,当125khz的低通抗混叠滤波器未开启或参数设置不正确时,下采样的结果如下:

这个频谱图反映信号处理中的经典问题------频率混叠(Aliasing)。虽然使用了 125 kHz 的低通滤波器,但图中出现的"倒 V 字形"(或三角形)轨迹说明,超出 125 kHz 的扫频信号并没有被完全滤除,并且在采样过程中发生了"折返"。

1.2原因

以下是详细的原因分析:

为什么会形成"倒 V 字形"?

这主要是由采样频率(Sampling Rate)奈奎斯特准则(Nyquist Theorem)决定的。

  • 奈奎斯特频率: 从图中 Y 轴可以看到,显示的最高频率正好是 125 kHz 。这是因为系统采样率 250 kHz。根据采样定理,系统能处理的最大不失真频率就是采样率的一半,即 125 kHz。

  • 频率折叠(Folding): 当你的扫频信号从 100 Hz 上升到 125 kHz 时,频谱图上显示的是正常的上升线。

  • 混叠发生: 当信号继续从 125 kHz 上升到 250 kHz 时,由于这部分频率超过了系统的处理上限,它们会以 125 kHz 为"镜面"发生镜像折返

    • 例如:当扫频信号到达 150 kHz 时,在频谱上会显示在的位置。

    • 当扫频信号到达 250 kHz 时,在频谱上会显示在的位置。

  • 结论: 这种"上升再下降"的视觉效果,实际上是线性扫频信号在经过采样节点时,高频部分折返回基带的结果。

为什么 125 kHz 的低通滤波器没有把它滤掉?

理论上,如果你接了 125 kHz 的低通滤波器(LPF),超过 125 kHz 的信号应该变弱甚至消失。图中依然有明亮的红色轨迹(强信号)折返,可能有以下几种原因:

  • 滤波器类型与阶数: 滤波器并不是像"墙"一样在 125 kHz 处瞬间切断。如果滤波器的阶数较低(斜率较缓),150 kHz 或 200 kHz 的信号依然会有很大的残余能量通过。

  • 数字滤波器 vs 模拟滤波器: 如果这个滤波器是数字滤波器 (在采样之后处理),那么它无法阻止混叠。因为混叠在 ADC(模数转换)采样的瞬间就已经发生了。(lhw:但是由于一开始采样的频率是4Mhz,所以不存在这种原因。

    • 要防止这种现象,必须在采样之前使用模拟抗混叠滤波器(Anti-aliasing Filter)
  • 信号强度过大: 如果输入扫频信号的功率非常高,即使滤波器衰减了 20-30 dB,剩余的能量在频谱图(通常是对数坐标)上看起来依然可能非常明显。

如何判断结果是否"正确"?

  • 如果目的是观察混叠: 那么这个图非常完美,它清晰地展示了信号如何折返。

  • 如果目的是测试滤波器的截止特性: 那么这个结果说明你的滤波器性能不足 (抑制效果不够)或者位置放错了(应该放在采样前端且使用模拟滤波器)。

总结建议

如果你希望频谱图只显示 0-125 kHz 的上升段,而不出现倒 V 字:

  1. 提高采样率: 将采样率提高到 500 kHz 以上,这样 250 kHz 的扫频信号就在奈奎斯特频率之内。

  2. 加强前端滤波: 在信号进入采集卡之前,加一个更陡峭的模拟低通滤波器。

  3. 缩小扫频范围: 将扫频范围限制在 100 Hz ~ 125 kHz 之间。


2.当抗混叠滤波器起作用时

2.1现象

采集的信号是100hz~250khz的信号,当125khz的低通抗混叠滤波器未开启或参数设置不正确时,下采样的结果如下:

该图是一个比较理想的频谱图,只保留截止频率以下的成分,而将除此之外的部分滤除。

根据滤波器的特性,线条的颜色(能量)会有以下变化:

  • 通带(< 125 kHz): 信号线是深红色,表示能量几乎没有损耗地通过。

  • 过渡带(接近 125 kHz): 线条颜色从红色转为黄色、绿色,表示信号开始被衰减。

  • 阻带(> 125 kHz): 信号线变为深蓝色或消失,表示信号被完全抑制。

以上现象就是抗混叠滤波器起作用那个的结果,这也是用来验证设计的滤波器是否正确的一种方法。

3.FPGA滤波器性能和参数生成代码

为了便于验证所设计的滤波器性能 ,因此编写了包含滤波器系数设计扫频信号仿真检验 以及 Verilog 硬件参数生成功能的完整代码,如下所示:

复制代码
%% FIR 滤波器全流程:250kHz 下采样 (标注增强版)
clc; clear; close all;

% ========================== 1. 开关与配置 ==========================
Enable_Sim = true; 
Enable_COE = true; 
Enable_Verilog = true; 

fs_raw = 4e6;              % 原始采样率 4MHz
fs_target = 250e3;         % 目标采样率 250kHz
f_cutoff = fs_target / 2;  % 抗混叠截止频率 (125kHz)

% 阶数
N = 128;  %FPGA的dsp资源有限,不宜过高                 

filename_str = sprintf('filter_params_%dk_N%d', fs_target/1000, N);
path_coe = './coe/'; path_v = './v/';

% ========================== 2. 滤波器设计 ==========================
f_nyquist = fs_raw / 2;
% 过渡带预留:从 110kHz 到 125kHz
Wn = [300/f_nyquist, 110e3/f_nyquist]; 
b = fir1(N, Wn, 'bandpass');

% --- 验证图 1: 频率响应图添加 125kHz 标注 ---
figure('Name', '滤波器响应验证', 'Color', 'w');
[h, f] = freqz(b, 1, 1024*4, fs_raw); 
plot(f, 20*log10(abs(h)), 'LineWidth', 1.5);
grid on; hold on;

% 标注 125kHz 拦截位置 (X轴单位为 Hz)
xline(f_cutoff, '--r', '125kHz 截止', 'LineWidth', 2, 'LabelOrientation', 'aligned', 'FontSize', 12);
% 标注阻带衰减目标 (例如 -60dB)
yline(-60, ':k', '目标衰减 -60dB', 'LineWidth', 1);

title('滤波器幅频特性');
xlabel('频率 (Hz)'); ylabel('幅度 (dB)');
xlim([0 500e3]); % 重点观察 0-500kHz

% 定点化处理
scale = 32767;
B_int = round(b / max(abs(b)) * scale);
hex_datas = cell(length(B_int), 1);
for i = 1:length(B_int)
    val = B_int(i);
    if val < 0, val = 65536 + val; end 
    hex_datas{i} = lower(dec2hex(val, 4));
end

% ========================== 3. 仿真检验 ==========================
if Enable_Sim
    t_duration = 0.1; 
    t_sim = 0:1/fs_raw:t_duration; 
    s_sweep = chirp(t_sim, 100, t_sim(end), 250e3); 
    s_filt = filter(b, 1, s_sweep);
    
    figure('Name', '时频分析验证', 'Color', 'w');%'Position', [100, 100, 1000, 750]
    
    % --- 子图 1: 滤波前 ---
    subplot(2,1,1);
    [S1, F1, T1] = spectrogram(s_sweep, 2048, 1024, 2048, fs_raw, 'yaxis');
    PSD1 = 20*log10(abs(S1) + eps); 
    imagesc(T1*1000, F1/1000, PSD1); 
    axis xy; colormap('jet'); hold on;
    
    % 标注 125kHz 拦截位置 (Y轴单位已转换为 kHz)
    yline(f_cutoff/1000, '--w', '125kHz', 'LineWidth', 2, 'FontSize', 11);
    
    title('滤波前 (0-250kHz 扫频)'); ylabel('频率 (kHz)'); xlabel('时间 (ms)');
    ylim([0 300]); clim([30 90]); colorbar;
    
    % --- 子图 2: 滤波后 ---
    subplot(2,1,2);
    [S2, F2, T2] = spectrogram(s_filt, 2048, 1024, 2048, fs_raw, 'yaxis');
    PSD2 = 20*log10(abs(S2) + eps);
    imagesc(T2*1000, F2/1000, PSD2);
    axis xy; colormap('jet'); hold on;
    
    % 标注 125kHz 拦截位置
    yline(f_cutoff/1000, '--w', '125kHz 拦截点', 'LineWidth', 2, 'FontSize', 11);
    
    title('滤波后 (观察 125kHz 以上能量衰减)'); 
    ylabel('频率 (kHz)'); xlabel('时间 (ms)');
    ylim([0 300]); clim([30 90]); colorbar;
end

% ========================== 4. 生成 .coe 文件 ==========================
if Enable_COE
    if ~exist(path_coe, 'dir'), mkdir(path_coe); end
    fid = fopen([path_coe, filename_str, '.coe'], 'w');
    fprintf(fid, 'memory_initialization_radix=16;\n');
    fprintf(fid, 'memory_initialization_vector=\n');
    for i = 1:length(hex_datas)
        if i == length(hex_datas), fprintf(fid, '%s;', hex_datas{i});
        else, fprintf(fid, '%s,\n', hex_datas{i}); end
    end
    fclose(fid);
    fprintf('COE 生成成功。\n');
end

% ========================== 5. 生成 Verilog 模块 ==========================
if Enable_Verilog
    if ~exist(path_v, 'dir'), mkdir(path_v); end
    fid = fopen([path_v, filename_str, '.v'], 'w');
    fprintf(fid, '/* FPGA FIR Filter Params Array */\n');
    fprintf(fid, '`default_nettype none\nmodule %s(\n', filename_str);
    fprintf(fid, '    output wire [%d:0] params\n);\n\n', length(hex_datas)*16-1);
    for i = 1:length(hex_datas)
        fprintf(fid, '    assign params[%d:%d] = 16''h%s;\n', ...
            (i-1)*16+15, (i-1)*16, hex_datas{i});
    end
    fprintf(fid, 'endmodule\n');
    fclose(fid);
    fprintf('Verilog 生成成功。\n');
end

以下是代码运行的结果:

图中的现象说明抗混叠滤波器起到了效果,能把高于125khz的频率衰减。至于说衰减的结果能否达到预期要求,目前我也不知道怎么判断。

在跑代码的过程中,发现无论阶数有多高,都无法完全把信号衰减掉。

再放几张图在这里保存一下:

以上就是本次笔记的内容。