GPS数据解析实战:如何用Python提取GPGGA和GPRMC中的经纬度与速度(附完整代码)
GPS数据解析实战如何用Python提取GPGGA和GPRMC中的经纬度与速度附完整代码如果你正在开发一个物联网追踪设备或者为一个车载系统添加实时位置功能那么你大概率会碰到一串串以$GPGGA或$GPRMC开头的、看起来有些神秘的文本数据。这些就是NMEA-0183协议下的标准GPS语句它们是GPS接收器与外界沟通的“语言”。很多开发者第一次看到这些数据时可能会被其紧凑的格式和逗号分隔的字段搞得有点懵。别担心今天我们就抛开复杂的协议理论直接上手用Python把这些数据“翻译”成我们程序能直接理解和使用的经纬度、速度和时间戳。我会分享一些在实际项目中踩过的坑以及如何写出既健壮又高效的解析代码。1. 理解NMEA数据从原始字符串到可用信息在动手写代码之前我们必须先搞清楚要处理的是什么。NMEA数据本质上是一行行以ASCII字符表示的文本每行以$开头以CRLF回车换行结束。数据字段之间用逗号分隔最后一个字段之后是校验和以*开头。为什么是GPGGA和GPRMC在众多NMEA语句中$GPGGA和$GPRMC是最核心、最常用的两条。$GPGGA(Global Positioning System Fix Data) 提供了最基础的定位信息。你可以把它理解为一张“快照”告诉你“此刻我在哪里”。它包含了时间、经纬度、定位质量、使用的卫星数量以及海拔高度。对于只需要知道位置的应用解析这一条通常就够了。$GPRMC(Recommended Minimum Specific GPS/TRANSIT Data) 提供了“推荐的最小特定数据”。顾名思义它包含了导航所需的最基本且动态的信息。除了位置和时间它还额外提供了对地速度SOG和真北航向COG。这对于任何移动中的物体比如车辆、船舶或无人机是至关重要的。在实际的GPS模块数据流中这两条语句往往是交替发送的。一个典型的场景是你的串口可能每秒会收到类似下面这样的一批数据$GPGGA,092750.000,5321.6802,N,00630.3372,W,1,8,1.03,61.7,M,55.2,M,,*76 $GPRMC,092750.000,A,5321.6802,N,00630.3372,W,0.02,31.66,280511,,,A*43乍一看有点乱但结构非常清晰。我们的任务就是编写一个“翻译官”把这些字段提取并转换成浮点数格式的纬度、经度单位度、速度单位公里/小时或米/秒和标准的日期时间对象。注意NMEA格式中的经纬度表示法与我们在谷歌地图上看到的十进制度数不同它是“度分”格式DDMM.MMMM。例如“5321.6802,N”表示北纬53度21.6802分。后续的代码会详细演示如何转换。2. 搭建Python解析环境与基础工具函数我们不需要任何复杂的外部依赖Python的标准库就足以胜任这项任务。不过为了代码的清晰和可维护性我会先构建几个核心的工具函数。首先校验和验证是解析NMEA数据的第一步也是保证数据完整性的关键。传输过程中可能会产生错误校验和能帮我们过滤掉无效数据。def verify_nmea_checksum(nmea_sentence: str) - bool: 验证NMEA语句的校验和。 参数: nmea_sentence: 完整的NMEA语句如 $GPGGA,...*47 返回: bool: 校验和是否正确 # 检查语句是否包含校验和部分即包含‘*’ if * not in nmea_sentence: return False try: # 分离数据部分和校验和部分 data_part, checksum_part nmea_sentence[1:].split(*) # 计算数据部分的异或校验和 calculated_checksum 0 for char in data_part: calculated_checksum ^ ord(char) # 将计算出的校验和与接收到的校验和进行比较十六进制 return f{calculated_checksum:02X} checksum_part.upper() except (ValueError, IndexError): # 如果格式错误返回False return False这个函数是数据可靠性的第一道防线。在实际项目中我强烈建议始终开启校验和验证尤其是在通过无线方式如4G、LoRa传输GPS数据时。接下来我们需要一个通用的字段提取器。NMEA语句字段间以逗号分隔但末尾可能存在空字段。直接使用split(‘,’)即可。def parse_nmea_fields(sentence: str) - list: 解析NMEA语句返回字段列表。 会自动去除末尾的换行符和校验和。 # 去除首尾空白字符和换行符 sentence sentence.strip() # 找到校验和标识符‘*’的位置只取前面的数据部分 if * in sentence: sentence sentence.split(*)[0] # 按逗号分割字段 fields sentence.split(,) return fields有了这两个基础函数我们就可以开始针对$GPGGA和$GPRMC进行特异性解析了。3. 深度解析GPGGA提取精确位置与质量信息$GPGGA语句是定位信息的基石。下面是一个完整的解析函数它不仅能提取经纬度还会评估定位质量这对于实际应用至关重要——你肯定不想用一个无效的定位去更新地图。import datetime def parse_gpgga(gpgga_sentence: str): 解析GPGGA语句提取时间、经纬度、海拔、卫星数及定位质量。 参数: gpgga_sentence: 完整的GPGGA语句字符串。 返回: dict: 包含解析后数据的字典。如果语句无效或校验失败返回None。 # 1. 校验 if not gpgga_sentence.startswith($GPGGA) or not verify_nmea_checksum(gpgga_sentence): return None fields parse_nmea_fields(gpgga_sentence) if len(fields) 15: # GPGGA标准字段数至少为15 return None result {sentence_type: GPGGA} # 2. 解析UTC时间 (HHMMSS.SSS) try: utc_time_str fields[1] if utc_time_str: time_obj datetime.datetime.strptime(utc_time_str.split(.)[0], %H%M%S).time() result[utc_time] time_obj except ValueError: result[utc_time] None # 3. 解析纬度 (格式DDMM.MMMM, 方向N/S) lat_str, lat_dir fields[2], fields[3] if lat_str and lat_dir in (N, S): # 将度分格式转换为十进制度数 degrees float(lat_str[:2]) minutes float(lat_str[2:]) decimal_degrees degrees minutes / 60.0 if lat_dir S: decimal_degrees -decimal_degrees result[latitude] decimal_degrees else: result[latitude] None # 4. 解析经度 (格式DDDMM.MMMM, 方向E/W) lon_str, lon_dir fields[4], fields[5] if lon_str and lon_dir in (E, W): degrees float(lon_str[:3]) minutes float(lon_str[3:]) decimal_degrees degrees minutes / 60.0 if lon_dir W: decimal_degrees -decimal_degrees result[longitude] decimal_degrees else: result[longitude] None # 5. 定位质量指示器 (最重要的质量指标之一) # 0无效1GPS定位2差分GPS定位6估算 fix_quality int(fields[6]) if fields[6] else 0 result[fix_quality] fix_quality result[is_valid_fix] fix_quality in (1, 2) # 只有1和2代表有效定位 # 6. 其他有用信息 result[satellites_tracked] int(fields[7]) if fields[7] else 0 result[hdop] float(fields[8]) if fields[8] else None # 水平精度因子 result[altitude] float(fields[9]) if fields[9] else None # 海拔高度单位米 result[altitude_units] fields[10] return result这个函数返回一个字典里面包含了所有关键信息。其中fix_quality和is_valid_fix字段是你决定是否使用当前定位数据的核心依据。在车载追踪器中我们通常会忽略fix_quality为0无效或6估算的数据点只记录有效定位这样可以避免在隧道或地下停车场产生大量无用的漂移点。为了更直观地对比GPGGA各字段的含义和重要性可以参考下表字段索引字段示例含义解析说明与重要性0$GPGGA语句标识符标识该条NMEA语句类型。1092750.000UTC时间 (HHMMSS.SSS)格林威治时间需转换为本地时间或datetime对象。25321.6802纬度 (DDMM.MMMM)核心字段需结合方向字段3进行“度分转十进制度”计算。3N纬度方向 (N/S)N为北纬S为南纬转换时决定正负号。400630.3372经度 (DDDMM.MMMM)核心字段需结合方向字段5进行转换。5W经度方向 (E/W)E为东经W为西经。61定位质量 (0-2,6)最关键的质量指标。0无效1GPS定位2差分定位6估算。708跟踪卫星数量数量越多通常定位越可靠。81.03水平精度因子 (HDOP)值越小精度越高2.0时精度可能较差。961.7海拔高度单位由字段10指定。10M海拔高度单位通常为米(M)。4. 实战解析GPRMC获取动态速度与航向当你的设备开始移动$GPRMC语句的价值就凸显出来了。它提供了速度对地速度和航向这是计算轨迹、估算到达时间ETA的基础。def parse_gprmc(gprmc_sentence: str): 解析GPRMC语句提取时间、日期、经纬度、速度、航向及定位状态。 参数: gprmc_sentence: 完整的GPRMC语句字符串。 返回: dict: 包含解析后数据的字典。如果语句无效或校验失败返回None。 if not gprmc_sentence.startswith($GPRMC) or not verify_nmea_checksum(gprmc_sentence): return None fields parse_nmea_fields(gprmc_sentence) if len(fields) 12: return None result {sentence_type: GPRMC} # 1. 解析UTC时间 try: utc_time_str fields[1] if utc_time_str: time_obj datetime.datetime.strptime(utc_time_str.split(.)[0], %H%M%S).time() result[utc_time] time_obj except ValueError: result[utc_time] None # 2. 定位状态 (A有效V无效) status fields[2] result[status] status result[is_active] (status A) # 只有‘A’代表有效导航 # 3. 解析纬度 (同GPGGA) lat_str, lat_dir fields[3], fields[4] if lat_str and lat_dir in (N, S): degrees float(lat_str[:2]) minutes float(lat_str[2:]) decimal_degrees degrees minutes / 60.0 if lat_dir S: decimal_degrees -decimal_degrees result[latitude] decimal_degrees else: result[latitude] None # 4. 解析经度 (同GPGGA) lon_str, lon_dir fields[5], fields[6] if lon_str and lon_dir in (E, W): degrees float(lon_str[:3]) minutes float(lon_str[3:]) decimal_degrees degrees minutes / 60.0 if lon_dir W: decimal_degrees -decimal_degrees result[longitude] decimal_degrees else: result[longitude] None # 5. 对地速度 (SOG - Speed Over Ground) - 核心动态字段 # 单位节 (knots), 1 knot 1.852 km/h ≈ 0.514 m/s speed_knots float(fields[7]) if fields[7] else 0.0 result[speed_knots] speed_knots result[speed_kmh] speed_knots * 1.852 # 转换为公里/小时 result[speed_ms] speed_knots * 0.514444 # 转换为米/秒 # 6. 真北航向 (COG - Course Over Ground) # 单位度0°表示正北90°为正东范围0~359.9 course float(fields[8]) if fields[8] else None result[true_course] course # 7. 解析UTC日期 (DDMMYY) date_str fields[9] if date_str and result[utc_time]: try: date_obj datetime.datetime.strptime(date_str, %d%m%y).date() # 合并日期和时间创建一个完整的datetime对象 result[utc_datetime] datetime.datetime.combine(date_obj, result[utc_time]) except ValueError: result[utc_datetime] None else: result[utc_datetime] None # 8. 磁偏角 (可选字段) mag_var fields[10] if len(fields) 10 else mag_var_dir fields[11] if len(fields) 11 else result[magnetic_variation] f{mag_var}{mag_var_dir} if mag_var else None return result这个函数最精彩的部分在于速度单位的转换。GPS模块默认输出的是“节”knots这是航海和航空的常用单位。但在物联网或车载应用中我们更习惯使用公里/小时或米/秒。函数中直接进行了计算你可以根据业务需求选择使用speed_kmh还是speed_ms。提示GPRMC中的status字段‘A’或‘V’是判断数据是否可用的快速方法。但在高要求场景下建议结合GPGGA的fix_quality一起判断双重验证更保险。5. 构建完整的数据处理流水线单个语句的解析只是第一步。在实际应用中GPS模块会通过串口如UART或网络Socket持续发送数据流。我们需要构建一个稳定的数据处理流水线来实时处理这些数据。这个流水线通常包含以下几个环节数据读取 从串口、TCP Socket或文件中逐行读取原始数据。数据过滤与校验 识别出$GPGGA和$GPRMC语句并进行校验和验证。数据解析 调用我们上面写好的parse_gpgga和parse_gprmc函数。数据融合与输出 将两条语句的信息合并生成一个更完整的定位数据包然后存入数据库、发送到消息队列或进行实时展示。下面是一个模拟从文件读取数据并处理的完整示例它展示了如何将上述所有环节串联起来import serial import time from typing import Optional, Dict class NMEAParser: 一个简单的NMEA数据流解析器类。 def __init__(self): self.last_gpgga None self.last_gprmc None def process_line(self, line: str) - Optional[Dict]: 处理单行NMEA数据返回融合后的定位信息字典。 line line.strip() if not line: return None result None if line.startswith($GPGGA): self.last_gpgga parse_gpgga(line) result self._merge_data() elif line.startswith($GPRMC): self.last_gprmc parse_gprmc(line) result self._merge_data() return result def _merge_data(self) - Optional[Dict]: 合并最近收到的GPGGA和GPRMC数据。 优先使用GPRMC中的动态信息速度、航向 并确保定位状态有效。 merged {} # 基础信息优先从GPGGA获取定位质量、卫星数等 if self.last_gpgga and self.last_gpgga.get(is_valid_fix): merged.update(self.last_gpgga) # 动态信息和完整时间从GPRMC获取 if self.last_gprmc and self.last_gprmc.get(is_active): # 如果GPRMC有位置且GPGGA无效则使用GPRMC的位置 if self.last_gprmc.get(latitude) is not None and (not merged or merged.get(latitude) is None): merged[latitude] self.last_gprmc[latitude] merged[longitude] self.last_gprmc[longitude] # 更新速度、航向、日期时间 merged.update({ speed_kmh: self.last_gprmc.get(speed_kmh), true_course: self.last_gprmc.get(true_course), utc_datetime: self.last_gprmc.get(utc_datetime), status: self.last_gprmc.get(status) }) # 确保句子类型标识清晰 merged[sentence_type] MERGED(GGARMC) # 只有当我们同时拥有有效的位置和状态时才返回合并结果 if merged.get(latitude) is not None and merged.get(longitude) is not None: # 添加一个本地时间戳用于记录数据到达系统的时刻 merged[system_timestamp] time.time() return merged return None # 示例从模拟数据文件读取并处理 def process_nmea_file(file_path): parser NMEAParser() with open(file_path, r) as f: for line in f: parsed_data parser.process_line(line) if parsed_data: # 这里可以替换为你的业务逻辑存入数据库、发送到MQTT等 print(f[{parsed_data.get(utc_datetime)}] fLat: {parsed_data[latitude]:.6f}, fLon: {parsed_data[longitude]:.6f}, fSpeed: {parsed_data.get(speed_kmh, 0):.2f} km/h, fSat: {parsed_data.get(satellites_tracked, 0)}) # 模拟一些业务处理 # save_to_database(parsed_data) # publish_to_mqtt(gps/track, parsed_data) if __name__ __main__: # 假设有一个包含NMEA数据的文本文件 process_nmea_file(sample_gps_data.txt)这个NMEAParser类实现了一个简单的状态机它缓存最近收到的GPGGA和GPRMC数据。当收到其中任意一条时都尝试将两者信息合并成一个更丰富的数据对象。这种设计很好地模拟了真实场景下数据流异步到达的情况。6. 进阶话题错误处理、性能优化与扩展在真实的生产环境中仅仅能解析数据是远远不够的。我们还需要考虑代码的健壮性、处理效率以及未来的扩展性。错误处理与数据清洗GPS数据在信号不佳时如城市峡谷、隧道内会产生大量无效或漂移数据。我们的解析器必须能优雅地处理这些情况字段缺失或为空 使用条件判断if fields[索引]和try...except块。校验和错误 坚决丢弃这是硬件或传输错误。数值范围异常 例如纬度应在-90到90之间经度在-180到180之间速度不应超过一个合理上限如500 km/h。可以添加验证函数。时间跳变 如果解析出的时间与上一条数据时间相差过大可能是无效数据。性能考量如果处理的是高频GPS数据如10Hz解析效率就变得重要。避免重复计算 像校验和验证、字符串分割只做一次。使用更高效的数据结构 对于最终输出的数据可以考虑使用dataclass或namedtuple来代替字典访问速度更快内存更紧凑。异步处理 对于IO密集型的操作如从网络读取、写入数据库使用asyncio可以大幅提升吞吐量。扩展性支持更多NMEA语句与协议GPGGA和GPRMC只是开始。NMEA协议还有很多其他有用的语句例如$GPVTG: 提供地面速度信息和航向。$GPGSV: 查看天空中每颗卫星的详细信息编号、仰角、方位角、信噪比用于信号质量分析。$GPGSA: 显示GPS精度因子和参与解算的卫星ID。解析这些语句的逻辑是相似的你可以轻松地扩展我们上面建立的框架。只需增加对应的解析函数并在process_line方法中添加新的if分支即可。此外对于有高精度定位需求的场景如自动驾驶、精准农业你会接触到RTCM差分数据。这与文本格式的NMEA完全不同它是二进制协议需要通过专门的库如rtklib的Python绑定来解析其目的是为GPS接收机提供修正信息将定位精度从米级提升到厘米级。这完全是另一个层面的技术栈但你的NMEA解析基础将是理解整个定位系统数据流的重要一环。最后分享一个我在处理车载GPS数据时的小技巧由于城市环境中多路径效应和信号遮挡严重单纯依赖单点定位跳动很大。我通常会实现一个简单的移动平均滤波器Moving Average Filter或卡尔曼滤波器Kalman Filter对连续解析出的经纬度进行平滑处理。这样在地图上显示的轨迹会干净很多用户体验提升非常明显。你可以尝试在NMEAParser类的_merge_data方法之后加入一个过滤环节看看效果。

相关新闻

PCIe时钟双雄:参考时钟的基石作用与嵌入式时钟的动态恢复

PCIe时钟双雄:参考时钟的基石作用与嵌入式时钟的动态恢复

1. 从一次调试经历说起:为什么我的PCIe设备时好时坏? 几年前,我接手了一个棘手的项目。一块新设计的PCIe数据采集卡,在实验室里跑得挺欢,可一到客户现场,数据传输就时不时地“卡顿”一下,甚至偶…

2026/5/17 12:35:11 阅读更多 →
GESP C++认证通关秘籍:计算机基础知识考点全解析(2024最新版)

GESP C++认证通关秘籍:计算机基础知识考点全解析(2024最新版)

GESP C认证通关秘籍:计算机基础知识考点全解析(2024最新版) 准备GESP C认证,很多同学会把精力全放在语法和算法上,这其实是个误区。我见过不少编程能力不错的孩子,在考试中却栽在了看似“简单”的计算机基础…

2026/5/17 12:35:10 阅读更多 →
Cadence OrCAD隐藏技巧:用Pin Array快速绘制LQFP封装原理图符号

Cadence OrCAD隐藏技巧:用Pin Array快速绘制LQFP封装原理图符号

Cadence OrCAD隐藏技巧:用Pin Array快速绘制LQFP封装原理图符号 刚接触Cadence OrCAD Capture的新手,面对一个拥有几十甚至上百个引脚的微控制器(MCU)时,最头疼的莫过于创建它的原理图符号。想象一下,你需要…

2026/5/17 12:35:07 阅读更多 →

最新新闻

Sunshine游戏串流完整指南:从零开始搭建你的私人云游戏平台

Sunshine游戏串流完整指南:从零开始搭建你的私人云游戏平台

Sunshine游戏串流完整指南:从零开始搭建你的私人云游戏平台 【免费下载链接】Sunshine Self-hosted game stream host for Moonlight. 项目地址: https://gitcode.com/GitHub_Trending/su/Sunshine Sunshine是一款开源免费的自托管游戏串流服务器&#xff0c…

2026/7/3 11:41:52 阅读更多 →
2026年桌面风扇推荐:别被参数迷惑,选对适合自己使用习惯的才明智

2026年桌面风扇推荐:别被参数迷惑,选对适合自己使用习惯的才明智

2026年桌面风扇推荐:别被参数迷惑,选对适合自己使用习惯的才明智2026年夏季,桌面风扇市场产品丰富,但不少消费者在“桌面风扇推荐2026”相关搜索中看到各种参数却不知如何对应实际需求。选购的核心不是看哪个指标最高,…

2026/7/3 11:41:52 阅读更多 →
冠宇仪器中标快检项目:盐都区农贸市场试剂采购彰显技术实力

冠宇仪器中标快检项目:盐都区农贸市场试剂采购彰显技术实力

近日,冠宇仪器制造(江苏)有限公司成功中标盐城市盐都区市场监督管理局农贸市场快检室试剂采购项目的消息,在食品安全快检行业引发广泛关注。企业凭借过硬的产品性能、全流程闭环服务体系和高性价比的落地方案脱颖而出,…

2026/7/3 11:39:50 阅读更多 →
在GEO优化中,是否应当优先考虑内容的视觉呈现?

在GEO优化中,是否应当优先考虑内容的视觉呈现?

随着生成式AI日益成为信息获取的重要渠道,GEO(生成式引擎优化)正悄然重塑品牌的数字曝光逻辑。在这场以内容质量为核心的角逐中,一个核心矛盾浮出水面:精心雕琢的文字,是否真的需要依赖夺目的视觉元素来“开…

2026/7/3 11:37:50 阅读更多 →
深度学习模型:量化与蒸馏

深度学习模型:量化与蒸馏

模型量化与知识蒸馏是深度学习模型轻量化的两大核心技术,广泛应用于移动端、嵌入式等低资源部署场景。二者核心逻辑完全不同,常搭配使用实现“高精度、低体积、高速度”的落地效果。本文融合理论与实战,精简冗余内容,搭配可直接运…

2026/7/3 11:37:50 阅读更多 →
Si4731与PIC18F4553构建数字收音机系统全解析

Si4731与PIC18F4553构建数字收音机系统全解析

1. Si4731与PIC18F4553的硬件搭档解析Si4731是Silicon Labs推出的一款高性能AM/FM/SW无线电接收芯片,采用数字低中频架构,支持从150kHz到30MHz的调幅广播和76MHz到108MHz的调频广播接收。其核心优势在于:集成完整的射频前端,仅需少…

2026/7/3 11:37:50 阅读更多 →

日新闻

Nginx防御TLS重协商攻击实战:从原理到配置与监控

Nginx防御TLS重协商攻击实战:从原理到配置与监控

1. 项目概述:为什么TLS重协商攻击至今仍需警惕十多年前的CVE-2011-1473,一个关于TLS/SSL协议重协商机制的漏洞,现在提起来还有必要吗?很多运维和开发朋友可能会觉得,这都老掉牙了,现代服务器和客户端不都默…

2026/7/3 0:03:59 阅读更多 →
华为防火墙双通道远程管理实战:Web与SSH配置详解

华为防火墙双通道远程管理实战:Web与SSH配置详解

1. 项目概述:为什么需要双通道远程管理防火墙?在任何一个稍具规模的企业网络里,防火墙都是那个默默守护在边界的关键角色。作为网络工程师,我们不可能每次都跑到机房,插上console线去配置它。远程管理能力,…

2026/7/3 0:03:59 阅读更多 →
AD74413R与PIC18F65K40的高精度工业数据采集方案

AD74413R与PIC18F65K40的高精度工业数据采集方案

1. 项目概述:AD74413R与PIC18F65K40的协同工作在工业自动化和精密测量领域,同时实现高精度模数转换(ADC)和数模转换(DAC)功能是许多复杂系统的核心需求。AD74413R作为一款四通道可配置模拟输入/输出器件,与PIC18F65K40微控制器的组合&#xf…

2026/7/3 0:05:59 阅读更多 →

周新闻

月新闻