☰
FMCW TDMA-MIMO毫米波雷达信号处理仿真全流程详解
2026/10/4 7:56:18 网站建设 项目流程

各位做毫米波雷达开发的朋友,今天聊一个特别实在的话题:怎么把一套FMCW TDMA-MIMO毫米波雷达信号处理仿真从头到尾搭起来。我最近刚好把一个基于TI IWR1443B的TDMA-MIMO工程在Matlab里完整跑通了,顺手把波形改成DDMA-MIMO也验证了一遍。这篇就把整个仿真链路拆开讲清楚,从FMCW测距测速原理、TDMA虚拟阵列构造,到距离-多普勒FFT、CFAR检测、角度估计、点云输出,每一步该怎么做、参数为什么这么定、代码怎么写、踩过哪些坑,全给你捋明白。适合刚接触雷达信号处理、准备做算法预研,或者正在为答辩/项目做仿真验证的开发者参考。


1. 仿真整体设计与思路拆解

1.1 先搞清楚FMCW在干什么

FMCW(Frequency Modulated Continuous Wave,调频连续波)毫米波雷达的核心逻辑可以一句话概括:发射一个频率随时间线性变化的chirp信号,碰到目标后反射回来,接收端把发射信号和回波信号混频,得到一个频率差(中频IF信号)。这个中频信号的频率直接反映目标距离,相位差反映目标速度。

很多初学者容易被一堆公式吓住,但工程上更常用的方式是先看参数再推信号。仿真的第一步就是明确chirp参数:起始频率f0、扫频带宽B、chirp时长Tc、ADC采样率fs、每帧chirp数。以IWR1443的典型配置为例,f0=77GHz,B=3.07GHz,Tc=58us,fs=10MHz,单帧128个chirp。这几个参数直接决定了雷达的距离分辨率、最大不模糊测距范围和多普勒分辨率。

  • 距离分辨率 d_res = c / (2B) ≈ 4.8cm
  • 最大不模糊距离 R_max = c * fs / (2 * 斜率),斜率 = B / Tc ≈ 52.9MHz/us,算下来R_max ≈ 28.3m
  • 最大不模糊速度由帧内相邻chirp的采样时间决定,后面展开说

这个参数体系非常重要,因为后续所有代码都在围绕它构建。如果你的仿真目标是看波束形成或角度估计,建议把chirp数设成16或32,速度维FFT点数可以小一点;如果目标是看目标检测和点云密度,就保持128甚至256个chirp。先想清楚“你要让这个仿真回答什么问题”,再决定参数规模,而不是随手拉一组数字。

1.2 为什么非要用MIMO,TDMA是什么角色

如果只有单发单收天线,目标的角度分辨率受限于物理孔径。想要窄波束,要么把天线做长,要么用MIMO的办法用虚拟阵列扩展孔径。毫米波雷达普遍采用多发射多接收的方式:发射天线轮流发射(TDMA)或者多普勒偏置发射(DDMA),接收天线同时接收。这样一来,N_TX个发射天线和N_RX个接收天线可以合成N_TX × N_RX个虚拟通道,等效于一个更大的接收阵列。我在仿真里用的就是3发4收配置,虚拟阵列为12通道。实际布站时发射天线间距通常是2倍波长(或更大),接收天线间距为半个波长,这样经过相位补偿后能得到均匀线阵的效果。

TDMA-MIMO的实现思路是让不同发射天线在时间上错开发射chirp。比如3发4收,每个chirp只由一个发射天线工作,4个接收通道同时采样,得到4×1组数据;下一个chirp切到另一个发射天线,得到下一组数据。把所有chirp按发射天线分组后,就可以在角度维构成12通道的阵列数据。

TDMA方案的优势是实现简单、通道隔离度高,缺点是每个发射天线的有效chirp率下降了1/N_TX倍,导致最大不模糊速度缩水。这是之后我们做参数设计和DDMA切换时会重点对比的一个问题。

1.3 为什么我要把DDMA-MIMO作为可替换选项

DDMA(Doppler Division Multiple Access,多普勒偏置多址)是TI在IWR1443/AWR1443上主推的另一种MIMO方式。它不让天线轮流独占时隙,而是让所有发射天线在同一时间同时发射,但给不同发射天线叠加一个不同的相位(相当于多普勒频偏)。这样做有两个直接收益:一是发射占空比提高,等效chirp率不下降,最大不模糊速度比TDMA高N_TX倍;二是在相同帧时长内能获得更多的慢时间采样,角度估计的样本量更充足。

但DDMA的代价也很明显:多普勒维上每个目标被复制成N_TX个子峰,分别对应不同发射天线。信号处理时需要先做多普勒解偏置,把不同发射天线分离出来,然后再构造虚拟阵列做角度估计。如果目标多或者信噪比低,解模糊出错就会造成点云残留或速度错误。所以DDMA不是“免费午餐”,而是把TDMA的时分代价转换成了信号处理侧的分离代价。我会在第4部分给出这两种波形的生成方法和切换细节。


2. FMCW TDMA-MIMO回波信号建模与核心参数计算

2.1 chirp参数和帧结构的确定

实际仿真的起点是一张参数表。我以IWR1443 Boost配置为例写了一套仿真参数,实测下来物理含义清晰、计算量适中,大家可以作为基础配置来改:

参数数值说明
载频 f077GHz毫米波频段,波长 lambda ≈ 3.9mm
扫频带宽 B3.07GHz决定距离分辨率
chirp时长 Tc58us含ADC采样窗口和空闲时间
ADC采样率 fs10MHz决定最大不模糊距离
ADC采样点数 N256距离维FFT点数
发射天线数 TX3TDMA时分发射
接收天线数 RX4同时接收
每帧chirp数 chirp_frame192128为数据体,余下用于器件配置/间插
帧周期 T_frame40ms影响多普勒分辨率与实时性

基于这张表,我们需要在代码里完成三件基础工作:

  1. 生成发射chirp的频率时间曲线并计算每个采样时刻的发射相位;
  2. 根据目标的位置、速度和反射系数,构造接收回波;
  3. 混频、低通滤波,输出中频复数采样信号。

工程上回波建模的公式不复杂。对第n个TX天线、第m个RX天线、第k个chirp、第i个采样点,理想中频信号可以写成:

s_if[n][m][k][i] = A_target * exp( j * 2π * ( f_b * t_i + 2 * v * f0 * (k * Tc + n * T_sub) / c ) )

其中f_b是差频频率,来自距离和速度的共同作用,t_i是快时间采样时刻,v是目标径向速度。括号里第一项是距离引起的频率项,第二项是跨chirp的速度相位项,第三项是TDMA切换时各发射天线之间的相位差,这项在构造虚拟阵列时必须处理得特别小心。

如果你之前看过一些开源雷达仿真代码,会发现很多人直接把中频信号表示成复数指数,这是对的,但往往忽略了不同发射天线之间的时间偏移会导致相位不连续。使用TDMA时,每个发射天线是在不同的慢时间时刻发射的,目标移动会让相位产生一个额外的偏移,如果不做补偿,角度估计会整体偏移。后面我给的代码里专门留了comp_phase这一步,用来修正这个偏移。

2.2 实数雷达中频信号的工程近似

另外要注意的是,真实TI毫米波雷达的ADC采样出来的是实信号(I/Q两路是分开的,有的平台只输出一路中频实信号)。仿真时为了简化,一般直接构造复数基带信号,等价于假设I/Q两路都采样并且正交。这个假设在算法验证阶段完全够用,但如果你准备把算法移植到嵌入式平台,就需要考虑实信号会带来镜像频率问题,仿真里不能自动帮你滤掉。

2.3 目标场景设计

回波建模里还需要设计目标列表。仿真里我通常用3种典型场景验证算法:

  • 单目标静态:验证距离维FFT峰值位置和幅值是否跟理论一致;
  • 单目标匀速运动:验证距离维和多普勒维是否同时出峰,速度值是否正确;
  • 双目标同距离不同速度或同速度不同距离:验证距离/多普勒二维FFT的分辨能力。

目标的位置(range, angle, velocity)用一个结构体数组存起来,比如target_struct.range、target_struct.azimuth、target_struct.velocity。生成回波时按目标逐个叠加,幅度用RCS和路径损耗近似。仿真里一般不用特别精确的传播方程,只要保证相对幅度合理、信噪比在20dB以上,算法验证已经足够。


3. 核心处理流程与Matlab代码实现

3.1 从原始数据到距离-多普勒谱

回波数据在仿真里是一个四维数组:TX × RX × chirp × ADC_samples。因为TDMA时分,我对每一帧数据按TX依次重组,得到虚拟通道形式的data_cube,维度是(VirtualChannels, chirp_per_tx, adc_samples)。重组后,距离维FFT沿第三维做,多普勒FFT沿第二维做,得到Range-Doppler Map(RDM)。

核心代码(Matlab):

% data_cube: [numVirtual, chirpPerTx, adcSamples] % Step 1: 距离维FFT,加窗抑制旁瓣 rangeWin = hanning(adcSamples).'; rangeFFT = fft(data_cube .* rangeWin, adcSamples, 3); % Step 2: 多普勒维FFT,注意这里直接对每个距离cell做 dopWin = hanning(chirpPerTx).'; rangeDoppler = fftshift(fft(rangeFFT .* dopWin, chirpPerTx, 2), 2);

这里有两个细节值得强调:

第一,距离维FFT前必须加窗。不加窗的情况下,旁瓣可能把弱目标淹没。我习惯用hanning或hamming窗,虽然主瓣会变宽一点点,但旁瓣抑制效果对CFAR检测的稳定性帮助很大。如果你处理的是4D毫米波雷达点云,甚至可以考虑用Blackman-Harris,旁瓣更低,代价是分辨率损失。

第二,fftshift的位置。多普勒FFT后,零频在索引1处,fftshift之后零频居中,方便后续按多普勒频率索引来匹配速度。这一步不要省,否则后面画图和CFAR检测都会变得别扭。

3.2 距离-多普勒维的CFAR检测

从RDM上找目标,最常用的是一维或二维CFAR。二维CFAR计算量大一点,但对低信噪比目标的检测能力更好。在仿真里,我倾向于先做一个简单的二维CA-CFAR,参考窗选8×8,保护窗选2×2,训练单元数取32。阈值的计算方式是对参考窗内幅度求平均,再乘一个缩放因子alpha。

% 二维CA-CFAR示意 for r = guard + ref + 1 : N_range - (guard + ref) for d = guard + ref + 1 : N_dop - (guard + ref) cell = abs(rangeDoppler(r, d)); % 参考窗均值 refWin = rangeDoppler(r-ref:r+ref, d-ref:d+ref); refWin(guard+1:end-guard, guard+1:end-guard) = []; % 挖掉保护窗 threshold = alpha * mean(abs(refWin(:))); if cell > threshold detections = [detections; r, d, cell]; end end end

这个双重循环在Matlab里跑起来比较慢,实际做仿真验证时,我会用filter2或者blockproc来做均值滤波,速度能提升几十倍。不过循环版本更直观,适合理解和调试。

CFAR之后需要对检测到的距离多普勒单元做峰值细化,常见做法是在峰值点周围3×3邻域内找最大值,或者直接用质心法。质心法在目标速度连续变化时效果更好,峰值法在旁瓣干扰明显时更稳。在纯仿真环境里,我建议先用3×3峰值搜索把点找干净,再考虑质心法。

3.3 目标距离和速度解算

得到峰值对应的距离索引r_idx和多普勒索引d_idx后,距离和速度可以按下面公式解算:

  • 距离:R = c * f_b * Tc / (2 * B),其中f_b = r_idx * fs / N_range
  • 速度:v = (d_idx - N_dop/2) * lambda / (2 * Tc * chirpPerTx) (因为fftshift后索引有偏移)

注意这里的chirpPerTx是每个发射天线在帧内对应的chirp数。TDMA方案下,虚拟通道数据里每个通道的慢时间采样率等于chirp_per_tx,而不是总chirp数,这个细节非常容易被忽略。你如果用总chirp数去算速度,结果会差整整3倍。

3.4 MIMO虚拟阵列角度估计

目标检测完之后,提取每个目标在RDM峰值处的复数值,拿到所有虚拟通道上,构成一个12×1的向量。对这个向量做FFT(或者波束形成扫描),就能得到角度-幅度谱。角度估计和FFT很像,区别是阵列流型是sin(angle)的非线性函数,所以需要把目标角度域均匀划分为若干网格点。

thetaGrid = -90:0.1:90; arrayVec = exp(1j * 2 * pi * d_lambda * (0 : numVirtual - 1).' * sin(deg2rad(thetaGrid))); % d_lambda = 0.5 接收阵元间隔,按波长归一化 % 得到角度谱 angleSpectrum = abs(arrayVec' * x_peak); [~, idxMax] = max(angleSpectrum); angleEst = thetaGrid(idxMax);

如果你的仿真目标里包含两个角度相近的强目标,FFT角度谱可能分不开,这时候可以换成MUSIC或求根MUSIC算法。但MUSIC需要先知道目标个数,且对信噪比比较敏感。工程上往往先用FFT做一个初筛,再对疑似目标点做超分辨处理。我在仿真里就保留了两个接口:一个get_angle_fft,一个get_angle_music,切换起来很方便。

3.5 点云输出的最后一公里

角度估计完成之后,把每个目标的距离、速度、角度、幅度组装成点云结构体。如果每个距离-多普勒峰值只有一组角度,那一个RDM峰值就对应一个点。但实际场景里同一个距离多普勒cell可能对应多个不同角度的目标,这时就需要在角度维做第二次峰值检测,或者对角度谱做CFAR/二分峰搜索。仿真里为了让效果直观,我往往是先设定目标数,再用角度谱检峰的方式输出对应数量的点,这样能直接验证算法正确性。


4. TDMA-MIMO到DDMA-MIMO的波形改造

4.1 TDMA波形生成的实现细节

TDMA波形生成的核心是给每个chirp打上发射天线的标签。仿真里我用了一个很简单的办法:对第k个chirp,其发射天线编号为mod(k, TX),对应回波信号中该chirp的发射相位是 exp(j * 2 * pi * f0 * (k - mod(k, TX)) * Tc * v_target / c)。这个相位项在低速目标下可以忽略,但目标速度较高时如果不补偿,角度估计误差会呈线性增长。

TDMA的实现代码片段:

for k = 1 : chirp_frame tx_idx = mod(k-1, numTx) + 1; % 该chirp只有第tx_idx个发射天线发射,其他发射天线幅度为0 for rx_idx = 1 : numRx for sample_idx = 1 : adcSamples t = (k-1) * Tc + sample_idx / fs; phase = 2 * pi * (f0 * t + 0.5 * slope * t^2); tx_signal = exp(1j * phase); % 对每个目标累加回波 for tgt = 1 : numTargets tau = 2 * (targets(tgt).range + v * t) / c; rx_signal(tx_idx, rx_idx, k, sample_idx) = rx_signal(tx_idx, rx_idx, k, sample_idx) + complex_amp * tx_signal * exp(-1j * 2 * pi * f0 * tau); end end end end

这里有个嵌套循环会跑得很慢,我实际验证时通常把目标累加部分改成向量化写法。下面给出向量化版本的核心思路,可以避免四层循环导致的仿真时间爆炸:

for k = 1 : chirp_frame tx_idx = mod(k-1, numTx) + 1; t_adc = (0 : adcSamples - 1) / fs; t_full = (k-1) * Tc + t_adc; tx_phase = exp(1j * (2 * pi * (f0 * t_full + 0.5 * slope * t_full.^2))); for tgt = 1 : numTargets tau = 2 * (R_tgt + v_tgt * t_full) / c; rx_phase = exp(-1j * 2 * pi * f0 * tau); rx_signal(tx_idx, :, k, :) = rx_signal(tx_idx, :, k, :) + A_tgt * tx_phase .* rx_phase; end end

向量化后的仿真计算量大约只是原来的百分之一,很多人第一次写仿真卡在Matlab跑不动,多半就是循环写得太粗放了。

4.2 DDMA波形生成以及多普勒解偏置

DDMA波形的不同点在于:每个chirp所有TX天线同时发射,但每个TX天线叠加一个不同的慢时间相位斜坡。常用的相位增量是2π/TX的整数倍,这样在慢时间维上就形成了频率偏置。

% DDMA偏置:每个TX对应的多普勒频偏 for k = 1 : chirp_frame for tx_idx = 1 : numTx dopplerOffsetTx = exp(1j * 2 * pi * (tx_idx - 1) * (k - 1) / numTx); % 对所有RX通道累加回波时,额外乘上dopplerOffsetTx end end

经过距离-多普勒FFT后,原本同一个真实目标会在多普勒维上出现3个峰,分别对应3个TX天线。下一步要做的就是把多普勒谱按偏置量切分成3个区间,再合并相同真实速度的目标信息。工程上常用方法是doppler de-aliasing,也就是把RDM沿多普勒维循环移位,再按每个TX对应的子带拼接。

如果目标速度很高或者多普勒模糊严重,解偏置阶段很容易出错。我的建议是:先仿真里把速度限制在最大不模糊速度以内,验证DDMA的核心链路,再逐步提高速度测试解模糊逻辑。纯算法上可以把多普勒维点数扩大4倍做插值后再切分,能显著提高分离精度。

4.3 TDMA和DDMA的优劣对比

对比维度TDMA-MIMODDMA-MIMO
发射天线工作方式分时发射,单通道独立同时发射,多通道并行
最大不模糊速度受chirp率/N_TX限制不受N_TX衰减,等效chirp率高
信号处理复杂度低,相位补偿容易高,需要多普勒解偏置
通道隔离度好,天线间干扰小需要额外相位校正
目标信噪比每个通道只有单个TX信号多TX同时发射,接收功率串扰风险高
典型适用场景低速短距高精度定位高速场景或远距目标检测

如果你的雷达系统工作在最高速度120km/h的场景,TDMA 3发4收可能直接碰到速度模糊,这个时候DDMA明显更合适。而如果算法平台算力有限,TDMA的简单可靠就是最大优势。仿真里两种模式可以做成一个开关,这也是很多大厂预研阶段的标准操作。


5. 常见问题与调试技巧实录

5.1 距离维FFT后峰值位置不对

这是最常踩的坑。现象是设置目标在10米,但FFT出来的峰在8米或者12米。原因通常是斜率或者采样率的单位换算出了问题。MHz、us、m、Hz这几组单位一混合,数字就很容易错。我建议所有参数统一用国际单位制(Hz、s、m),只在输出显示时再转成MHz和us,这样能少一半的低级错误。

另一个常见原因是把ADC采样率和chirp斜率搞混。ADC采样率决定中频频率的采样范围,而不是中频本身的频率。距离分辨率和最大不模糊距离只跟带宽和采样率有关,一定要确认这两个参数在回波生成和FFT处理两侧用的是同一个值。

5.2 目标速度出现多普勒模糊

TDMA模式下,每个发射天线的有效慢时间采样率是chirp_per_tx / T_frame,如果目标速度太高,多普勒频偏超过系统能表示的范围,就会出现速度回绕。仿真里表现为主峰旁边出现一个虚假的镜像峰。此时要么提高chirp率,要么切换DDMA,要么在检测后做多普勒解模糊。我在仿真里加了一个参数maxVelCheck,每次检测后都对比目标真实速度和速度维最大值,一旦超限就提示“velocity ambiguous”,方便快速定位问题。

这里要多说一句:多普勒模糊不一定是坏事。有些人会用两段不同PRF的波形来解模糊,这是雷达界很成熟的MTD解模糊思路。但在仿真预研阶段,我建议先把不模糊速度范围内的性能做扎实,再考虑解模糊。

5.3 角度估计出现左右镜像

角度谱FFT方法在全向天线时可正常测角,但很多阵列的单元方向图不是全向的,左右90°附近的响应衰减不同,导致目标被估计到镜像位置。仿真里如果没加方向图模型,一般不会出这个问题。但如果你在回波建模里加入了天线方向图,或者想模拟真实天线罩效应,就容易踩到。

解决办法有两个方向:一是加天线方向图校正系数,二是限制角度搜索区间(比如只搜索-60°到60°)。我在最终点云输出里给每条检测加了一个quality指标,如果角度谱的次峰跟主峰幅度差小于3dB,就标记为“低置信度”,方便后续处理过滤。

5.4 CFAR检测在低信噪比下虚警率升高

CFAR的缩放因子alpha和参考窗大小直接决定虚警率。仿真里如果目标回波幅度变化很大(远近目标差几十dB),单阈值CFAR很容易出问题。工程上建议使用OS-CFAR(有序统计CFAR)或者SO-CFAR(最小选择CFAR)来应对多目标遮挡。我在仿真里简单实现时做了两级检测:先用CA-CFAR粗筛,再用角度谱一致性校验,虚警率能降一个数量级。

5.5 仿真运行速度太慢怎么办

回波生成的循环结构是性能瓶颈。除了向量化之外,还可以考虑减少每帧chirp数,比如先用16个chirp跑通全链路,再逐步往64、128加。另外,Matlab的fft在多维数组上默认沿第一维或指定维执行,如果你对每一帧都做循环,性能会很差;把数据排列成矩阵后一次性fft,速度提升明显。


6. 后续可扩展的方向

整个仿真框架跑通之后,我已经把TDMA和DDMA两个模式封装成两个函数,后面做扩展非常顺手。我自己接下来打算继续补三个方向:

一是把天线方向图模型加进去,研究真实阵列的旁瓣和遮挡对角度估计的影响。二是把点云输出接到一个简易的聚类和跟踪模块上,验证多目标跟踪的预处理效果。三是把整个信号处理链路移植到C++,用相同的数据集对比Matlab和C++的浮点结果,这一步对工程落地的参考价值很大。

如果你也想在这个仿真上继续做文章,我的建议是先别急着上深度学习或者3D检测,把2D FFT、CFAR和MIMO测角这几板的性能摸透。雷达信号处理的难点从来不是某个模块多高级,而是模块之间的接口和误差传递。仿真能做到“每个环节都能解释清楚为什么这么设计”,比堆出一堆跑得动但说不清的结果要有用得多。

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询