简介:面向雷达通信一体化系统研究人员的CPM-LFM信号抗干扰分析资源,系统覆盖射频噪声、移频、噪声调频与噪声卷积四类典型干扰的建模仿真与效果评估。资源共18个文件,包含11个MATLAB脚本和7个figure图形文件,脚本用于完成CPM调制、相位状态分析、维特比解调、干扰信号生成及干信比计算,图形则直观展示干扰前后的波形与频谱对比,压缩包约2.5MB,便于快速下载与复用。已有182人学习下载。脚本从状态网格、脉冲响应、解调性能等多个维度展开,可帮助读者快速复现各类干扰场景,观察干扰对信号距离估计、相位连续性和解调效果的影响。对于从事雷达通信一体化波形设计、干扰抑制或接收机优化研究的工程师和学生,这套代码与仿真结果提供了直接可用的实验平台和优化参考。
1. 各式干扰对 CPM-LFM 信号干扰效果分析:把压制效果的评估做对才是重点
CPM-LFM 信号在大带宽探测、雷达通信一体化和低截获概率波形设计里出现得越来越密。它把连续相位调制和线性调频放在同一条相位轨迹上,既靠 LFM 的大时宽带宽积拿到脉冲压缩增益,又用 CPM 的相位连续特性压低带外泄漏。工程上真正难的从来不是怎么把这种信号生成出来,而是把干扰效果的评估做对:噪声调频、单频窄带、梳状谱、转发式欺骗在相同干信比下对输出的影响完全不是一个量级,带宽口径、相参性和统计样本都会明显改变结论。这篇文章从 CPM-LFM 信号建模、干扰建模说起,给出最小可复现的评估脚本和一批常见避坑点位,适合正在做波形设计、干扰效果评估和对抗仿真的工程师直接照着落地。
2. 先把 CPM-LFM 信号模型立住:生成方式与四个关键参数
2.1 LFM 之外为什么要叠加连续相位
线性调频信号的相位本来就是频率的积分,瞬时频率按 k=B/T 线性扫,相位是一条光滑的二次曲线。匹配滤波器能在大时宽里把能量聚起来,输出脉冲宽度被压到接近 1/B,因此处理增益 G≈10lg(TB) 是这个波形的立身之本。
但 LFM 单独用有两个不好处理的问题。时频图是一条直线,截获接收机做主特征识别很容易把它认出来;如果要同时传数据,符号边界直接跳相会迅速抬升带外频谱,脉压旁瓣跟着恶化。CPM 补的正是这两块:发射数据先经过相位脉冲整形,再叠加进累积相位,符号在任何时刻都不会突变。CPM-LFM 把两者叠在一起,LFM 负责拉开带宽、提供脉冲压缩收益,CPM 负责让相位“滑着走”,干扰方很难用脉冲边沿去估计码元同步。
从干扰评估角度看,这个叠加带来的直接后果是:接收机只需要一个与完整 CPM-LFM 波形匹配的副本做脉压,而干扰方若想做转发式欺骗,就必须把 LFM 扫频规律和 CPM 数据相位一起复制,工程难度比单纯复制一个常规线性调频脉冲高不少。这为后面讨论各类干扰的带宽匹配和相参性埋了个重要前提。
2.2 在 Python 里生成一个干净的 CPM-LFM
我习惯用 Python 的 numpy/scipy 做最小验证,生成这段信号也就十几行。重点不在写得多花哨,而在把“相位连续”这个点做扎实。
import numpy as np from scipy import signal Fs = 200e6 # 采样率 200 MHz T = 10e-6 # 时宽 10 us B = 20e6 # 调频带宽 20 MHz Ns = int(Fs * T) # 总采样点数 t = np.arange(Ns) / Fs # LFM 部分:瞬时频率从 0 线性扫到 B,相位是频率的积分 k = B / T s_lfm = np.exp(1j * np.pi * k * t**2) # CPM 数据部分:h=0.5,用累加方式保证符号边界相位连续 h = 0.5 Tsym = 1e-6 nsym = int(T / Tsym) data = 2 * np.random.randint(0, 2, nsym) - 1 # 双极性 ±1 seg = int(Tsym * Fs) phase_cpm = np.zeros(Ns) phase_start = 0.0 for n in range(nsym): idx = slice(n * seg, (n + 1) * seg) inc = np.pi * h * data[n] / seg phase_cpm[idx] = phase_start + inc * np.arange(seg) phase_start += np.pi * h * data[n] # CPM-LFM 复基带信号 s = s_lfm * np.exp(1j * phase_cpm)这段代码把信号分成两层:LFM 相位由np.pi * k * t**2直接给出,CPM 数据相位则用一个循环把每个符号的相位增量累加进去。每个符号内部相位线性变化,符号末尾的相位值正好成为下一个符号的起点,所以整体相位轨迹没有跳变。
参数表里需要重点解释的是inc = np.pi * h * data[n] / seg:它表示在该符号持续时间内,每个采样点增加的相位是固定值。h 是调制指数,取 0.5 时每个 ±1 符号贡献 ±π/2 的相位增量,这是最小频移键控那类 CPM 的经典配置。seg 是每个符号对应的采样点数,直接由Tsym * Fs决定。最后把两段相位相乘取指数,得到完整基带信号s。
| 参数 | 仿真值 | 作用与影响 |
|---|---|---|
| Fs | 200 MHz | 至少是信号带宽的数倍,否则相位展开和脉压都会失真 |
| T | 10 us | 时宽,直接决定脉压增益的 T 分量 |
| B | 20 MHz | 调频带宽,决定距离分辨率和带宽口径 |
| h | 0.5 | 调制指数,影响数据项附加带宽和旁瓣抑制 |
| Tsym | 1 us | 码元宽度,决定数据速率和信息带宽 |
2.3 时宽带宽积、调制指数、符号率对干扰评估的影响
这几个参数不只是“信号长相”问题,它们决定了后面评价干扰效果的坐标系。TB 乘积这里等于 20e6×10e-6=200,换算成处理增益约为 23 dB。这个数字是后面所有干信比讨论的基准:想让脉压输出信噪比下降 3 dB,压制式干扰至少要在有效带内抬高约 20 dB 的输入功率,否则干扰只是给底噪“挠痒痒”。
调制指数 h 会扩大 CPM 数据项的频谱范围。h 越大,信息相位变化越剧烈,信号有效带宽会比纯 LFM 的 B 更宽。仿真时如果把 h 调大而干扰带宽还按原 B 对准,部分干扰能量就会落在带外,脉压输出自然会变好,但这不是干扰真的变弱,而是你换了被干扰对象。符号率同理,Tsym 缩短会使数据分量带宽提升,干扰与信号的频谱重叠比例改变。
所以我一般建议做干扰对比的实验室把信号参数固定成一个基准,h 取 0.5、符号率要明显低于扫频带宽,这样 CPM 附加带宽对频谱重叠的影响可以控制在小数分贝内。后续所有干扰效果分析都基于这个基准信号展开,否则任何一个结论换一套参数都无法复现。
3. 各式干扰的数学模型与选择逻辑
3.1 噪声调频干扰:宽带压制噪声常用的模型
噪声调频干扰是压制式干扰里最常用的样式。它的思想是先产生一个带宽受限的高斯噪声,再用这个噪声去调制干扰载波的瞬时频率,使干扰功率分散到一个较宽的频带内。对 CPM-LFM 这类大带宽信号,干扰带宽只有贴近甚至略超过信号带宽,才能把干扰功率有效注入接收机通带。
基带仿真里不需要真正去算载波,直接用 cumsum 模拟频率积分即可:
def noise_fm_jammer(N, Fs, Bj, power, seed=0): """带宽受限噪声调频干扰,Bj 控制有效干扰带宽""" rng = np.random.default_rng(seed) sigma = 1.0 n = rng.standard_normal(N) # 先对噪声做低通,限制调制噪声本身的频带 b = signal.firwin(101, (2.0 * Bj) / Fs) nf = signal.lfilter(b, 1.0, n) # 调频灵敏度:让噪声幅度变化对应到 Bj 量级的瞬时频偏 Kf = Bj / np.std(nf) phase = 2.0 * np.pi * Kf * np.cumsum(nf) / Fs j = np.exp(1j * phase) j = j * np.sqrt(power / np.mean(np.abs(j)**2)) return j代码里signal.firwin先对高斯白噪声做低通,得到带宽受限的调制噪声;cumsum是对它积分,即从噪声到相位的转换。Kf = Bj / np.std(nf)是调频灵敏度校准,它把噪声波动和瞬时频率偏移联系起来,保证干扰能量主要落在 Bj 以内,而不是靠 FFT 看才知道实际带宽是多少。
这里有个容易忽略的点:噪声调频干扰的功率谱密度形状接近高斯形,不是矩形,所谓“带宽 Bj”通常指半功率带宽。评估时如果只看频谱外包络,容易把干扰带宽估计偏高,后面第 5 章我会专门说这个坑。
3.2 噪声调幅干扰与单频窄带干扰:简单但经常被低估
噪声调幅干扰的模型是把带宽受限噪声调制到载波幅度上。它和噪声调频最大的差别是:调频干扰的瞬时频率在大范围扫动,平均功率谱比较平坦;调幅干扰只是载波幅度上下抖动,频带更窄、峰功率有时反而更高。
def am_jammer(N, Fs, fc, m, Bj, power, seed=0): """噪声调幅干扰,m 为调幅深度,Bj 为调制噪声带宽""" rng = np.random.default_rng(seed) t = np.arange(N) / Fs n = rng.standard_normal(N) b = signal.firwin(101, (2.0 * Bj) / Fs) nf = signal.lfilter(b, 1.0, n) nf = nf / np.std(nf) # 归一化 am = 1.0 + m * nf j = am * np.exp(1j * 2.0 * np.pi * fc * t) j = j * np.sqrt(power / np.mean(np.abs(j)**2)) return j调幅深度 m 不要大于 1,否则am会过零甚至反向,产生严重谐波失真,干扰带宽失控。单频载波干扰不用专门写函数,一行np.exp(1j*2π*fc*t)就够了,只是效果差异很大:单频只压一个频点,对宽带 CPM-LFM 的脉压主瓣影响有限,但能抬高接收机本底噪声、压缩 AGC 动态范围,让对方弱信号检测变难。
工程里我遇到不少团队看不起这种“简单干扰”,但它是最接近工程样机功率输出特性的干扰方式。评估 CPM-LFM 对抗能力时,单频干扰适合当作基础对比项,噪声调频当作强干扰项,二者之间的一系列曲线才能说明抗干扰能力的动态范围。
3.3 梳状谱干扰与部分带宽干扰:省功率的选择
梳状谱干扰是把多个等幅单频或者窄带分路并排放到信号频带内,形成一座一座的窄尖峰。它和全带宽噪声调频相比,最大的优势是功率利用率高:只占需要的频点,不会把钱花在带外。
def comb_jammer(N, Fs, Bsig, num_tones, power): """梳状谱干扰:在 -Bsig/2 到 +Bsig/2 内均匀排列 num_tones 个等幅分量""" t = np.arange(N) / Fs j = np.zeros(N, dtype=complex) for m in range(num_tones): fm = -Bsig/2 + (m + 0.5) * (Bsig / num_tones) j += np.exp(1j * 2.0 * np.pi * fm * t) j = j * np.sqrt(power / np.mean(np.abs(j)**2)) return j梳状谱干扰的实际效果要分情况看。如果只放几个点,脉压输出里会出现几个较宽的旁瓣峰,主峰只是轻微下降;如果点位数密集到覆盖信号带宽的一半以上,脉压底噪会被明显拉高,效果接近部分带宽压制。仿真时重点观察的是“峰值旁瓣比”而不是总干扰功率,因为部分频带干扰会制造虚假的弱目标。
参数num_tones和覆盖比例直接决定干扰在脉压输出端的形态。一般我会先固定总功率,扫描 num_tones 从 4 到 64,看主峰什么时候开始明显跌落,这个拐点就是该谱型对 CPM-LFM 的“有效覆盖门限”。
3.4 转发式欺骗干扰:相干增益的另一面
转发式欺骗干扰的思路是截获一段 CPM-LFM 后,延迟一段时间再发射出去。由于复制的是真实信号,它也能获得脉压处理的部分相干收益,于是接收机脉压输出里会出现多个与真实目标形状相似的假峰,比单纯抬底噪更难识别。
# 转发式欺骗干扰:截获后延迟重发,相位上叠一个多普勒偏移 delay = int(1.5 * Tsym * Fs) # 延迟 1.5 个码元 doppler_phase = np.exp(1j * 2.0 * np.pi * fd * np.arange(Ns) / Fs) j = np.zeros_like(s) j[delay:] = s[:Ns-delay] * doppler_phase[:Ns-delay]转发干扰的成败完全取决于波形复制度。CPM-LFM 的 LFM 部分容易估计扫频斜率,但 CPM 数据相位是随机的,干扰机不知道数据序列,只能把截获的整段波形直接转发。这会带来两个限制:一是延迟必须和接收处理帧对齐,否则假峰落在距离门之外;二是多普勒偏移一旦不精确,相位连续特性被破坏,假峰幅度迅速掉下来,变成普通窄带干扰。
因此在做干扰效果分析时,不要把转发式欺骗想成万能药。它的问题是:对复制精度要求高,对波形参数变化敏感;优点是:干信比稍高一点,接收机脉压输出里就可能出现置信度很高的假目标,导致检测逻辑误判。评估时既要看主峰变化,也要记录假峰个数和假峰与主峰的幅度差。
| 干扰样式 | 带宽匹配依赖 | 相参性 | 对脉压输出的主要影响 | 工程实现难度 |
|---|---|---|---|---|
| 单频窄带 | 低 | 不相参 | 抬高底噪、压缩 AGC | 很低 |
| 噪声调幅 | 中 | 不相参 | 底噪抬升,波形较粗 | 低 |
| 噪声调频 | 高 | 不相参 | 宽带底噪抬升、输出 SINR 下降 | 中 |
| 梳状谱 | 中 | 不相参 | 多旁瓣峰、部分频带压制 | 中 |
| 转发欺骗 | 极高 | 相参 | 假目标峰,测距欺骗 | 高 |
4. 评估指标体系与仿真流程搭建
4.1 四个评估维度:输出 SINR、脉压峰值损耗、旁瓣比、误码率
干扰效果不能只拿一个数字说话,我一般固定看四个维度。
第一是脉压输出 SINR,也就是峰值与受保护区域外底噪的比值。它直接对应接收机做恒虚警检测时还能不能看到主峰,这是压制式干扰的核心指标。第二是脉压峰值损耗,用加干扰后的峰值比无干扰峰值再取对数,衡量即使没有完全压制,测距精度和检测门限也被削弱了多少。第三是峰值旁瓣比,看干扰是否把旁瓣区域抬高到能和主峰混淆,这是欺骗式干扰和非连续谱干扰最典型的效应。第四是误码率或者假目标个数,当 CPM-LFM 带通信数据时,直接看数据解调是否出错;纯雷达探测场景就看假目标数量。
这四个维度要在同一组采样曲线里一起提取,不要分别写四套仿真程序。一次性把接收信号做完脉压,再在时域上分区域统计,结果才可复现且互相可对照。
4.2 一个可复用的最小评估脚本
下面这段代码是我每次做干扰效果评估都会先跑通的最小框架。它把无干扰和有干扰两种情况都走一遍,输出 SINR 和峰值损耗。
def matched_filter(r, s): """对接收信号 r 做脉冲压缩,匹配滤波器由信号副本 s 生成""" h = np.conj(s[::-1]) # 匹配滤波器的时域冲击响应 y = signal.fftconvolve(r, h, mode='full') y = y / np.sum(np.abs(s)**2) # 除以信号能量,归一化到相关峰 return y def evaluate_pc(y, Fs, B): """提取脉压后的主峰、底噪和输出 SINR""" y_abs = np.abs(y) peak = np.max(y_abs) peak_idx = np.argmax(y_abs) # 保护区域:主瓣 3 倍宽度,避免主峰能量污染底噪统计 guard_len = int(3.0 * Fs / B) mask = np.ones(len(y), dtype=bool) mask[max(0, peak_idx-guard_len): peak_idx+guard_len] = False side = y_abs[mask] noise_floor = np.sqrt(np.mean(side**2)) sinr = peak / noise_floor return peak, noise_floor, sinr # 无干扰基准 y_clean = matched_filter(s, s) peak_clean, _, _ = evaluate_pc(y_clean, Fs, B) # 加一个 JSR=0 dB 的噪声调频干扰 jsr_db = 0.0 pj = np.mean(np.abs(s)**2) * 10**(jsr_db / 10) j = noise_fm_jammer(Ns, Fs, B, pj, seed=42) r = s + j y_jam = matched_filter(r, s) peak_jam, floor_jam, sinr_jam = evaluate_pc(y_jam, Fs, B) loss = 20*np.log10(peak_jam / peak_clean) print(f"输出SINR: {20*np.log10(sinr_jam):.2f} dB, 峰值损耗: {loss:.2f} dB")matched_filter里把结果除以信号能量,这一步很关键。不归一化的话,不同信号副本下峰值绝对值会差很多,跨配置比较时整个曲线都缠在一起。evaluate_pc里的guard_len = 3.0 * Fs / B是按主瓣物理宽度算的,比随手取一个固定点数更稳定。干扰加入前先按 JSR 换算pj,这里 JSR=0 dB 只表示干扰功率和信号功率相等,不代表压制效果为 0。
4.3 批量扫参实验设计
单点评估只能判断“这一个干扰行不行”,真正要写成报告,需要扫干信比和干扰带宽两个维度。
def sweep_jsr(s, jammer_factory, jsr_list, repeat=20): """固定干扰带宽,扫描 JSR,取中位数结果""" result = {} for db in jsr_list: vals = [] for k in range(repeat): pj = np.mean(np.abs(s)**2) * 10**(db / 10) j = jammer_factory(pj=pj, seed=k) r = s + j y = matched_filter(r, s) _, _, sinr = evaluate_pc(y, Fs, B) vals.append(20*np.log10(sinr)) result[db] = np.median(vals) return resultrepeat=20是压制式干扰仿真的最低要求,因为噪声调频的随机相位会带来 ±1~2 dB 的波动。seed=k保证每个 JSR 点的不同重复之间只有随机种子不同,统计口径一致。扫参时要注意保持干扰带宽不变,只变功率;如果同时改带宽和功率,观察到的输出 SINR 变化就无法归因于主变量。
扫完后我一般会把曲线画成“横轴 JSR、纵轴输出 SINR”,不同干扰样式各画一条。这样一个图就能直接读出:到底需要多少干信比才能把输出 SINR 压到检测门限以下,以及哪条曲线斜率更陡。
5. 干扰效果仿真中的常见问题与避坑记录
仿真做多了会发现,干扰效果评估的结论经常翻车,但翻车原因往往不是干扰模型本身,而是信号生成或者指标提取里的细节。
5.1 频谱泄漏让干扰带宽“虚高”
现象:设计好的噪声调频干扰带宽本来是 20 MHz,用 FFT 一看频谱,半功率带宽明显超出,脉压底噪也跟着异常升高。
原因:直接用abs(fft(干扰片段))看单段时域截断的频谱,矩形窗会带来大量频谱泄漏,测量结果被展宽。这段展宽的假带宽在带宽匹配修正里多算了好几 dB。
解决:测量干扰实际带宽时改用汉明窗加长 FFT 点数,用半功率门限去度量。
def measure_bw(x, Fs): Nfft = 2**18 xw = x * signal.windows.hamming(len(x)) X = np.fft.fft(xw, Nfft) f = np.fft.fftfreq(Nfft, 1/Fs) p = np.abs(X[:Nfft//2])**2 fpos = f[:Nfft//2] active = p > 0.5 * np.max(p) return fpos[active].max() - fpos[active].min()注意测量用的窗函数和仿真生成干扰时的滤波器不要混为一谈。窗函数只影响“测量口径”,不会改变干扰的真实频谱,报告里写清测量条件,结论才能在不同团队间复现。
5.2 相位不连续污染脉压旁瓣
现象:加干扰后脉压旁瓣莫名其妙高出 5~10 dB,而输出 SINR 却变化不大,曲线趋势也乱。
原因:生成 CPM-LFM 时,有人直接把数据符号乘以固定相位再乘到 LFM 上,符号边界处相位突变,产生了额外的高频分量。这个假频谱被接收机匹配滤波器当作信号的一部分相干积累,旁瓣自然被顶上去。
解决:必须用累积相位方式生成 CPM 项,也就是第 2.2 节代码里的phase_start += π*h*data[n]。自检时可以直接检查phase_cpm在符号边界两侧的差值,理论上是 0,数值上误差小于 1e-6 才算正常。如果发现边界差值接近 π 或者更大,先把信号生成修对再谈干扰效果。
5.3 干信比“口径”不一致导致对比失真
现象:同一个干扰,A 团队认为 20 dB JSR 才能压住主峰,B 团队测试 10 dB 就压住了,两边吵不出结果。
原因:A 团队把干扰功率除以整个采样带宽,B 团队只算落在信号带宽内的那部分功率。对宽带噪声调频干扰,这两种计算结果相差好几 dB,谁都没算错,但放不到一张图里。
解决:统一约定“信号带宽内有效干信比”。对带宽大于信号带宽的噪声类干扰,用 JSR_eff = JSR - 10lg(BJ/B) 做带宽修正;对单频干扰和窄带干扰,如果频率落在信号带内,修正项取 1 即可。报告里必须把这个口径写进图例,否则每次换人接手都要重新猜。
5.4 随机仿真单次实验结果不可信
现象:重复跑同一组干扰参数,输出 SINR 波动 ±3 dB,光看一次结果根本无法判断哪种干扰样式更好。
原因:噪声调频和噪声调幅干扰都驱动随机过程,CPM 数据相位也是随机生成的,单次仿真的方差天然存在。特别在干信比 10 dB 附近的过渡区,随机性影响最明显。
解决:每组参数至少重复 20 次,取中位数和四分位范围。统计误码率时,码元数要上千,少于 200 个码元算出来的误码率基本是玄学。我现在的习惯是先把随机种子固定一套,得到可复现曲线后再单独开一组随机种子验证稳定性,两者趋势一致才敢把结论写出去。
6. 从处理增益门限反推干信比预算:让仿真结果经得起推敲
如果只是想知道“哪种干扰更好”,前面四章的指标已经够用。但工程上往往还要回答更直接的问题:对方干扰机至少要有多少输出功率?我现在这套干扰配置能不能压住 CPM-LFM 接收机?
我的做法是用处理增益做一把“尺子”,把输出指标反推成输入干信比门限。对匹配接收的 CPM-LFM,脉压处理增益约为 10lg(TB),仿真基准里是 23 dB。如果认为接收机输出端至少要保持 γ dB 的 SINR 才能稳定检测,那么输入端允许的干信比门限大约是 JSR_limit = γ - G + 带宽修正。带宽修正项只对宽带噪声类干扰生效,干扰带宽翻倍意味着有效功率密度减半,修正项约等于 -3 dB。
| 干扰样式 | 带宽修正近似 | 说明 |
|---|---|---|
| 单频对准信号带内 | 0 dB | 但脉压输出旁瓣形貌复杂,不能全按噪声处理 |
| 噪声调频 BJ=信号带宽 | 0 dB | 功率利用率最高,最省功率 |
| 噪声调频 BJ=2 倍信号带宽 | -3 dB | 多花一倍功率补偿带宽损失 |
| 梳状谱覆盖 50% 频带 | -3 dB 左右 | 若覆盖点避开了关键频点,实际效果要打折 |
这个表是工程近似,不是理论公式,用它做预算足够,写论文或评审报告时要以仿真曲线为准。
我最后一道工作习惯是把理论门限和仿真曲线叠在一张图里。取第 4 节的扫参结果,找到输出 SINR 降到 γ 时对应的 JSR,再与表里的推导值做交叉验证。如果曲线斜率几乎水平,说明干扰带宽其实没对准信号带内,或者功率被频谱泄漏假象骗了;如果斜率接近 1 dB 输出对应 1 dB 输入,说明干扰在脉压后基本按噪声积分,模型行为正常。这种交叉验证堵住了很多仿真 bug,也比只看单点数字更能说服评审。希望这个反推门限的习惯也能帮到你,少在干扰效果评估上走弯路。
本文还有配套的精品资源,点击获取