4. UWB与BLE融合定位系统架构设计

各位做定位的朋友,咱们今天聊点实在的。UWB 和 BLE 各有各的脾气——UWB 精度高但容易受遮挡,BLE 覆盖广但稳定性差。把它们捏在一起,就是融合定位的核心思路。

但怎么捏?这里头有讲究。我最早做融合时,直接把两个定位结果求平均,结果精度还不如单用 UWB。后来才明白,融合架构选错了,后面全白搭。

4.1 松耦合 vs 紧耦合:两种融合思路

说白了,松耦合和紧耦合的区别,就是「各自算完再合」还是「原始数据就合」。我画了张图,你看一眼就明白。

核心区别一句话:松耦合融合的是定位结果,紧耦合融合的是原始观测数据。

松耦合 vs 紧耦合架构对比 松耦合架构 UWB 定位引擎 BLE 定位引擎 UWB 位置 (x,y) BLE 位置 (x,y) 融合滤波器(加权/切换) 最终位置输出 紧耦合架构 UWB 原始测距 (TOF/RSSI) BLE 原始观测 (RSSI/信道) 联合卡尔曼滤波器 (状态向量包含所有传感器信息) 最优状态估计 位置+速度+偏置

4.1.1 松耦合架构

松耦合,就是 UWB 和 BLE 各自独立解算位置,然后把两个位置结果扔给一个融合模块做决策。我早期做的一个仓储项目用的就是这种方案。

优点很明显:

  • 模块独立,UWB 和 BLE 可以分别调试、分别升级
  • 计算量小,嵌入式 MCU 跑得动
  • 系统鲁棒性好——一个挂了另一个还能用

缺点也扎心:

  • 精度上限低,因为融合的是「结果」而不是「原始信息」
  • 无法利用 UWB 的精确测距去校正 BLE 的 RSSI 波动

我的经验:松耦合适合对实时性要求高、MCU 资源紧张的场景。比如手持终端定位,每秒要出 10 次位置,松耦合轻松搞定。

4.1.2 紧耦合架构

紧耦合就狠多了。它把 UWB 的原始测距值(TOF)和 BLE 的 RSSI 观测值直接塞进同一个滤波器。状态向量里同时包含位置、速度、甚至时钟偏置。

我曾经在一个隧道定位项目里试过紧耦合。隧道里 UWB 信号经常被金属支架遮挡,但 BLE 信号反而稳定。紧耦合滤波器能自动利用 BLE 的 RSSI 变化趋势来「撑住」UWB 丢帧时的位置估计——这个能力松耦合做不到。

紧耦合的代价:

  • 状态维度高,计算量大——STM32F4 级别勉强够用
  • 调试复杂,任何一个传感器的噪声模型不准,整个滤波器可能发散
  • 代码耦合度高,改一个传感器逻辑可能影响全局
对比维度 松耦合 紧耦合
融合层级 位置级 观测级
精度上限 中等(约 30-50cm) 高(约 10-20cm)
计算开销 低 高
调试难度 低 高
典型 MCU STM32F1/F4 STM32H7/RT1052

4.2 数据融合层级:你在哪一层融合?

除了松紧耦合,还有个维度——数据融合的层级。我习惯把它分成三层:

  1. 数据级融合:直接对原始采样数据做处理。比如把 UWB 的 TOF 值和 BLE 的 RSSI 值做归一化后加权。这层最底层,信息损失最少,但数据量巨大。
  2. 特征级融合:先提取特征再融合。比如从 UWB 测距序列中提取「视距/非视距」特征,从 BLE 序列中提取「信号稳定性」特征,然后融合这些特征做定位决策。
  3. 决策级融合:每个传感器独立做出定位决策,最后用投票或加权方式决定最终位置。松耦合本质上就是决策级融合。

避坑提醒:我曾经在一个项目中试图做数据级融合,把 UWB 和 BLE 的原始数据直接拼接成向量输入神经网络。结果数据量太大,MCU 内存直接爆了。后来老老实实降到特征级融合才跑通。

4.3 卡尔曼滤波基础:融合的数学引擎

聊融合架构,绕不开卡尔曼滤波。它几乎是所有定位融合算法的基石。我尽量用白话讲清楚。

4.3.1 卡尔曼滤波在干什么?

你想想看,你有一个系统状态(比如位置和速度),但你没法直接测量它。你只能通过传感器得到一些带噪声的观测值。卡尔曼滤波就是帮你从这些「脏数据」里,递归地估计出最可能的状态。

它分两步走:

  • 预测(Predict):根据上一时刻的状态和运动模型,猜一下当前状态大概在哪
  • 更新(Update):用当前的传感器观测值,修正这个猜测

说白了,就是「猜一下,量一下,修正一下」的循环。

4.3.2 核心公式(别怕,就五个)

卡尔曼滤波的核心就五个公式。我当年第一次看时也觉得头大,但实际写代码时发现,就是矩阵乘法和加减法。

// 预测步骤
x_pred = A * x_prev + B * u          // 状态预测
P_pred = A * P_prev * A^T + Q        // 协方差预测

// 更新步骤
K = P_pred * H^T * (H * P_pred * H^T + R)^(-1)  // 卡尔曼增益
x_est = x_pred + K * (z - H * x_pred)            // 状态更新
P_est = (I - K * H) * P_pred                     // 协方差更新

这里每个符号都有物理意义:

符号 含义 在融合定位中的例子
x 状态向量 [位置x, 位置y, 速度vx, 速度vy]
A 状态转移矩阵 匀速运动模型:x_k = x_{k-1} + v*dt
z 观测向量 UWB 测距值、BLE RSSI 值
H 观测矩阵 把状态映射到观测空间
Q 过程噪声协方差 运动模型的不确定性
R 观测噪声协方差 传感器的噪声水平
K 卡尔曼增益 相信模型还是相信传感器

关键理解:卡尔曼增益 K 决定了「我更相信预测模型」还是「我更相信传感器」。如果传感器噪声大(R 大),K 就小,滤波器更依赖模型预测。反之亦然。

4.3.3 在 UWB+BLE 融合中的实际用法

我拿一个实际项目举例。当时做室内人员定位,状态向量取 4 维:[x, y, vx, vy]。UWB 提供的是距离观测(TOF 转成距离),BLE 提供的是 RSSI 观测。

观测矩阵 H 的设计很有意思:

  • 对于 UWB,H 是距离对位置的偏导数——也就是从状态空间到测距空间的雅可比矩阵
  • 对于 BLE,H 是 RSSI 路径损耗模型对位置的偏导数

嗯,这里要注意:UWB 和 BLE 的观测更新频率不同。UWB 通常 10-50Hz,BLE 只有 1-5Hz。所以实际代码里,我通常把预测步骤跑在 UWB 的更新周期上,BLE 的观测到了才做一次更新。

// 伪代码:UWB + BLE 融合卡尔曼滤波主循环
while (1) {
    // 1. 预测步骤(每个 UWB 周期执行)
    x = A * x;
    P = A * P * A^T + Q;

    // 2. 如果有 UWB 测距到达
    if (uwb_data_ready()) {
        z_uwb = get_uwb_range();
        H_uwb = compute_jacobian_uwb(x);  // 距离对位置的雅可比
        K = P * H_uwb^T * inv(H_uwb * P * H_uwb^T + R_uwb);
        x = x + K * (z_uwb - h_uwb(x));
        P = (I - K * H_uwb) * P;
    }

    // 3. 如果有 BLE RSSI 到达(频率较低)
    if (ble_data_ready()) {
        z_ble = get_ble_rssi();
        H_ble = compute_jacobian_ble(x);  // RSSI 对位置的雅可比
        K = P * H_ble^T * inv(H_ble * P * H_ble^T + R_ble);
        x = x + K * (z_ble - h_ble(x));
        P = (I - K * H_ble) * P;
    }

    // 4. 输出当前最优位置估计
    output_position(x[0], x[1]);
}

调参经验:Q 和 R 的比值决定了滤波器的「惯性」。我习惯先让系统在纯 UWB 下跑通,调好 Q,再加入 BLE 观测,单独调 R_ble。两个一起调容易找不到问题根源。

4.3.4 扩展卡尔曼滤波(EKF)的必要性

标准的卡尔曼滤波假设系统是线性的。但 UWB 的测距方程是非线性的——距离和位置的关系是平方根关系。BLE 的 RSSI 路径损耗模型更是典型的对数非线性。

所以实际项目中,我几乎不用标准 KF,而是用 EKF(扩展卡尔曼滤波)。EKF 的核心思想就是:在每次预测和更新时,对非线性函数做一阶泰勒展开,用雅可比矩阵代替线性 KF 中的 A 和 H。

说白了,就是「把弯的掰直了再算」。

我曾经踩过的坑:EKF 的雅可比矩阵如果算错了,滤波器会直接发散。有一次我在计算 UWB 测距的雅可比时,把偏导数符号搞反了,结果位置估计直接往反方向跑。调试了整整两天才发现是符号问题。所以建议你写 EKF 时,先用数值微分验证一下雅可比矩阵的正确性。

4.4 架构选型建议

说了这么多,到底怎么选?我个人的经验是:

  • 产品原型阶段:先用松耦合快速验证。把 UWB 和 BLE 各自的位置结果用加权平均或简单切换融合,先跑通流程。
  • 性能优化阶段:如果精度不达标,再上紧耦合 EKF。这时候你已经有了 UWB 和 BLE 的噪声特性数据,调参会快很多。
  • 量产阶段:根据 MCU 资源做取舍。如果用的是 Cortex-M4 以下的内核,建议用松耦合+简单滤波;如果是 M7 或 A 系列芯片,紧耦合完全扛得住。

融合定位架构没有银弹。松耦合简单可靠,紧耦合精度更高但调试成本大。选哪个,取决于你的项目阶段和硬件资源。嗯,先跑起来,再优化,这是我一直坚持的原则。