毫米波雷达数据处理:峰值搜索在距离-多普勒图上提取目标的工程实战
简介:这是一份面向雷达信号处理与数据解析的MATLAB工具包,共两个m文件:readDCA1000.m负责读取DCA1000采集板生成的雷达I/Q数据,完成文件解析、采样时刻换算、I/Q分量拆分等必要步骤;findAllPeak.m则聚焦峰值检测,通过滤波去噪、峰谷条件判断、导数寻峰等手段提取信号峰值,并设置验证规则减少虚警。两者组合后,得以实现从原始雷达数据读入到目标特征峰值输出的完整处理链路,可直接用于目标探测、姿态感知等课题研究或工程调试。压缩包共两个文件,均为m脚本,大小仅2KB,轻巧易用,便于对照源码理解处理流程。已有363人学习查看,适合雷达工程、信号处理等方向的本科生、研究生及科研人员作为参考模板,可显著缩短前期编码和调试时间,将更多精力投入核心算法改进。
1. 一根天线扫出的不是距离,是一串峰值:findAllPeak 在雷达数据处理里的真正用处
做毫米波雷达数据处理时,最常被低估的一步不是 FFT 也不是 CFAR,而是“找到目标对应的那个峰”。很多人把 CFAR 跑完就拿到目标列表了,但实际工程里,CFAR 输出的只是“疑似有目标的检测点”,真正把距离、速度、角度算出来,还要靠一次精确的峰值搜索。findAllPeak 这个名字像是随手起的工具函数,但它背后就是雷达信号处理里最核心的“峰值提取”环节:从幅度谱里把目标的局部极大值挑出来,再映射成物理量。这篇文章不聊泛泛的原理,直接讲我在雷达数据处理里用 findAllPeak 这类函数时的完整落地路径,包括数据怎么准备、参数怎么设、哪些边界坑让我返工过最多次,以及最后怎么把它封装成能用的目标检测小工具。适合正在写毫米波雷达数据处理代码、被 RD 图上杂散峰搞到头疼的人,也适合刚接手雷达信号处理板、需要快速看明白目标是怎么从 ADC 数据里“冒出来”的新手。
2. 峰值搜索前的雷达信号准备:从 RD 图到一维序列的常见处理链
2.1 为什么不能直接对 RD 图用 findAllPeak
雷达信号经过距离 FFT 和多普勒 FFT 之后,得到一个二维矩阵,行是距离门,列是多普勒门,幅度代表该距离-速度格点的回波强度。这个时候直接对整个二维矩阵调用 find_peaks(或者自己写 findAllPeak)是能跑,但结果基本没法用。原因有三个:第一,二维峰值搜索要考虑邻域窗口,单纯按“比身边的8个点都大”来判断,会把同一个目标在距离和速度维的旁瓣都当成独立峰值,一个目标变成几十个点;第二,CFAR 检测通常已经给出的目标位置(比如第 15 个距离门、第 -20 个多普勒门),如果你在二维矩阵上再做一次峰值搜索,会重复劳动且容易把强目标的副瓣当成新目标;第三,RD 图上每个格点的幅度是复数模值,不同距离、不同速度的杂波底噪差异很大,不做归一化直接设一个固定阈值,弱目标会被漏掉。
所以我的处理顺序一定是:先做检测(目标在哪个距离、哪个速度),再做峰值提取(在这个检测点附近,精确算出峰的位置和幅度)。检测这一步用 CA-CFAR 或者 OS-CFAR 都行,峰位提取这一步才轮到 findAllPeak。注意,检测输出的位置是离散的格点索引,比如距离门 15、多普勒门 -20,而实际目标的精确距离可能不是 15 对应的那个距离门中心,特别是在低信噪比时,能量会泄漏到相邻格点。峰值搜索在这里的价值,就是对检测位置附近做插值或精细搜索,把离散索引变成亚格点精度。
2.2 把二维 RD 图压成一维序列的两种常见做法
既然 findAllPeak 大多实现为一维峰值搜索,就需要把二维 RD 图降维。常见做法有两种,我分别用在不同的场景里。
第一种是按距离向处理:固定每一个多普勒门,沿距离维取一维幅度序列,然后在这个序列上找峰。也就是说,第 k 个多普勒门对应一条一维曲线,曲线横坐标是距离门索引,纵坐标是幅度。我们在这个曲线上找局部极大值,得到“该多普勒频率下,有哪些距离上存在目标”。做距离向峰值搜索时,峰值位置对应目标距离,峰值幅度反映目标反射强度。FMCW 毫米波雷达做单目标测距时,用这种方式就够了。
第二种是按多普勒向处理:固定距离门,沿多普勒维取一维序列,找峰得到目标的速度。实际中常把这两种做法组合:先用 CFAR 拿到若干个“距离-多普勒对”,然后对每个距离门,取该距离门对应的整行多普勒幅度序列,用 findAllPeak 在该行上找主峰和次峰。组合起来的逻辑是:CFAR 负责筛选可疑格点,findAllPeak 负责把每个可疑格点附近真正的主峰找出来,去掉 CFAR 由于栅栏效应产生的偏移。
还有第三种,更工程化:直接对 CFAR 输出的检测点集合做聚类(比如 DBSCAN),每个聚类簇内部用质心法求峰位,等于跳过了一维峰值搜索。这种方式的好处是抗噪,但代价是实时性差,而且参数(聚类半径)要和距离/多普勒分辨率强相关。我一般只在后处理分析时用聚类,实时运行时仍然用一维 findAllPeak,因为计算量小、可解释性强。
2.3 最小可复现的峰值搜索代码:先跑通再谈参数
为了让后面所有讨论都落在实处,先给一段最简实现。这里用一个合成的 FMCW 中频信号,做一维距离 FFT,然后对幅度谱调用基于 scipy.signal.find_peaks 封装的 findAllPeak。scipy 里的 find_peaks 就是典型的峰值搜索函数,它返回峰值索引和属性(峰值高度、左右边缘等)。在雷达数据处理里,我通常在此基础上加一层封装,把索引转换成距离。
import numpy as np from scipy.signal import find_peaks # 模拟中频采样:256个采样点,采样率10MHz,FMCW斜率50MHz/ms fs = 10e6 N = 256 slope = 50e12 # Hz/s ts = np.arange(N) / fs # 两个目标:距离对应高频分量,幅度不同 f_targets = [200e3, 450e3] # 中频频率 200kHz, 450kHz r_targets = [25.0, 56.25] # 对应距离(单位m),用 c*T*f/(2*B) 换算 if_sig = np.zeros(N) for f, a in zip(f_targets, [1.0, 0.6]): if_sig += a * np.exp(2j * np.pi * f * ts) # 距离FFT r_fft = np.fft.rfft(if_sig) r_mag = np.abs(r_fft) freq_bins = np.fft.rfftfreq(N, d=1/fs) # 峰值搜索:最小高度0.1,最小间距3个采样点 peaks, properties = find_peaks(r_mag, height=0.1, distance=3) # 把峰值索引转为距离 c = 3e8 dist_per_bin = c / (2 * slope * (N / fs)) # 每格对应距离 distances = peaks * dist_per_bin print("检出峰值台数:", len(peaks)) print("峰索引:", peaks) print("对应距离:", distances)这段代码里最关键的是distance=3和height=0.1两个参数。distance表示两个峰之间至少间隔 3 个采样点,目的是避免同一个目标的旁瓣被重复算成两个峰。雷达数据里的旁瓣间隔通常和窗函数相关,如果用了 Hamming 窗,第一旁瓣大概在主瓣外主瓣宽度的两倍位置,distance至少要大于主瓣宽度的采样点数。height是绝对幅度阈值,这里设 0.1 是因为我模拟信号的峰值约 1.0 左右。实际雷达数据里,绝对幅度会和 ADC 增益、FFT 点数强相关,所以更稳的做法是先把幅度序列做归一化,比如除以整条序列的最大值,再设height=0.2这类相对值。归一化能避免不同雷达设备、不同距离门之间的判决不一致。
代码跑完之后你应该能看到两个峰,分别对应 25 米和 56.25 米的目标。如果distance设成 1,很可能会在真实峰旁边多出一两个小峰,特别是当你加了窗函数之后。这就是峰值搜索最需要直接观察的“黑匣子”现象:同样的数据,参数不同,结果差一倍。
3. 用 findAllPeak 提取距离 / 速度 / 角度:参数怎么设才不丢目标
3.1 距离向峰值提取:每一个距离门的谱线怎么处理
在 2D FFT 得到 RD 图之后,距离向的峰值提取通常按“每一个多普勒门对应的距离谱线”来做。为什么要按多普勒门拆开?因为同一个目标在距离维上只有一个峰,但在不同多普勒门里,这个峰的能量会分散——目标径向速度会跨越多个多普勒格,而且强目标会有多普勒泄漏。如果只看 CFAR 给出的那一个多普勒门,很可能只看到目标峰的半边,幅度偏低,峰值索引也偏到相邻格点上。
常见处理是:对 CFAR 检测到的每个多普勒索引 k,取出 RDM[:, k] 这一列,沿距离维做峰值搜索。但这里有一个细节,CFAR 检测的点可能不止一个,多个检测点可能属于同一个目标(目标在 RD 图上占据多个连续格点)。所以我会先对检测点做简单合并:如果两个检测点的距离差小于 3 个距离门且多普勒差小于 3 个多普勒门,就把它们视为同一个目标簇,然后只对这个簇的联合区域做峰值搜索。具体做法是在两个维度的邻域里取最大幅度点作为粗峰,再用二维抛物线插值得到亚格点距离。
对于一维搜索,findAllPeak 的prominence(峰显著性)参数要比height重要。prominence衡量一个峰相对周围低点的突出程度。雷达回波里底噪不平,远距离段噪声底,近距离段有耦合波,绝对幅度阈值很难统一。用prominence可以解决:只要峰相对于它的左右最低谷高出设定值,就算峰,这比一刀切的幅度阈值合理得多。我在实际工程中,height只用来排除零频耦合(通常设在噪声底之上一点),prominence才是判断目标是否存在的主力。
# 假设rdm是距离-多普勒矩阵,cfar_idx 是CFAR检测到的[距离门, 多普勒门]列表 import numpy as np from scipy.signal import find_peaks def peak_on_range_dim(rdm, doppler_bin): # 取指定多普勒门下的距离幅度序列 range_mag = np.abs(rdm[:, doppler_bin]) # 归一化,防止不同距离段的噪声起伏影响阈值 range_mag_norm = range_mag / np.max(range_mag) peaks, props = find_peaks( range_mag_norm, height=0.3, # 相对幅度阈值,排除低幅度噪声 distance=5, # 距离门间隔5,防止旁瓣重复计数 prominence=0.15, # 峰显著性,允许近距和远距不同底噪 rel_height=0.5 # 用于计算峰值宽度,后面可用来估计主瓣范围 ) return peaks, props["peak_heights"]这里distance=5的理由是:雷达距离分辨率如果按c/(2B)计算,加 Hamming 窗后主瓣宽度大约是 2~3 个距离门。两个目标要能被分辨,至少需要相隔一个主瓣宽度。如果你设distance=2,很可能同一个目标的距离旁瓣被算成两个目标。rel_height=0.5可以用来计算峰宽,峰宽能告诉你这个峰是尖锐目标还是被噪声拖宽的疑似峰——我一般用峰宽上限来排除强杂波反射造成的宽峰。
3.2 速度维峰值提取:多普勒模糊、零速杂波和微多普勒
速度维的峰值提取比距离维更敏感,因为零速杂波(静止物体反射)和地杂波经常在零多普勒附近形成一个非常高的峰。这个峰会严重影响findPeaks的判定,因为它会把整条多普勒序列的底噪抬高,导致弱目标峰被按下“阈值线”下面。处理顺序建议是:先对整个距离门的多普勒谱做均值滤波,把零速附近的尖峰记下来,然后对这个距离门选峰时,把零速附近的 ±2 个多普勒门直接屏蔽掉。
另一个坑是多普勒模糊。FMCW 雷达的 PRF 决定了最大不模糊速度,当目标速度超过这个值,它的多普勒峰会被折返到序列的另一端,造成“虚假低速”目标。遇到这种情况,仅凭峰值搜索无法分辨,必须用双 chirp 或调频斜率不同的帧数据来解模糊。峰值搜索在这里能做的,就是保证在折返峰附近只取一个峰,不要把原位置和折返位置的旁瓣都算上。为此,在速度维搜索时,distance通常要设为 4 以上——多普勒主瓣在加窗后大约 3 个格点宽。
对速度维做 findAllPeak 的另一个场景是提取微多普勒特征。人员在走动时,身体反射会产生一个主峰,四肢摆动会产生围绕主峰的一串小峰。这些小峰幅度低、距离主峰近,很容易被distance参数过滤掉。如果你想保留微多普勒信息,就不能用distance=5这种粗过滤,而是先检测主峰,然后在主峰左右一段范围内用height=0.05的低阈值再搜一次。这一步通常用在 4D 毫米波雷达的人体识别数据里,作为点云前的特征补充。
3.3 角度估计时的峰值配对:一个目标对应多个峰怎么选
MIMO 毫米波雷达做角度估计时,先对虚拟天线阵的每一维做 FFT(或 MUSIC/ESPRIT)。用 FFT 时,角度谱也是一个峰值搜索问题:目标角度对应角度谱上的峰。但多目标场景下,角度谱上会有多个峰,且幅度和目标的反射面积相关。findAllPeak 在这里的作用,是把角度谱的峰值和前面得到的距离-速度对配对起来。
常见的配对逻辑是:对每个距离-速度对,在那个距离门和速度门下的天线维做角度 FFT,得到一个角度谱,然后在角度谱上找峰。理想情况是一个目标一个峰,实际会出现同一距离-速度处的两个峰来自两个不同角度的目标——这需要让 findAllPeak 同时返回多个峰,而不是只取最高峰。我会设置distance=3(角度谱的主瓣宽度大概在半个波束宽度),并把height设在噪声底上二分之一处,然后把所有过阈值的峰全部输出,再通过聚类把这些峰归到目标点云。
这里的常见失误是只取主峰,导致两个靠近的目标在角度维被合并成一个,点云数量变少。另一个失误是把角度谱的旁瓣当成第二个目标。我后来用了一个“峰有效性判定”:主峰旁边的次级峰,如果它的位置与主峰的角度差小于天线的半波束宽度,且幅度低于主峰 3dB,就视为旁瓣直接丢弃,不参与配对。这个逻辑写在 findAllPeak 的封装函数里,而不是在调用之后才做,能少写很多事后补救的代码。
4. 雷达峰值搜索的避坑指南:那些让目标“凭空消失”的细节
4.1 距离门两端的目标被截断
现象:目标明明就在雷达正前方很近(小于最小距离),或刚好在最大检测距离附近,CFAR 能检测到,但 findAllPeak 返回的峰值索引偏到边界,距离值明显不对。
原因:FFT 之后的距离谱在索引 0 附近有直流耦合,在索引 N/2 附近有镜像能量。距离门两端的目标峰会被这些“结构性过高”的边界值淹没,或者峰的另一半超出序列范围,导致prominence计算时找不到完整的左右谷底。
解决:搜索前先裁剪序列,比如把距离维索引限制在 1 到 N/2-2 之间;对于接近边界的峰,单独用抛物线插值从相邻三个点插值出峰位,不要再调用完整的 find_peaks。边界目标我建议直接交给 CFAR 的“多普勒折叠”处理逻辑,不要依赖峰值搜索的精度。
4.2 旁瓣重复峰:最小间距设个数字就完事?
现象:同一个强目标,在距离维返回了三个相距 2~3 个距离门的峰,和目标个数完全对不上。
原因:distance参数设置得太小。这通常是因为只按主瓣宽度估算,却忽略了加窗后旁瓣的间隔可能恰好是主瓣宽度的一半。有些窗函数(比如 Blackman-Harris)旁瓣衰减快但旁瓣位置离主瓣近。
解决:用数值法直接量一下典型目标峰的主瓣宽度。可以先用弱目标(接近噪声底)做一次搜索,测出主瓣两个零值点之间的格点数,再把distance设为该格点数的 1.5 倍。我在代码里会写一个estimate_mainlobe_width()函数,离线跑一遍,把值打到配置里,而不是拍脑袋设 3 或 5。
4.3 强目标分裂成两个峰:峰值搜索赢了,检测输了
现象:一个金属角反射器目标,在距离谱上出现两个高度差不多的相邻峰,各自距离差约一个距离门。findAllPeak 把它们当成两个目标,导致目标数翻倍。
原因:目标反射占据了多个距离门,且幅度在相邻门之间波动,形成局部极小值。这常见于目标距离正好在距离门边界一半处,能量平均分配到两个格点。
解决:先用峰宽度属性(widths)判断,如果两个相邻峰之间的距离小于主瓣宽度,且两个峰之间的谷底和峰顶的比例高于 0.8,那么合并为一个目标,峰位取两个峰的幅度加权平均。具体实现时,我把这个判定放在 find_peaks 返回之后,而不是调用前,因为只有看到峰属性才能做这个决策。
4.4 噪声底不平,固定 height 失效
现象:相同的目标,在近距(比如 5 米)能被检测,在远距(比如 50 米)却搜不到峰,但 CFAR 明确告诉你 50 米处检测到了。
原因:距离平方反比导致远距回波显著变小,近距残留噪声和天线耦合反而大。固定的height阈值在近距噪声底之上,在远距却比噪声还高。
解决:不直接对幅度谱用 height,而是对“CFAR 输出的噪声归一化幅度谱”用 height。即spectrum /= noise_floor_est,然后height=1.5含义就是超过噪声底 1.5 倍算峰。这个方法比设置绝对幅度可靠,但需要预处理把每个距离门的噪声底存下来。如果你没有噪声底,可以退而求其次,用prominence替代height,因为 prominence 本质上是相对值。
4.5 雷达模式差异:FMCW 和 FSK 的峰值含义不能互换
现象:同一段代码,从 FMCW 模式切到 FSK 模式,目标距离和速度全乱了。
原因:FMCW 通过差频频率测距和测速耦合,而 FSK 通过相邻 chirp 的相位差测速,距离则靠多频相位解�。findAllPeak 找的峰在两种模式下代表的物理量完全不同——FMCW 的峰是“中频频率”,FSK 的峰可能是“角度谱或相位谱”。
解决:在封装 findAllPeak 时,把“峰索引到物理量”的换算函数作为参数传入,不同雷达模式传入不同的映射函数。我吃过一次亏,把 FSK 模式下角度谱上的峰当成距离峰,输出了一组负距离,后来才意识到模式切换时换算关系没有更新。现在我的建议是:峰值搜索代码不做模式假设,只返回峰索引和峰高,后续物理量换算单独写,避免把两个模式耦合在一起。
5. 进阶:把 findAllPeak 封装成雷达目标检测的验证工具
5.1 峰到目标(peak_to_target)的封装与输出
把 findAllPeak 从单纯的数学函数变成雷达目标列表,关键是输出结构。我习惯用一个 dataclass 保存目标:距离(米)、速度(米/秒)、角度(度)、信噪比(dB)、峰宽(格点数)。封装好的函数应当接受一个“谱数据容器”和一组峰值搜索参数,返回一个目标列表。下面的代码展示这种封装的核心部分,包含了归一化、边界裁剪和亚格点插值。
import numpy as np from scipy.signal import find_peaks from dataclasses import dataclass @dataclass class RadarTarget: range_m: float velocity_ms: float azimuth_deg: float snr_db: float peak_width: int def peak_to_target(range_spectrum, dist_per_bin, search_params): # 裁剪边界,避免直流和镜像干扰 start = 1 end = len(range_spectrum) - 2 spec = np.abs(range_spectrum[start:end]) spec = spec / np.max(spec) # 归一化到相对幅度 peaks, props = find_peaks( spec, height=search_params["height"], distance=search_params["distance"], prominence=search_params["prominence"] ) targets = [] for p, h in zip(peaks, props["peak_heights"]): # 用峰值及其相邻两点做抛物线插值,得到亚格点峰位 if p == 0 or p == len(spec) - 1: idx = p else: y0, y1, y2 = spec[p-1], spec[p], spec[p+1] delta = 0.5 * (y0 - y2) / (y0 + y2 - 2*y1) idx = p + delta # 还原到原始索引 range_idx = idx + start dist = range_idx * dist_per_bin # 信噪比近似:峰高 / 该序列中值 noise_level = np.median(spec) snr = 10 * np.log10(h / max(noise_level, 1e-9)) targets.append(RadarTarget( range_m=dist, velocity_ms=0.0, # 由多普勒维搜索填入 azimuth_deg=0.0, # 由角度维搜索填入 snr_db=snr, peak_width=props["widths"][list(peaks).index(p)] if "widths" in props else 0 )) return targets这个封装里最值得注意的不是峰值搜索本身,而是峰位插值。因为离散 FFT 的距离门分辨率有限,目标落在两个距离门中间时,不插值会引入至少半个距离门的系统误差。抛物线插值能把误差降到 1/10 格左右。信噪比的计算也是实际中比较好用的近似:用中值估计噪声底,比均值更抗强目标影响。
5.2 和 CFAR 联动:峰值搜索不是用来替代检测的
有的同学尝试用 findAllPeak 替代 CFAR 做目标检测。我的观点是,对单目标高信噪比场景这样做没问题,但雷达数据处理进入多目标、杂波环境后,峰值搜索的假警率会高到没法用。CFAR 的价值在于提供了自适应阈值,随距离、多普勒门的噪声底变化而调整;findAllPeak 的价值在于精确定位和峰属性分析。两者结合的正确姿势是:
先用 CFAR 得到一组检测门位置。然后以每个检测门为中心,取一个 3×3 或 5×5 的距离-多普勒邻域,在邻域内用峰值搜索找最大峰,再用这个最大峰的索引替换 CFAR 的粗糙索引。这样做不会增加太多计算量,但能明显提升目标位置的精度。更重要的是,当 CFAR 因为栅栏效应漏检时,峰值搜索还能在相邻门发现能量峰,作为“疑似目标”补回来。
我在实际项目里,还让 findAllPeak 的输出反向校验 CFAR:如果峰值搜索找到的峰距离 CFAR 检测点太远(超过 2 个距离门),我就要怀疑 CFAR 检测点是不是杂波虚警,或者峰值搜索是否被旁瓣干扰。这个互相校验的逻辑,比任何单一算法都更能帮助排查问题。
5.3 用仿真验证峰值搜索的正确性:三种波形各写一段回归用例
做雷达信号处理板驱动时,没有真实天线也能先验证峰值搜索逻辑。我通常用三组仿真数据来做回归:单目标回波、双目标等幅回波、双目标幅度相差 10 倍的回波。单目标验证基本峰位精度,双目标等幅验证距离分辨率,双目标强/弱验证prominence筛选能力。
import numpy as np from scipy import signal def synth_ifc(sample_rate, num_samples, distances, amps): t = np.arange(num_samples) / sample_rate sig = np.zeros(num_samples, dtype=complex) # FMCW 斜率 slope = 50e12 c = 3e8 for d, a in zip(distances, amps): f_if = 2 * slope * d / c sig += a * np.exp(2j * np.pi * f_if * t) return sig # 用例:近距强目标 10m (1.0),远距弱目标 30m (0.3) sig = synth_ifc(10e6, 256, [10, 30], [1.0, 0.3]) r_fft = np.fft.rfft(sig) r_mag = np.abs(r_fft) # 找峰 peaks, props = signal.find_peaks(r_mag, height=0.2, distance=5, prominence=0.1) print("峰值索引:", peaks, "对应距离:", peaks * (3e8/(2*50e12*(256/10e6))))这段仿真里,距离 10m 和 30m 的对应中频频率分别是 200kHz 和 600kHz,FFT 分辨率是 39kHz 左右,两个峰相隔超过 10 个格点,distance=5足够分开。但如果你把距离改成 10m 和 10.5m(相差 0.5m),对应中频频率差 10kHz,FFT 分辨不出,distance设置也没用。这说明峰值搜索的上限受限于 FFT 分辨率,不是调参数能突破的。想提高距离分辨率,得提高 FMCW 带宽或增加采样点数,而不是在峰值搜索里做文章。
仿真回归测试跑不过,基本都是参数设置和分辨率不匹配造成的。我会把每一组仿真对应的预期峰位写成一个 yaml 配置,每次改代码后跑一遍,只要有一个用例的峰位偏差超过半个距离门就直接报警。这个习惯帮我拦截了至少三次因为 FFT 补零方式改变导致的距离索引偏移问题——那些问题在人眼观察时很难发现,但回归测试一跑就现原形。
一个多年留在我心里的踩坑记忆是:有一版峰值搜索代码为了提高处理速度,把距离维序列做了降采样,结果近距目标峰被平均掉,目标彻底消失。当时我在车里测试了整整一天,最后发现是降采样把目标的峰宽抹平了。从那以后我给自己定了个规矩:峰值搜索前的任何降采样、去均值、归一化操作,都必须保留峰宽大于降采样窗口宽度的保证。现在写每一版雷达数据处理代码,我几乎闭眼都能说出 findAllPeak 该设什么距离、该在什么时候用 prominence 而不是 height,但每次遇到新雷达芯片,我还是会先跑一遍仿真回归,再拿真值验证。希望这些用真金白银换来的经验,能帮你省下一点调试时间。
本文还有配套的精品资源,点击获取