hello~这里是维构lbs智能定位,如果有项目需求和技术交流欢迎来私信我们~点击文章最下方可获取免费获取技术文档和解决方案
我国的北斗卫星导航系统(BDS)的定位核心原理是"空间星座+地面控制+用户终端"协同,以伪距测量与空间后方交会为底层逻辑,通过多颗卫星的信号计算接收机的三维坐标,结合多频信号、差分增强等技术实现从米级到厘米级的定位,本文就核心框架到定位流程将从展开论述。

一、北斗卫星导航定位的系统核心框架
北斗三号由三大核心部分组成,是定位的基础设施,缺一不可
|------|----------------------------------------|---------------------------------------------|
| 组成部分 | 核心构成 | 核心功能 |
| 空间星座 | 30+颗卫星(MEO中圆轨道+GEO地球静止轨道+IGSO倾斜地球同步轨道) | 播发导航电文(星历+时钟)、测距信号,GEO/IGSO卫星增强亚太区域信号与短报文服务 |
| 地面控制 | 主控站、注入站、监测站、地基增强基准站(CORS) | 测算卫星轨道/钟差、生成修正数据、注入卫星、实时监控星座健康状态 |
| 用户终端 | 北斗接收机(单频/双频/多频)、天线、数据处理模块 | 接收卫星信号、解算伪距、修正误差、输出三维坐标(经度/纬度/高度)+ 时间 |
二、北斗卫星导航 定位全流程:从信号到坐标的7个核心步骤
北斗定位的底层逻辑是根据已知多颗卫星的空间位置,测量接收机到每颗卫星的距离,再通过几何计算确定接收机位置,类似"地面找一点,测量它到三个已知坐标地标点的距离,就能锁定位置",本质是"解4元方程组"(3个空间坐标+1个时间误差)。
1.卫星播发导航信号与电文
每颗北斗卫星会持续发射测距码(如B1C/B2a/B3I)和导航电文:
(1)测距码
用于测量信号传播时间,多频设计可抑制电离层延迟,提升抗干扰能力。
(2)导航电文
包含卫星星历(实时三维坐标)、卫星钟差、电离层/对流层延迟修正参数(如TGD)、卫星健康状态等关键数据,为定位提供"已知参考"。
(3)卫星搭载铷原子钟/氢原子钟
授时精度达20纳秒级,确保时间基准一致。
2.用户终端接收与伪距测量
接收机天线捕获≥4颗卫星信号后,计算信号从卫星到终端的传播时间Δt,再通过公式伪距ρ = c×Δt(c为光速)得到"近似距离"。
伪距≠真实距离:因卫星钟差、接收机钟差、大气延迟、多路径效应等,存在固有偏差,需后续修正。
注:需4颗卫星的原因:3颗卫星解算三维坐标(经度、纬度、高度)+ 1颗卫星用于修正终端与卫星的时间同步误差,共4个未知数,需要4组伪距方程联立求解。
3.伪距误差初步修正(单频/双频策略)
接收机先通过导航电文内置参数做初步修正,核心修正项如下:
(1)卫星钟差修正
用导航电文中的钟差参数+TGD(群延迟偏差)修正单频/双频伪距。
(2)电离层延迟修正
单频用户用Klobuchar模型,双频用户通过无电离层组合(如B1C+B2a)抵消大部分电离层影响。
(3)对流层延迟修正
用Hopfield/Saastamoinen模型,基于终端位置、时间、气象数据估算延迟。
伪距误差初步修正(单频 / 双频)Python 实现:
import math
import numpy as np
def satellite_clock_error_correction(t_transmit, a0, a1, a2, tgd=0.0):
"""
卫星钟差修正
:param t_transmit: 卫星信号发射时刻(s)
:param a0: 钟差常数项(s)
:param a1: 钟差一次项(s/s)
:param a2: 钟差二次项(s/s²)
:param tgd: 群延迟偏差TGD(s,单频/双频均需传入,双频根据频率组合调整)
:return: 修正后的卫星发射时刻(s)、卫星钟差(s)
"""
# 卫星钟差计算:Δt_sv = a0 + a1*(t - t_oc) + a2*(t - t_oc)²
delta_t_sv = a0 + a1 * t_transmit + a2 * (t_transmit ** 2)
# 加入TGD群延迟偏差修正
delta_t_sv += tgd
# 修正后的发射时刻
t_transmit_corrected = t_transmit - delta_t_sv
return t_transmit_corrected, delta_t_sv
def klobuchar_ionospheric_correction(lat_user, lon_user, t, elev, azim,
alpha0, alpha1, alpha2, alpha3,
beta0, beta1, beta2, beta3):
"""
单频用户电离层延迟修正(Klobuchar模型)
:param lat_user: 用户纬度(rad)
:param lon_user: 用户经度(rad)
:param t: GPS周内秒(s)
:param elev: 卫星高度角(rad)
:param azim: 卫星方位角(rad)
:param alpha0-alpha3: Klobuchar模型alpha参数(导航电文提供)
:param beta0-beta3: Klobuchar模型beta参数(导航电文提供)
:return: 电离层延迟修正量(m,伪距修正用)
"""
# 1. 计算电离层穿刺点(IPP)的地心纬度
psi = 0.0137 / (elev / math.pi * 180 + 0.11) - 0.022
lat_ipp = lat_user + psi * math.cos(azim)
# 限制纬度范围在±80°
lat_ipp = max(min(lat_ipp, 80 * math.pi / 180), -80 * math.pi / 180)
lon_ipp = lon_user + psi * math.sin(azim) / math.cos(lat_ipp)
# 2. 计算太阳赤纬角
t_utc = t + 14400 # 转换为世界时(UTC),GPS时比UTC快14s(实际可调整,此处简化)
t_day = t_utc % 86400 # 日秒数
omega = 2 * math.pi * (t_day - 43200) / 86400 # 太阳时角
delta_sun = 0.0167 * math.sin(2 * math.pi * (t_utc / 86400 - 80) / 365) # 太阳赤纬角简化计算
# 3. 计算电离层延迟的周期项
phi_m = lat_ipp + delta_sun * math.cos(omega)
lambda_m = lon_ipp
t_m = 43200 * lambda_m / math.pi + t_day # 地方太阳时
t_m = t_m % 86400 # 归一化到0-86400s
# 4. 计算振幅和周期
amp = alpha0 + alpha1 * phi_m + alpha2 * (phi_m ** 2) + alpha3 * (phi_m ** 3)
amp = max(amp, 0.0) # 振幅非负
per = beta0 + beta1 * phi_m + beta2 * (phi_m ** 2) + beta3 * (phi_m ** 3)
per = max(per, 72000.0) # 周期不小于20小时
# 5. 计算电离层延迟
if abs(t_m - 54000) < per / 2:
ion_delay = 5e-9 + amp * (1 - ( (t_m - 54000) ** 2 ) / ( (per / 2) ** 2 ) +
( (t_m - 54000) ** 4 ) / ( (2 * per / 2) ** 4 ))
else:
ion_delay = 5e-9 # 夜间电离层延迟恒定
# 6. 高度角修正
ion_delay = ion_delay / math.sin(elev + 0.11 * (elev / math.pi * 180) ** 2 / (elev / math.pi * 180 + 0.11))
# 转换为距离延迟(m,光速c=3e8 m/s)
ion_delay_m = ion_delay * 3e8
return ion_delay_m
def tropospheric_correction(lat_user, elev, height_user, temp=20.0, press=1013.25, humi=50.0):
"""
对流层延迟修正(Hopfield模型,兼顾干、湿分量)
:param lat_user: 用户纬度(rad)
:param elev: 卫星高度角(rad)
:param height_user: 用户海拔高度(m)
:param temp: 地面温度(℃,默认20℃)
:param press: 地面气压(hPa,默认标准大气压)
:param humi: 地面相对湿度(%,默认50%)
:return: 对流层延迟修正量(m)
"""
# 单位转换
temp_k = temp + 273.15 # 转换为开尔文
elev_deg = elev / math.pi * 180 # 转换为角度
if elev_deg < 5:
elev_deg = 5 # 高度角不小于5°,避免分母过小
# 1. 干分量修正(Hopfield模型)
# 干大气常数
R_d = 287.05 # 干空气气体常数(J/(kg·K))
g = 9.80665 # 重力加速度(m/s²)
T0_d = temp_k # 干大气底层温度
P0_d = press * 100 # 转换为Pa
H_d = 40136 + 148.72 * (temp_k - 273.15) # 干大气标高(m)
# 干分量延迟
delta_d = (0.002277 / math.sin(math.radians(elev_deg))) * P0_d
delta_d *= (1 + (height_user / H_d) - (0.002 * lat_user ** 2))
# 2. 湿分量修正
# 湿大气常数
T0_w = temp_k # 湿大气底层温度
e0 = 6.1078 * math.exp( (17.27 * (temp_k - 273.15)) / (temp_k - 35.85) ) # 饱和水汽压
P0_w = (humi / 100) * e0 * 100 # 水汽压(Pa)
H_w = 11000 # 湿大气标高(m,经验值)
# 湿分量延迟
delta_w = (0.002277 * 0.0026 / math.sin(math.radians(elev_deg))) * (P0_w * T0_d) / T0_w
delta_w *= (1 + height_user / H_w)
# 总对流层延迟
tropo_delay_m = (delta_d + delta_w) / 100 # 转换为m
return tropo_delay_m
def undifferenced_ionospheric_free_combination(pseudo1, pseudo2, f1, f2):
"""
双频用户无电离层组合(抵消大部分电离层影响)
:param pseudo1: 频率1伪距观测值(m,如B1C)
:param pseudo2: 频率2伪距观测值(m,如B2a)
:param f1: 频率1(Hz,如B1C: 1.57542e9 Hz)
:param f2: 频率2(Hz,如B2a: 1.20714e9 Hz)
:return: 无电离层组合伪距(m)
"""
# 无电离层组合系数
k1 = (f1 ** 2) / (f1 ** 2 - f2 ** 2)
k2 = - (f2 ** 2) / (f1 ** 2 - f2 ** 2)
# 无电离层组合伪距
pseudo_if = k1 * pseudo1 + k2 * pseudo2
return pseudo_if
def pseudo_range_correction(pseudo_ranges, freq_info, user_info, sat_clock_params,
iono_params, tropo_params, is_dual_frequency=True):
"""
伪距误差综合修正入口函数
:param pseudo_ranges: 伪距观测值字典,key=频率标识,value=伪距(m)
:param freq_info: 频率信息字典,key=频率标识,value=频率(Hz)
:param user_info: 用户信息字典,包含lat(rad)、lon(rad)、height(m)、t(gps周内秒)
:param sat_clock_params: 卫星钟差参数 (a0, a1, a2, tgd)
:param iono_params: 电离层参数,单频=Klobuchar参数,双频=None
:param tropo_params: 对流层气象参数 (temp, press, humi)
:param is_dual_frequency: 是否双频用户(True=双频,False=单频)
:return: 修正后的伪距(m)
"""
# 1. 卫星钟差修正(先修正伪距对应的发射时刻)
a0, a1, a2, tgd = sat_clock_params
t_transmit = user_info['t'] # 初始发射时刻
t_transmit_corr, delta_t_sv = satellite_clock_error_correction(t_transmit, a0, a1, a2, tgd)
# 钟差对应的距离修正量(m)
clock_corr_m = delta_t_sv * 3e8
# 2. 电离层修正 + 双频无电离层组合
if is_dual_frequency:
# 双频:无电离层组合抵消电离层影响
if len(pseudo_ranges) < 2:
raise ValueError("双频用户需要至少两个频率的伪距观测值")
freq_keys = list(pseudo_ranges.keys())
f1, f2 = freq_info[freq_keys[0]], freq_info[freq_keys[1]]
pseudo1, pseudo2 = pseudo_ranges[freq_keys[0]], pseudo_ranges[freq_keys[1]]
# 先扣除卫星钟差影响
pseudo1 -= clock_corr_m
pseudo2 -= clock_corr_m
# 无电离层组合
pseudo_iono_corr = undifferenced_ionospheric_free_combination(pseudo1, pseudo2, f1, f2)
else:
# 单频:Klobuchar模型修正电离层
if len(pseudo_ranges) < 1:
raise ValueError("单频用户需要至少一个频率的伪距观测值")
freq_key = list(pseudo_ranges.keys())[0]
pseudo = pseudo_ranges[freq_key]
# 先扣除卫星钟差影响
pseudo -= clock_corr_m
# Klobuchar模型参数
alpha0, alpha1, alpha2, alpha3, beta0, beta1, beta2, beta3 = iono_params
# 计算电离层延迟修正量
ion_delay_m = klobuchar_ionospheric_correction(
user_info['lat'], user_info['lon'], user_info['t'],
user_info['elev'], user_info['azim'],
alpha0, alpha1, alpha2, alpha3, beta0, beta1, beta2, beta3
)
# 修正电离层延迟(伪距减去电离层延迟)
pseudo_iono_corr = pseudo - ion_delay_m
# 3. 对流层修正
temp, press, humi = tropo_params
tropo_delay_m = tropospheric_correction(
user_info['lat'], user_info['elev'], user_info['height'],
temp, press, humi
)
# 修正对流层延迟(伪距减去对流层延迟)
pseudo_final_corr = pseudo_iono_corr - tropo_delay_m
return pseudo_final_corr
# -------------------------- 测试示例 --------------------------
if __name__ == "__main__":
# 1. 输入参数
# 伪距观测值(双频:B1C、B2a;单频:仅B1C)
pseudo_ranges = {
"B1C": 20000000.0, # B1C伪距(m)
"B2a": 20000005.0 # B2a伪距(m)
}
# 频率信息(B1C:1.57542e9 Hz,B2a:1.20714e9 Hz)
freq_info = {
"B1C": 1.57542e9,
"B2a": 1.20714e9
}
# 用户信息
user_info = {
"lat": 30 * math.pi / 180, # 纬度30°(rad)
"lon": 120 * math.pi / 180, # 经度120°(rad)
"height": 100.0, # 海拔100m
"t": 3600.0, # GPS周内秒3600s
"elev": 30 * math.pi / 180, # 卫星高度角30°(rad)
"azim": 90 * math.pi / 180 # 卫星方位角90°(rad)
}
# 卫星钟差参数(a0,a1,a2,TGD)
sat_clock_params = (1.2e-8, 5e-15, 0.0, 2.0e-9)
# Klobuchar电离层参数(单频使用)
iono_params = (1.0e-8, 0.0, 0.0, 0.0, 7.2e4, 0.0, 0.0, 0.0)
# 对流层气象参数(温度20℃,气压1013.25hPa,湿度50%)
tropo_params = (20.0, 1013.25, 50.0)
# 2. 双频用户伪距修正
try:
pseudo_corr_dual = pseudo_range_correction(
pseudo_ranges, freq_info, user_info, sat_clock_params,
iono_params, tropo_params, is_dual_frequency=True
)
print(f"双频(无电离层组合)修正后伪距:{pseudo_corr_dual:.2f} m")
except Exception as e:
print(f"双频修正异常:{e}")
# 3. 单频用户伪距修正(仅使用B1C频率)
pseudo_ranges_single = {"B1C": 20000000.0}
freq_info_single = {"B1C": 1.57542e9}
try:
pseudo_corr_single = pseudo_range_correction(
pseudo_ranges_single, freq_info_single, user_info, sat_clock_params,
iono_params, tropo_params, is_dual_frequency=False
)
print(f"单频(Klobuchar模型)修正后伪距:{pseudo_corr_single:.2f} m")
except Exception as e:
print(f"单频修正异常:{e}")
4. 空间后方交会解算原始坐标
以4颗卫星的已知坐标为球心,以修正后的伪距为半径,建立4个球面方程,联立求解唯一交点,得到用户的原始三维坐标(WGS - 84坐标系)。
核心算法:最小二乘法,通过迭代降低观测误差对坐标解算的影响,确保结果收敛。
5.差分增强修正(高精度定位关键)
米级定位满足消费级需求,工业场景需进一步提升精度,主流技术如下:
|-------------|----------------------------|-------------|----------------|
| 增强技术 | 工作原理 | 精度水平 | 适用场景 |
| RTK实时动态差分 | 基准站计算误差并播发修正数据,终端接收后消除系统误差 | 静态厘米级,动态分米级 | 厂区管廊、测绘、农机自动驾驶 |
| 星基增强(SBAS) | 同步轨道卫星播发修正信息,覆盖广 | 亚米级 | 民航、海事、大范围户外作业 |
| 精密单点定位(PPP) | 接收IGS精密星历/钟差,长时间解算消除误差 | 静态毫米级,动态厘米级 | 地质监测、大型工程施工 |
6.多系统融合与辅助定位(复杂环境兜底)
卫星信号遮挡/弱信号场景下,接收机自动融合惯性导航(IMU)、UWB、蓝牙AOA等技术,实现实现"室内外无缝定位":
室外开阔区:北斗+RTK提供厘米级定位,适配高压管廊、厂区道路人员/设备盯防。
室内金属密集区:卫星信号被屏蔽,自动切换UWB基站接管,保障定位连续性。
7.输出最终定位结果
经上述步骤修正后,终端输出经纬度、高度、速度、时间等数据,定位频率可达1--10Hz,满足动态追踪需求。
希望本篇对大家有所帮助~因为篇幅有限,(二)将会放在下篇,感兴趣的朋友可以关注一下~
点击下方可获取免费获取技术文档和解决方案↓↓↓↓↓↓↓