简介:一份面向通信与信号处理初学者及工程实践者的匹配滤波器学习包,围绕噪声环境下已知信号的最佳检测展开,帮助读者理解匹配滤波器为何能最大化输出信噪比,并借助 MATLAB 把互相关、时间反转共轭、滤波与峰值检测等环节串成可运行示例。压缩包共 2 个文件,以 1 个 m 脚本和 1 个 txt 文本为主,整体约 822B,m 文件承载核心实现代码,txt 可用于补充说明或参考资料,体积轻便,便于快速解压查看与对照实验。已有 4926 人学习,说明该主题在通信接收机与信号检测学习中具有较高关注度。读者可从中获得从信号生成、高斯白噪声添加到匹配滤波器设计、滤波输出及峰值定位的完整思路,并据此观察不同信噪比下的检测效果,为课程实验、算法验证和后续工程实现提供可复用的脚本框架与排错参照。
1. 匹配滤波器:从噪声里捞出一根尖峰,靠的不是运气
第一次把回波丢进conv的人,大多会被结果误导一次:在时域里完全看不出形状的包络,卷积之后冒出一根干净的尖峰,峰值信噪比比输入高出十几 dB,看上去像是凭空多出来的增益。兴奋劲还没过,把采样率从 10 MHz 改成 20 MHz,峰值位置就对不上了,门限也跟着失效。匹配滤波器不是一段能随便复制的代码,它有一条硬性约束:滤波器形状必须和发射波形严格共轭镜像,任何一处下标、翻转或者归一化写错,输出的就不再是最优检测量,而是一段看起来像那么回事的噪声。它适合的场景也很明确:已知波形、未知到达时刻的检测问题,脉冲压缩、扩频同步捕获、超声测距回波定位、突发解调的前导检测都套得上。下面按原理骨架、MATLAB 落地、参数标定、翻车排查、多普勒通道组五段往下推。
2. 匹配滤波器的原理骨架:为什么白噪声下它能达到信噪比上限
2.1 先分清是相关还是卷积
很多人第一次写匹配滤波就卡在这里:教科书给的是卷积公式,代码里写的却是相关,两边结果对不上,于是开始怀疑自己。把两件事拆开看就清楚了。设发射波形为复基带 $s(t)$,持续 $T$ 秒,接收信号 $r(t)=s(t-t_0)+n(t)$,其中 $t_0$ 是未知到达时刻。线性时不变滤波器的输出是
$$y(t)=\int r(\tau)h(t-\tau),d\tau$$
我们希望在某一个时刻 $t=T$ 上让输出最大,把 $h(T-\tau)=s^*(\tau)$ 代进去:
$$y(T)=\int r(\tau)s^*(\tau),d\tau$$
右边这个式子是对 $r$ 和 $s$ 做相关。也就是说,匹配滤波器的冲激响应取 $h(t)=s^*(T-t)$ 时,它在 $t=T$ 时刻的采样值,等价于接收信号和发射波形的互相关。卷积与相关在这里是一回事,差别只在于滤波器是否做了时间翻转。
这条等价关系有个很实际的后果:如果你直接调用xcorr(rx, tx),峰值出现在延迟对应的索引上,物理含义直观;如果用conv(rx, h),峰值会整体后移 $T$ 秒,因为滤波器本身有一个 $T$ 的群延迟。二者数值上完全一致,只是时间轴起点不同。我在做链路联调时习惯先固定用卷积形式,把延迟补偿写死在索引上,避免两种写法混着用导致对账时差一个脉宽。
还有一个容易被忽略的点:这里的推导对复信号成立,实信号同样成立,但实信号的相关峰两侧是对称的,虚部为零;复基带信号的相关峰只在正确对齐时出现尖峰,失配时迅速跌落。做扩频捕获或者 LFM 压缩时用复基带,主瓣更窄、旁瓣结构更干净。
2.2 最大输出信噪比的推导,以及 h(t)=s*(T-t) 是怎么冒出来的
原理章最有价值的部分不是结论,而是「为什么偏偏是这个形状」。把输出拆成信号项和噪声项。设输入噪声是双边功率谱密度 $N_0/2$ 的白噪声,滤波器冲激响应 $h(t)$,那么在 $t=T$ 时刻:
信号分量:
$$y_s(T)=\int s(\tau)h(T-\tau),d\tau$$
噪声分量方差:
$$\sigma^2=\frac{N_0}{2}\int |h(T-\tau)|^2,d\tau=\frac{N_0}{2}\int|h(u)|^2,du$$
输出信噪比
$$\text{SNR}=\frac{\left|\int s(\tau)h(T-\tau)d\tau\right|^2}{\frac{N_0}{2}\int|h(u)|^2du}$$
对分子用柯西-施瓦茨不等式:
$$\left|\int s(\tau)h(T-\tau)d\tau\right|^2\le \int|s(\tau)|^2d\tau\cdot\int|h(T-\tau)|^2d\tau=E\cdot\int|h(u)|^2du$$
其中 $E=\int|s(\tau)|^2d\tau$ 是信号能量。代回上式,$\text{SNR}\le 2E/N_0$,而且这个上界与 $h$ 的具体形状无关,只与信号能量和噪声谱密度有关。
等号成立的条件是 $h(T-\tau)=k,s^(\tau)$,取 $k=1$ 就是 $h(t)=s^(T-t)$。这就是匹配滤波器名字里「匹配」二字的全部含义:滤波器的形状匹配发射波形的共轭镜像,一点不能改。改了会怎样?输出信噪比必然低于 $2E/N_0$,而且下降速度取决于失配程度,多普勒失配、码元相位偏差、采样时钟偏差,本质上都是在这条不等式上做减法。
有一个数字值得记住:最大输出信噪比 $2E/N_0$ 与波形形状无关,只与能量有关。这意味着你没法靠「设计一个更聪明的波形」突破这个上界,能做的只有提高能量或者降低噪声。雷达里提高发射功率、通信里加长前导序列,都是在往 $E$ 上加码。
2.3 频域视角:匹配滤波器是信号的共轭镜像
时域推导之外,频域的解释在实际工程里更好用。对 $h(t)=s^*(T-t)$ 做傅里叶变换,得到
$$H(f)=S^*(f)e^{-j2\pi fT}$$
幅度上 $|H(f)|=|S(f)|$,相位上 $\angle H(f)=-\angle S(f)-2\pi fT$。两句话概括:
第一,幅度响应等于信号幅度谱。信号能量集中的频段滤波器增益高,信号能量弱的频段滤波器增益低,等于给有用频段加权、给噪声频段衰减。这一点直接解释了为什么匹配滤波器在带限噪声下依然有效,只要噪声谱在信号带内是平的。
第二,相位响应是信号相位的共轭。各个频率分量经过滤波器后相位被拉平,在 $t=T$ 时刻同相叠加,形成尖峰;失配时各分量相位散开,叠加结果互相抵消。
做 MATLAB 实现时,频域形式往往更省事:H = conj(fft(s, Nfft)) .* exp(-1j*2*pi*f*T)在复基带里可以简化为conj(fft(s, Nfft)),因为线性相位项对峰值位置的影响可以统一折算到索引上。我在处理长序列时基本都用频域形式,点数取到 $2^{\lceil\log_2(N+M-1)\rceil}$,速度比时域conv快一个数量级。
2.4 把一条公式拆成五个 MATLAB 变量
理论推到这一步,落到代码上其实只有五个变量:采样率fs、脉宽T、带宽B、样点数N、滤波器系数h。这五个量定死,后面的仿真才有可比性。
fs = 10e6; % 采样率 10 MHz T = 20e-6; % 脉宽 20 us B = 2e6; % 调频带宽 2 MHz K = B / T; % 调频斜率,单位 Hz/s N = round(fs * T); % 一个脉宽内的样点数,应为 200 t = (0:N-1) / fs; % 时间轴,起点 0 tx = exp(1j*pi*K*(t - T/2).^2); % 复基带 LFM,瞬时频率对称于 0 h = conj(fliplr(tx)); % 匹配滤波器 h(t) = s*(T-t)这段代码里最需要解释的是t - T/2。LFM 的瞬时频率是调频斜率乘以时间,如果不做中心化,瞬时频率从 0 线性涨到 $B$,频谱整体偏移 $B/2$,在复基带里会引入一个额外载波,匹配滤波后峰值位置和相位都会偏。减去 $T/2$ 之后瞬时频率关于零对称,落在 $[-B/2,,B/2]$,才是标准的复基带表示。
fliplr只做翻转不做共轭,所以conj必须在外面。写成conj(tx(end:-1:1))效果一样。这个顺序写反是新手最常见的错误,翻转和共轭交换之后滤波器变成 $s(T-t)$,对实信号没有区别,对复信号直接导致相关峰消失或者跑到镜像位置。判断方法很简单:conv(tx, h)的最大值应该出现在索引N处,值等于N(因为|tx|=1,自相关峰等于样点数)。这一步对不上,后面全是白费。
处理增益也可以在这一步先估出来:时宽带宽积 $BT=40$,对应 $10\log_{10}(40)\approx16$ dB。后面仿真出来的峰值信噪比与输入信噪比之差如果偏离这个数太多,说明链路里某处出了问题。
3. MATLAB 完整链路:从 LFM 回波到峰值索引的六步落地
3.1 造一个可复现的回波场景
仿真最怕的是每次跑出来都不一样,出了问题没法复现。第一行固定随机种子,后面所有噪声都由它派生。场景设成一个单目标回波:发射波形延迟tau秒到达,叠加复高斯白噪声,输入信噪比设成 -10 dB,也就是人眼在时域波形上完全看不出信号的位置。
rng(2024); % 固定种子,保证可复现 tau = 30e-6; % 目标双程时延 30 us L = round(tau * fs); % 折算成样点延迟,300 点 tail = round(60e-6 * fs); % 尾部留白,方便观察完整峰值 rx = [zeros(1,L), tx, zeros(1,tail)]; snr_in = -10; % 输入信噪比,dB Ps = (tx * tx') / numel(tx); % 信号平均功率 Pn = Ps / (10^(snr_in/10)); % 由目标 SNR 反推噪声功率 noise = sqrt(Pn/2) * (randn(size(rx)) + 1j*randn(size(rx))); rx = rx + noise; % 复基带含噪回波sqrt(Pn/2)这个因子是复噪声的标准写法:实部和虚部各承担一半功率,合起来才是Pn。直接写sqrt(Pn)会让噪声功率翻倍,输入信噪比比设定值低 3 dB,后面算处理增益时会莫名其妙对不上,这种坑很难靠看波形发现,只能靠功率核算。
zeros(1,L)前面的这段空白很重要。匹配滤波的峰值位置等于「延迟样点 + 脉宽样点」,如果信号从索引 1 就开始,峰值会落在N-1附近,与滤波器的群延迟重叠,看不出到底补偿对没有。前面留出 300 点,峰值应该稳稳落在L + N - 1 = 499,一眼就能验证。
3.2 时域卷积实现与延迟补偿
有了回波,第一版实现用时域卷积,逻辑最直白。
y = conv(rx, h, 'full'); % 线性卷积,长度 = numel(rx)+N-1 y = y / max(abs(y)); % 按峰值归一化,便于统一门限 [~, pk] = max(abs(y)); % 峰值索引,MATLAB 从 1 开始 delay_est = (pk - 1) - (N - 1); % 扣掉滤波器群延迟,得到时延样点 fprintf('峰值索引 %d,估计时延 %.3f us\n', pk, delay_est/fs*1e6);三行代码里有两个细节。'full'不能省,虽然默认就是 full,但写出来是给自己看的,提醒这里要的是完整线性卷积而不是'same'。'same'会截掉两端,峰值靠近边界时直接被削掉,表现是「目标明明在,就是检测不到」。
归一化用max(abs(y))而不是max(y),因为复基带输出的峰值可能是复数,取实部会漏掉相位不为零的情况。这一步只影响显示和门限,不影响峰值位置,但如果后面要做相位测量或者相干积累,绝对不能归一化,归一化后的相位信息仍然保留,幅度信息丢了,做通道间相位比对时会吃亏。
延迟补偿这行(pk-1) - (N-1)是整段代码里最容易写错的地方。MATLAB 索引从 1 开始,pk-1换算成 0 基,再减去滤波器群延迟N-1,剩下的才是回波相对发射时刻的样点延迟。少减或者多加一个N,估计时延就差一个脉宽 20 us,对应 3 km 的距离误差。我见过不止一次有人把这行写成pk - N,结果所有目标距离系统性偏了一个脉宽。
3.3 FFT 快速实现与点数选择
时域卷积在几百点规模上完全够用,但回波一长,比如 1 ms 的采集窗口配上 200 点滤波器,conv的复杂度立刻显出来。这时候换频域。
Nfft = 2^nextpow2(numel(rx) + N - 1); % 保证不产生循环卷积混叠 H = fft(h, Nfft); % 滤波器频响,补零到 Nfft X = fft(rx, Nfft); % 回波频谱 yf = ifft(X .* H); % 频域相乘等价于时域卷积 yf = yf(1:numel(rx)+N-1); % 截掉补零带来的尾部 err = max(abs(yf - y)); % 与时域结果逐点比对 fprintf('频域与时域最大偏差 %.3e\n', err);Nfft取numel(rx)+N-1向上取到 2 的幂,是为了让循环卷积等价于线性卷积。如果图省事取Nfft = numel(rx),卷积结果的尾部会绕回到开头,污染低时延区,表现是「零延迟附近凭空多出一个峰」,而且这个峰的位置随Nfft变化,非常迷惑。判断方法就是看err,正常应该在 1e-12 量级,如果到了 1e-2 甚至更大,先查Nfft够不够。
ifft之后截取前numel(rx)+N-1点,是因为补零会让输出长度变成Nfft,多出来的部分全是数值噪声。这一步不做,后面做峰值搜索时可能在尾部抓到虚假最大值。
频域实现还有一个附带好处:H算一次可以复用。做多帧处理或者多普勒通道组时,滤波器频响只跟发射波形有关,每帧只需要一次fft和一次ifft,省掉一半计算量。这一点在实时链路上很关键。
3.4 峰值检测与门限设定
峰值索引有了,门限怎么定是另一个问题。固定门限在仿真里能用,换一批数据就失效。工程上常见做法是单元平均恒虚警,用待检测单元两侧的参考单元估计本地噪声底。
function [det_idx, thr] = ca_cfar(mag, num_ref, num_guard, pfa) % 一维单元平均 CFAR,mag 为幅度序列 mag = mag(:).'; n = numel(mag); alpha = 2*num_ref * (pfa^(-1/(2*num_ref)) - 1); % CA-CFAR 门限因子 thr = zeros(1, n); det_idx = []; for k = num_ref+num_guard+1 : n-num_ref-num_guard left = mag(k-num_guard-num_ref : k-num_guard-1); right = mag(k+num_guard+1 : k+num_guard+num_ref); noise = mean([left, right]); % 两侧参考单元取均值 thr(k) = alpha * noise; if mag(k) > thr(k) det_idx(end+1) = k; end end end调用时num_ref取 32、num_guard取 4、pfa取 1e-4,对应门限因子大约 13 dB。三个参数的含义:num_ref决定噪声估计的平滑程度,取太小门限抖动大,取太大在噪声非平稳时跟不上变化;num_guard是为了防止目标能量泄漏进参考单元把噪声底抬高,一般取主瓣宽度的一半以上,LFM 压缩后主瓣约fs/B个点,这里是 5 点,取 4 到 8 都合理;pfa直接决定门限高低,1e-4 是检测概率和虚警的常见折中。
循环写法在 MATLAB 里慢,实际工程会向量化,用movmean加索引偏移一次性算完两侧均值。但第一版建议保留循环,逻辑清楚,出问题好断点。
3.5 用两组结果互相对账
仿真跑完不能只看峰值出来没有,要做三组对账。第一组,时域卷积和频域实现逐点比对,最大偏差应在 1e-10 以下。第二组,峰值索引与设定的L + N - 1比对,偏差为 0 或 1 个样点。第三组,输出信噪比与处理增益比对。
peak_val = abs(y(pk)); noise_bg = median(abs(y)); % 用中位数估计输出噪声底 snr_out = 20*log10(peak_val / noise_bg); fprintf('输入 SNR %.1f dB,输出 SNR %.1f dB,增益 %.1f dB\n', ... snr_in, snr_out, snr_out - snr_in);用中位数估计噪声底比用均值稳,因为输出序列里除了主峰还有距离旁瓣,均值会被旁瓣抬高。算出来的增益应该接近10*log10(B*T) = 16 dB,考虑峰值采样损失和旁瓣影响,实测在 14 到 16 dB 之间都算正常。低于 12 dB 就要查:滤波器是否共轭翻转正确、Nfft是否够、噪声功率是否算错。
三组对账都过了,这条链路才算真正跑通,后面换波形、换采样率、加多普勒,才有基准可比。
4. 参数怎么定:采样率、脉宽、带宽与处理增益的联动
4.1 采样率与带宽的倍数关系
采样率不是随便取的。对带宽为 $B$ 的复基带信号,奈奎斯特要求 $f_s\ge B$,但工程上一般取 1.2 到 2 倍,原因是峰值采样损失。匹配滤波输出的主瓣宽度约 $1/B$,如果 $f_s=B$,主瓣只有 1 个采样点,峰值很可能落在两个采样点之间,测出来比真实峰值低 1 到 3 dB,时延估计也会有一个采样点的量化误差。
| 采样率与带宽比 | 主瓣样点数 | 峰值损失 | 适用场景 |
|---|---|---|---|
| 1.0 | 1 | 1.5 到 3 dB | 只看有无,不测时延 |
| 1.2 | 1.2 | 约 1 dB | 资源紧张的低功耗链路 |
| 2.0 | 2 | 小于 0.5 dB | 常规测距测速 |
| 4.0 | 4 | 小于 0.1 dB | 高精度时延估计 |
我在做测距链路时固定取 4 倍,代价是数据量涨 4 倍、FFT 点数涨 4 倍,换来的是时延估计的插值误差可以忽略。如果非要用 2 倍,记得在峰值附近做三点抛物线插值,能把时延估计精度拉回到亚采样级。
提高采样率还有一个隐性副作用:如果前端抗混叠滤波器没跟上,带外噪声会折叠进来,输入信噪比下降,处理增益看着没变但绝对检测性能变差。仿真里可以随便提采样率,实际链路里采样率是被 ADC 和前端带宽卡死的。
4.2 脉宽与时宽带宽积决定的压缩比
脉宽 $T$ 和带宽 $B$ 的乘积决定处理增益,这一点在 2.2 节已经推过。工程上的取舍在于:$T$ 决定能量,$B$ 决定距离分辨率,两者相乘决定增益。
距离分辨率 $\Delta R=c/(2B)$,与脉宽无关。这是脉冲压缩最反直觉的地方:发射一个 20 us 的长脉冲,压缩后分辨率却由 2 MHz 带宽决定,等于 75 m,和发射 0.5 us 的窄脉冲相当,但能量多了 40 倍。这个「用长脉冲换能量、用带宽换分辨率」的交换,就是脉冲压缩存在的全部理由。
| 参数 | 符号 | 本例取值 | 决定什么 |
|---|---|---|---|
| 脉宽 | T | 20 us | 信号能量、最小可检测信噪比 |
| 带宽 | B | 2 MHz | 距离分辨率、主瓣宽度 |
| 时宽带宽积 | BT | 40 | 处理增益 16 dB |
| 距离分辨率 | c/2B | 75 m | 相邻目标能否分开 |
$BT$ 不是越大越好。$BT$ 大意味着调频斜率大,对采样率、时钟抖动、多普勒失配都更敏感。做高速目标检测时,$BT$ 超过 1000 就要认真考虑多普勒补偿,否则压缩损失能把增益吃光。
4.3 加窗抑制旁瓣,代价是主瓣展宽
不加窗的 LFM 匹配滤波输出,第一旁瓣约 -13.2 dB,这个电平在强目标旁边会淹没弱目标。工程上常用汉明窗或者泰勒窗压低旁瓣,代价是主瓣展宽、分辨率下降、峰值信噪比略有损失。
win = hamming(N).'; % 汉明窗,第一旁瓣约 -43 dB h_w = h .* win; % 频域加窗等价于时域逐点相乘 y_w = conv(rx, h_w, 'full');注意窗是加在滤波器上还是加在发射波形上,两者不等价。加在滤波器上属于「失配滤波」,接收端单方面压低旁瓣,发射波形不变;加在发射波形上会同时改变发射频谱,接收端还得匹配新波形。实际链路里通常是发端加窗、收端匹配,也有些系统为了简化发端,只在收端加。
加窗的代价可以用数字量化:汉明窗让主瓣展宽约 1.5 倍,距离分辨率相应变差 1.5 倍,峰值信噪比损失约 1.3 dB。如果系统对分辨率的要求刚好卡在边界,加窗之后就不达标了,这个账要提前算。
4.4 多普勒失配:新手最容易忽略的一根斜线
前面的推导都假设目标静止。目标一动,回波带多普勒频移 $f_d$,相当于发射波形在频域整体平移。匹配滤波器是按零多普勒设计的,频移之后失配,输出峰值下降、主瓣展宽、测距偏移。
下降多少取决于 $f_d T$ 这个无量纲量。经验值:$f_d T<0.1$ 时损失小于 0.5 dB,可以忽略;到 0.5 时损失约 4 dB,峰值已经明显塌陷;超过 1 基本就检测不到了。本例中 $T=20$ us,$f_d=0.1/T=5$ kHz 对应径向速度约 750 m/s(X 波段),也就是说中低速目标问题不大,高速目标必须做多普勒补偿。
补偿方式有两种:一是多普勒通道组,用一组不同频移的参考波形并行匹配,取最大输出;二是先估计多普勒再补偿,用相邻脉冲的相位差测速,然后修正参考波形。前者计算量大但鲁棒,后者计算量小但依赖测速精度。第 6 章会给出通道组的实现。
5. 常见问题排查:六个让峰值消失的典型问题
5.1 峰值位置总是差一个脉宽
现象:仿真跑出来峰值索引比预期大或小N个点,时延估计系统性偏移 20 us。
原因:延迟补偿公式写错,把滤波器群延迟加成了减,或者把conv的输出索引当成了相关结果的索引。另一种可能是h定义时用了fliplr但漏了conj,对实信号没影响,对复基带信号会让峰值跑到镜像位置。
解决:先用无噪声的单点目标验证。conv(tx, h)的峰值必须严格在索引N,值等于N。这一条不成立,先修滤波器定义,别往下走。成立之后再验证conv(rx, h)峰值在L+N-1,两条都对,补偿公式自然不会错。
5.2 归一化之后门限全部失效
现象:固定门限在某一批数据上表现正常,换一批数据要么全虚警要么全漏检。
原因:用了y/max(abs(y))这种按峰值归一化的写法。峰值本身随目标大小变化,归一化之后门限的相对位置也跟着变,固定门限等于没有门限。
解决:归一化只用于显示,检测一律用绝对幅度加 CFAR。如果非要用固定门限,就在每帧数据上先估计噪声底,thr = k * median(abs(y)),k取 6 到 10。更稳的做法是 3.4 节的 CA-CFAR,门限随本地噪声自适应。
5.3 换采样率结果就对不上
现象:10 MHz 下峰值 16 dB 增益,换成 20 MHz 增益变成 13 dB,峰值位置也偏了。
原因:滤波器h是按旧采样率生成的,N和调频斜率K都没跟着改。h的长度和采样率不匹配,等效于用一个时间尺度错误的参考波形去做相关,失配直接体现在增益上。
解决:把fs、T、B、N、K五个量集中在一个配置结构体里,任何一处改采样率,全部重算。我在代码里习惯写一个make_lfm(fs, T, B)函数,返回tx和h,禁止在脚本里手写exp(1j*pi*K*t.^2),就是为了堵这个漏洞。
5.4 FFT 长度没取够,低时延区被污染
现象:频域实现的结果在零延迟附近多出一个峰,时域实现没有,两者对账偏差 1e-2 量级。
原因:Nfft小于numel(rx)+N-1,循环卷积的尾部绕回开头,和真实的低时延回波叠加。
解决:Nfft = 2^nextpow2(numel(rx)+N-1),宁可多算一点。验证方法就是 3.3 节的err,正常在 1e-12 量级。如果嫌 FFT 点数太大影响速度,可以用 overlap-save 分段卷积,但分段长度和重叠点数要算清楚,别为了省事又引入新的边界问题。
5.5 单精度和定点输入把动态范围消耗干净
现象:仿真用 double 一切正常,换成 int16 采样的实测数据,弱目标全部消失,强目标旁边出现大片虚假峰值。
原因:int16 的动态范围只有约 96 dB,强目标的距离旁瓣加上量化噪声,把弱目标淹没了。另外很多前端直接给实数采样,忘了做复下变频,匹配滤波时把负频率也卷进来,增益损失 3 dB。
解决:先做直流去除和增益归一化,把数据转成 double 再进匹配滤波。确认输入是复基带还是实中频,实中频要先数字下变频再匹配,不能直接套复基带滤波器。动态范围不够时,考虑在匹配滤波前做一次分段增益控制,或者在强目标附近做旁瓣相消。
5.6 多目标下大目标把小目标压住
现象:两个目标相距较近,强目标的旁瓣盖住了弱目标的主瓣,CFAR 只检出强目标。
原因:未加窗时第一旁瓣 -13.2 dB,强弱目标差 20 dB 时,弱目标主瓣正好落在强目标旁瓣下方。CFAR 的参考单元里还包含了强目标的旁瓣能量,本地噪声底被抬高,门限跟着抬,弱目标更检不出来。
解决:加窗把旁瓣压到 -40 dB 以下,代价是分辨率下降。如果分辨率不能再降,用 CLEAN 类的方法:检出强目标后重建其响应并从原信号中减掉,再检测剩余。还有一种做法是限制 CFAR 参考窗长度,避开强目标旁瓣的影响范围,但这要求先知道强目标位置,属于半监督处理。
6. 进阶:把单通道匹配滤波扩成多普勒通道组,再补一道验证
单通道匹配滤波在目标静止或者低速时够用,一旦目标速度未知,就得靠通道组覆盖多普勒范围。做法不复杂:把参考波形按不同多普勒频移复制若干份,每份单独匹配,取所有通道输出的最大值作为检测量,最大值所在的通道给出速度粗估。
fd_list = -20e3 : 2e3 : 20e3; % 多普勒搜索范围 ±20 kHz,步进 2 kHz map = zeros(numel(fd_list), numel(rx) + N - 1); for k = 1:numel(fd_list) ref = tx .* exp(1j*2*pi*fd_list(k)*t); % 给参考波形加多普勒 hk = conj(fliplr(ref)); % 对应通道的匹配滤波器 map(k,:) = abs(conv(rx, hk, 'full')); % 每个通道一行 end [~, lin] = max(map(:)); % 全局最大值 [ch, pk] = ind2sub(size(map), lin); fprintf('检测到时延 %.3f us,多普勒 %.1f kHz\n', ... ((pk-1)-(N-1))/fs*1e6, fd_list(ch)/1e3);步进怎么选是个权衡。步进太粗,通道间的失配损失大,峰值塌陷;步进太细,计算量成倍涨。经验规则是步进不超过 $0.5/T$,本例 $T=20$ us,对应 25 kHz,取 2 kHz 已经过采样了。实际系统里会用 FFT 一次性把多普勒维算出来,等价于对慢时间做一次变换,比循环快得多。
通道组跑通之后,一定要做一次增益核算,这是整套流程里最有价值的验证。做法是:固定输入信噪比,扫一遍目标时延和多普勒,记录每个格点的输出峰值,画成时延-多普勒二维图。理想情况下主瓣应该是一个规则的斜椭圆,沿时延方向宽度约 $1/B$,沿多普勒方向宽度约 $1/T$。如果发现主瓣在某些区域异常塌陷,大概率是通道间隔不够或者某个通道的参考波形生成有误。
snr_axis = -20:2:0; % 输入信噪比扫描 pd = zeros(size(snr_axis)); for i = 1:numel(snr_axis) % 每个信噪比下做 200 次蒙特卡洛,统计检测概率 % 检测判据:峰值超过 CFAR 门限且时延误差在一个样点内 end蒙特卡洛这一步别省。单次仿真看到峰值漂亮不代表统计性能达标,检测概率曲线在低信噪比段的斜率才是链路真正的能力边界。我一般会拿实测的 $P_d$ 和理论值对一遍,偏差超过 1 dB 就回头查噪声功率估计和 CFAR 门限因子。
从那以后我每次写匹配滤波,都强制先用单点目标、整数样点延迟、无噪声三个条件跑一遍对齐检查,确认峰值严格落在N和L+N-1,再逐级加噪声、加多普勒、加多目标。这套顺序救过我很多次,因为一旦跳过基础对齐直接上复杂场景,出了问题根本分不清是滤波器写错了还是场景设错了。希望帮到你。
本文还有配套的精品资源,点击获取