Bootstrap

NMEA-0183 导航电文解析实验

实验原理

NMEA 0183是美国国家海洋电子协会(National Marine Electronics Association)为海用电子设备制定的标准格式。GPS接收机根据NMEA-0183协议的标准规范,通过串口输出位置、速度等信息。随着GLONASS、北斗等卫星导航系统的逐渐成熟,NMEA-0183不再仅限于GPS设备的数据协议,而成为适用于各大卫星导航系统的标准协议。

NMEA-0183格式数据串的所有数据都采用ASCII文本字符表示,数据传输以“ ”开头,后面是语句头。语句头由五个字母组成,分为两部分:前两个字母表示“系统 I D ”,即表示该语句属于何种系统或设备,后三个字母表示“语句 I D ”,表示该语句关于何方面的数据。语句头后是数据体,包含不同的数据体字段,语句末尾为校验码(可选),以回车换行符 ‘ < C R > < L F > ‘ 结束,即 A S C I I 字符“回车”(十六进制的 0 D )和“换行”(十六进制的 0 A )。每行语句最多包含 82 个字符(包括回车换行符和 ‘ ”开头,后面是语句头。语句头由五个字母组成,分为两部分:前两个字母表示“系统ID”,即表示该语句属于何种系统或设备,后三个字母表示“语句ID”,表示该语句关于何方面的数据。语句头后是数据体,包含不同的数据体字段,语句末尾为校验码(可选),以回车换行符 `<CR><LF>` 结束,即ASCII字符“回车”(十六进制的0D)和“换行”(十六进制的0A)。每行语句最多包含82个字符(包括回车换行符和` 开头,后面是语句头。语句头由五个字母组成,分为两部分:前两个字母表示系统ID,即表示该语句属于何种系统或设备,后三个字母表示语句ID,表示该语句关于何方面的数据。语句头后是数据体,包含不同的数据体字段,语句末尾为校验码(可选),以回车换行符<CR><LF>结束,即ASCII字符回车(十六进制的0D)和换行(十六进制的0A)。每行语句最多包含82个字符(包括回车换行符和`符号)。数据字段以逗号分隔识别,空字段保留逗号。以下是常用的语句类型及其包含的数据内容:

语句开头数据内容
$XXGGA全球定位数据
$XXGSA卫星PRN数据
$XXGSV卫星状态信息
$XXRMC运输定位数据
$XXVTG地面速度信息
$XXGLL大地坐标信息
$XXZDAUTC时间和日期

其中,“XX”为系统ID,常见的系统ID有:“GP”表示GPS系统相关语句,“BD”表示北斗系统相关语句。

实验目的

  1. 深入理解卫星导航产品输出的NMEA0183格式电文;
  2. 能阅读NMEA导航电文,提取所需的定位数据。

实验内容及步骤

  1. 采集60秒以上NMEA数据。
  2. 解析GGA数据,整理为表格数据或画图(注意时间标签)。
  3. 解析RMC数据,整理为表格数据或画图。
  4. 解析GSA和GSV数据,整理为表格数据或画图(注意按卫星号分别存放)。

这是一个用MATLAB编写的解析NMEA-0183导航电文的实验程序,它可以将包含特定格式的导航数据文件解析为结构化的数据,并将数据写入Excel文件的不同工作表。以下是关于代码的一些解释和讲解:

解析NMEA-0183导航电文

1. 主程序 main()

主程序 main() 负责整个数据处理流程的执行,包括读取NMEA格式的数据文件、解析数据并将解析后的数据写入Excel文件。

2. 数据读取函数 readNMEA()

readNMEA() 函数用于从给定的文件名读取NMEA 0183格式的导航电文数据,并将数据存储为字符串数组。

3. 数据解析函数 parseNMEA()

parseNMEA() 函数根据语句类型解析NMEA数据,并将解析后的数据存储在结构化的数据结构中,以便后续处理和写入到Excel文件。

4. NMEA数据解析子函数

以下是各种不同类型的NMEA语句数据解析函数,每个函数用于解析特定类型的NMEA语句数据:

  • parseGNGGA(): 解析GNGGA类型的数据
  • parseGNRMC(): 解析GNRMC类型的数据
  • parseGNGSA(): 解析GNGSA类型的数据
  • parseGPGSV(): 解析GPGSV类型的数据
  • parseBDGSV(): 解析BDGSV类型的数据

5. NMEA句子解析函数 parseNMEASentence()

parseNMEASentence() 函数将单个NMEA句子解析为结构化的数据,根据提供的字段名称,将每个字段的数据存储在一个结构体中。

6. 数据写入Excel函数 writeDataToExcel()

writeDataToExcel() 函数负责将解析后的数据按照指定的工作表顺序写入到Excel文件中,每个工作表对应一个特定类型的数据,数据以表格形式存储。

7. 实验步骤描述

实验步骤包括:

  • 采集NMEA数据
  • 解析GGA、RMC、GSA和GSV数据
  • 将解析后的数据整理为表格数据或图表。
    在这里插入图片描述
function main()
    % 文件名
    filename = 'data.txt';
	%%filename='你的NMEA.txt文件的路径,你也可以把NEMA文件和这个.m文件放在一起,就如上图所示';
    % 读取NMEA 0183格式的电文
    data = readNMEA(filename);

    % 解析NMEA数据
    parsedData = parseNMEA(data);

    % 将解析后的数据写入Excel文件
    outputExcelFile = 'parsed_data.xlsx';
    % 指定工作表顺序
    sheetsOrder = {'GGA', 'RMC', 'GSA', 'GSV', 'GNGGA', 'GNGSA', 'GPGSV', 'BDGSV', 'GNRMC'};
    writeDataToExcel(parsedData, outputExcelFile, sheetsOrder);

    disp(['数据已成功解析并按指定顺序写入到 Excel 文件: ' outputExcelFile]);
end

function data = readNMEA(filename)
    % 读取NMEA 0183格式的电文
    fid = fopen(filename, 'r');
    if fid == -1
        error('无法打开文件');
    end

    % 逐行读取电文数据
    data = textscan(fid, '%s', 'Delimiter', '\n', 'Whitespace', '');
    data = data{1}; % 将数据转换为字符串数组

    fclose(fid); % 关闭文件
end

function parsedData = parseNMEA(data)
    % 初始化解析后的数据结构
    parsedData.GNGGA = [];
    parsedData.GNGSA = [];
    parsedData.GPGSV = [];
    parsedData.BDGSV = [];
    parsedData.GNRMC = [];
    parsedData.GGA = [];
    parsedData.RMC = [];
    parsedData.GSA = [];
    parsedData.GSV = [];

    % 遍历每行NMEA数据
    for i = 1:numel(data)
        sentence = data{i};
        if startsWith(sentence, '$GNGGA')
            parsedData.GNGGA = [parsedData.GNGGA; parseGNGGA(sentence)];
        elseif startsWith(sentence, '$GNGSA')
            parsedData.GNGSA = [parsedData.GNGSA; parseGNGSA(sentence)];
        elseif startsWith(sentence, '$GPGSV')
            parsedData.GPGSV = [parsedData.GPGSV; parseGPGSV(sentence)];
        elseif startsWith(sentence, '$BDGSV')
            parsedData.BDGSV = [parsedData.BDGSV; parseBDGSV(sentence)];
        elseif startsWith(sentence, '$GNRMC')
            parsedData.GNRMC = [parsedData.GNRMC; parseGNRMC(sentence)];
        elseif startsWith(sentence, '$GGA')
            parsedData.GGA = [parsedData.GGA; parseGNGGA(sentence)]; % 使用相同的解析函数
        elseif startsWith(sentence, '$RMC')
            parsedData.RMC = [parsedData.RMC; parseGNRMC(sentence)]; % 使用相同的解析函数
        elseif startsWith(sentence, '$GSA')
            parsedData.GSA = [parsedData.GSA; parseGNGSA(sentence)]; % 使用相同的解析函数
        elseif startsWith(sentence, '$GSV')
            parsedData.GSV = [parsedData.GSV; parseGPGSV(sentence)]; % 使用相同的解析函数
        end
    end
end

function gnggaData = parseGNGGA(sentence)
    % 解析GNGGA数据
    gnggaData = parseNMEASentence(sentence, ...
        {'UTC', 'Latitude', 'LatitudeDirection', 'Longitude', 'LongitudeDirection', ...
        'FixQuality', 'NumSatellites', 'HDOP', 'Altitude', 'HeightOfGeoid'});
end

function gnrmcData = parseGNRMC(sentence)
    % 解析GNRMC数据
    gnrmcData = parseNMEASentence(sentence, ...
        {'UTC', 'Status', 'Latitude', 'LatitudeDirection', 'Longitude', 'LongitudeDirection', ...
        'Speed', 'Course', 'Date', 'MagneticVariation'});
end

function gngsaData = parseGNGSA(sentence)
    % 解析GNGSA数据
    gngsaData = parseNMEASentence(sentence, ...
        {'Mode', 'FixType', 'PRNs', 'PDOP', 'HDOP', 'VDOP'});
end

function gpgsvData = parseGPGSV(sentence)
    % 解析GPGSV数据
    gpgsvData = parseNMEASentence(sentence, ...
        {'TotalSentences', 'SentenceNumber', 'TotalSatellites', 'Satellites'});
end

function bdgsvData = parseBDGSV(sentence)
    % 解析BDGSV数据
    bdgsvData = parseNMEASentence(sentence, ...
        {'TotalSentences', 'SentenceNumber', 'TotalSatellites', 'Satellites'});
end

function parsedData = parseNMEASentence(sentence, fieldNames)
    % 将NMEA句子解析为数据结构
    parts = strsplit(sentence, ',');
    parsedData = struct();

    for i = 1:numel(fieldNames)
        fieldName = fieldNames{i};
        if i <= numel(parts)
            parsedData.(fieldName) = strtrim(parts{i});
        else
            parsedData.(fieldName) = [];
        end
    end
end

function writeDataToExcel(parsedData, filename, sheetsOrder)
    % 创建一个新的Excel文件
    [~, sheetsIdx] = ismember(sheetsOrder, fieldnames(parsedData));
    
    % 按指定顺序写入Excel文件
    for s = 1:numel(sheetsOrder)
        sheetName = sheetsOrder{s};
        data = parsedData.(sheetName);
        if ~isempty(data)
            % 创建表格
            T = struct2table(data);

            % 写入Excel文件
            if s == 1
                writetable(T, filename, 'Sheet', sheetName);
            else
                writetable(T, filename, 'Sheet', sheetName, 'WriteMode', 'append');
            end
        end
    end
end

8. 实验报告内容

实验报告应包括实验目的、实验流程图、实验过程描述、实验运行结果和实验代码。

该MATLAB代码实现了从NMEA 0183数据文件中解析导航电文数据,并将解析后的数据按照指定顺序写入Excel文件。通过该程序,您可以深入理解和处理卫星导航设备输出的NMEA格式数据。

;