简介:一套面向雷达与通信信号处理学习者的MATLAB代码包,聚焦线性调频(LFM)信号的模糊函数计算与可视化,适合需要理解信号时频特性、评估雷达波形分辨能力的本科生、研究生或工程师。压缩包共3个文件,均为m脚本,整体仅1KB,轻量易读;三个脚本分别处理单频脉冲、线性调频单脉冲和线性调频脉冲串的模糊函数,从单频脉冲到脉冲串的递进设计便于循序渐进掌握波形参数的影响,也可从主瓣宽度、零点分布、旁瓣水平等角度直观对比不同波形的时频分辨率与目标分辨能力。代码支持自定义初始频率、频扫率、脉冲宽度等参数,重新运行即可观察参数改变对模糊函数倾斜方向、测距测速耦合的影响,便于将理论与工程应用联系起来。已有404人学习下载,既可辅助雷达信号处理课程设计与科研预研,也可作为波形设计、目标检测与分辨能力评估的二次开发模板。
1. 为什么 LFM 波形好不好,先看模糊函数图
拿到一个新的雷达波形,我一般不会盯着时域波形看,而是先让 MATLAB 把它的模糊函数图画出来。模糊函数衡量的是发射信号对目标时延和多普勒的联合分辨能力,相当于把匹配滤波输出铺成一张二维地图。对 LFM 信号来说,这张图里会有一条非常显眼的斜“刀刃”:刀刃走向由调频斜率决定,刀刃越薄说明距离和多普勒分辨能力越好,刀刃偏离坐标轴则把多普勒-时延耦合暴露得一清二楚。用 MATLAB 计算并绘制 LFM 信号模糊函数图,是波形设计从“拍脑袋选参数”转向“可量化判断”的关键一步。下文把信号生成、模糊函数计算、画图到参数调节的完整链路拆开讲,适合雷达信号处理工程师、通信感知一体化方向的研究生,以及正在做波形设计相关毕设的同学直接照着跑。
2. LFM 的模糊函数理论:复基带模型与“斜刀刃”从哪来
画图之前先要把信号模型和模糊函数定义对齐,否则后面所有坐标轴都会跟着错。这里的 LFM 是线性调频,也叫 Chirp,是雷达里最常用的脉压波形。
2.1 LFM 信号的复基带表达式与三个基础参数
LFM 信号最常见的复基带形式如下:
s(t) = rect(t / T) * exp(j * pi * K * t^2) , t ∈ [-T/2, T/2]rect 是矩形窗,T 是脉宽,B 是带宽,K = B / T 是调频斜率。相位 θ(t) = πKt²,瞬时频率等于相位对时间的导数除以 2π,即 f(t) = Kt,线性地从 -B/2 扫到 B/2。这个 B 是基带带宽,不是射频载频附近的绝对带宽。
本文后续示例采用一组经典参数:T = 100 μs,B = 10 MHz,这样 K = 1e11 Hz/s,时宽带宽积 TB = 1000。TB 越大,模糊函数的主瓣越窄、刀刃越长,波形的脉冲压缩比也越大,这是 LFM 区别于简单单频脉冲的核心。
| 参数 | 符号 | 本文取值 | 对模糊函数的影响 |
|---|---|---|---|
| 脉宽 | T | 100 μs | 决定多普勒主瓣宽度,约 2/T |
| 带宽 | B | 10 MHz | 决定时延主瓣宽度,约 1/B |
| 调频斜率 | K | 1e11 Hz/s | 决定刀刃方向,耦合系数 fd = Kτ |
| 时宽带宽积 | TB | 1000 | 越大刀刃越长越薄 |
用 MATLAB 生成这个复基带信号只要五行:
T = 100e-6; % 脉宽 100 us B = 10e6; % 带宽 10 MHz fs = 40e6; % 采样率 40 MHz K = B / T; % 调频斜率 1e11 Hz/s t = (0:round(T*fs)-1) / fs - T/2; % 以脉冲中心为零点 s = exp(1j * pi * K * t.^2); % 复基带 LFM注意相位系数是 pi 而不是 2*pi。写成 exp(1j * 2 * pi * K * t.^2) 会让瞬时频率变成 2Kt,实际带宽翻倍成 2B,后面匹配滤波、模糊函数刀刃方向全都会偏。这个坑在排错章节还会再提。
2.2 模糊函数的定义:从一维互相关到二维互相关
模糊函数是信号 s(t) 与自身时延-多普勒副本的二维互相关,常用定义如下:
chi(tau, fd) = ∫ s(t) * conj(s(t - tau)) * exp(-j * 2 * pi * fd * t) dt其中 tau 是时延,fd 是多普勒频率。这个式子可以拆成两步理解:先对信号做时延 tau 的共轭相乘,也就是自相关核;再对这个核做傅里叶变换,得到不同多普勒频率上的响应。所以模糊函数本质上是一组“带多普勒失配的自相关函数”。
两个退化切面很有用。fd = 0 时,chi(tau, 0) 退化为普通自相关函数,对应匹配滤波器零多普勒输出;tau = 0 时,chi(0, fd) 描述的是只存在多普勒失配、没有时延失配时的峰值衰减。真正的匹配滤波二维输出就是模糊函数本身,区别只在幅度归一化和时延参考点。
不同教材对模糊函数的定义有细节差异,画图前要心里有数:
| 定义差异 | 常见写法 | 对幅值图的影响 |
|---|---|---|
| 积分核符号 | exp(-j2πfd t) 或 exp(+j2πfd t) | 绝对幅度一致,fd 轴可能左右翻转 |
| 共轭对象 | conj(s(t-tau)) 或 conj(s(t+tau)) | tau 轴左右翻转,幅度不变 |
| 时延中心 | 常用 t 或 (t+tau/2) 对称形式 | 对称定义会平移 tau 轴,幅度谱不变 |
| 归一化 | 除以信号能量或最大值 | 本文归一化到最大值,便于看 -3dB 轮廓 |
对只看 |chi(tau, fd)| 的工程场景,这些差异不改变分辨率、旁瓣位置和刀刃方向,MATLAB 里任选一套自洽即可。
2.3 刀刃的数学来源:多普勒-时延耦合
把 LFM 信号代入自相关核,能得到一个非常直观的结果:
s(t) * conj(s(t - tau)) = exp(j * pi * K * (t^2 - (t - tau)^2)) = exp(j * 2 * pi * K * tau * t - j * pi * K * tau^2)第二项 -jπKτ² 是固定相位,不影响幅度;第一项是一个频率为 Kτ 的复指数。对这个核做傅里叶变换时,只有当多普勒频率 fd 与 Kτ 接近时,积分才会显著不为零。于是模糊函数的能量集中出现在:
fd ≈ K * tau这条直线就是 LFM 模糊函数里的“斜刀刃”。K 越大,刀刃越陡;TB 越大,刀刃越细长。信号沿时延方向的主瓣宽度约为 1/B,沿多普勒方向的主瓣宽度约为 2/T,所以 LFM 的模糊函数不是一个图钉,而是一条倾斜的窄脊线,这是它无法同时消除“距离模糊”和“多普勒模糊”的根本原因。
这个耦合也直接反映在工程上:如果目标存在多普勒频移 fd,匹配滤波输出的时延峰值会偏移 fd/K。用本文参数计算,fd = 10 kHz 时峰值时延偏移约 0.1 μs,折算成单程距离约 15 m。这就是雷达原理教材里常说的“LFM 距离-多普勒耦合”,在模糊函数图上就是刀刃上每一点对应的物理含义。
3. MATLAB 计算 LFM 模糊函数图:完整代码与坐标标定
这一章直接给能跑通的代码。算法上采用最稳妥的“时延逐点扫描 + FFT 一次算出多普勒维”方式,不做任何近似,代码短且容易验证。
3.1 核心计算函数:lfm_amb.m
先写一个独立函数,之后所有画图都复用它:
function [af, tau, fd] = lfm_amb(s, fs, fftlen, taumax) % 计算复基带信号 s 的模糊函数幅度谱 % s : 1xN 复基带 LFM 信号 % fs : 采样率, 单位 Hz % fftlen : 多普勒维 FFT 点数, 全貌图建议 2048 % taumax : 时延轴最大偏移, 单位 s; 默认取整个信号时长 N = numel(s); if nargin < 4 taumax = N / fs; end L = min(round(taumax * fs), N - 1); % 最大时延对应的采样点数 shifts = -L:L; % 线性移位量序列 tau = shifts / fs; % 时延轴, 单位 s M = fftlen; af = zeros(M, 2*L+1); % 每列是同一时延下的多普勒截面 for i = 1:numel(shifts) d = shifts(i); s_shift = zeros(1, N); % 线性移位, 不是循环移位 if d >= 0 s_shift(d+1:N) = s(1:N-d); % 信号右移 d 个采样点 else s_shift(1:N+d) = s(-d+1:N); % 信号左移 |d| 个采样点 end r = s .* conj(s_shift); % 自相关核 af(:, i) = fftshift(fft(r, M)); % FFT 得到该时延下全部多普勒通道 end af = abs(af) / max(abs(af(:))); % 以原点峰值归一化 fd = (-M/2:M/2-1) * (fs / M); % 多普勒轴, 单位 Hz end这个函数的计算复杂度是 O((2L+1) * M * log M)。外层 only 遍历时延偏移,内层用一次 FFT 把整个多普勒维算完,比暴力三重循环快几个数量级。fftshift 的作用是把零多普勒通道放到数组正中央,这样 fd 轴就是负值在左、正值在右。输出 af 的尺寸是 fftlen × (2L+1),行对应多普勒,列对应时延,与 mesh 函数要求的 X、Y、Z 维度一致。
3.2 全貌图与主瓣放大图:先看走向,再看细节
主脚本把信号生成、全貌图、主瓣图一次画完:
T = 100e-6; B = 10e6; fs = 40e6; K = B / T; N = round(T * fs); t = (0:N-1) / fs - T/2; s = exp(1j * pi * K * t.^2); % 全貌图: 时延覆盖 ±T, 多普勒用 2048 点 FFT [af, tau, fd] = lfm_amb(s, fs, 2048, T); figure; mesh(tau*1e6, fd*1e-3, af); xlabel('时延 \tau (\mus)'); ylabel('多普勒 f_d (kHz)'); zlabel('|\chi(\tau, f_d)|'); title('LFM 模糊函数全貌');这段跑完后会看到一个细长的斜面,有时看起来像一条线,这是正常的,因为 TB = 1000 时刀刃太薄,线性幅度下几乎看不到厚度。想看清楚主瓣的三维形态,用放大模式:时延轴只保留 ±3/B,多普勒 FFT 点数加到 32768:
[af2, tau2, fd2] = lfm_amb(s, fs, 32768, 3/B); idx = abs(fd2) <= 3/T; % 多普勒轴裁剪到 ±3/T 附近 figure; surf(tau2*1e6, fd2(idx)*1e-3, af2(idx,:), 'EdgeColor', 'none'); xlabel('时延 \tau (\mus)'); ylabel('多普勒 f_d (kHz)'); zlabel('|\chi(\tau, f_d)|'); title('LFM 模糊函数主瓣放大');surf 配合 EdgeColor 设为 none,会得到平滑的着色曲面,比 mesh 更适合表现主瓣的“鼓包”形状。之所以敢把 fftlen 加到 32768,是因为时延轴只留了很少的列,内存不会爆炸,这一点在第四章末尾专门算账。
3.3 四种画图方式与适用场景
MATLAB 里画模糊函数常见的有 mesh、surf、imagesc、contour 四种,各有各的用途。
| 绘图方式 | 适合展示的内容 | 常见注意点 |
|---|---|---|
| mesh | 三维线框,看刀刃走向和旁瓣起伏 | 数据点多时卡,可隔点采样 |
| surf + EdgeColor none | 平滑三维曲面,适合主瓣局部 | 颜色条加 caxis 控制动态范围 |
| imagesc | 俯视二维强度图,适合报告与对比 | 加 axis xy,配合 dB 显示 |
| contour | 等高线,适合提取 -3dB/主瓣边界 | 数据网格需要较密 |
imagesc 配合 dB 显示是工程上最常用的“一眼看清旁瓣”的方式:
af_db = 20 * log10(af + eps); figure; imagesc(tau*1e6, fd*1e-3, af_db); axis xy; caxis([-40 0]); % 只看 40dB 动态范围 colormap(jet); colorbar; xlabel('时延 \tau (\mus)'); ylabel('多普勒 f_d (kHz)'); title('LFM 模糊函数俯视图(dB)');加 eps 是为了避免 log10(0) 出现 -Inf。动态范围压在 40dB,能同时看到主瓣和第一旁瓣,又不至于被数值噪声淹没。如果旁瓣结构看不清,可以再把 caxis 下限改到 -60。
3.4 时延轴和多普勒轴的标定公式
轴标定比画图本身更容易出错。两条轴的换算关系固定如下:
| 坐标轴 | 相邻点间隔 | 覆盖范围 | 本文示例 |
|---|---|---|---|
| 时延 τ | Δτ = 1 / fs | ±taumax | 全貌 ±100 μs,主瓣 ±300 ns |
| 多普勒 fd | Δfd = fs / fftlen | ±fs / 2 | 全貌 ±20 MHz,裁剪后 ±30 kHz |
注意多普勒轴物理范围是 ±fs/2,但刀刃本身只占据 ±B 附近一段。全貌图如果不做任何裁剪,整个刀刃会变成贴在地面上的一条细线,所以画全貌图时按 idx 截取 fd 到 ±1.2B 附近是常见做法;画主瓣图时要裁剪到 ±3/T 才能看到多普勒方向的鼓包厚度。
4. 模糊函数图的参数设置与常见坑:采样率、轴范围与内存控制
代码跑通只是第一步,真正判断一张模糊函数图算得对不对,要回到参数设置和常见坑上。下面这些是我在实际画图时踩过、也给同事排查过的点。
4.1 采样率与带宽的配套选择:fs = 2B 起步
从采样定理角度看,复基带 LFM 带宽 B,理论采样率只要 fs ≥ B。但模糊函数计算需要对信号做整数采样点移位,时延分辨率就是 1/fs,因此主瓣宽度 1/B 内能容纳的采样点数等于 fs/B。如果 fs = B,主瓣只有两个采样点,画出来是方形的,无法做 -3dB 切片测量。所以工程上画模糊函数通常用 fs = 2B 到 4B,兼顾计算量和视觉平滑度。
几组典型参数对应的观感差异:
| T | B | fs | TB 积 | 观察到的现象 |
|---|---|---|---|---|
| 10 μs | 1 MHz | 4 MHz | 10 | 刀刃短而粗,耦合不明显 |
| 100 μs | 10 MHz | 40 MHz | 1000 | 长刀刃,切面主瓣很薄 |
| 1 ms | 50 MHz | 200 MHz | 50000 | 刀刃极薄,内存压力大 |
fs 不是越高越好。fs 翻倍,时延列数 2L+1 跟着翻倍,af 矩阵尺寸线性增长,计算时间也近似线性增长。对于 B = 10 MHz 的信号,fs = 40 MHz 已经足够,再高只会更平滑,不会带来额外物理信息。
4.2 用两个切面验证距离分辨率和多普勒分辨率
验证计算是否正确的最快办法,是把模糊函数在零时延和零多普勒处切一刀,和理论值对比。本文例子中,零多普勒时延切面的 -3dB 宽度应接近 1/B = 100 ns,零时延多普勒切面的 -3dB 宽度应接近 0.886/T ≈ 8.9 kHz,主瓣第一零点约在 ±1/T = ±10 kHz。
[~, i0] = min(abs(tau2)); % 找零时延所在列 [~, j0] = min(abs(fd2(idx))); % 找零多普勒所在行 fd_cut = fd2(idx); figure; plot(fd_cut*1e-3, af2(idx, i0)); xlabel('多普勒 f_d (kHz)'); ylabel('|\chi(0, f_d)|'); title('零时延多普勒切面'); figure; plot(tau2*1e6, af2(j0, :)); xlabel('时延 \tau (\mus)'); ylabel('|\chi(\tau, 0)|'); title('零多普勒时延切面');如果这两条曲线的峰值不在原点,说明信号中心没对齐,检查 t 是否减去了 T/2;如果切面宽度明显大于理论值,优先怀疑 fftlen 不够导致多普勒轴分辨率太粗,或者 fs 太低导致时延轴采样点太少。
4.3 四个高频踩坑:相位系数、循环移位、多普勒裁剪、内存
第一个坑是相位系数。写成 exp(1j * 2 * pi * K * t.^2),带宽变成 2B,刀刃斜率变成 2K,整张图都变陡。用瞬时频率表达式自检:对 exp(jπKt²) 求导后除以 2π,得到 Kt,正好覆盖 ±B/2。
第二个坑是误用 circshift 代替线性移位。circshift 会把信号尾部绕到头部,相当于在时域上做了周期延拓,模糊函数里会出现一条不该有的环形亮带,旁瓣结构完全失真。正确做法如 lfm_amb.m 中那样,用 zeros 补出空缺部分。
第三个坑是多普勒轴没有裁剪。全貌图直接 mesh(tau, fd, af) 时,fd 轴范围是 ±20 MHz,刀刃只占中间 ±10 MHz 的一小部分,看上去就是一条扁线,很容易被误判成程序 bug。处理方式前面已经给过:全貌图截 ±1.2B,放大图截 ±3/T。
第四个坑是内存失控。af 在 abs 之前是复数矩阵,每个元素占 16 字节,FFT 中间结果还会额外占一份。盲目把 fftlen 和 taumax 同时拉满,16 GB 内存的机器也会卡死。
4.4 内存估算表:先全貌后放大才是正解
以下内存按存储复数 af 的峰值估算,即 fftlen × (2L+1) × 16 字节,abs 之后占一半:
| 场景 | fftlen | taumax | af 尺寸 | 峰值内存 |
|---|---|---|---|---|
| 全貌 | 2048 | T | 2048 × 7999 | 约 262 MB |
| 全貌 | 4096 | T | 4096 × 7999 | 约 524 MB |
| 主瓣 | 8192 | 2/B | 8192 × 17 | 约 2.2 MB |
| 主瓣 | 32768 | 3/B | 32768 × 25 | 约 13 MB |
从表里能看出一个明确策略:先用 taumax = T、fftlen = 2048 的低分辨率全貌图确定刀刃走向和大致旁瓣位置;再用小 taumax、大 fftlen 的高分辨率模式放大主瓣。这样内存峰值始终可控,画出来的图还比一次硬算全分辨率更平滑。如果需要反复改参数,建议把 af 在 abs 之后转成 single,内存再减半,对绘图精度没有任何可感知影响。
5. 把 LFM 模糊函数图用起来:切片自检、等高线与批量出图
模糊函数图画出来不是终点,怎么从图里读出波形参数、怎么批量出报告图,才是日常工作里真正花时间的部分。
5.1 成图前的三个快速自检项
每次算完模糊函数,先用三件事确认结果可用:峰值是否在 (0, 0) 且归一化后等于 1,不在原点说明信号时间窗没有中心对齐;零多普勒切面主瓣宽度是否接近 1/B,偏差超过 10% 要检查采样率和 FFT 长度;旁瓣是否在 -13.2 dB 附近,这是未加窗 LFM 的典型距离旁瓣水平,如果高出很多,说明有截断泄漏或循环移位污染。
5.2 用 -3dB 等高线量化分辨椭圆
模糊函数的 -3dB 轮廓形状可以用 regionprops 直接提取,用于量化“距离-多普勒分辨椭圆”:
af_db = 20 * log10(af2 + eps); mask = af_db >= -3; % 提取 -3dB 以上区域 stats = regionprops(mask, 'MajorAxisLength', 'MinorAxisLength', ... 'Orientation', 'Centroid');得到的 MajorAxisLength 和 MinorAxisLength 是像素数,要分别乘以时延轴步长 Δτ 和多普勒轴步长 Δfd 才变成物理单位。LFM 的轮廓应该是一个狭长椭圆,长轴方向由调频斜率 K 决定,长短轴比例随 TB 增大而增大。如果想做波形参数寻优,完全可以把“长短轴比例最小”作为目标函数,丢进 MATLAB 优化工具箱里搜索 T 和 B 的组合,比肉眼对比清晰得多。
5.3 批量改参数出图并导出 EPS/PNG
论文和报告里通常需要同一组参数下多张对比图。用循环批量生成并导出是标准做法:
for fftlen = [1024 2048 4096] [af, tau, fd] = lfm_amb(s, fs, fftlen, T); figure('Visible', 'off'); imagesc(tau*1e6, fd*1e-3, 20*log10(af + eps)); caxis([-40 0]); axis xy; colorbar; title(sprintf('FFT length = %d', fftlen)); exportgraphics(gcf, sprintf('lfm_af_fft%d.png', fftlen), 'Resolution', 300); end导出矢量图时,新版本 MATLAB 用 exportgraphics(gcf, 'lfm_af.eps') 即可,线宽和字体与屏幕上一致;老版本兼容写法是 print('-depsc2', 'lfm_af.eps')。所有图把 caxis 固定在 [-40 0],这样不同参数之间的旁瓣水平才有可比性,不会因为自动色标产生误导。
本文还有配套的精品资源,点击获取