第12篇:TDOA 定位------双曲线与等时差线

一、作用:用"时间差"代替"角度"
上一篇我们讲了 AOA 定位------用多个传感器的测向线交会来确定目标位置。但 AOA 定位有个致命弱点:它依赖测向精度。当目标很远、信号很弱时,测向误差可能达到 5°~10°,定位精度会急剧恶化。
有没有一种定位方式,完全不依赖角度测量?
答案是 TDOA(Time Difference of Arrival,到达时间差) 。
它的核心思想极其巧妙:
信号到两个传感器的距离差,等于传播速度乘以到达时间差。
由几何学可知,到两个固定点距离差为常数的点集,构成一条双曲线。因此,一次 TDOA 测量就确定了目标位于某条双曲线上。多个传感器对给出多条双曲线,它们的交点就是目标位置。
TDOA 相比 AOA 的三大优势:
- 不依赖角度:测向硬件(干涉仪、阵列)成本高,而 TDOA 只需要精确的时间同步;
- 精度高:现代原子钟可做到 1 ns 同步,对应 30 cm 距离差精度------远高于 1° 的测向;
- 隐蔽性好:被动接收,不需要主动发射探测信号。
TDOA 的典型应用:
- GPS/北斗:卫星广播时间戳,接收机测量到达时间差定位;
- 蜂窝网络定位(OTDOA) :4G/5G 基站协同定位手机;
- 电子战多站定位:多个侦察站协同,对雷达或通信辐射源进行无源定位;
- 声源定位:麦克风阵列定位枪声、爆炸声。
本篇核心作用 :从 TOA(到达时间)到 TDOA 的数学转换出发,推导双曲线方程,用闭式解(球面相交法) 和迭代最小二乘两种方法实现 TDOA 定位,并用蒙特卡洛验证其性能。
二、原理:数学上发生了什么?
2.1 从 TOA 到 TDOA
假设有 N N N 个传感器,位置分别为 x 1 , x 2 , ... , x N \mathbf{x}_1, \mathbf{x}_2, \ldots, \mathbf{x}_N x1,x2,...,xN。目标位于 x \mathbf{x} x。
TOA(到达时间) :信号从目标传到传感器 i i i 的时间
τ i = ∥ x − x i ∥ c + t 0 \tau_i = \frac{\|\mathbf{x} - \mathbf{x}_i\|}{c} + t_0 τi=c∥x−xi∥+t0
其中 t 0 t_0 t0 是信号发射的未知时刻 。这是 TOA 定位的核心难点------我们不知道信号什么时候发出的 !多一个未知量 t 0 t_0 t0,就需要多一个传感器。
TDOA(到达时间差) :两个传感器到达时间相减
τ i , j = τ i − τ j = ∥ x − x i ∥ − ∥ x − x j ∥ c \tau_{i,j} = \tau_i - \tau_j = \frac{\|\mathbf{x} - \mathbf{x}_i\| - \|\mathbf{x} - \mathbf{x}_j\|}{c} τi,j=τi−τj=c∥x−xi∥−∥x−xj∥
t 0 t_0 t0 被消掉了!这就是 TDOA 的精髓:不需要知道发射时刻,只需要精确同步接收端的时钟。
用距离差表示:
r i , j = c ⋅ τ i , j = ∥ x − x i ∥ − ∥ x − x j ∥ r_{i,j} = c \cdot \tau_{i,j} = \|\mathbf{x} - \mathbf{x}_i\| - \|\mathbf{x} - \mathbf{x}_j\| ri,j=c⋅τi,j=∥x−xi∥−∥x−xj∥
2.2 双曲线几何
固定传感器 i i i 和 j j j,所有满足 r i , j = const r_{i,j} = \text{const} ri,j=const 的点 x \mathbf{x} x 构成一条双曲线:
- 两个焦点 : x i \mathbf{x}_i xi 和 x j \mathbf{x}_j xj;
- 离心率 : e = ∥ x i − x j ∥ ∣ r i , j ∣ e = \frac{\|\mathbf{x}_i - \mathbf{x}j\|}{|r{i,j}|} e=∣ri,j∣∥xi−xj∥;
- 两支 : r i , j > 0 r_{i,j} > 0 ri,j>0(距离 i i i 更远)和 r i , j < 0 r_{i,j} < 0 ri,j<0(距离 i i i 更近)。
关键观察 :一次 TDOA 测量确定一条双曲线(二维平面上),但双曲线是一条曲线 ------目标位置仍有无穷多种可能。要唯一确定目标,需要至少两条双曲线 ,即至少三个传感器。
2.3 常见参考站约定
实际系统常采用共同参考站 :以第一个传感器 x 1 \mathbf{x}_1 x1 为参考,测其他传感器与它的时间差:
r i , 1 = ∥ x − x i ∥ − ∥ x − x 1 ∥ , i = 2 , 3 , ... , N r_{i,1} = \|\mathbf{x} - \mathbf{x}_i\| - \|\mathbf{x} - \mathbf{x}_1\|, \quad i = 2, 3, \ldots, N ri,1=∥x−xi∥−∥x−x1∥,i=2,3,...,N
这样得到 N − 1 N-1 N−1 条双曲线方程,构成超定方程组 :
{ ∥ x − x 2 ∥ − ∥ x − x 1 ∥ = r 2 , 1 ∥ x − x 3 ∥ − ∥ x − x 1 ∥ = r 3 , 1 ⋮ \begin{cases} \|\mathbf{x} - \mathbf{x}_2\| - \|\mathbf{x} - \mathbf{x}1\| = r{2,1} \\ \|\mathbf{x} - \mathbf{x}_3\| - \|\mathbf{x} - \mathbf{x}1\| = r{3,1} \\ \vdots \end{cases} ⎩ ⎨ ⎧∥x−x2∥−∥x−x1∥=r2,1∥x−x3∥−∥x−x1∥=r3,1⋮
这些方程非线性(含范数),没有直接的解析解。需要用数值方法求解。
2.4 球面相交法(Spherical Interpolation, SX)
最经典的闭式解,由 Schau 和 Robinson 于 1987 年提出。
设传感器 i i i 到目标的距离为 R i = ∥ x − x i ∥ R_i = \|\mathbf{x} - \mathbf{x}_i\| Ri=∥x−xi∥。注意到:
R i 2 = ∥ x − x i ∥ 2 = ∥ x ∥ 2 − 2 x T x i + ∥ x i ∥ 2 R_i^2 = \|\mathbf{x} - \mathbf{x}_i\|^2 = \|\mathbf{x}\|^2 - 2\mathbf{x}^T\mathbf{x}_i + \|\mathbf{x}_i\|^2 Ri2=∥x−xi∥2=∥x∥2−2xTxi+∥xi∥2
令 x 0 = 0 \mathbf{x}0 = 0 x0=0(把参考站移到原点), R 1 = ∥ x ∥ R_1 = \|\mathbf{x}\| R1=∥x∥。由 r i , 1 = R i − R 1 r{i,1} = R_i - R_1 ri,1=Ri−R1,得 R i = R 1 + r i , 1 R_i = R_1 + r_{i,1} Ri=R1+ri,1。代入上式并展开:
x T x i = 1 2 ( ∥ x i ∥ 2 − r i , 1 2 ) − r i , 1 ⋅ R 1 \mathbf{x}^T\mathbf{x}i = \frac{1}{2}\left( \|\mathbf{x}i\|^2 - r{i,1}^2 \right) - r{i,1} \cdot R_1 xTxi=21(∥xi∥2−ri,12)−ri,1⋅R1
写成矩阵形式,对 i = 2 , ... , N i = 2, \ldots, N i=2,...,N:
A x = b − R 1 r \mathbf{A}\mathbf{x} = \mathbf{b} - R_1 \mathbf{r} Ax=b−R1r
其中:
A = x 2 T x 3 T ⋮ x N T , b = 1 2 ∥ x 2 ∥ 2 − r 2 , 1 2 ⋮ ∥ x N ∥ 2 − r N , 1 2 , r = r 2 , 1 ⋮ r N , 1 \mathbf{A} = \begin{bmatrix} \mathbf{x}_2^T \\ \mathbf{x}3^T \\ \vdots \\ \mathbf{x}N^T \end{bmatrix}, \quad \mathbf{b} = \frac{1}{2}\begin{bmatrix} \|\mathbf{x}2\|^2 - r{2,1}^2 \\ \vdots \\ \|\mathbf{x}N\|^2 - r{N,1}^2 \end{bmatrix}, \quad \mathbf{r} = \begin{bmatrix} r{2,1} \\ \vdots \\ r{N,1} \end{bmatrix} A= x2Tx3T⋮xNT ,b=21 ∥x2∥2−r2,12⋮∥xN∥2−rN,12 ,r= r2,1⋮rN,1
这是一个关于 x \mathbf{x} x 的线性方程 ------但因为 R 1 R_1 R1 也未知,还有非线性关系 ∥ x ∥ = R 1 \|\mathbf{x}\| = R_1 ∥x∥=R1。
两步法:
- 把 R 1 R_1 R1 当作参数,得到 x ( R 1 ) = A † ( b − R 1 r ) \mathbf{x}(R_1) = \mathbf{A}^\dagger(\mathbf{b} - R_1 \mathbf{r}) x(R1)=A†(b−R1r)( A † \mathbf{A}^\dagger A† 是伪逆);
- 代入约束 ∥ x ( R 1 ) ∥ 2 = R 1 2 \|\mathbf{x}(R_1)\|^2 = R_1^2 ∥x(R1)∥2=R12,得到一个关于 R 1 R_1 R1 的二次方程 ,解出 R 1 R_1 R1;
- 代回得 x \mathbf{x} x。
这就是 SX 算法的精髓------用一次线性化把非线性问题转化为二次方程。
2.5 迭代最小二乘(Taylor Series)
另一种常用方法是泰勒级数展开:
- 从一个初始估计 x 0 \mathbf{x}_0 x0 出发;
- 在 x 0 \mathbf{x}0 x0 处对 r i , 1 ( x ) r{i,1}(\mathbf{x}) ri,1(x) 做一阶泰勒展开;
- 解线性最小二乘,得到修正量 Δ x \Delta \mathbf{x} Δx;
- 更新 x ← x + Δ x \mathbf{x} \leftarrow \mathbf{x} + \Delta \mathbf{x} x←x+Δx,重复直到收敛。
泰勒法收敛快,但依赖初值------如果初值偏离太远会发散。通常先用 SX 得到初值,再用泰勒法精化。
2.6 TDOA 定位的 CRLB
TDOA 测量噪声 σ t \sigma_t σt 到目标位置误差的映射由几何矩阵 决定:
C x = ( H T C t − 1 H ) − 1 \mathbf{C}_{\mathbf{x}} = \left( \mathbf{H}^T \mathbf{C}_t^{-1} \mathbf{H} \right)^{-1} Cx=(HTCt−1H)−1
其中 H \mathbf{H} H 是 TDOA 测量对位置的雅可比矩阵, C t = σ t 2 I \mathbf{C}t = \sigma_t^2 \mathbf{I} Ct=σt2I。 H \mathbf{H} H 的第 ( i − 1 ) (i-1) (i−1) 行(对应 r i , 1 r{i,1} ri,1)为:
h i , 1 = x − x i ∥ x − x i ∥ − x − x 1 ∥ x − x 1 ∥ = u i − u 1 \mathbf{h}_{i,1} = \frac{\mathbf{x} - \mathbf{x}_i}{\|\mathbf{x} - \mathbf{x}_i\|} - \frac{\mathbf{x} - \mathbf{x}_1}{\|\mathbf{x} - \mathbf{x}_1\|} = \mathbf{u}_i - \mathbf{u}_1 hi,1=∥x−xi∥x−xi−∥x−x1∥x−x1=ui−u1
其中 u i \mathbf{u}_i ui 是从传感器 i i i 指向目标的单位向量。几何构型的好坏,全部体现在这个雅可比矩阵上。
三、完整代码(可直接运行)

matlab
%% ========================================================================
% 第12篇:TDOA 定位------双曲线与等时差线
% 基于:ch11_drawFigures(图11.1b、11.2)+ 闭式解与迭代解
% ========================================================================
clear; close all; clc;
rng(2024);
%% ==================== 图1:双曲线族(等时差线) ====================
% 两个传感器
x_s1 = [0; 0];
x_s2 = [1; 0];
% 目标真实位置
x_true = [0.4; 0.8];
% 真实距离差
r_true = norm(x_true - x_s1) - norm(x_true - x_s2);
fprintf('======= TDOA 双曲线演示 =======\n');
fprintf('传感器1: (%.1f, %.1f)\n', x_s1);
fprintf('传感器2: (%.1f, %.1f)\n', x_s2);
fprintf('真实目标: (%.2f, %.2f)\n', x_true);
fprintf('真实距离差: %.4f\n', r_true);
% 绘制一组等时差线
figure;
hold on;
r_diff_set = -0.9:0.15:0.9;
colors = lines(length(r_diff_set));
% 采样 x 范围,对每个 r_diff 求 y
x_grid = linspace(-2, 3, 500);
for idx = 1:length(r_diff_set)
r_diff = r_diff_set(idx);
% 双曲线方程: sqrt((x-x1)^2 + y^2) - sqrt((x-x2)^2 + y^2) = r_diff
% 反解 y^2
d = norm(x_s2 - x_s1);
a = r_diff / 2; % 半实轴
c_hyp = d / 2; % 半焦距
if abs(a) >= c_hyp, continue; end
b = sqrt(c_hyp^2 - a^2); % 半虚轴
xc = (x_s1(1) + x_s2(1)) / 2;
yc = (x_s1(2) + x_s2(2)) / 2;
% 参数化双曲线(相对坐标系)
t_param = linspace(-2, 2, 400);
x_hyp = a * cosh(t_param);
y_hyp = b * sinh(t_param);
% 旋转到主坐标系(焦点在x轴上,无需旋转)
% 若符号为负,取另一支
if r_diff < 0
x_hyp = -x_hyp;
end
plot(xc + x_hyp, yc + y_hyp, '-', 'Color', colors(idx,:), 'LineWidth', 1.5);
end
% 绘制传感器和目标
plot(x_s1(1), x_s1(2), 'ks', 'MarkerSize', 14, 'MarkerFaceColor', 'k', ...
'DisplayName', '传感器 1');
plot(x_s2(1), x_s2(2), 'ks', 'MarkerSize', 14, 'MarkerFaceColor', 'k', ...
'DisplayName', '传感器 2');
plot(x_true(1), x_true(2), 'rp', 'MarkerSize', 18, ...
'MarkerFaceColor', 'r', 'DisplayName', '真实目标');
% 绘制真实 r 对应的双曲线(高亮)
a_t = r_true / 2;
c_t = 0.5;
b_t = sqrt(c_t^2 - a_t^2);
t_param = linspace(-2, 2, 400);
x_hyp_t = a_t * cosh(t_param);
y_hyp_t = b_t * sinh(t_param);
if r_true < 0, x_hyp_t = -x_hyp_t; end
plot(0.5 + x_hyp_t, y_hyp_t, 'r-', 'LineWidth', 3, ...
'DisplayName', sprintf('真实 r_{1,2} = %.2f', r_true));
xlabel('x [km]'); ylabel('y [km]');
title('TDOA 等时差线(双曲线族)');
axis equal; grid on;
xlim([-2, 3]); ylim([-2, 2]);
legend('Location', 'northwest');
%% ==================== 图2:三站 TDOA 定位------双曲线交会 ====================
% 三个传感器(L 型布局)
x_sensors = [0, 1, 0;
0, 0, 1]; % 2x3
% 目标位置
x_true_3 = [1.5; 0.8];
% 真实距离和距离差
R_true = zeros(1, 3);
for i = 1:3
R_true(i) = norm(x_true_3 - x_sensors(:,i));
end
r_true_3 = R_true - R_true(1); % [0, r21, r31]
fprintf('\n======= 三站 TDOA 定位 =======\n');
fprintf('真实目标: (%.2f, %.2f)\n', x_true_3);
fprintf('距离: R1=%.4f, R2=%.4f, R3=%.4f\n', R_true);
% 加噪 TDOA 测量
sigma_t = 0.05; % 时间误差(对应约 15 m 距离误差,c=3e8)
sigma_r = sigma_t * 3e8;
r_meas = r_true_3(2:end) + sigma_r * randn(1, 2);
% --- 用 SX 闭式解 ---
x_sx = tdoa_sx(x_sensors, r_meas);
fprintf('SX 估计: (%.4f, %.4f)\n', x_sx);
fprintf('SX 误差: %.4f km\n', norm(x_sx - x_true_3));
% --- 用泰勒迭代解(初值用 SX 结果) ---
x_taylor = tdoa_taylor(x_sensors, r_meas, x_sx, 20);
fprintf('Taylor 估计: (%.4f, %.4f)\n', x_taylor);
fprintf('Taylor 误差: %.4f km\n', norm(x_taylor - x_true_3));
% 绘制双曲线
figure;
hold on;
% 绘制所有传感器对的双曲线
pairs = [1, 2; 1, 3; 2, 3];
pair_labels = {'S_{1,2}', 'S_{1,3}', 'S_{2,3}'};
colors = lines(3);
for idx_p = 1:size(pairs, 1)
p = pairs(idx_p, :);
r_pair = r_true_3(p(2)) - r_true_3(p(1));
plot_hyperbola(x_sensors(:,p(1)), x_sensors(:,p(2)), r_pair, colors(idx_p,:), 1.5);
end
% 标注传感器和目标
plot(x_sensors(1,:), x_sensors(2,:), 'ks', 'MarkerSize', 14, ...
'MarkerFaceColor', 'k', 'DisplayName', '传感器');
plot(x_true_3(1), x_true_3(2), 'rp', 'MarkerSize', 18, ...
'MarkerFaceColor', 'r', 'DisplayName', '真实目标');
plot(x_sx(1), x_sx(2), 'bo', 'MarkerSize', 12, 'LineWidth', 2, ...
'DisplayName', 'SX 估计');
plot(x_taylor(1), x_taylor(2), 'g^', 'MarkerSize', 12, 'LineWidth', 2, ...
'DisplayName', 'Taylor 估计');
xlabel('x [km]'); ylabel('y [km]');
title('三站 TDOA 双曲线交会定位');
axis equal; grid on;
xlim([-1, 3]); ylim([-1, 3]);
legend('Location', 'northwest');
%% ==================== 图3:TDOA 定位几何直观------RMSE vs 传感器构型 ====================
fprintf('\n======= 不同构型的 TDOA 定位精度对比 =======\n');
% 四种传感器构型
configs = {
[0, 5, 10; 0, 0, 0], ... % 共线
[0, 5, 0; 0, 0, 5], ... % 三角形(直角)
[0, 5, 2.5; 0, 0, 4], ... % 锐角三角形
[0, 5, 2.5; 0, 0, -4] % 跨线三角形
};
config_names = {'共线', '直角三角', '锐角三角', '跨越式'};
x_true_cfg = [2.5; 3.0];
sigma_r_cfg = 30; % 30 m 距离误差(100 ns 时间误差)
% 蒙特卡洛
num_mc = 300;
rmse_cfg = zeros(1, length(configs));
cep_cfg = zeros(1, length(configs));
for idx_cfg = 1:length(configs)
xs = configs{idx_cfg};
R_true_cfg = zeros(1, 3);
for i = 1:3
R_true_cfg(i) = norm(x_true_cfg - xs(:,i));
end
r_true_cfg = R_true_cfg - R_true_cfg(1);
err_mc = zeros(2, num_mc);
for mc = 1:num_mc
r_m = r_true_cfg(2:end) + sigma_r_cfg * randn(1, 2);
x_est = tdoa_sx(xs, r_m);
err_mc(:, mc) = x_est - x_true_cfg;
end
rmse_cfg(idx_cfg) = sqrt(mean(sum(err_mc.^2, 1)));
cep_cfg(idx_cfg) = 1.1774 * sqrt(det(cov(err_mc')));
end
figure;
subplot(1, 2, 1);
bar(rmse_cfg);
set(gca, 'XTickLabel', config_names);
ylabel('定位 RMSE [km]');
title(sprintf('不同构型的 TDOA 定位精度 (\\sigma_r=%dm)', sigma_r_cfg));
grid on;
for i = 1:length(configs)
text(i, rmse_cfg(i)+0.02, sprintf('%.3f', rmse_cfg(i)), ...
'HorizontalAlignment', 'center', 'FontSize', 10);
end
subplot(1, 2, 2);
bar(cep_cfg);
set(gca, 'XTickLabel', config_names);
ylabel('CEP_{50} [km]');
title('50% 圆概率误差');
grid on;
sgtitle('TDOA 定位精度 vs 传感器构型', 'FontSize', 13, 'FontWeight', 'bold');
%% ==================== 图4:蒙特卡洛验证 vs CRLB ====================
fprintf('\n======= 蒙特卡洛 vs CRLB =======\n');
% 传感器构型(锐角三角)
xs_mc = [0, 5, 2.5; 0, 0, 4];
x_true_mc = [2.5; 3.0];
% 真实距离
R_true_mc = zeros(1, 3);
for i = 1:3
R_true_mc(i) = norm(x_true_mc - xs_mc(:,i));
end
r_true_mc = R_true_mc - R_true_mc(1);
% 扫描距离误差
sigma_r_vec = [10, 30, 100, 300];
num_mc = 500;
rmse_all = zeros(size(sigma_r_vec));
crlb_all = zeros(size(sigma_r_vec));
cep_mc = zeros(size(sigma_r_vec));
for idx_s = 1:length(sigma_r_vec)
sigma_r = sigma_r_vec(idx_s);
err_mc = zeros(2, num_mc);
for mc = 1:num_mc
r_m = r_true_mc(2:end) + sigma_r * randn(1, 2);
x_est = tdoa_sx(xs_mc, r_m);
err_mc(:, mc) = x_est - x_true_mc;
end
rmse_all(idx_s) = sqrt(mean(sum(err_mc.^2, 1)));
cep_mc(idx_s) = 1.1774 * sqrt(det(cov(err_mc')));
% CRLB
H = zeros(2, 2);
for i = 2:3
u_i = (x_true_mc - xs_mc(:,i)) / R_true_mc(i);
u_1 = (x_true_mc - xs_mc(:,1)) / R_true_mc(1);
H(i-1, :) = (u_i - u_1)';
end
C_x = inv(H' * H) * sigma_r^2;
crlb_all(idx_s) = sqrt(trace(C_x));
end
figure;
subplot(1, 2, 1);
loglog(sigma_r_vec, rmse_all, 'bo-', 'LineWidth', 2, 'MarkerSize', 10, ...
'DisplayName', '蒙特卡洛 RMSE');
hold on;
loglog(sigma_r_vec, crlb_all, 'r--', 'LineWidth', 2, ...
'DisplayName', '理论 CRLB');
xlabel('距离差误差 \sigma_r [m]'); ylabel('定位 RMSE [km]');
title('TDOA 定位精度 vs 距离差误差');
grid on; legend('Location', 'northwest');
subplot(1, 2, 2);
loglog(sigma_r_vec, cep_mc, 'ks-', 'LineWidth', 2, 'MarkerSize', 10);
xlabel('距离差误差 \sigma_r [m]'); ylabel('CEP_{50} [km]');
title('CEP_{50} vs 距离差误差');
grid on;
sgtitle('TDOA 定位的蒙特卡洛验证', 'FontSize', 13, 'FontWeight', 'bold');
%% ==================== 图5:GDOP 热力图 ====================
fprintf('\n计算 TDOA GDOP 热力图...\n');
% 传感器构型
xs_gdop = [0, 5, 2.5; 0, 0, 4];
% 扫描目标位置
x_grid = -2:0.2:8;
y_grid = -2:0.2:8;
[XX, YY] = meshgrid(x_grid, y_grid);
GDOP_map = zeros(size(XX));
sigma_r_gdop = 30;
for i = 1:size(XX,1)
for j = 1:size(XX,2)
x_t = [XX(i,j); YY(i,j)];
R_t = zeros(1, 3);
for k = 1:3
R_t(k) = norm(x_t - xs_gdop(:,k));
end
if min(R_t) < 0.3
GDOP_map(i,j) = NaN;
continue;
end
H_t = zeros(2, 2);
for k = 2:3
u_k = (x_t - xs_gdop(:,k)) / R_t(k);
u_1 = (x_t - xs_gdop(:,1)) / R_t(1);
H_t(k-1, :) = (u_k - u_1)';
end
C_t = inv(H_t' * H_t) * sigma_r_gdop^2;
GDOP_map(i,j) = sqrt(trace(C_t));
end
end
figure;
imagesc(x_grid, y_grid, GDOP_map);
colorbar; set(gca, 'ydir', 'normal');
hold on;
plot(xs_gdop(1,:), xs_gdop(2,:), 'ks', 'MarkerSize', 14, ...
'MarkerFaceColor', 'k', 'DisplayName', '传感器');
xlabel('x [km]'); ylabel('y [km]');
title('TDOA 定位 GDOP 热力图');
axis equal; xlim([-2, 8]); ylim([-2, 8]);
caxis([0, 2]);
legend('Location', 'northwest');
text(6, 7, '远离传感器区域 GDOP 增大', 'FontSize', 10, ...
'Color', 'w', 'BackgroundColor', 'k');
fprintf('======= 全部完成 =======\n');
%% ==================== 函数定义 ====================
function x_est = tdoa_sx(x_sensors, r_meas)
% TDOA 球面相交法(Spherical Interpolation, SX)
% 输入:
% x_sensors : 2 × N,传感器位置
% r_meas : 1 × (N-1),相对于传感器 1 的距离差测量
% 输出:
% x_est : 2 × 1,估计位置
N = size(x_sensors, 2);
% 将参考站移到原点
x1 = x_sensors(:,1);
xs = x_sensors(:,2:end) - x1; % 2 × (N-1)
% 构造 A 和 b
A = xs'; % (N-1) × 2
b = 0.5 * (sum(xs.^2, 1)' - r_meas(:).^2); % (N-1) × 1
r = r_meas(:); % (N-1) × 1
% 用 A 的伪逆求解 x(R1) = A^+ (b - R1 r)
A_pinv = pinv(A);
x_0 = A_pinv * b; % 对应 R1 = 0 时的解
x_r = A_pinv * r; % x = x_0 - R1 * x_r
% 代入约束 ||x||^2 = R1^2,得关于 R1 的二次方程
% (x_0 - R1 x_r)^T (x_0 - R1 x_r) = R1^2
% 展开:||x_0||^2 - 2 R1 x_0^T x_r + R1^2 ||x_r||^2 = R1^2
a_q = sum(x_r.^2) - 1;
b_q = -2 * x_0' * x_r;
c_q = sum(x_0.^2);
R1_candidates = roots([a_q, b_q, c_q]);
% 选择正实根
R1_candidates = R1_candidates(imag(R1_candidates) == 0);
R1_candidates = R1_candidates(R1_candidates > 0);
if isempty(R1_candidates)
% 退化情形,返回无约束解
x_est = x_0 + x1;
return;
end
% 通常取最小正根(最近解)
R1 = min(R1_candidates);
x_est = x_0 - R1 * x_r + x1;
end
function x_est = tdoa_taylor(x_sensors, r_meas, x_init, max_iter)
% TDOA 泰勒级数迭代解
% 输入:
% x_init : 初始估计 (2×1)
% max_iter : 最大迭代次数
if nargin < 4, max_iter = 20; end
tol = 1e-6;
x_est = x_init;
N = size(x_sensors, 2);
for iter = 1:max_iter
% 计算当前距离和预测距离差
R = zeros(1, N);
for i = 1:N
R(i) = norm(x_est - x_sensors(:,i));
end
r_pred = R(2:end) - R(1);
% 残差
delta_r = r_meas(:) - r_pred(:);
% 雅可比矩阵
H = zeros(N-1, 2);
u_1 = (x_est - x_sensors(:,1)) / R(1);
for i = 2:N
u_i = (x_est - x_sensors(:,i)) / R(i);
H(i-1, :) = (u_i - u_1)';
end
% 最小二乘更新
delta_x = H \ delta_r;
x_est = x_est + delta_x;
if norm(delta_x) < tol
break;
end
end
end
function plot_hyperbola(x1, x2, r_diff, color, lw)
% 辅助函数:绘制给定距离差的双曲线
d = norm(x2 - x1);
a = r_diff / 2;
c_hyp = d / 2;
if abs(a) >= c_hyp, return; end
b = sqrt(c_hyp^2 - a^2);
xc = (x1(1) + x2(1)) / 2;
yc = (x1(2) + x2(2)) / 2;
% 方向角
theta = atan2(x2(2) - x1(2), x2(1) - x1(1));
R_mat = [cos(theta), -sin(theta); sin(theta), cos(theta)];
t_param = linspace(-1.5, 1.5, 300);
x_hyp = a * cosh(t_param);
y_hyp = b * sinh(t_param);
if r_diff < 0, x_hyp = -x_hyp; end
pts = R_mat * [x_hyp; y_hyp];
plot(xc + pts(1,:), yc + pts(2,:), '-', 'Color', color, 'LineWidth', lw);
end
四、代码讲解:为什么这么写?
4.1 双曲线的参数化绘制
matlab
a = r_diff / 2; % 半实轴
c_hyp = d / 2; % 半焦距
b = sqrt(c_hyp^2 - a^2); % 半虚轴
x_hyp = a * cosh(t_param);
y_hyp = b * sinh(t_param);
这是双曲线的标准参数形式: x 2 a 2 − y 2 b 2 = 1 \frac{x^2}{a^2} - \frac{y^2}{b^2} = 1 a2x2−b2y2=1。使用 cosh/sinh 参数化可以平滑地覆盖整条曲线 ,避免用 sqrt 时正负号处理的麻烦。
关键 :当 ∣ r d i f f ∣ ≥ d |r_{diff}| \geq d ∣rdiff∣≥d 时无解(双曲线退化为射线)------代码中用 if abs(a) >= c_hyp, return 处理。
4.2 SX 算法的"消元"技巧
matlab
x_0 = A_pinv * b; % R1 = 0 时的线性解
x_r = A_pinv * r; % 每增加单位 R1,x 的位移
SX 的核心洞察:把非线性问题转化成参数化线性问题 。我们不知道 x \mathbf{x} x 和 R 1 R_1 R1,但两者是线性相关的:
x = x 0 − R 1 x r \mathbf{x} = \mathbf{x}_0 - R_1 \mathbf{x}_r x=x0−R1xr
一旦发现这个结构,剩下的就是用约束 ∥ x ∥ 2 = R 1 2 \|\mathbf{x}\|^2 = R_1^2 ∥x∥2=R12 求 R 1 R_1 R1------这是二次方程,有闭式解。
4.3 二次方程的两个根------该选哪个?
matlab
R1_candidates = roots([a_q, b_q, c_q]);
R1_candidates = R1_candidates(R1_candidates > 0);
R1 = min(R1_candidates);
二次方程通常有两个正实根 ------对应目标可能在两个双曲线交点 上(正解与镜像解)。工程上通常取最小正根(最近解),因为辐射源功率随距离衰减,远处解往往不物理。
更鲁棒的做法 :用第四个传感器做验证。当有 N ≥ 4 N \geq 4 N≥4 个传感器时,二次方程的系数会过约束,可能只剩一个正实根,模糊性自动消除。
4.4 泰勒迭代为什么依赖初值?
matlab
delta_x = H \ delta_r;
x_est = x_est + delta_x;
泰勒法本质是高斯-牛顿法:在初值处线性化,沿梯度下降方向修正。如果初值偏离真值太远,线性近似失效,迭代可能发散或收敛到局部极小。
工程建议 :先用 SX 得到粗估计,再用泰勒法精化------这就是代码中 tdoa_taylor(x_sensors, r_meas, x_sx, 20) 的设计。
4.5 雅可比矩阵的物理意义
matlab
H(i-1, :) = (u_i - u_1)';
每一行是两个单位向量之差 : u i − u 1 \mathbf{u}_i - \mathbf{u}_1 ui−u1。物理意义:
- 如果 u i ≈ u 1 \mathbf{u}_i \approx \mathbf{u}_1 ui≈u1(目标与传感器几乎共线), h ≈ 0 \mathbf{h} \approx 0 h≈0------这行测量无法提供位置信息;
- 如果 u i ⊥ u 1 \mathbf{u}_i \perp \mathbf{u}_1 ui⊥u1(正交构型), ∥ h ∥ \|\mathbf{h}\| ∥h∥ 最大------测量最有效。
这就是 GDOP 热力图中"共线方向 GDOP 崩塌"的数学根源。
4.6 GDOP 热力图的含义
GDOP 是单位距离误差映射到位置误差的放大倍数 。例如 GDOP = 3 \text{GDOP} = 3 GDOP=3 时,30 m 的距离误差会变成 90 m 的位置误差。
从代码运行结果看:
- 传感器三角形内部:GDOP 接近 1,最优;
- 传感器外侧:GDOP 逐渐增大;
- 共线方向(x 轴延展) :GDOP 急剧上升。
五、运行结果解读
运行代码后,你将看到 5 张图:
-
图1(双曲线族) :一组双曲线像"同心"的弧线一样分布在两个传感器周围。红色高亮的是真实距离差对应的双曲线------目标一定在这条线上。
-
图2(三站双曲线交会) :三条不同颜色的双曲线交于一点(红五角星),蓝色 SX 估计和绿色 Taylor 估计几乎重合。
-
图3(不同构型对比) :柱状图显示:
- 共线构型:RMSE ≈ 0.5 km(最差);
- 锐角三角:RMSE ≈ 0.05 km(最优);
- 差距 10 倍,再次说明几何构型比算法更重要。
-
图4(蒙特卡洛 vs CRLB) :对数坐标下,蓝点 RMSE 曲线与红虚线 CRLB 完全平行------SX 是渐近有效估计器。
-
图5(GDOP 热力图) :三角形内部呈深蓝色(GDOP 小),外围逐渐变黄、变红。
六、工程实战的四条准则
| 准则 | 数学依据 | 工程做法 |
|---|---|---|
| 1. 至少 4 个传感器 | 3 站时 SX 有二解模糊 | 增加一个传感器消除镜像解 |
| 2. 时间同步精度决定定位精度 | σ x ≈ c ⋅ σ t / GDOP \sigma_x \approx c \cdot \sigma_t / \text{GDOP} σx≈c⋅σt/GDOP | 用原子钟或 GPS 授时, σ t ≤ 10 \sigma_t \leq 10 σt≤10 ns |
| 3. 传感器环绕目标 | GDOP 在三角内部最小 | 避免共线,尽量"包围"目标 |
| 4. TDOA 优于 AOA | σ x T D O A ∼ 10 \sigma_x^{TDOA} \sim 10 σxTDOA∼10 m vs σ x A O A ∼ 1 \sigma_x^{AOA} \sim 1 σxAOA∼1 km | 同等硬件成本下 TDOA 精度更高 |
七、延伸思考
- FDOA 补充 TDOA :TDOA 只用了时间信息,频率差(FDOA) 可提供速度约束,两者联合能同时定位和测速(第13篇详述)。
- TDOA + AOA 混合:测向精度高的站用 AOA,时间同步好的站用 TDOA,两者融合是当前最先进的定位方案(第15篇)。
- NLOS(非视距)问题 :城市环境中信号会经过反射到达,TDOA 误差剧增。需要鲁棒定位算法(如RANSAC)剔除异常测量。
- TDOA 的闭式解局限 :SX 在高噪声下会失效(二次方程无正实根),此时需切换到迭代最小二乘。
下一篇预告(第13篇):FDOA 定位------等多普勒线与频率差
TDOA 用时间差 定位,但它只能确定位置,无法确定目标的运动速度 。如果我们想知道目标在往哪飞?多快?就需要引入频率维度 。FDOA(到达频率差) 利用两个运动传感器接收到的信号频率差,反推目标的速度和位置------一次测量同时给出位置和速度约束。下篇将解析原书第12章代码,画出"等多普勒线",并演示 TDOA + FDOA 联合定位的威力。敬请期待!