简介:这份压缩包面向雷达信号处理方向的学生与工程师,提供了一套完整的调频连续波FMCW雷达测距Matlab仿真代码。通过发射锯齿波/三角波调频信号并处理回波差频,可清晰展现目标距离解算的核心流程,适用于课程设计、毕业设计或相关项目预研;该技术也常见于汽车防撞雷达、液位计、无人机避障等场景。资源共25个文件,主要包含5个.m程序文件(发射、差频、解算等模块),10个ps矢量图文件和10张jpg运行结果图,整体仅500KB,轻量便携;ps文件可直接用于论文配图,jpg便于快速预览实验效果。目前已有204人学习。通过运行主程序并结合频谱图,读者能深入理解FMCW差频测距原理,调整信号参数即可观察不同距离目标的峰值变化,还可参考ps图表完善论文写作,是快速掌握雷达测距仿真的实用素材。
1. 为什么工业测距方案都在向 FMCW 迁移
工业液位计、车载角雷达、无人机避障模块,这几年陆续从单频连续波和脉冲体制转向调频连续波(FMCW),原因很直接:同一个低成本收发链路,FMCW 能同时拿到距离、速度和回波强度,测距精度又不依赖脉冲峰值功率,几毫瓦发射功率配合 FFT 积累就能测到数百米。FMCW 不直接测飞行时间,而是让回波与发射信号混频,得到一个频率与距离成正比的差拍信号,后端只需一次 FFT 就能把距离读出来。这个处理流程在 Matlab 里非常适合反复推敲——参数表写清楚,相干积累、窗函数、CFAR 检测几分钟就能跑通,再决定要不要落 C++ 或 FPGA。下面从差拍原理、完整仿真到多目标测速和工程校准一条线讲透,代码思路可直接照搬到自己的 Matlab 工程里。
2. FMCW 差拍原理:距离是怎么被搬到低频的
2.1 为什么选线性调频而不是单频连续波
单频连续波只能测速度,测不了距离,因为回波只是原载波延迟了 τ,频率没有发生变化。线性调频让发射频率随时间线性增长,回波到达时,发射频率已经比离开时高了 S·τ,其中 S 是调频斜率,由带宽 B 和扫频周期 Tc 决定,S = B/Tc。这个频率差 f_b 就是测距的关键:
R = f_b · c · Tc / (2B)
把扫频周期、带宽代入,测距问题就变成了测量一个正弦波的频率,而 FFT 天然就是干这个的。
2.2 差拍信号模型与关键公式
发射信号基带相位写作 2π·(f_c·t + 0.5·S·t²),回波是它的延迟版本,延迟 τ = 2R/c。混频器把回波与发射信号共轭相乘,得到的中频信号频率就是 S·τ,幅度与目标回波强度成正比。这个中频信号通常是几十千赫到几兆赫,远低于载频,后端 ADC 用较低采样率就能采集,这是 FMCW 硬件成本低的主要原因。
| 参数 | 符号 | 典型值 | 说明 |
|---|---|---|---|
| 载频 | f_c | 24 GHz / 77 GHz | 决定多普勒灵敏度 |
| 扫频带宽 | B | 250 MHz / 1 GHz | 决定距离分辨率 δR = c/(2B) |
| 扫频周期 | Tc | 50~100 μs | 决定最大差拍频率 |
| 采样率 | fs | 4~10 MHz | 需大于最大差拍频率的 2 倍 |
距离分辨率只由带宽决定:250 MHz 带宽对应 0.6 m,1 GHz 带宽对应 0.15 m。想提高分辨率就加大带宽,但采样率和数据量也随之上来,这是第一个要权衡的点。
2.3 用一段最小 Matlab 代码验证差拍测距
%% FMCW 差拍测距最小验证:单目标、无噪声 fc = 77e9; % 载频 77 GHz B = 1e9; % 扫频带宽 1 GHz Tc = 50e-6; % 扫频周期 50 us fs = 10e6; % 采样率 10 MHz Ns = round(Tc*fs); % 单个 chirp 采样点数 t = (0:Ns-1)/fs; S = B/Tc; % 调频斜率 R = 30; % 目标距离 30 m c = 3e8; tau = 2*R/c; % 回波时延 % 发射 chirp 基带相位(忽略载频项) phase_tx = 2*pi*(0.5*S*t.^2); tx = exp(1j*phase_tx); % 回波:模拟时延后的发射信号 delay_n = round(tau*fs); rx = zeros(1,Ns); if delay_n < Ns rx(delay_n+1:end) = tx(1:end-delay_n); end % 去斜处理:回波与发射信号共轭相乘 beat = rx .* conj(tx); % 加窗 + 补零 FFT win = hann(Ns,'periodic').'; Nfft = 2^14; spec = fft(beat .* win, Nfft); f_ax = (0:Nfft-1)/Nfft*fs; range_ax = f_ax * c * Tc / (2*B); [~, idx] = max(abs(spec)); fprintf('估计差拍频率: %.2f kHz\n', f_ax(idx)/1e3); fprintf('估计距离: %.2f m\n', range_ax(idx));代码逻辑:发射 chirp 用复指数表示,回波就是同一段序列向右循环移位;共轭相乘模拟混频器去斜,得到单频差拍信号;FFT 峰值对应的频率再代入距离公式。这里有几个注意点:Hann 窗抑制频谱泄漏,但会略微展宽主瓣;补零不提高分辨率,只让频谱采样更密,方便读峰。
提示:这段代码假设目标静止,也没加噪声,实际仿真里回波还要叠加多普勒频移和接收机噪声。
3. Matlab 实现 FMCW 测距的完整流程:参数设计、去斜、FFT、CFAR
3.1 先定参数还是先测目标:仿真参数的自洽约束
做仿真之前,先把参数之间的互相约束列出来,否则测出来会得到明显不对的距离。约束有三条:最大差拍频率不能超过 fs/2,最大测距距离与 f_b,max 对应;距离分辨率只由 B 决定;慢时间维的 chirp 数决定多普勒分辨率。
%% 参数自洽性检查 B = 250e6; Tc = 100e-6; fs = 4e6; c = 3e8; Rmax = fs/2 * c * Tc / (2*B); % 最大不模糊距离 dR = c / (2*B); % 距离分辨率 fprintf('Rmax = %.1f m, dR = %.2f m\n', Rmax, dR);如果 Rmax 只有几十米,而你的液位计量程是 200 米,就得降 fs 或升 Tc。降 fs 会限制差拍频率上限,升 Tc 会拖慢数据率,这就是参数表里每个数字都是取舍的结果。
3.2 多目标回波仿真与距离维 FFT
%% FMCW 测距完整流程:多目标 + 噪声 B = 250e6; Tc = 100e-6; fs = 4e6; c = 3e8; fc = 24e9; Ns = round(Tc*fs); t = (0:Ns-1)/fs; S = B/Tc; targets = [30 12; 45 8]; % [距离(m) 回波幅度] % 发射 chirp phase_tx = 2*pi*(0.5*S*t.^2); tx = exp(1j*phase_tx); % 合成多目标回波 rx = zeros(1,Ns); for k = 1:size(targets,1) tau = 2*targets(k,1)/c; dn = round(tau*fs); if dn < Ns rx(dn+1:end) = rx(dn+1:end) + targets(k,2)*tx(1:end-dn); end end rx = rx + 0.1*(randn(1,Ns)+1j*randn(1,Ns)); % 接收机噪声 % 去斜 beat = rx .* conj(tx); % 加窗 + 补零 FFT win = hann(Ns,'periodic').'; Nfft = 4096; spec = fft(beat.*win, Nfft); f_ax = (0:Nfft-1)/Nfft*fs; range_ax = f_ax*c*Tc/(2*B); % CA-CFAR 检测 det = cfar_ca(abs(spec), 10, 3, 1e-3); det_ranges = range_ax(det); for i = 1:length(det_ranges) fprintf('检测到目标: %.2f m\n', det_ranges(i)); endfunction det = cfar_ca(x, guard, train, pfa) % 单元平均恒虚警检测 N = length(x); det = false(1,N); for i = train+guard+1 : N-train-guard cell_left = x(i-guard-train : i-guard-1); cell_right = x(i+guard+1 : i+guard+train); noise = mean([cell_left cell_right]); thr = noise * (2*train) * (pfa^(-1/(2*train)) - 1); det(i) = x(i) > thr; end end固定门限在噪声不平坦时不好用:近距大目标的旁瓣会触发误检,远端弱目标又可能被抬高的底噪淹没。CA-CFAR 用待检测单元两侧的参考单元估计噪声底,动态生成门限,是雷达信号处理里最常见的选择。guard 单元用来避开目标主瓣泄漏到参考窗,train 越大估计越稳,但代价是检测不到靠得太近的两个目标。
3.3 峰值读数的误差边界:栅栏效应与抛物线插值
FFT 频点是离散的,真实峰值落在两个频点之间时,直接读最大点会有最多半个频点间隔的误差。一个频点间隔对应 c·fs/(2B·Nfft) 米,补零把 Nfft 加大可以减小这个间隔,但计算量也变大。工程上更划算的做法是抛物线插值:
% 在峰值附近做抛物线插值 k = idx; if k > 1 && k < length(spec) a = abs(spec(k-1)); b = abs(spec(k)); c = abs(spec(k+1)); delta = 0.5*(a-c)/(a-2*b+c); f_est = (k + delta) / Nfft * fs; R_est = f_est * c * Tc / (2*B); fprintf('插值后距离: %.2f m\n', R_est); enddelta 是偏离整数频点的分数,通常能补偿掉 80% 以上的栅栏误差。插值公式要求谱峰附近没有其他目标干扰,多目标场景下要先用 CFAR 把各峰的门限定出来,再逐个插值。
提示:抛物线插值只对单音信号有效。如果谱峰被展宽严重,插值反而引入偏移,这时候优先检查窗函数和调频线性度。
4. 多目标与动目标:距离-多普勒二维 FFT 与参数约束
4.1 快时间与慢时间:为什么一组 chirp 能同时测距测速
单个 chirp 内的采样叫快时间维,距离信息体现在快时间维的 FFT 峰值位置;跨 chirp 看同一个距离门的相位变化,叫慢时间维,目标径向运动让回波时延逐行变化,表现为相位逐行旋转,对慢时间再做一次 FFT 就得到多普勒频率:
f_d = 2·v/λ,v = f_d·λ/2
其中 λ = c/fc。要把测距和测速放在同一帧里,发射 M 个相同的 chirp 组成一帧,距离 FFT 之后沿 chirp 维再做一次 FFT,就是距离-多普勒图。
4.2 距离-多普勒二维 FFT 的 Matlab 实现
%% FMCW 距离-多普勒二维 FFT:动目标测速 M = 128; % 一帧 chirp 数 Tc = 100e-6; fs = 4e6; B = 250e6; fc = 24e9; c = 3e8; Ns = round(Tc*fs); t_fast = (0:Ns-1)/fs; S = B/Tc; R0 = 50; v = 5; % 目标初始距离 50 m,径向速度 5 m/s % 发射参考 chirp phase_tx = 2*pi*(0.5*S*t_fast.^2); tx = exp(1j*phase_tx); % 逐 chirp 生成回波,考虑时延随慢时间变化 data = zeros(M, Ns); for mIdx = 1:M tm = (mIdx-1)*Tc; tau = 2*(R0 + v*tm)/c; % 时延随慢时间变化 dn = round(tau*fs); if dn < Ns data(mIdx, dn+1:end) = tx(1:end-dn); end end % 去斜 beat_mat = data .* conj(tx); % 距离维 FFT win_r = hann(Ns,'periodic').'; RDM = fft(beat_mat .* win_r, 2048, 2); % 多普勒维 FFT win_d = hann(M,'periodic').'; RDM = fft(RDM .* win_d, 1024, 1); RDM = fftshift(RDM, 1); % 坐标轴 range_ax = (0:2047)/2048*fs*c*Tc/(2*B); f_dop = (-512:511)/1024/Tc; v_ax = f_dop * c / (2*fc); % 取峰 [mIdx, nIdx] = find(abs(RDM) == max(abs(RDM(:))), 1); fprintf('估计距离: %.2f m, 估计速度: %.2f m/s\n', ... range_ax(nIdx), v_ax(mIdx));慢时间维 FFT 之前也要加窗,否则多普勒谱的旁瓣会盖住邻近弱目标。速度分辨率是 λ/(2·M·Tc),这个例子里约 0.49 m/s;速度不模糊范围是 ±λ/(4·Tc) ≈ ±31.25 m/s。如果目标速度超过这个范围,多普勒维会折叠,需要改用更短的 Tc 或换波形。
4.3 参数约束:一张表说清雷达参数怎么互相牵制
| 设计目标 | 调整方式 | 代价 |
|---|---|---|
| 提高距离分辨率 | 增大 B | fs 或数据量上升 |
| 提高最大测距 | 降低 fs 或增大 Tc | 速度模糊范围变小 |
| 提高速度分辨率 | 增加 M 或增大 Tc | 帧率下降 |
| 提高速度不模糊范围 | 降低 Tc | 最大测距下降 |
这四个参数互相咬合,调任何一个都要重算一遍 Rmax、vmax、δR、δv,最好写成一个参数自检脚本放在工程入口处,防止改着改着某个约束被悄悄破坏。
4.4 从仿真走向实测:替换数据源就能继续用
仿真里的 beat_mat 换成实际射频前端 IQ 两路 ADC 数据,后面的距离 FFT 和 CFAR 流程完全不用改。实测数据通常是 CSV 或二进制文件,导入后先确认快时间维的方向和时间戳对齐。如果整个段落要落 C++,用 Matlab Coder 生成代码时保持相同的 Nfft 和窗函数,结果才能和仿真逐点对齐。现在 Codex 这类 Agent 已经能直接读 Matlab 脚本并帮你跑仿真调度,但 ADC 数据的字节序、通道交织这类硬件细节它判断不了,最终还是得靠自己对着时序图确认。
5. 工程上必调的 5 个参数与校准技巧
5.1 窗函数选择:分辨率与旁瓣的交换
矩形窗旁瓣只有 -13 dB,近距离强目标的旁瓣会掩盖远距离弱目标;Hann 窗旁瓣 -31 dB,主瓣展宽到 2 个频点;Blackman-Harris 旁瓣 -92 dB,主瓣展宽到 4 个频点。多目标动态范围超过 30 dB 时,我一般直接上 Blackman-Harris,少调几次旁瓣的麻烦。
5.2 峰值相位测距:突破距离分辨率下限
距离 FFT 峰值处的复相位携带亚距离单元的位移信息。对静止目标,目标位移 ΔR 会造成峰值相位变化 Δφ ≈ 4πΔR/λ,把相位差测出来就能反推微小位移:
% 两次测量的峰值相位差 phi1 = angle(spec1(idx)); phi2 = angle(spec2(idx)); dphi = angdiff(phi1, phi2); % 相位差,处理 ±π 跳变 dR = dphi * c / (4*pi*fc); % 亚毫米级位移相位测距的精度远高于幅度峰值读频,但存在 2π 模糊,适合测相对位移而不是绝对距离,多用于振动测量和高精度形变监测。
5.3 环路延迟标定:消除系统固有偏差
射频前端、滤波器、线缆会引入固定时延,直接让所有距离读数整体偏移。标定方法是用一段已知长度的短延迟线代替天线,测出差拍频率偏移 f_b,off,校准后距离公式变成:
R = (f_b - f_b,off) · c · Tc / (2B)
这个偏移是慢漂移的,温度变化明显时建议重新标定,而不是一次性写死。
5.4 调频非线性检查
找一台高分辨率频谱仪看差拍信号的谱线宽度,调频非线性会让单目标谱线展宽,直接表现为距离维主瓣变肥。仿真阶段可以用 pwelch 观察实测差拍信号的功率谱密度,如果主瓣底部比理论值宽出 20% 以上,优先怀疑扫频源的锁相环环路带宽。
最后一行留给一个最容易被忽略的细节:把扫频参考时钟从普通晶振换成恒温晶振,再看相位谱,1 Hz 以下的慢漂移会被明显削掉,这类问题用 Matlab 的 pwelch 能直接观察到,是判断发射源相位噪声和调频线性度最省事的办法。
本文还有配套的精品资源,点击获取