2、雷达信号处理流程:脉冲压缩、MTI/MTD、CFAR检测、目标参数估计

各位同学,今天我们来聊聊雷达信号处理的核心流程。说实话,这个流程我在不同项目里摸爬滚打了好几年,才真正吃透。你想想看,雷达回波从天线进来,到最终输出目标坐标,中间要经过好几道工序。每一道都像在「淘金」——从噪声和杂波里把目标信号捞出来。

2.1 脉冲压缩:把「胖脉冲」变「瘦脉冲」

脉冲压缩,说白了就是解决一个矛盾:既要看得远,又要看得清

雷达发射宽脉冲,能量大,能传得远。但宽脉冲距离分辨率差——两个目标挨得近,就分不开了。怎么办?发射时把脉冲「调制」一下,接收时再用匹配滤波器「压缩」回来。

核心思想:发射大时宽带宽积信号,接收时通过匹配滤波,把脉冲宽度压缩到 1/B(B 是带宽)。

我记得第一次调脉冲压缩算法时,遇到一个坑:匹配滤波器的系数没取共轭,结果压缩出来的波形全是乱的。嗯,这里要注意——匹配滤波器的冲激响应是发射信号的共轭反转

常见的调制方式有两种:

  • 线性调频(LFM):频率随时间线性变化。实现简单,应用最广。
  • 相位编码:用伪随机序列调制相位。旁瓣控制更好,但多普勒敏感。

代码实现上,我习惯用频域方式做脉冲压缩:

// 脉冲压缩 - 频域实现(伪代码)
void pulse_compression(complex* rx_signal, complex* tx_ref, int len) {
    // 1. 对接收信号和参考信号做 FFT
    fft(rx_signal, len);
    fft(tx_ref, len);
    
    // 2. 频域相乘(匹配滤波)
    for (int i = 0; i < len; i++) {
        rx_signal[i] = rx_signal[i] * conj(tx_ref[i]);
    }
    
    // 3. IFFT 回到时域
    ifft(rx_signal, len);
}

实战技巧:如果目标速度未知,LFM 信号会有「距离-多普勒耦合」。我在项目中遇到过这种情况——目标明明没动,压缩后却显示有微小位移。后来加了去斜处理才解决。

2.2 MTI/MTD:把「不动」的杂波滤掉

脉冲压缩做完,信号里还混着大量杂波——地面、建筑物、树木……这些静止目标回波强度往往比运动目标大得多。怎么办?用 MTI(动目标显示)和 MTD(动目标检测)。

MTI 的原理很简单:静止目标回波在相邻脉冲间相位不变,运动目标回波相位会变化。用对消器把固定相位成分干掉。

最常用的是双脉冲对消器:

// 双脉冲对消器
void mti_2pulse(complex* data, int num_pulses, int num_range_bins) {
    for (int r = 0; r < num_range_bins; r++) {
        for (int p = num_pulses - 1; p >= 1; p--) {
            data[p * num_range_bins + r] -= data[(p-1) * num_range_bins + r];
        }
    }
}

但 MTI 有个问题——它只能滤掉零多普勒附近的杂波。如果杂波有频谱展宽(比如风吹动的树叶),效果就差了。这时候要用 MTD。

MTD 的本质:对同一距离门上的多个脉冲做 FFT,得到多普勒谱。这样不仅能滤杂波,还能测目标速度。

我曾经在一个项目中,MTI 做完后杂波残留还是很大。后来换成 MTD,加了个汉明窗,效果立竿见影。你想想看,MTD 相当于把每个距离门上的慢时间信号变换到频域,杂波和运动目标在频域上就分开了。

MTD 的典型参数:

参数 典型值 说明
FFT 点数 16 / 32 / 64 点数越多,速度分辨率越高
窗函数 汉明 / 布莱克曼 降低旁瓣,但主瓣会变宽
脉冲重复频率 1~20 kHz 决定最大不模糊速度

注意:MTD 做完后,数据变成了三维——距离 × 多普勒 × 脉冲。我建议把多普勒维的数据存成复数形式,因为后续 CFAR 可能需要相位信息。

2.3 CFAR检测:在噪声里「找不同」

MTD 做完,我们有了距离-多普勒图。但哪些点是目标?哪些是噪声?CFAR(恒虚警率检测)就是干这个的。

CFAR 的核心思想:对每个待检测单元,用周围参考单元的统计量估计噪声功率,然后设定自适应门限

常用的 CFAR 类型:

  • CA-CFAR(单元平均):取参考单元的平均值。均匀噪声环境下最优。
  • GO-CFAR(选大):取左右两侧参考单元中较大的均值。适合杂波边缘场景。
  • SO-CFAR(选小):取较小的均值。适合多目标场景。
  • OS-CFAR(有序统计):对参考单元排序,取第 k 个值。抗干扰能力强。

我个人习惯用 OS-CFAR。为什么?因为实际场景中杂波分布往往不是均匀的,CA-CFAR 容易在杂波边缘产生虚警。我曾经在机场雷达项目里吃过这个亏——跑道边缘的杂波导致大量虚警,后来换成 OS-CFAR 才压下来。

// OS-CFAR 实现(一维情况)
int os_cfar(float* data, int len, int guard_cells, int ref_cells, int k, float factor) {
    int half_guard = guard_cells / 2;
    int half_ref = ref_cells / 2;
    float sorted[ref_cells];
    
    for (int i = half_guard + half_ref; i < len - half_guard - half_ref; i++) {
        // 收集参考单元
        int idx = 0;
        for (int j = i - half_ref - half_guard; j < i - half_guard; j++) {
            sorted[idx++] = data[j];
        }
        for (int j = i + half_guard + 1; j <= i + half_ref + half_guard; j++) {
            sorted[idx++] = data[j];
        }
        
        // 排序,取第 k 个值
        qsort(sorted, ref_cells, sizeof(float), cmp);
        float threshold = sorted[k] * factor;
        
        if (data[i] > threshold) {
            // 检测到目标
            return i;
        }
    }
    return -1;
}

参数调优建议:保护单元数一般取 2~4 个距离单元。参考单元数取 16~32。因子 factor 根据虚警率要求设定,典型值 1.5~3.0。我一般先在仿真数据上调好,再拿到实测数据微调。

2.4 目标参数估计:距离、速度、角度

CFAR 检测出目标后,下一步就是精确估计参数。说白了,就是回答三个问题:目标在哪?跑多快?朝哪个方向?

距离估计

  • 粗估计:根据 CFAR 检测到的距离门索引,乘以距离分辨率。
  • 精估计:对峰值附近做插值(抛物线拟合或 sinc 插值),精度可达亚距离门级。

速度估计

  • 粗估计:根据 MTD 多普勒通道索引,乘以速度分辨率。
  • 精估计:同样做插值。注意多普勒模糊问题——如果目标速度超过最大不模糊速度,需要解模糊。

角度估计

  • 单脉冲法:利用和差波束比幅测角。精度高,计算量小。
  • 比相法:利用两个接收通道的相位差。适合小间距天线。
  • 超分辨算法(MUSIC/ESPRIT):精度最高,但计算量大,嵌入式上要谨慎。

我的经验:在嵌入式平台上,我通常用「粗估计 + 抛物线插值」做距离和速度精估计。角度用单脉冲法。这套组合在计算量和精度之间取得了很好的平衡。

举个例子,距离精估计的抛物线插值:

// 抛物线插值求峰值位置
float parabolic_interp(float y0, float y1, float y2) {
    // y0: 峰值左侧值, y1: 峰值, y2: 峰值右侧值
    float delta = (y2 - y0) / (2 * (2 * y1 - y0 - y2));
    return delta;  // 相对于峰值索引的偏移量
}

嗯,到这里,雷达信号处理的核心流程就串起来了。从脉冲压缩到参数估计,每一步都有它的物理意义和工程考量。我在实际项目中,经常需要根据具体场景调整参数——比如城市环境杂波多,CFAR 的参考单元就要选大一些;高速目标多,MTD 的 FFT 点数就要增加。

下一章,我们会把这些算法搬到嵌入式 AI 加速器上,看看怎么用硬件加速让它们跑得更快。到时候你会发现,很多算法在硬件上实现时,思路和软件完全不同。