3. 载波相位观测值生成与周跳探测
任务目标
生成一段模拟的GNSS载波相位观测值序列,并在其中人为注入周跳,实现基于高次差分的周跳探测算法,输出探测到的周跳位置与大小。
实现原理
载波相位观测值在无周跳时,其时间序列应保持平滑。对相邻历元做差分(一次差分),若仍有周跳则继续差分。周跳会使差分序列在对应历元处产生显著跳变。本案例采用四阶差分进行探测:对无周跳的静态数据,四阶差分值应在噪声水平附近;当某历元发生周跳时,该历元附近的四阶差分值会出现远超阈值的尖峰。
关键完整代码
import numpy as np
def generate_phase_data(n_epochs=300, dt=1.0, freq=1.57542e9,
phase_noise_std=0.01, cycle_slips=None):
"""
生成模拟载波相位观测值(单位:周)
cycle_slips: list of (epoch_index, slip_cycles)
"""
c = 299792458.0
# 模拟静态接收机,几何距离恒定
true_range = 20000000.0 # 20,000 km
wavelength = c / freq
# 基准相位(周)
base_phase = true_range / wavelength
# 时间序列
t = np.arange(n_epochs) * dt
# 模拟钟差漂移引起的缓慢相位变化(斜坡+二次项)
clock_drift = 1e-9 * t + 2e-12 * t**2 # 秒
phase_drift = clock_drift * freq # 转换为周
# 随机噪声(周)
noise = np.random.normal(0, phase_noise_std, n_epochs)
# 初始相位
phase = np.full(n_epochs, base_phase) + phase_drift + noise
# 注入周跳
if cycle_slips:
for epoch_idx, slip in cycle_slips:
if epoch_idx < n_epochs:
phase[epoch_idx:] += slip # 从该历元起所有后续值都偏移
return phase
def detect_cycle_slips(phase, threshold_factor=8.0):
"""
基于四阶差分的周跳探测
返回: [(epoch_index, slip_size), ...]
"""
# 计算四阶差分
diff4 = np.diff(phase, n=4)
# 四阶差分的标准差(使用中位数偏差估计鲁棒性更好)
mad = np.median(np.abs(diff4 - np.median(diff4)))
sigma = 1.4826 * mad
if sigma < 1e-10:
sigma = np.std(diff4)
threshold = threshold_factor * sigma
# 找到超过阈值的差分位置
slip_indices = np.where(np.abs(diff4) > threshold)[0]
# 差分后索引偏移:diff4[i] 对应原始历元 i+4 处的变化
results = []
for idx in slip_indices:
epoch = idx + 4 # 周跳实际发生的历元
# 估计周跳大小:四阶差分值 / 组合系数
# 四阶差分系数: [1, -4, 6, -4, 1]
# 若在epoch处发生大小为s的阶跃,则diff4[epoch-4] = s
slip_size = diff4[idx]
# 避免重复检测同一周跳(相邻历元可能同时超限)
if not results or epoch - results[-1][0] > 2:
results.append((epoch, slip_size))
return results
# ===== 运行与验证 =====
if __name__ == "__main__":
np.random.seed(42)
# 生成数据:在历元100处注入5周周跳,在历元200处注入-3周周跳
true_slips = [(100, 5.0), (200, -3.0)]
phase = generate_phase_data(n_epochs=300, cycle_slips=true_slips)
# 探测周跳
detected = detect_cycle_slips(phase, threshold_factor=8.0)
print("真实周跳:", true_slips)
print("探测结果:", detected)
# 验证
correct = 0
for det_epoch, det_size in detected:
for true_epoch, true_size in true_slips:
if abs(det_epoch - true_epoch) <= 1 and abs(det_size - true_size) < 1.0:
correct += 1
break
print(f"正确探测: {correct}/{len(true_slips)}")
if correct == len(true_slips):
print("测试通过:所有周跳均被正确探测")
else:
print("测试未完全通过")
运行方式
python cycle_slip_detection.py
验证方法与判定标准
- 数据生成验证:代码使用固定随机种子(seed=42),保证可复现性。生成300个历元的载波相位数据,噪声标准差为0.01周。
- 周跳注入:在第100历元注入+5周跳变,第200历元注入-3周跳变。注入方式为从该历元起所有后续相位值整体偏移,模拟真实周跳的持续性影响。
- 探测算法:四阶差分将周跳转换为单历元尖峰。阈值设为8倍MAD估计的标准差,兼顾灵敏度与抗噪声能力。
- 通过条件:程序输出中“正确探测”数量等于2,且显示“测试通过”。探测到的周跳历元与真实值偏差不超过1个历元,大小偏差小于1周。
关键参数说明
- 四阶差分:对静态或低动态场景,四阶差分可有效消除多项式趋势,使周跳信号凸显。
- 阈值因子:8倍σ在噪声标准差0.01周时,虚警率极低;若噪声增大,可适当降低阈值因子。
- 周跳大小估计:四阶差分值直接等于周跳大小(单位:周),无需额外换算。