PLFM雷达波形设计:线性调频与相位编码融合的脉冲压缩实践

发布时间:2026/11/2 10:39:02
PLFM雷达波形设计:线性调频与相位编码融合的脉冲压缩实践

1. PLFM_RADAR 项目定位与波形设计思路

1.1 什么是 PLFM:把线性调频和相位编码揉在一根脉冲里

PLFM_RADAR 这个项目,我在立项时先把名字拆开了:PLFM 是 Phase-coded Linear Frequency Modulation,相位编码线性调频;RADAR 不用解释,就是雷达。这个项目的核心就一句话:在一根脉冲宽度内,同时叠加线性调频和相位编码两种调制,再通过匹配滤波器做脉冲压缩,从回波里提取目标的距离和速度。

为什么会想出这种东西?因为在设计雷达波形时,我一直在跟两个老伙计打交道:LFM(线性调频)和相位编码。LFM 的优点是工程上非常成熟,理论清晰,匹配滤波后的距离分辨率完全由带宽决定,多普勒容限也相当好;缺点是匹配滤波后的距离旁瓣高达 -13.2dB,这个旁瓣水平在强目标旁边探测弱目标时,很容易把弱目标淹没。相位编码信号的优点是频谱能量被“摊开”,不容易被简单截获,而且接收机用匹配滤波解调时,自身具备一定的抗干扰能力;缺点是对多普勒很敏感,目标一运动,邻近码元间就产生相位变化,匹配滤波效果急剧下降。

PLFM 的思路就是取两者之长:线性调频负责维持多普勒容限和距离分辨率,相位编码负责压低截获概率、打散频谱能量。单看每一项指标,它都不是最顶尖的,但组合在一起,能兼顾探测能力、低截获特性和工程可实现性。这也是我在 PLFM_RADAR 里选择它的理由。

1.2 PLFM 的数学表达和物理含义

我习惯先把信号形式写出来再谈实现。PLFM 信号的复包络可以写成:

s(t) = rect(t/T) · exp(j·π·k·t²) · c(⌊t/Tc⌋)

其中 rect(t/T) 表示宽度为 T 的矩形包络,k = B/T 是线性调频率,B 是信号带宽,c(⌊t/Tc⌋) 是相位编码序列在第 ⌊t/Tc⌋ 个码片处的取值。假如采用二相编码,c(n) 取 +1 或 -1;若用四相编码,则取 1、j、-1、-j 其中之一。

这个公式看起来简单,但设计时要小心三点。第一,码片宽度 Tc 必须远小于脉冲宽度 T,通常每个线性调频脉冲里要包含几十个以上相位编码码片,编码才有意义。第二,相位编码的 chip 率要和线性调频的瞬时频率变化对齐,否则调频和编码之间存在不可控的耦合,匹配滤波时会出现额外的畸变。第三,Barker 码、m 序列、随机序列的旁瓣特性不同,要结合场景选择。

我在 PLFM_RADAR 里验证了两种编码:一是 13 位 Barker 码,因为它的非周期自相关旁瓣峰值能压到 1/13,约 -22.3dB,作为试探足够干净;二是自己生成的伪随机 m 序列,虽然旁瓣不会像 Barker 码那样完美,但在长序列下,旁瓣包络会趋向于 -10·log10(N),N 越大,旁瓣越平坦,适合做干扰条件下的稳定性试验。

1.3 系统指标设计和实验场景规划

既然标题是 PLFM_RADAR,我第一次迭代想清楚的问题,就是整套指标要在什么平台上验证。我最终选择的做法是“仿真先行,SDR 实测跟上”。仿真用 Python 纯粹跑数学链路,SDR 硬件用 USRP B210 做中频收发的验证。

整机指标按一个低成本实验雷达来定:

参数数值设计考虑
载频5.8GHz工业与实验频段易获取设备
信号带宽20MHz距离分辨率约 7.5 米
脉冲宽度100μs兼顾作用距离与占空比限制
编码序列13 位 Barker 或 63 位 m 序列验证短码与长码两种形态
脉冲重复周期1ms对应最大不模糊距离 150km
采样率50MHz满足 20MHz 复基带信号的过采样要求
速度测量范围±15m/s取决于重频和载频,可再扩展

这套指标算不上高大上,但是能覆盖大部分城市交通、无人机等慢速目标的探测场景。很多人做雷达一上来就想要巨大带宽,其实在 SDR 平台上带宽越大,对采样率、存储和实时处理的要求越高,第一版能把 20MHz 做通,后面扩带宽自然水到渠成。

2. 核心细节解析:波形生成与匹配滤波实现

2.1 用 Python 快速生成 PLFM 波形

我相信把波形先在仿真里跑干净,再上硬件,能省掉大量现场排查的时间。PLFM 波形生成在 Python 里非常直接,核心代码如下。

import numpy as np fs = 50e6 # 采样率 50 MHz T = 100e-6 # 脉冲宽度 100 us B = 20e6 # 带宽 20 MHz N_c = 13 # 相位编码码片个数,这里先用 13 位 Barker Tc = T / N_c # 码片宽度 # 1. 生成基础线性调频信号 t = np.arange(0, T, 1/fs) k = B / T lfm = np.exp(1j * np.pi * k * t**2) # 2. 生成 13 位 Barker 码 barker13 = np.array([1, 1, 1, 1, 1, -1, -1, 1, 1, -1, 1, -1, 1], dtype=float) # 3. 将编码序列扩展成与 LFM 同样长度的信号 code_samples = int(round(Tc * fs)) code_wave = np.repeat(barker13, code_samples)[:len(t)] # 4. 合成 PLFM 信号 plfm = lfm * code_wave

这里有一个我反复强调的细节:np.repeat之后一定要做长度截断或填充,因为Tc * fs未必是整数。采样点数和码片宽度对不齐,匹配滤波输出会出现毫米级别的距离偏移,后面测角、测距就全歪了。我前面排错时最多的问题就是这个。

2.2 匹配滤波器:为什么必须是参考信号的时间反褶共轭

很多初学者会把匹配滤波理解成“拿信号和自身做相关”,这在数学上没错,但工程实现有个常见的坑:匹配滤波器的冲激响应是发射信号的时间反转,再取共轭。

matched_filter = np.conj(plfm[::-1]) # 匹配滤波输出 compressed = np.convolve(plfm, matched_filter, mode='full')

注意这里用的是plfm[::-1]而不是plfm。因为卷积的定义里需要做时间反转,如果不反褶,得到的是互相关而不是卷积,峰值的位置会左右颠倒。还有一点,匹配滤波只能在“发射信号是确定已知”的前提下做。如果发射链路上有非线性失真、载波泄漏,匹配滤波器的输出就会出现一堆假目标,这也是我后来在实测试验里花时间最多的部分。

PLFM 信号匹配滤波之后的峰值形状跟纯 LFM 不完全相同。纯 LFM 脉压后主瓣附近呈 sinc 函数形状,第一旁瓣在 -13.2dB;PLFM 因为叠加了相位编码,短码时旁瓣结构与 Barker 码的自相关函数类似,能做到更低。我用 13 位 Barker 码做 PLFM 仿真时,未加窗前第一旁瓣大约 -22dB 左右,肉眼已经比 LFM 干净很多。

2.3 加窗处理:旁瓣是被压下去了,但主瓣也胖了

旁瓣这个东西,在强目标旁边尤其讨厌。一个 30dB 的大目标,它的 -22dB 旁瓣仍然相当于一个 8dB 的小目标,很容易造成虚警。所以我在匹配滤波之前会在参考信号上做加权,也就是工程上常说的加窗。

window = np.hanning(len(plfm)) matched_filter = np.conj(plfm[::-1]) * window[::-1] compressed = np.convolve(plfm, matched_filter, mode='full')

不过要明确一点:加窗是拿距离分辨率和信噪比换旁瓣抑制的。汉明窗能把第一旁瓣压到 -40dB 以下,但主瓣宽度会从原来的约 1/B 展宽到约 1.5/B,距离分辨率下降;同时匹配滤波的匹配增益也会损失一些。所以加不加窗,加什么窗,要看场景:我建议在探测弱小目标的场景里用汉明窗,在需要分辨两个近距离目标的场景里优先保主瓣,不加窗或者用泰勒窗。泰勒窗是介于两者之间的好选择,我在后续版本里也引入过。

3. 实操过程:从回波模拟到距离多普勒二维处理

3.1 目标回波建模与仿真链路搭建

有了发射波形,第二步就是让它在仿真环境里“飞”起来。我构造了一个包含多个目标的回波模型:两个静止目标,分别在 300 米和 1200 米;一个匀速运动目标,初始距离 700 米,径向速度 10m/s;再加一个高斯白噪声本底。这样一个回波模型能同时覆盖距离维和速度维的算法验证。

回波模拟的简化公式是:

rx(t) = Σ A_i · s(t - τ_i) · exp(j·2π·f_d_i·t) + noise

其中 τ_i = 2R_i/c 是第 i 个目标的时延,f_d_i = 2v_i/λ 是多普勒频移,A_i 是幅度衰减。我把这三个目标的回波加在一起,再用匹配滤波做脉冲压缩。这个阶段我使用脉冲间相参积累,即把多个重复周期的脉冲回波排成一个二维矩阵,行是快时间(距离维),列是慢时间(速度维)。

3.2 距离多普勒处理:两次 FFT 走天下

雷达最经典的处理就是距离多普勒二维 FFT。第一步,对每个脉冲回波做匹配滤波,得到距离维压缩后的数据。第二步,在同一个距离单元里,对慢时间维做 FFT,得到速度维频谱。这样最终输出的二维矩阵,就是距离-多普勒图,简称 RD 图。

rd_map = np.zeros((n_pulses, n_range_bins), dtype=complex) for i in range(n_pulses): rd_map[i, :] = np.convolve(rx_pulse[i], matched_filter, mode='same') # 距离维已经是压缩后的,接下来对慢时间维做 FFT rd_spectrum = np.fft.fftshift(np.fft.fft(rd_map, axis=0), axes=0)

处理完之后,目标的峰值应该出现在对应的距离速度格子里。仿真结果很清晰:300 米和 1200 米两个静止目标出现在多普勒零频附近,700 米运动目标不仅位置对,而且速度维度上偏离了零频,根据多普勒频移反算出来的速度约 10m/s,和预设完全一致。

这里有个工程细节,我第一次做二维 FFT 时因为脉冲数太少,速度维出现严重的栅栏效应。脉冲重复周期是 1ms,10ms 积累时间只有 10 个脉冲,频率分辨率只有 100Hz,对应到速度分辨率是 2.58m/s。于是我提高脉冲积累数到 64 个,速度分辨率立刻提升到约 0.4m/s,目标峰值在速度维上就稳定了。可以说,慢时间积累数直接决定测速精度,仿真时别急着优化算法,先把积分时间拉够。

3.3 CFAR 检测与目标提取

RD 图做完以后,还不算完整的探测结果。如果只是把幅度图显示出来人肉找目标,那只能叫演示,不能叫雷达。我给它接上恒虚警率检测,也就是 CFAR。我选了单元平均 CFAR,在二维平面上滑动窗口,对每个待检单元估计噪声功率,再用门限系数判断是否属于目标。

from scipy.signal import convolve2d # 距离-多普勒平面上的二维 CFAR noise_avg = convolve2d(abs_rd, np.ones((2*n_guard+1, 2*n_guard+1)), mode='same') / ((2*n_guard+1)**2) threshold = noise_avg * alpha detect_map = abs_rd > threshold

单元平均 CFAR 的门限系数 α 跟虚警概率 Pfa 之间的关系是 α = Pfa^(-1/N) - 1,N 是参考单元数。我在程序里设置 Pfa = 1e-5,参考单元两侧各取 16 个,保护单元取 4 个。因为仿真数据信噪比足够高,检测结果非常稳,目标全部检出,虚警为 0。但在真实外场数据里,杂波不是均匀的,单元平均很容易在强杂波边缘产生“旁瓣虚警”,后面值得换用有序统计 CFAR。

3.4 多目标场景下的脉冲压缩旁瓣问题

多目标场景下最折磨人的,就是强目标旁瓣掩盖弱目标。我在仿真里故意加了一个非常强的静止目标在 400 米处,幅度比 1200 米目标高 30dB。未加窗时,400 米目标的旁瓣尾巴直接把 1200 米目标埋掉,RD 图上一片模糊。加上汉明窗之后,旁瓣被压到 -40dB 以下,1200 米目标重新浮现。这个过程我反复验证过,也在外场数据里遇到过类似情况。所以建议大家在调试多目标雷达时,边看 RD 图边注意旁瓣高度,千万不要只盯着主峰。

4. 常见问题与排查技巧实录

4.1 问题排查速查表

我想把这几周攒下的问题整理成一张可以直接对照的速查表,每个问题都是我真实踩过的。

现象可能原因排查方法
匹配滤波后主峰不在预期距离上采样点数与码片宽度不对齐检查Tc * fs取整后的长度截断,统一码片边界
RD 图速度维出现模糊目标脉冲积累数不足或重频歧义增加积累脉冲数,检查目标多普勒是否超过 PRF/2
强目标旁边出现对称假峰载波泄漏或 I/Q 不平衡在射频链路上加泄漏校正,检查零中频信号直流分量
加窗后峰值变宽但仍可接受但信噪比下降窗函数损耗改用泰勒窗或凯泽窗,以可接受的旁瓣换取较低损耗
相位编码波形匹配滤波旁瓣异常高编码序列没有与 LFM 同步起止确保编码序列从脉冲起点对齐,不要额外延时
目标速度反算符号反了FFT 后频谱单边取错做fftshift后从零频向两侧取,不要从数组头部直接读

4.2 实操心得:为什么 SDR 实测时 PLFM 更容易受失真影响

仿真做得再好,到了 SDR 实测环节,PLFM 的参数敏感性一下子就暴露出来了。原因在于相位编码本质上是把信息藏在相位跳变里,而射频前端任何非线性失真都会产生相位噪声,比如本振的相位噪声、功放压缩、ADC 的量化噪声都会直接侵蚀相位精度。我在 USRP B210 上做 5.8GHz 外场小实验时,第一次测出来的匹配滤波输出旁瓣比仿真高了近 10dB,排查到最后发现是发射链路增益过高,功放进入非线性区,相位编码跳变被“抹圆”了。解决办法是降低发射功率,让信号增益避开 1dB 压缩点,旁瓣立刻恢复正常。

这里给大家一个非常实在的补测建议:实测前先在接收机里直接采集发射机的参考波形,用这个参考波形做匹配滤波,而不要用仿真里的理想波形。因为理想波形和实际链路输出之间存在系统性差异,匹配滤波器的“匹配”就失效了。用实测参考波形之后,我的旁瓣水平从 -15dB 拉回到 -25dB 左右,效果立竿见影。

4.3 相位编码长码与短码的取舍

Barker 码最长的已知序列只有 13 位,继续扩展下去没有更长的完美序列。所以当系统需要更长的编码长度来进一步压低截获概率时,只能用 m 序列等伪随机序列。我在 PLFM_RADAR 第二阶段把编码长度扩到 63 位,匹配滤波后旁瓣不再有严格的窄峰,而是整体落在 -18dB 附近,比 13 位 Barker 差一些,但频谱更加“白”。这个取舍取决于工程任务:对抗单频窄带干扰时,长码的频谱扩展效果更好;对抗强杂波附近的弱目标时,短码加窗后的旁瓣更低。二者没有绝对优劣,只有合不合适。

5. 经验沉淀:从仿真到实测的几点共识

5.1 先解决时间同步,再谈波形设计精度

这个项目做完之后,我最大的体会是,波形算法本身并不是最难的,最难的是把时间基准搞得足够干净。PLFM 信号的距离测量本质上是通过匹配滤波输出峰值位置反推时延,而峰值位置对应的时间精度直接受采样时钟和脉冲触发同步影响。仿真里所有信号都是理想对齐的,实测时一旦 PRF 触发抖动超过一个采样点,距离像上就会出现横向拉条,目标峰值忽左忽右。我的做法是在每轮脉冲发射前插入一个同步头脉冲,接收端拿同步头做相关校准,把所有脉冲的时间基准拉到同一个原点上。这个技巧让我省掉了一整天的倒查时间。

5.2 距离分辨率与多普勒分辨率永远在打架

雷达设计里的一个老生常谈,在 PLFM_RADAR 里表现得特别明显:距离分辨率靠带宽,速度分辨率靠积累时间,测速范围靠脉冲重复频率。想要距离看得细,就要增加带宽;带宽一增加,采样率就要跟着涨,数据量变大,存储和处理压力上升。想要速度看得准,就要延长积累时间;积累时间一长,运动目标在积累窗口内可能已经跨了多个距离单元,出现距离走动,反而导致速度维模糊。这个矛盾没有一劳永逸的解法,只能按任务场景折衷。我在项目里用的折衷办法是:慢速目标场景用长积累,快速目标场景用短积累加运动补偿。这也提醒我,雷达参数设计永远不是单点最优,而是一个全局优化问题。

5.3 外场角度的开门经验

最后说一个外场实验的小教训,也算是一点实用经验。我最初把天线对准一片楼宇区域测试,结果 RD 图里全是静止强反射体,运动目标峰值被死死压在旁瓣里。后来换到相对空旷的操场,把天线稍微上仰,减少地面多径,目标才从 RD 图上干净地“浮”出来。所以做雷达实测,环境选择本身就是一个算法设计步骤。我建议所有做类似项目的朋友,第一轮外场测试尽量选在后向散射弱、反射面干净的地方,先把算法链路跑通,再去挑战强杂波环境。否则杂波和旁瓣叠加在一起,你根本分不清是波形的问题、算法的问题还是环境的问题。

PLFM_RADAR 这个项目做到现在,我不敢说波形方案有多先进,但整个过程让我把线性调频、相位编码、匹配滤波、二维 FFT、CFAR 检测这条链路由浅入深完整走了一遍。仿真与实测互相印证的模式,也让我后续做新波形时多了一份底气。如果你也在折腾雷达信号处理,建议先动手生成一段 PLFM 波形,跑通匹配滤波,再往里加目标、加噪声、加杂波,一步步来。这套路虽然朴素,却极其有效。