去年把一个 TDOA 四基站方案铺到仓库之后,我发现一个很务实的问题:定位精度再往上走,卡住的往往不是测距,而是几何。基站围一圈下来,标签只要走到两端或者高处,TDOA 的几何因子(GDOP)就会变得很糟,坐标噪声肉眼可见。后来把 PDOA 测角加进去,相当于给每个基站装了一只“眼睛”,单站就能输出方位角,多站融合的收敛速度和稳定性都高了一个台阶。这篇文章就把我踩过一遍的 PDOA 实现链路整理出来——从数学原理、天线布局到 DW1000 的相位提取配置,以及最后实测的误差数据。想直接抄作业的朋友可以跳到第四章的配置部分,但我还是建议把原理过一遍,后面排查问题会省很多力气。
1. TDOA定位的盲区:我为什么转向PDOA测角
1.1 多径环境下,TDOA的漂移让人头疼
TDOA 的原理不用多讲,本质上是测出标签到两个基站的距离差,画一条双曲线。距离差依靠报文的到达时间戳,而 DW1000 的时间戳分辨率做得很高,裸测距在视距下能到 10cm 以内。但真正部署到厂房、仓库这种金属货架和叉车到处跑的环境,第一波多径反射很容易把首径检测干趴下,导致时间戳往前或往后跳。基站多了以后,某一对基站的测距差只要偏 30cm,融合出来的坐标就可能产生半米级别的跳变。
我当时的解决思路有两个:一是上更复杂的首径检测算法,二是引入角度信息来做约束。前者我试过,增强效果取决于信道环境,很难一劳永逸;后者——也就是本文要聊的 PDOA——带来的收益更可控,而且它不需要额外增加基站。另一个被低估的问题是几何结构本身。用四个基站围一个 20m×20m 的区域,中心区域精度尚可,但标签走到区域边缘或者两个基站连线的延长线上,定位结果就像喝醉了一样乱飘。这不是算法代码写得差,而是 TDOA 在这类几何条件下的病态本质决定的。单基站如果具备测角能力,即使只有“角度 + 距离”两个量,也能形成二维坐标;就算不做单站定位,角度信息也能给融合定位提供很强的先验。
1.2 测角方案的三条技术路线对比
市面上能实现 UWB 测角的方案大致有三类,我在选型的时候逐个对比过:
- RSSI 比幅测角:利用两个天线的接收信号强度差标定角度。优点是硬件上最省事,缺点是 RSSI 在室内受多径、极化、遮挡影响波动极大,角度误差经常超过 15°,只能做个粗略方向判断。
- 阵列天线波束赋形:天线阵元多、角度分辨率高,但成本和板面积都上去了,对后端的基带计算能力要求很高,适合雷达或高端室内基站。
- PDOA(Phase Difference of Arrival):比较两个天线对同一信号的载波相位差来推算角度。它不需要阵列那么多接收通道,两个天线就能出可观的角度精度;在无遮挡视距下可以做到 ±3°~5°,兼顾成本、面积和精度。这也是 Decawave 官方主推的测角路线。
PDOA 的短板在于相位天生模糊和多径敏感,但这两点在工程上都有解法:相位模糊靠天线间距约束,多径敏感靠信号处理和滤波。后面的章节会分别展开。
2. PDOA测角的数学底子:相位差如何换算成角度
2.1 从两个天线到一束平面波
PDOA 的思想很直白。假设标签和基站的距离足够远,从标签到达基站两个天线的信号可以近似看成平面波。两个天线之间的距离记为 L,平面波的入射方向与天线基线法线方向的夹角为 θ,那么信号到达两天线的路程差 Δd = L·sin(θ)。无线信号是周期性的正弦波,路程差必然表现为相位差。
设信号波长为 λ,则相位差 Δφ 与路程差的关系是:
Δφ = (2π / λ) × Δd = (2π / λ) × L × sin(θ)
反过来,当我们从接收机上读出 Δφ,就能解出入射角度:
θ = arcsin(Δφ × λ / (2π × L))
这里要注意,上式里的 Δφ 是“同一时刻、同一信号到达两个天线之间的相位差”,而不是两个不同报文之间的相位差。这个细节后面配置 DW1000 的时候会反复遇到。
2.2 波长、天线间距和 2π 模糊问题
DW1000 常用 Channel 5,中心频率 6489.6MHz,波长 λ ≈ c / f ≈ 46.2mm。代入公式会发现一个很关键的问题:相位差 Δφ 是以 2π 为周期的。如果天线间距 L 太大,不同入射角度可能对应同一个相位差,也就是产生了角度模糊。为了保证在 -90°~+90° 范围内单值映射,天线间距一般取不超过 λ/2。用 λ/2 ≈ 23mm 代入,θ = 90° 时刚好 Δφ = π,处于临界点,工程上通常再留一点余量,取 15~20mm 比较多。
但天线间距也不是越小越好。从误差传播的角度看,在同样的相位噪声 σ_Δφ 下,L 越小,反解出的角度噪声越大,因为 sinθ 对相位差的缩放比例变小了。所以 L 的选择是一个“测角范围”和“测角精度”之间的折中。如果你只需要在 ±30° 内测角,把 L 拉到 30mm 也问题不大;如果要求 ±60° 可用,建议老老实实压在 20mm 附近。
2.3 相位差提取的两条路线
实现 PDOA 有两种常见的接收端架构。第一种是双接收通道同时采样,DW3110/DW3120 这类芯片原生支持,两个天线各走一路接收链路,相位一致性天然有保障,但芯片成本会高一些。第二种是单通道 + 射频开关分时切换,也就是用普通 DW1000 也能实现的路子:标签连续发多个相同的数据帧,基站在天线 A 和天线 B 之间快速切换,分别接收同一信号的副本,然后对比两次接收到的载波相位。
分时方案的好处是硬件兼容 DW1000,缺点也很明显:两次接收之间的微小频率偏差(CFO)会给相位差带来额外的线性漂移,所以实测中不能只收两帧就完事,通常要连续收 4~8 帧,用线性拟合把 CFO 的影响估出来再扣除。这个技巧是整套方案里最不起眼但最影响结果的部分,后文实测部分会再次提到。
3. 硬件方案设计与天线布局要点
3.1 单通道分时采样架构(DW1000 + RF开关)
我用的评估方案是 DW1000 + 一颗单刀双掷射频开关,两颗天线分别经开关接到 DW1000 的 RF 引脚。天线 A 和 B 之间在 PCB 上保持严格对称,走线长度尽量一致,否则等于人为引入一个固定相位偏移。射频开关的切换时间要短,普通 PIN 二极管开关或者 GaAs 开关都能到几纳秒级别,足够在帧间空隙完成切换。
这里有个关键点:DW1000 接收报文的时刻必须落在“天线已经切换到对应通道”之后。UWB 报文的前导码有几十微秒,实际测试中提前 5~10μs 完成切换即可,完全来得及。切换信号由基站主控的 GPIO 产生,GPIO 的抖动会直接映射到相位上,所以这里要用定时器比较输出,而不是在中断服务函数里翻转 IO,这是很多人没注意到的细节。
3.2 天线间距与相位中心
前面计算过,Channel 5 下 λ/2 约 23mm。有些方案会直接做成 39mm 的间距(约 3λ/4),用查表法解决模糊,但我不建议新手一上来就上超间距设计。原因很简单:模糊解在理想条件下可以靠多组间距配合消除,但只要有一个天线相位中心偏离机械中心,查表阶段的错误率会迅速上升。稳妥的做法是先按 20mm 间距做出第一版,拿到干净的相位数据后再考虑压缩天线尺寸。
还要注意“相位中心”和“几何中心”不是一回事。PCB 天线的相位中心通常离馈点有一段距离,且随频率轻微移动。你用卡尺量两个天线焊盘之间的距离是 20mm,不代表电磁波到达相位中心的距离差就是 20mm。这块只能靠实测校准去修正,没法在设计阶段一刀切算干净。
3.3 布局中的机械和射频细节
- 天线周围的铺铜要对称,最好天线区域正下方挖空,避免地平面改变天线方向图。
- 两天线若放在同一块 PCB 两端,基站的金属外壳会显著影响相位,最好用尼龙或塑料外壳;不得不用金属外壳的话,至少要保证天线区域完全露出。
- 供电纹波对载波积分器的读数影响比想象中更大。DW1000 的接收前端对电源噪声比较敏感,DC-DC 后面一定要加 LDO,并且在靠近 RF 区域增加 π 型滤波。
- 天线与射频开关之间若走 50Ω 微带线,转角处要加倒角,两个通道的走线长度差控制在 0.5mm 以内。0.5mm 在 Channel 5 下就是约 12° 的相位误差,已经足以让角度数据不可信。
4. DW1000配置实战:寄存器、时序与相位提取
4.1 无线参数配置
PDOA 测角的前提是先把 DW1000 的通信链路配置稳。我使用的参数如下:
| 参数 | 取值 | 说明 |
|---|---|---|
| Channel | 5(6489.6MHz) | 波长较短,天线尺寸容易做 |
| PRF | 64MHz | 首径能量集中,抗多径更好 |
| 前导码 | 128 symbol | 给载波积分器足够的积累时间 |
| 数据速率 | 6.8Mbps | 帧短,便于分时切换收发 |
| TX 功率 | 配置为标准 -41.3dBm/MHz | 满足法规要求 |
前导码长度对相位测量特别重要。载波积分器是在前导码接收期间对载波相位进行累积的,前导码越长,单次测量的信噪比越高,但占用时间也越长。128 symbol 是我测试下来精度和处理开销比较均衡的档位;如果基站数量多、标签刷新率要求高,再考虑降到 64 symbol。另外,PRF 建议直接锁 64MHz,32MHz 模式下首径能量分散,在反射较多的环境里相位读数更容易被多径污染。
4.2 读取RX_TIME与相位信息
DW1000 在接收完一帧报文后,可以从中断或 polling 状态里拿到接收时间戳。关键寄存器是RX_TIME(0x15),里面同时带了载波积分器信息。载波积分器反映的是接收时间内载波相位的累积量,可以换算成载波相位偏移。读取方式如下:
uint64_t rx_time_reg = read_64bit_register(0x15); uint64_t timestamp = rx_time_reg & 0xFFFFFFFFFFULL; // 40bit 接收时间戳 uint16_t ci_value = (rx_time_reg >> 40) & 0xFFFF; // 载波积分器载波积分器换算成相位时,要扣除前导码长度的比例系数。不同版本驱动里对ci_value的使用方式略有差异,我建议直接用官方 Decawave 驱动里估算 CFO 的公式,把ci_value转成等效的载波相位偏移——自己闷头推导容易在系数上出问题,实测差一个符号就会让角度正负反向。如果你用的是较新的固件并开启了 STS(加扰时间戳序列),还可以直接从 STS 段提取载波相位,理论上比普通前导码更干净。但 DW1000 的 STS 能力有限,更完善的 STS-PDOA 是 DW3000 系列的主场。手上只有 DW1000 的话,先老老实实用前导码载波积分器路径就好。
4.3 双天线交替接收与相位差解算流程
下面是完整的一次测量流程,我简化为 A/B 两路天线的多次成功接收:
- 标签以固定间隔连续发送 N 个数据帧(实测 N=8 够用)。
- 基站收到第 1 帧前,把射频开关切到天线 A,记录
ci_a1、timestamp_a1。 - 收到第 2 帧前,切到天线 B,记录
ci_b1、timestamp_b1。 - 之后再切回 A、再切回 B,收集多组数据,用于估算并扣除 CFO 引入的相位斜率。
- 对同一物理测量,将 A/B 两路的等效相位作差,修正 CFO 后得到 Δφ。
伪代码如下:
double phase_a = carrier_integral_to_phase(ci_a, preamble_len, prf); double phase_b = carrier_integral_to_phase(ci_b, preamble_len, prf); double dphi = wrap_to_pi(phase_b - phase_a - cfo_correction); double angle = asin(dphi * lambda / (2.0 * M_PI * antenna_spacing));这里cfo_correction不是固定值,而是根据 A/B 两次接收的时间间隔和前导码长度算出来的线性项。我的实测经验是:即使短到 1ms 内的两次接收,CFO 造成的相位漂移也可能到 10°~20° 量级,不扣的话角度结果会来回晃。扣完之后,视距环境下角度曲线明显平滑很多。
5. 校准与误差补偿:精度上限的真正决定因素
5.1 相位偏置校准
PDOA 不像测距,拿根卷尺量完就能跑。它天生要求校准。原因很好理解:公式里的天线间距 L 用的是理想值,但实际相位中心位置、射频开关插入相移、PCB 走线长度差都会引入一个“固定偏移”。不校准就直接算角度,你会发现 0° 方向放标签读出来可能是 8°,而且这个偏差在正角度和负角度方向还不完全对称。
最实用的校准方法是“0° 同轴校准”:标签放在基站两天线连线的中垂线上、距离 3~5m 开外,让入射角正好是 0°,此时 Δφ 的理论值为 0。实测得到的非零 Δφ 就是系统的固定相位偏移,把它存成一个常数,在每次测量中直接减掉。如果测角范围大,建议在 ±30°、±60° 等几个角度各采一组数据,做查表偏移补偿,能更好地修正天线方向图不对称带来的非线性误差。
5.2 温度、机械公差与多径补偿
温度对相位的影响很容易被忽视。UWB 前端和射频开关的相移都会随温度漂移,漂移量虽然不大,但精度要求到 ±2° 时就不能无视。我遇到过夏天晚上和白天测角结果整体平移 2° 的情况,后来在板子上贴了温度传感器,把校准偏移做成温度的函数,才算压下去。如果你的产品要在户外或者车间这种温差大的地方跑,这一步一定别省。
另外,PDOA 对多径的敏感程度比 TDOA 还高。原因是多径信号会与直射信号矢量叠加,直接扭曲合成信号的相位。实测中,如果测角目标附近有金属柱子或者人来回走动,角度输出会出现明显的毛刺。处理手段有两个思路:一是让天线具备一定的方向性,把后瓣和侧瓣压低;二是在算法端加中值滤波或卡尔曼滤波,把突变值视为野值剔除。两者结合,定位体验会好很多。
5.3 为什么要做温度标定而不是简单加容差
有朋友问过我,能不能在软件里把可能出现的温度偏差当成噪声处理,省掉温度标定的工时。我的看法是,如果目标是 demo 或者招标演示,确实可以;但要进量产,温度标定省不掉。原因在于,相位偏置随温度的曲线不是单调的,不同批次射频开关的温漂方向也不一样,你无法用一个固定的大容差同时覆盖所有工作温度点。容差给大了,角度精度直接崩掉;给小了,低温或者高温工况又会越界。老老实实做三点温度标定(比如 -20°C、25°C、60°C),线性插值得到的补偿效果,比任何“万能容差”都靠谱。
6. 实测数据与踩坑记录
6.1 实测场景与结果
我在一间 10m×6m 的办公区做了对比测试,基站放角落 1.5m 高,标签在 3m、5m、8m 三个距离点上,从 -60° 到 +60° 每隔 15° 采样一次,每次采集 50 帧取均值。结果如下表:
| 距离 | 角度范围 | 平均误差 | 最大误差 |
|---|---|---|---|
| 3m | ±60° | 2.8° | 5.1° |
| 5m | ±60° | 3.4° | 6.2° |
| 8m | ±60° | 4.1° | 8.3° |
近距离和远距离的差异主要来自信噪比。8m 距离上标签发射功率已经接近极限,载波积分器的噪声明显变大;另外天线方向图在小角度和高角度增益不一致,也是误差来源。整体来说,这个精度对单站定位或者辅助 TDOA 融合已经完全够用,但如果你追求的是 1° 级别的高精度测角,DW1000 这套分时方案会比较吃力,建议直接考虑双通道芯片。
6.2 排查链路:从跳变的角度值到供电噪声
在实际调试时,我遇到过最典型的问题是:角度输出在静止目标上每秒跳变 5°~10°,肉眼可见地“抖”。排查过程大概走了一遍以下链路:
- 先怀疑算法,直接把原始相位差打点,发现 A/B 两路相位本身都在抖,问题不在三角函数换算。
- 再怀疑射频开关,换了几颗开关没有本质改善。
- 然后用示波器量 DW1000 供电,发现 DC-DC 输出上有明显开关纹波,而且和相位抖动的频段高度相关。
- 把后级 LDO 的输入输出电容加大,并把 RF 区域的电源走线单独割开,抖动幅度立刻降了一半。
这类问题就是典型的“数据五颜六色,根因却是电源”的案例。我在前面布局章节反复强调供电,不是空话——载波相位测量比纯 RSSI 测量对电源噪声的敏感度高出一个数量级。如果你的角度静止时也乱跳,先查电源,再查天线,最后才查算法。
6.3 分时模式下帧间隔对精度的影响
分时切换需要标签把报文连续发好几遍,帧间隔的大小直接决定 CFO 校正能不能做好。我用几个不同帧间隔做过对比:
| 帧间隔 | CFO 残余相位误差 | 角度晃动幅度 |
|---|---|---|
| 100μs | 较小 | ±1.5° |
| 500μs | 中等 | ±2.8° |
| 1ms | 偏大 | ±4.5° |
原因是帧间隔越长,两次接收之间的载波频率偏移积累出的相位误差越大,线性拟合虽然能扣掉一大部分,但残余误差还是随间隔增长。所以标签端发报文的调度尽量紧凑,不要把多帧当成普通轮询任务来处理。另外,如果标签是别的厂商做的,你无法控制它的发送节奏,那基站端就要多收几帧做拟合,靠帧数换精度。
6.4 PDOA与TDOA融合的后续思路
测角单独用当然有意义,但最有价值的是和 TDOA 融合。最简单的融合方式是把角度作为约束项加到扩展卡尔曼滤波的观测方程里,比如状态量是标签的 (x, y, vx, vy),TDOA 给出距离差观测,PDOA 给出基站到标签的方位角观测。融合之后,基站边缘区域的定位漂移问题可以得到明显改善,因为角度项直接把 GDOP 差的维度补齐了。
融合实现时最需要注意的是协方差矩阵别拍脑袋填,最好先单独测出 TDOA 和 PDOA 的噪声统计特性,再做离线回归拟合。PDOA 在远距离误差增大,协方差应该随距离增大而放大,否则滤波器会在远距离上被错误的高权重角度带偏。另外,卡尔曼滤波里的角度观测要做 wrap 处理,否则角度跨过 ±180° 边界时,残差会突然变得很大,滤波器会被瞬间打飞。
结尾:给打算上手PDOA的朋友一些实在建议
如果你正准备从 TDOA 切到 PDOA,我的建议是先别急着打磨算法,先做一套最简单的双天线验证板,把原理跑通。固定相位偏移要校,CFO 漂移要扣,这两件事做扎实了,角度精度自然上一个台阶。至于要不要上 DW3000 或者双通道芯片,完全取决于你的成本框和量产规模,DW1000 这套方案虽然折腾,但在很多场景下依然有足够性价比。
最后分享一个我常用来快速判断载波相位读数是否正常的小技巧:把标签放在 0° 方向,连续打印 A/B 两路的载波积分器差值。如果这个差值在 ±5° 以内稳定跳动,说明链路基本健康;如果动不动跳到 30° 以上,先回去查天线走线和供电,别再调算法参数,那是浪费时间的开始。