论文引用信息
本文内容基于以下SPIE会议论文:
Zixia Shang, “Off-line Data Processing Based on GNSSLOGGER, GNSS System Positioning Data Quality and Accuracy Analysis,”Fourth International Conference on Geology, Mapping, and Remote Sensing (ICGMRS 2023), Wuhan, China, 14-16 April 2023.Proceedings of SPIE, Vol. 12978. DOI: 10.1117/12.3019575
论文实验数据已上传至GitHub:https://github.com/ZixiaShang/GNSSLOGGER-Data-8
PS:懒得找图了,直接贴海报了
MATLAB读取GNSSLogger数据:Fix记录筛选与提取实战
一、引言
在前两篇文章中,我们完成了GNSS数据的采集(第一篇)和数据质量分析(第二篇)。现在,我们将进入数据处理的核心环节——使用MATLAB读取GNSSLogger生成的日志文件,筛选出定位解算结果(Fix记录),并按定位提供者(Provider)进行分类提取。
在论文第四章B节中,作者详细阐述了基于MATLAB的离线数据处理流程。本文将从论文中的zixia4.m代码出发,带你一步步实现:
- 读取GNSSLogger的
.txt日志文件 - 筛选出所有的
Fix行 - 按照
FLP(融合定位)、GPS(纯GNSS定位)、NLP(网络定位)进行分类 - 提取经纬度、速度等关键字段,为后续轨迹绘制做准备
二、Android原始GNSS API版本差异与数据字段说明
在深入MATLAB代码之前,有必要了解不同Android版本对GNSS原始数据输出的影响,这直接关系到我们解析到的数据内容。
2.1 Android版本与GNSS API演进
| Android版本 | API Level | GNSS核心变化 | 对Fix数据的影响 |
|---|---|---|---|
| Android 7.0 | API 24 | 首次引入GnssMeasurement和GnssClock,支持原始GNSS测量 | 基础Fix数据可用,但卫星数量和测量类型有限 |
| Android 8.0 | API 26 | 添加GnssMeasurement.getState()(码锁定状态) | Fix数据的Accuracy字段更可靠 |
| Android 9 | API 28 | 添加GnssMeasurement.getCarrierFrequencyHz()(载波频率) | 支持多频段(L1/L5)区分,Fix数据更丰富 |
| Android 10 | API 29 | 必须支持原始GNSS测量,添加GnssMeasurement.getAutomaticGainControlLevelDb() | 固定输出,兼容性大幅提升 |
| Android 11 | API 30 | 支持动态数据注入 | Fix输出更稳定 |
| Android 12 | API 31 | 增强多星座支持,添加GnssMeasurement.getElapsedRealtimeNanos() | 多系统(GPS/GLO/GAL/BDS)Fix数据齐全 |
论文中的设备:论文使用的三款设备均运行Android 12(API 31),因此能够完整接收GPS、GLONASS、Galileo和BeiDou四大系统的Fix数据。
2.2 GNSSLogger Fix行的Provider字段含义
Fix行中的第2列是Provider,它直接对应Android定位框架中的定位提供者:
| Provider | 全称 | Android对应API | 数据来源 |
|---|---|---|---|
| GPS | GNSS Location Provider | LocationManager.GPS_PROVIDER | 纯GNSS卫星定位 |
| NLP | Network Location Provider | LocationManager.NETWORK_PROVIDER | 基站三角定位 + Wi-Fi定位 |
| FLP | Fused Location Provider | FusedLocationProviderClient | GPS + NLP + 传感器多源融合 |
论文中的关键结论:融合系统(FLP)的稳定性、刚性和精度远优于单一GNSS系统(GPS)。因此在实际应用中,如果没有特殊限制,应优先使用FLP数据。
三、MATLAB代码详解:从原始日志到结构化数据
3.1 步骤1:读取日志文件并筛选Fix行
GNSSLogger的输出文件是混合了多种数据类型的文本文件。我们的第一步是将所有以Fix开头的行筛选出来,单独保存到一个新文件中。
%% ==================== 步骤1:筛选Fix行 ====================% 打开原始GNSSLogger日志文件(只读模式)fid=fopen('gnss_log_2023_03_08_19_48_23.txt','r');% 创建一个新文件用于存储筛选出的Fix数据out_fid=fopen('fix_data2.txt','w');% 逐行读取tline=fgetl(fid);whileischar(tline)% 当读取到文件末尾时,tline变为-1% strncmp比较前3个字符是否为'Fix',匹配则写入新文件ifstrncmp(tline,'Fix',3)==1fprintf(out_fid,'%s\n',tline);endtline=fgetl(fid);end% 关闭所有文件句柄fclose(fid);fclose(out_fid);disp('Fix行筛选完成!结果已保存至 fix_data2.txt');代码解析:
strncmp(tline, 'Fix', 3):只比较前3个字符,避免误匹配如"Fixed"等其他词- 为什么单独写一个新文件?——便于后续调试和重复使用,避免反复读取大文件
- 如果原始日志文件很大(几百MB),这个循环可能较慢。优化方案见后文"工程化建议"
3.2 步骤2:解析Fix数据的CSV格式
Fix行是CSV(逗号分隔值)格式。我们使用MATLAB的textscan函数进行解析:
%% ==================== 步骤2:解析Fix数据 ====================filename='fix_data2.txt';delimiter=',';% 分隔符为逗号% 格式说明符:14个字段,类型依次为 字符串,字符串,浮点数×12formatSpec='%s%s%f%f%f%f%f%f%f%f%f%f%f%f';fileID=fopen(filename,'r');dataArray=textscan(fileID,formatSpec,'Delimiter',delimiter,...'EmptyValue',NaN,'ReturnOnError',false);fclose(fileID);disp('Fix数据解析完成!');Fix行的17个字段说明(为什么代码中只读取了14个?):
- 不同的Android版本和GNSSLogger版本,Fix行的列数可能略有不同
- 论文代码读取了前14列,包含了最核心的字段:
- 列1:
Fix(固定标识) - 列2:
Provider(定位提供者) - 列3:
Lat(纬度) - 列4:
Lon(经度) - 列5:
Alt(高度) - 列6:
Speed(速度,m/s) - 列7:
Accuracy(精度,米) - 后续列:时间戳、方位角等
- 列1:
💡 提示:如果你的日志文件列数更多,可以扩展
formatSpec或在textscan中设置'CollectOutput', true灵活处理。
3.3 步骤3:按Provider分类
这是整个数据处理中最关键的步骤。论文中将Fix数据按Provider分为三类:
%% ==================== 步骤3:按Provider分类 ====================% dataArray{2} 是第二列,即Provider字段FLP_index=strcmp(dataArray{2},'FLP');GPS_index=strcmp(dataArray{2},'GPS');NLP_index=strcmp(dataArray{2},'NLP');% 提取各类数据:[纬度, 经度, 高度, 速度, 精度]% 列索引:3=Lat, 4=Lon, 5=Alt, 6=Speed, 7=AccuracyFLP_data=[dataArray{3}(FLP_index),dataArray{4}(FLP_index),...dataArray{5}(FLP_index),dataArray{6}(FLP_index),...dataArray{7}(FLP_index)];GPS_data=[dataArray{3}(GPS_index),dataArray{4}(GPS_index),...dataArray{5}(GPS_index),dataArray{6}(GPS_index),...dataArray{7}(GPS_index)];NLP_data=[dataArray{3}(NLP_index),dataArray{4}(NLP_index),...dataArray{5}(NLP_index),dataArray{6}(NLP_index),...dataArray{7}(NLP_index)];% 显示各Provider的数据点数量fprintf('FLP数据点: %d\n',size(FLP_data,1));fprintf('GPS数据点: %d\n',size(GPS_data,1));fprintf('NLP数据点: %d\n',size(NLP_data,1));3.4 步骤4:提取经纬度用于后续绘图
从分类数据中提取经纬度,并输出基本信息:
%% ==================== 步骤4:提取关键字段 ====================% 从FLP数据中提取经纬度和速度lat1=FLP_data(:,1);% 纬度lon1=FLP_data(:,2);% 经度t1=FLP_data(:,3);% 高度(可选)spd1=FLP_data(:,4);% 速度(m/s)% 从GPS数据中提取lat2=GPS_data(:,1);lon2=GPS_data(:,2);t2=GPS_data(:,3);spd2=GPS_data(:,4);% 打印经纬度范围,检查数据合理性fprintf('FLP 纬度范围: [%.6f, %.6f]\n',min(lat1),max(lat1));fprintf('FLP 经度范围: [%.6f, %.6f]\n',min(lon1),max(lon1));fprintf('GPS 纬度范围: [%.6f, %.6f]\n',min(lat2),max(lat2));fprintf('GPS 经度范围: [%.6f, %.6f]\n',min(lon2),max(lon2));四、完整MATLAB代码(核心部分整合)
以下是论文中前30行代码的完整整理版本,添加了详细注释:
%% ========================================================================% 文件名:read_gnss_fix_data.m% 功能:读取GNSSLogger日志,筛选Fix行,按Provider分类提取经纬度/速度% 参考:论文 "Off-line Data Processing Based on GNSSLOGGER..."% 作者:Zixia Shang (UNSW)% 对应论文章节:第四章 B节% =========================================================================clear;clc;close all;%% -------------------- 1. 配置输入输出文件 --------------------inputFile='gnss_log_2023_03_08_19_48_23.txt';% 原始日志文件outputFile='fix_data2.txt';% 筛选后的Fix数据文件%% -------------------- 2. 筛选Fix行 --------------------fid=fopen(inputFile,'r');out_fid=fopen(outputFile,'w');tline=fgetl(fid);count=0;whileischar(tline)ifstrncmp(tline,'Fix',3)==1fprintf(out_fid,'%s\n',tline);count=count+1;endtline=fgetl(fid);endfclose(fid);fclose(out_fid);fprintf('共筛选出 %d 条Fix记录\n',count);%% -------------------- 3. 解析Fix CSV数据 --------------------delimiter=',';% 14列:Fix, Provider, Lat, Lon, Alt, Speed, Accuracy, ...formatSpec='%s%s%f%f%f%f%f%f%f%f%f%f%f%f';fileID=fopen(outputFile,'r');dataArray=textscan(fileID,formatSpec,'Delimiter',delimiter,...'EmptyValue',NaN,'ReturnOnError',false);fclose(fileID);%% -------------------- 4. 按Provider分类 --------------------% 逻辑索引idxFLP=strcmp(dataArray{2},'FLP');idxGPS=strcmp(dataArray{2},'GPS');idxNLP=strcmp(dataArray{2},'NLP');% 提取数据:[Lat, Lon, Alt, Speed, Accuracy]FLP_data=[dataArray{3}(idxFLP),dataArray{4}(idxFLP),...dataArray{5}(idxFLP),dataArray{6}(idxFLP),...dataArray{7}(idxFLP)];GPS_data=[dataArray{3}(idxGPS),dataArray{4}(idxGPS),...dataArray{5}(idxGPS),dataArray{6}(idxGPS),...dataArray{7}(idxGPS)];NLP_data=[dataArray{3}(idxNLP),dataArray{4}(idxNLP),...dataArray{5}(idxNLP),dataArray{6}(idxNLP),...dataArray{7}(idxNLP)];%% -------------------- 5. 统计与输出 --------------------fprintf('='*50);fprintf('数据统计结果:\n');fprintf('FLP: %d 个点\n',size(FLP_data,1));fprintf('GPS: %d 个点\n',size(GPS_data,1));fprintf('NLP: %d 个点\n',size(NLP_data,1));% 保存为MAT文件,便于后续处理(第四篇博客会用到)save('gnss_parsed_data.mat','FLP_data','GPS_data','NLP_data');disp('数据已保存至 gnss_parsed_data.mat');代码运行结果示例
>> read_gnss_fix_data 共筛选出 98778 条Fix记录 数据统计结果: FLP: 11236 个点 GPS: 85342 个点 NLP: 2200 个点 数据已保存至 gnss_parsed_data.mat五、调试与数据验证
5.1 检查数据合理性
在得到分类数据后,建议进行快速验证:
%% 快速检查:绘制经纬度散点图figure;subplot(1,2,1);plot(FLP_data(:,2),FLP_data(:,1),'r.','MarkerSize',2);hold on;plot(GPS_data(:,2),GPS_data(:,1),'b.','MarkerSize',2);legend('FLP','GPS');xlabel('经度');ylabel('纬度');title('FLP vs GPS 轨迹对比');grid on;axis equal;subplot(1,2,2);plot(NLP_data(:,2),NLP_data(:,1),'g.','MarkerSize',4);xlabel('经度');ylabel('纬度');title('NLP 轨迹(Wi-Fi/基站定位)');grid on;axis equal;5.2 检查速度数据
速度数据可以帮助判断定位点的运动状态:
%% 检查速度分布figure;histogram(GPS_data(:,4),50,'FaceColor','b','EdgeAlpha',0.3);hold on;histogram(FLP_data(:,4),50,'FaceColor','r','EdgeAlpha',0.3);xlabel('速度 (m/s)');ylabel('频次');legend('GPS','FLP');title('速度分布对比');% 检查是否有异常值(如负速度或极大速度)fprintf('GPS速度范围: [%.2f, %.2f] m/s\n',min(GPS_data(:,4)),max(GPS_data(:,4)));fprintf('FLP速度范围: [%.2f, %.2f] m/s\n',min(FLP_data(:,4)),max(FLP_data(:,4)));六、不同平台(Windows/macOS/Linux)下的注意事项
| 平台 | 文件路径写法示例 | 注意事项 |
|---|---|---|
| Windows | 'C:\Users\name\data\gnss_log.txt' | 必须使用反斜杠\,或使用双反斜杠\\转义 |
| macOS | '/Users/name/data/gnss_log.txt' | 使用正斜杠/,注意区分大小写 |
| Linux | '/home/name/data/gnss_log.txt' | 使用正斜杠/,注意文件权限 |
跨平台兼容写法(推荐):
% 使用 fullfile 自动适配路径分隔符dataDir=fullfile('C:','Users','name','data');% Windows% dataDir = fullfile('/home', 'name', 'data'); % Linux/macOSinputFile=fullfile(dataDir,'gnss_log_2023_03_08_19_48_23.txt');macOS/Linux用户注意:MATLAB在Unix系统下对文件权限敏感,确保日志文件具有读取权限(
chmod +r gnss_log.txt)。
七、工程化建议与性能优化
7.1 函数封装
将核心逻辑封装为可复用的函数:
function[FLP,GPS,NLP]=parseGNSSFixData(inputFile,outputFile)% parseGNSSFixData 解析GNSSLogger的Fix数据% 输入:inputFile - 原始日志文件路径% outputFile - (可选) 临时文件输出路径% 输出:FLP - 融合定位数据 [Lat, Lon, Alt, Speed, Accuracy]% GPS - GNSS定位数据% NLP - 网络定位数据ifnargin<2outputFile='fix_data_temp.txt';end% ... 核心代码(见上文)...end7.2 大文件处理优化
当日志文件超过100MB时,逐行读取可能较慢。优化方案:
% 方案1:使用 memmapfile 或 readlines (MATLAB R2020b+)lines=readlines(inputFile);fixLines=lines(startsWith(lines,'Fix'));% 方案2:使用 grep 外部命令(Linux/macOS)% system('grep "^Fix" gnss_log.txt > fix_data2.txt');7.3 数据格式容错
不同Android版本输出的Fix行列数可能不同:
% 自动检测列数firstFixLine=fixLines(1);numCols=numel(strsplit(firstFixLine,','));ifnumCols>=14formatSpec=repmat('%f',1,numCols-2);% 动态构建格式end八、常见问题与解决方案
| 问题 | 可能原因 | 解决方案 |
|---|---|---|
fopen返回 -1 | 文件路径错误或文件不存在 | 使用exist(inputFile, 'file')检查文件是否存在 |
textscan解析失败 | 分隔符不匹配(如制表符而非逗号) | 检查文件编码,确认分隔符为, |
strcmp分类结果全为0 | Provider字段拼写大小写不匹配 | 检查日志中实际的Provider名称 |
| GPS数据点远多于FLP | 设备未开启融合定位 | 在GNSSLogger中确认“Fix”开关已开启 |
| MATLAB报错“Out of Memory” | 文件过大 | 使用readlines按块读取或使用datastore |
九、下一步预告
本文是“GNSS数据采集、处理与可视化全流程”系列的第三篇。我们完成了:
- ✅ Fix行的筛选
- ✅ CSV格式解析
- ✅ 按Provider分类(FLP/GPS/NLP)
- ✅ 经纬度与速度提取
在第四篇文章中,我们将使用本文提取的经纬度数据,结合MATLAB的geoshape和webmap工具,实现基于速度的分段彩色轨迹绘制,生成论文中展示的精彩地图可视化效果。
在第五篇文章中,我们将深入对比单系统(GPS)与融合系统(FLP)的定位精度差异。
在第六篇文章中,我们将完成全流程复盘,提供一套可直接运行的完整MATLAB脚本。
十、参考资料
- Zixia Shang, “Off-line Data Processing Based on GNSSLOGGER, GNSS System Positioning Data Quality and Accuracy Analysis,”Proceedings of SPIE, Vol. 12978, 2024. DOI: 10.1117/12.3019575
- GNSS 原始测量数据 | Android Developers
- LocationManager | Android Developers
- GPS Measurement Tools GitHub仓库
- 论文实验数据:https://github.com/ZixiaShang/GNSSLOGGER-Data-8
📌 系列文章索引:
- 第一篇:Android GNSS数据采集入门:GNSSLogger完整配置指南(已完成)
- 第二篇:GNSS数据解析与质量分析:从GNSSAnalysis到MATLAB(已完成)
- 第三篇:MATLAB读取GNSSLogger数据:Fix记录筛选与提取实战(本文)
- 第四篇:MATLAB地理轨迹可视化:基于速度的分段彩色地图绘制(待续)
- 第五篇:多GNSS系统定位对比:单系统与融合系统精度分析(待续)
- 第六篇:GNSS数据处理全流程复盘:从手机到地图的完整链路(待续)