
做雷达信号处理或者做成像算法仿真的人大概率都碰到过同一个问题匹配滤波已经把一个点目标压成了尖峰可尖峰旁边那串旁瓣反而成了压制弱目标的最大麻烦。强杂波回波幅度一大它的距离旁瓣就能把附近的弱小目标整个埋掉这时候你拿普通滤波器滤来滤去效果往往很尴尬。我这次要讲的就是用CLEAN算法做杂波抑制的一套Matlab仿真实现。它不依赖统计建模不靠堆滤波器阶数而是把强散射体一个一个“挖”出来再把它在数据里留下的旁瓣烙印抹掉。如果你正在做一维距离像、SAR/ISAR图像处理或者需要一个适合课程设计、论文复现的直观算法demo这篇东西应该能给你省不少时间。这套仿真做完之后我最大的感受是CLEAN是个老算法但老算法不等于过时算法。它用在“强点旁瓣干扰”这类问题上比很多花哨的现代算法都干净利落。下面我把整个项目的设计思路、仿真细节、代码结构和踩坑记录都拆开讲。1. 为什么我偏偏选CLEAN来做杂波抑制1.1 杂波抑制不是简单的高通滤波很多刚接触雷达信号处理的人听到“杂波抑制”四个字第一反应是上高通滤波器、动目标显示MTI或者动目标检测MTD。这些方法确实能对付多普勒频率为零或者接近零的地物杂波因为它们利用的是“动目标回波有多普勒偏移静止杂波没有”这个物理差异。但问题在于有一类杂波并不是时域均匀铺开的大范围回波而是离散强散射体比如建筑物边缘、金属塔架、大型船舶的角反射器效应。这些强散射体在距离维上就是一个很高的尖峰它的旁瓣会直接覆盖周围几米到几十米范围内的弱目标信号。对这种离散强杂波传统的多普勒滤波基本无效因为它的多普勒特性和静止地物一模一样你滤不掉它。更麻烦的是脉冲压缩本身是有副作用的。线性调频信号通过匹配滤波之后点目标响应是一个sinc形状的窄脉冲主瓣宽度由带宽决定但第一旁瓣只比主瓣低约13.2 dB。这是什么概念如果一个强杂波回波幅度是100那么它第一旁瓣的幅度大约是20多而一个弱目标回波可能只有1甚至0.5。弱目标完全淹没在强杂波的旁瓣里你在距离像上看它就像在满月旁边找一颗星星。只靠加窗函数能把旁瓣压低一些但代价是主瓣展宽、距离分辨率变差。我实测下来Hamming窗能把旁瓣压到约-43 dB但主瓣也展宽了大约1.3到1.5倍。就算这样100幅度强杂波的旁瓣仍然有0.7左右和0.5幅度的弱目标依然是一个量级检测还是困难。所以杂波抑制在这个场景下本质上是“将强散射体在匹配滤波输出中留下的旁瓣污染剥离出去”而不是简单滤波。1.2 CLEAN到底在“洗”什么CLEAN算法最早是射电天文学里的方法1974年由Högbom提出用来处理综合孔径成像里的“脏图”。它的核心思路可以用一句话概括观测数据是真实场景和一个点扩散函数的卷积那么我就用迭代方式把真实场景中的强点一一猜出来再从数据中减去这些强点对应的点扩散函数。放到雷达脉冲压缩里这句话可以改写为匹配滤波输出y(t)是真实目标散射系数分布σ(t)与系统点扩散函数p(t)的卷积再加上噪声。如果真实场景里只有少数几个强散射点那卷积的结果就是几个尖峰周围带着一串旁瓣。CLEAN做的事情就是不断寻找当前输出中幅度最大的位置把它判定为一个真实散射点记录它的位置和复振幅然后以这个位置为中心把“这个点贡献出来的那套旁瓣花纹”从数据中减掉。每减一次剩余数据里的最大峰值就会下降一点直到剩下的是噪声和其他弱目标。我习惯用一个生活类比解释这个事情想象一个房间里有人说话你录到了这段声音但某个大嗓门的人离麦克风特别近他的声音把其他人的说话内容全盖住了。CLEAN的思路不是硬调音量而是把这个大嗓门的声音波形整个抠出来从录音里减掉。减掉一次还不够干净就再找下一个最大的继续减。减完之后房间里其他人的声音就露出来了。这就是CLEAN做杂波抑制的本质。1.3 CLEAN的适用边界新手最容易搞错我必须先泼一盆冷水CLEAN不是万能的杂波抑制器它只适用于“场景可以由少数离散强散射点主导”的情况。如果杂波是海面回波、气象杂波这类连续分布的强起伏信号CLEAN的效果会很差甚至会把连续区域碎成一堆虚假点目标。这时候你应该去看MTI、AMTI、STAP或者空时自适应处理那些算法才是为均匀杂波背景设计的。CLEAN的优势场景非常清晰目标稀疏、强散射点集中、点扩散函数已知且稳定。比如雷达一维距离像中的人造金属目标、ISAR成像后飞机或舰船上的强散射中心、SAR图像中建筑物和角反射器造成的旁瓣串扰。这种地方用CLEAN一是原理直观二是实现简单三是参数可解释性很强。我在做这个仿真时刻意把场景设计成强杂波旁瓣淹没弱目标的状况就是为了让CLEAN的“每一步在干什么”看得清清楚楚。2. 仿真场景怎么搭才能让CLEAN有用武之地2.1 场景设计思路强杂波旁瓣必须真的盖住弱目标很多算法demo失败的共同原因是场景设计得太温和算法跑完看不出效果。做CLEAN仿真也是一样。如果你随手设两个目标幅度差异不大距离又拉得开那CLEAN和普通加窗滤波没什么区别完全展示不出算法的价值。我设计的场景是这样的存在一个幅度为100的强杂波散射点位于50米处两个弱目标分别位于52.5米和57米幅度分别只有0.8和0.5。强杂波和第一个弱目标之间的距离差只有2.5米而我们的距离分辨率大概是1.5米加窗后主瓣宽度约2.1米所以弱目标刚好落在强杂波第一旁瓣和第二旁瓣之间的区域。这个位置设计非常关键它让弱目标在脉冲压缩输出里完全被盖住同时又保留了恢复的可能性。第二个弱目标放在57米作为对照。它距离强杂波7米旁瓣泄漏相对小一些但仍然受强杂波较高阶旁瓣的影响。这样处理完之后你可以同时看到两个弱目标不同程度的恢复效果比单目标演示有说服力得多。2.2 回波生成与匹配滤波参数这个仿真我采用线性调频信号带宽B100 MHz脉宽T10微秒采样率Fs200 MHz。距离分辨率由带宽决定ΔRc/(2B)≈1.5米。采样率取200 MHz意味着距离采样间隔约为0.75米刚好在两个可分辨单元之间插入一个采样点这样旁瓣的凹陷位置能被更精细地刻画CLEAN减掉的模板也会更接近真实情况。载频我没有过多纠结只在回波中加入了一个固定的相位项因为我们的目标是处理脉冲压缩后的基带复信号不是射频链路仿真。如果你想做完整的雷达链路仿真可以把中频、混频、IQ解调都加进去但CLEAN这一层关心的是匹配滤波输出所以基带建模足够用。发射信号可以定义为Fs 200e6; B 100e6; T 10e-6; K B / T; % 调频斜率 t (0 : round(T*Fs)-1) / Fs; % 快时间轴 s_tx exp(1j * pi * K * t.^2); % 基带LFM信号接收回波则通过将每个散射点的信号延时并叠加来生成c 3e8; r_range [50, 52.5, 57]; % 强杂波、弱目标1、弱目标2 amp [100, 0.8, 0.5]; % 幅度 rx zeros(1, length(t) 200); for m 1:length(r_range) tau 2 * r_range(m) / c; n0 round(tau * Fs) 1; rx(n0 : n0 length(s_tx)-1) rx(n0 : n0 length(s_tx)-1) amp(m) * s_tx; end这里把强杂波定义成幅度100就对应了前文说的旁瓣压制效果。加Hamming窗的匹配滤波可以用频域快速卷积实现。有一点要提醒如果用FFT做匹配滤波一定要把FFT长度设置成大于等于输入信号加参考信号长度减一否则循环卷积会把尾部泄漏到头部产生虚假目标。我在代码里加了padding就是为了避开这个坑。2.3 为什么必须单独准备一个PSF模板CLEAN算法的核心输入有两个一个是待处理的匹配滤波输出另一个是点扩散函数PSF。PSF就是单位幅度点目标经过同一套脉冲压缩链路之后得到的输出形状。我建议在仿真里显式生成它而不是直接用理论sinc函数代替。原因很简单加窗、过采样、FFT长度、边界效应都会影响PSF的实际形状理论sinc往往不够准确。用系统自身的脉冲响应做模板CLEAN减的时候才减得干净。生成PSF的代码其实很简单就是让一个位于零距离延时的单位冲激通过你的匹配滤波器imp zeros(1, length(t) 200); imp(1) 1; [psf_unorm, ~] matched_filter(imp, s_tx, Nfft); psf psf_unorm / max(abs(psf_unorm)); % 归一化中心峰值为1这段代码体现了CLEAN实施中一个非常容易被忽略的原则模板必须归一化而且归一化系数要固定。因为后续在CLEAN主循环里你找到某个峰值val后要在残差中减去的是val乘以psf。如果psf中心峰值不是1那么减去的幅度就不等于你找到的那个点的贡献幅度迭代就会发散或者收敛极慢。匹配滤波函数也要单独封装一下因为在后面的参数测试里会反复调用。封装之后你只需要改变窗函数类型或采样率就能看PSF如何变化进而影响CLEAN表现。这比把匹配滤波代码重复粘贴几十次好维护得多。3. CLEAN算法核心实现代码和细节一起讲3.1 主循环到底在做什么CLEAN算法的流程看起来非常短短到很多人觉得“就这么点东西”。但它每一步背后都有对应的物理含义。完整流程如下第一步输入初始残差R它就是匹配滤波后的复距离像。第二步找到R中幅度最大的位置记录位置索引idx和复数值val。第三步把val乘以一个衰减因子alpha加到模型向量model的idx位置。第四步以idx为中心将归一化PSF乘以alpha和val然后从残差R中减去。第五步检查当前最大峰值是否低于阈值或者迭代次数是否用尽如果满足条件就停止否则回到第二步。第六步如果要做传统的CLEAN图重构就把model和一个更窄的clean beam卷积再加上最终残差得到恢复后的图像。但在杂波抑制场景里我通常直接观察model和最终残差因为model就对应了被清洗出来的离散散射中心。这个流程里为什么每次都要乘以alpha因为实际数据中峰值位置处的幅度并不完全等于那个点目标的真实幅度它可能还混着附近目标的部分旁瓣贡献。如果你一次减掉100%很容易过补偿在残差里出现一个反向的鬼峰。乘一个0.1到0.5之间的衰减因子相当于每次只“清掉一部分污染”让剩余部分在下一轮继续迭代。这个思想看起来保守但非常稳。3.2 Matlab实现里的四个关键细节第一个关键细节是复数域处理。很多初学者会把CLEAN写成只对幅度谱操作这是错的。匹配滤波输出是复信号PSF也是复信号减的时候必须进行复数减法。如果只取模相位信息就丢了减出来的残差会出现严重失真。所以代码里我保存的val_c是res(idx)的完整复数值而不是abs(res(idx))。第二个关键细节是PSF中心归一化。前面已经说过了这里再强调一句归一化基准要统一一旦PSF标定为峰值1后续所有减法操作都以这个标定为依据。第三个关键细节是边界处理。PSF长度可能比残差长度短但减法时仍可能越界。我在循环里做了索引约束当传播模板落在残差范围内时才执行减法。这看起来是小事但如果不处理跑上一百次迭代后边界上的误差会积累成很大的假峰。第四个关键细节是搜索区域的限制。在真实工程里我们往往不会在整段距离像上无差别搜索最大幅度因为噪声尖峰也可能被当成目标。合理做法是先做CFAR检测确定潜在目标范围然后只在这个范围内执行CLEAN。仿真里为了演示纯净的算法我用了全范围搜索但代码中预留了mask变量。如果你想贴近工程把mask设成检测单元附近的局部区域即可。主循环代码我给你贴出来alpha 0.3; maxIter 500; peakThresh 1e-3 * max(abs(Y)); res Y; model zeros(size(Y), like, Y); Npsf length(psf); cp ceil(Npsf / 2); for k 1:maxIter [amp, idx] max(abs(res)); if amp peakThresh break; end val_c res(idx); model(idx) model(idx) alpha * val_c; shift idx - cp; startIdx shift 1; endIdx shift Npsf; lo max(1, startIdx); hi min(length(res), endIdx); psfLo lo - startIdx 1; psfHi Npsf - (endIdx - hi); res(lo:hi) res(lo:hi) - alpha * val_c * psf(psfLo:psfHi).; end这段代码不是我随手写的是经过很多轮实验后确定下来的写法。最关键的一点是减法时psf的截取段和res的截取段必须一一对应不能错位。我曾经在这里犯过错误结果每轮迭代都会引入一个固定的位置偏置最终导致目标位置偏了半个采样点。3.3 参数选取alpha、迭代次数和停止阈值参数选择是CLEAN项目里最影响结果的一环。alpha太小比如0.05收敛会很慢500迭代都不一定把强散射点旁瓣洗干净alpha太大比如1.0一两次迭代确实能把强点抹掉但也会在目标周围制造出明显的过补鬼峰。我的经验是如果信噪比比较高、PSF标定很准alpha取0.2到0.5比较合适如果数据里噪声较大或者PSF不够准alpha往0.1以下调宁可慢一点也要稳。停止阈值的设置也有讲究。最简单的是用初始峰值乘以一个小比例比如千分之一作为阈值。这样做的好处是天然和信号幅度挂钩换场景不用重新调整。更稳妥的做法是用噪声底估计来设阈值比如先取残差尾部一段纯噪声区域的幅度计算均值和标准差然后把阈值设在均值加3到5倍标准差。这样能避免CLEAN把噪声也当成一个个点目标“清洗”出来。相信我阈值设得太大弱目标还没恢复就停了阈值设得太小你会看到最终模型里出现几十个幅度很小的假目标那都是噪声被强行拟合成点散射体的结果。这里我给一个参数参考表是我在那个仿真条件下的实测趋势具体数值会随采样率和窗函数变化参数取值偏小取值偏大我的建议alpha收敛极慢迭代次数不足时效果差过补偿明显目标周围出现鬼峰0.2~0.5迭代上限强点旁瓣未清洗完计算时间长且可能拟合噪声200~1000停止阈值把噪声当成目标弱目标恢复不足初始峰值0.1%~1%4. 仿真结果怎么看、怎么评估4.1 处理前后的波形对比跑完仿真第一件事肯定是画图。我会把三个图放在同一张图里上子是原始匹配滤波输出的幅度谱中子是CLEAN处理后的残差幅度谱下子是模型向量model的stem图。原始输出里50米强杂波处有个大尖峰52.5米和57米的弱目标根本看不清。处理后的残差里强杂波尖峰大幅降低弱目标处出现了明显可辨的峰。model图则更清楚50米处一个高柱子52.5米和57米处两个矮柱子。这三个柱子分别对应强杂波和两个弱目标幅度比例也基本符合输入的0.8和0.5。图是给人看的量化的东西还要靠数据。我通常会同时打印出处理前后弱目标位置的幅度值和局部信杂比。在你自己的仿真里可以先用光标工具直接读图上的峰值但更推荐写脚本自动定位峰值并输出不然测几十个参数时会疯掉。4.2 定量指标怎么算评估CLEAN效果我一般看四个量。第一个是弱目标位置的信杂比改善量。定义很简单处理前在弱目标所在位置附近一定范围内取最大值作为信号估计再取该范围外的最大旁瓣作为杂波估计两者之比就是信杂比。处理后重新计算两个值相减就是改善量。第二个是弱目标幅度估计误差公式是20log10(|估计幅度-真实幅度|/真实幅度)。这个值能反映CLEAN重构出的弱目标幅度准不准。第三个是残差能量收敛曲线记录每一轮迭代的残差峰值画出一条下降曲线。正常的曲线应该是平滑单调下降如果出现振荡说明alpha太大或者PSF有问题。第四个是峰值旁瓣比PSLR输出图中最大旁瓣与主瓣峰值的比值处理前后对比。CLEAN的典型效果就是把强杂波贡献的旁瓣压到接近噪声底。有一个重要的实操细节计算信杂比改善量时一定要把范围选对。如果范围选得太大把别的真实目标或者残余旁瓣也算进去了结果就会失真。我通常以目标位置为中心取正负一个距离分辨率单元为信号区正负3到5个距离分辨率单元为杂波区。4.3 参数敏感性测试我做完基准结果之后又花了不少时间跑参数敏感性。这个测试非常值得因为只有知道参数怎么影响结果你才敢把算法交给别人用。我测了三组alpha从0.1变到0.9阈值从初始峰值的1%变到0.01%以及PSF中加入幅度和相位误差。结果和我预期的一样alpha在0.2到0.5之间表现稳定alpha为0.9时在弱目标附近出现了明显的负值鬼峰信杂比改善量反而下降阈值太小导致最终模型多出十来个假峰位置随机分布PSF幅度误差对结果影响相对小但相位误差非常致命哪怕只有5度收敛速度也会变慢旁瓣残余明显变多。这个测试给我一个很重要的经验在实际系统里PSF的相位准确性必须认真对待。如果你要处理的是实测雷达数据最好用已知强定标体的实测回波去估PSF而不是用理论公式算完就完事。5. 实操中的坑与排查笔记5.1 收敛慢或者永远收敛不到阈值我遇到过的最常见问题是CLEAN跑了几百轮还达不到停止阈值或者残差峰值下降幅度很小。排查顺序基本是先看PSF中心是否归一化为1再看减法是否在复数域进行再看alpha是否取得太小。我最初犯过的错误是在构造psf时忘了归一化结果每一次减法都把目标幅度缩水一截迭代虽然能跑但旁瓣始终减不干净弱目标恢复得也不对。如果你确认这些都正常那可能是目标距离太近多个PSF主瓣互相重叠这种情况下CLEAN的分辨率极限天然受限可以在更细的采样网格上运行算法再试试。另一个容易忽视的点是FFT匹配滤波的padding长度。如果Nfft选得太小循环卷积会把尾部信号卷到头部产生的“鬼目标”会干扰CLEAN的峰值搜索。我调试时习惯先把单目标场景跑一遍如果CLEAN结果里出现对称位置的一对假目标立刻去检查padding。5.2 弱目标恢复后位置偏了或幅度不对就算能收敛也可能出现弱目标位置和真实位置差了一两个采样点、幅度差几个dB的情况。这多半是过补偿造成的。alpha太大时减掉的强点模板会连累邻近的弱目标因为CLEAN在做减法时用的是整体PSF它不会区分这个PSF的主瓣和旁瓣分别覆盖了哪些相邻目标。如果弱目标距离强点太近强点的主瓣本身就是覆盖弱目标的你怎么减都会带走一部分弱目标的能量。这种情况不是CLEAN失效而是目标本身就落在别人家里了处理完之后的幅度估计就会偏低。解决办法有两个方向。一是降低alpha让每次减掉的比例小一点减小连带损失。二是对最终模型做幅度校正比如根据目标位置和PSF相对关系用最小二乘估计真实散射系数。在仿真里我更推荐直接调小目标间距的测试先把CLEAN的能力边界摸清楚再谈精细校正。5.3 从一维距离像扩展到二维图像CLEAN绝不只能做一维ISAR和SAR图像里的旁瓣抑制同样常用。只是扩展成二维之后有几个额外的坑。一个是PSF变成二维矩阵峰值搜索变成二维峰值检测另一个是每次减法不再是更新一段向量而是更新一个局部二维窗。如果还是照着二维全图卷积去做减法计算量会大得离谱。我的建议是先在一维环境里把这个算法吃透再扩展到二维。二维CLEAN的代码结构和一维几乎一样区别在于找峰函数从max(abs(res))变成max(max(abs(res)))减法模板从一维psf变成二维psfmatrix循环内部改成二维矩阵切片更新。只要一维版本的成功经验和参数调整方法掌握了二维只是时间问题。6. 一些绕不开的真实体会仿真做完我最想叮嘱的就一句话CLEAN算法看起来简单但它极其依赖“模型和真实数据匹配”这个前提。PSF标得准、场景稀疏度高、目标以强点为主CLEAN就是一把又快又稳的剔骨刀。反过来如果场景不满足稀疏性PSF又带有未知误差再漂亮的迭代公式也救不回来。我自己在这个项目里最大的收获倒不是把弱目标从强杂波旁瓣里挖了出来而是养成了“先构造可解释的场景再跑算法”的习惯。仿真不是为了把结果跑得好看而是为了让你理解每个参数在物理上到底代表什么。你把这个逻辑捋顺了后面不管换到二维成像还是实测数据处理心里都会很有底。另外Matlab调试时别只盯着最终图看。花点时间把每一轮迭代的res和model都存下来连续播放几帧你会直观看到强杂波旁瓣是怎么一层层被剥掉的。这个画面比任何指标都能帮你理解CLEAN。