DAY20---GINav学习

  PPP

1.读取文件

1.1RINEX观测文件(.**o)

观测文件这部分在SPP里面已经进行详细的介绍

1.2精密星历文件(.sp3)

调用readsp3()函数

function nav=readsp3(nav,fname)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% only surpport to read ".sp3" or ".eph" file
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
global glc
%首先是查找文件名,是否是空的,如果没有发现文件名的格式为.sp3、eph等,提示错误,文件格式不支持
if ~isempty(strfind(fname,'.'))
    if isempty(strfind(fname,'sp3'))&&isempty(strfind(fname,'SP3'))&&...
        isempty(strfind(fname,'eph'))&&isempty(strfind(fname,'EPH'))
        error('The file %s is not surpported!!!',fname);
    end
end
idx=strfind(fname,glc.sep); fname0=fname(idx(end)+1:end);%这段代码的作用是从字符串 fname 中截取最后一个分隔符 glc.sep 后面的部分,并将结果保存到变量 fname0 中。这可能用于文件名的处理,提取文件名中的文件扩展名或最后一个目录的名称。
fprintf('Info:reading sp3 file %s...',fname0);%读取后缀为.sp3文件的名字,最终在命令行窗口输出Info:reading obs file wum20464.sp3...over
fid=fopen(fname);%打开sp3文件
% read sp3 header
[headinfo,fid]=decode_sp3h(fid);%读取精密星历的头文件
% read sp3 body
nav=decode_sp3b(nav,headinfo,fid);%读取精密星历的主体文件
fprintf('over\n');
return

在读取精密星历文件的时候分为两部分,先通过调用decode_sp3h()函数来读取精密星历的头文件,之后通过调用decode_sp3b()函数来读取精密星历的主体文件。

调用decode_sp3h()函数

function [headinfo,fid]=decode_sp3h(fid)%一个函数 decode_sp3h(fid),用于解析 SP3 文件的头部信息。
%函数的输入参数是文件句柄 fid,表示要解析的 SP3 文件。函数通过逐行读取文件,提取文件头部信息,并将其保存在一个 headinfo 结构体中。
%函数首先定义了一些变量 type、time、ns、sats、tsys 和 bfact,用来存储头部信息的各个字段。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%read file header information
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
global glc gls
type=' '; time=gls.gtime; ns=0;
sats=zeros(1,glc.MAXSAT); tsys=''; bfact=zeros(1,2);
n=0; idxns=0; idxc=0; idxf=0; idx_break=0;
while ~feof(fid)%然后,函数通过循环读取文件的每一行,并根据行的不同内容,执行不同的操作来解析头部信息。
    line=fgetl(fid);n=n+1;
    if n==1%当 n 等于 1 时,解析第一行,获取文件类型 type 和时间信息 time。
        type=line(3);
        time=str2time(line(4:31));
    elseif strcmp(line(1),'+')%当行以 + 开头时,表示卫星编号信息,解析卫星编号,并存储在 sats 数组中。
        if n==3,ns=str2double(line(3:6));end
        if idxns<ns
            j=0;
            while j<17
                sys=code2sys(line(10+3*j));%在每次迭代中,首先使用函数 code2sys(line(10+3*j)) 将字符串中的字符转换为卫星系统代码(如 GPS、GLO、GAL 等),存储在变量 sys 中。
                prn=str2double(line(11+3*j:12+3*j));%使用 str2double(line(11+3*j:12+3*j)) 解析出卫星的 PRN 号码,存储在变量 prn 中。
                if sys==glc.SYS_QZS,prn=prn+192;end%如果卫星系统为 QZSS (glc.SYS_QZS),则将 PRN 号码加上 192,因为 QZSS 的 PRN 号码是 GPS PRN 号码加上 192。
                if idxns<=glc.MAXSAT
                    sats(idxns+1)=satno(sys,prn);
                    idxns=idxns+1;
                end%最后,如果索引 idxns 小于等于 glc.MAXSAT,则将卫星的编号存储在数组 sats 的对应位置上,并将索引 idxns 加 1。
                j=j+1;
            end
        end
    elseif strcmp(line(1:2),'%c')&&idxc==0%当行以 %c 开头时,表示时钟系统信息,解析并存储在 tsys 变量中。
        tsys=line(10:12);
        idxc=idxc+1;
    elseif strcmp(line(1:2),'%f')&&idxf==0 %当行以 %f 开头时,表示钟差比例因子信息,解析并存储在 bfact 数组中。
        bfact(1)=str2double(line(4:13));
        bfact(2)=str2double(line(15:26)); 
        idxf=idxf+1;
    elseif strcmp(line(1:2),'/*')%当行以 /* 开头时,表示头部信息解析结束,跳出循环。
        idx_break=idx_break+1;
        if idx_break==4
            break;
        end
    end    
end
%最后,将解析得到的头部信息存储在 headinfo 结构体中,并返回该结构体作为函数的输出。
headinfo.type=type;
headinfo.time=time;
headinfo.ns=ns;
headinfo.sats=sats;
headinfo.tsys=tsys;
headinfo.bfact=bfact;
return

调用decode_sp3b()函数 

function nav=decode_sp3b(nav,headinfo,fid)
global glc gls
peph=gls.peph;%精密星历 
NMAX=10000; nav.peph=repmat(gls.peph,NMAX,1);
if headinfo.type=='P'
    ns=headinfo.ns;
else
    ns=2*headinfo.ns;
end
%这段代码的作用是初始化导航结构体 nav 中的精密星历部分,并根据头部信息结构体 headinfo 中的数据确定导航结构体中精密星历的数量 ns。
%按照时间步进遍历)是一种处理数据或执行操作的方法。它通常用于按照时间顺序逐个处理一系列数据点或执行一系列操作。在时间序列数据处理中,"traversal by epoch"指的是按照时间的顺序,从最早的数据点开始,逐个处理每个数据点,并按照一定的步进(如固定时间间隔)依次处理下一个数据点,直到遍历完所有的数据点。
while ~feof(fid) 
    line=fgetl(fid);
    if strcmp(line,'EOF'),continue;end    
    if line(1)~='*'
        fprintf('sp3 invalid epoch\n');
        continue;
    end
    time=str2time(line(4:31));
    if strcmp(headinfo.tsys,'UTC'),time=utc2gpst(time);end
    peph.time=time;
    %这段代码的作用是解析 SP3 文件中的每个时刻的数据,并将时间信息存储在精密星历结构体 peph 中的 time 字段中。该代码还进行了一些错误处理,例如检查是否到达文件末尾、验证时间信息的有效性等。
    %初始化精密星历的结构体
    for i=1:glc.MAXSAT
        for j=1:4
            peph.pos(i,j)=0;%位置
            peph.std(i,j)=0;%标准差
            peph.vel(i,j)=0;%速度
            peph.vst(i,j)=0;%速度标准差
        end
        for j=1:3
            peph.cov(i,j)=0;%协方差
            peph.vco(i,j)=0;%速度协方差
        end
    end
    %这段代码的作用是将精密星历结构体 peph 中每个卫星的位置、标准差、速度、速度标准差、协方差矩阵和速度协方差矩阵等字段初始化为 0,为后续的数据填充和存储做好准备。
    for i=1:ns
        line=fgetl(fid);
        if size(line,2)<4||(line(1)~='P'&&line(1)~='V'),continue;end        
        if line(2)==' '
            sys=glc.SYS_GPS;
        else
            sys=code2sys(line(2));
        end
        prn=str2double(line(3:4));
        if sys==glc.SYS_QZS,prn=prn+192;end
        sat=satno(sys,prn); 
        if ~sat,continue;end
        %此代码段的作用是解析 SP3 文件中每个卫星的信息,并通过解析卫星系统类型和 PRN 号将其转换为卫星号。同时,此代码段还进行了一些错误处理,例如检查行的长度是否符合要求、验证卫星系统类型和 PRN 号的有效性等。
        for j=1:4%对于前三个 j 值,执行以下赋值操作:m=2:将变量 m 的值设置为 2。k1=1000:将变量 k1 的值设置为 1000。%base=headinfo.bfact(1):将变量 base 的值设置为 headinfo.bfact(1) 的值,headinfo.bfact 是一个结构体或数组,表示其中的第一个元素。%base=headinfo.bfact(1):将变量 base 的值设置为 headinfo.bfact(1) 的值,headinfo.bfact 是一个结构体或数组,表示其中的第一个元素。%k3=0.1:将变量 k3 的值设置为 0.1。k4=10^-7:将变量 k4 的值设置为 0.0000001。
            if j<=3
                m=2;k1=1000;base=headinfo.bfact(1);k2=10^-3;k3=0.1;k4=10^-7;
            else
                m=3;k1=10^-6;base=headinfo.bfact(2);k2=10^-12;k3=10^-10;k4=10^-16;
            end%m=3:将变量 m 的值设置为 3。k1=10^-6:将变量 k1 的值设置为 0.000001。base=headinfo.bfact(2):将变量 base 的值设置为 headinfo.bfact(2) 的值,headinfo.bfact 是一个结构体或数组,表示其中的第二个元素。k2=10^-12:将变量 k2 的值设置为 0.000000000001。k3=10^-10:将变量 k3 的值设置为 0.0000000001。            
            val=str2double(line(4+14*(j-1)+1:4+14*(j-1)+14));
            if size(line,2)>61
                std=str2double(line(61+3*(j-1)+1:61+3*(j-1)+m));
            else
                std=0;
            end%段代码的作用是解析文本行 line 中特定位置的字符串,并将其转换为数字,分别存储在变量 val 和 std 中。具体的位置计算是根据变量 j 和之前的条件判断得出的。
            if line(1)=='P'
                if val~=0&&abs(val-999999.999999)>=10^-6
                    peph.pos(sat,j)=val*k1; v=1;%这两行代码的作用是对变量 peph.pos 和 v 进行赋值操作。根据给定的索引 sat 和 j,将 val 与 k1 相乘的结果赋值给 peph.pos。同时,将变量 v 的值设置为 1。
                end
                if base>0&&std>0
                    peph.std(sat,j)=base^std*k2;
                end%这段代码的作用是根据不同的条件,对 peph 数据结构进行赋值操作。如果 line 的第一个字符为 'P',并且满足一定条件,将 val 乘以特定的系数并赋值给 peph.pos,将 base 的 std 次方乘以另一个系数并赋值给 peph.std。同时,在满足特定条件时,设置变量 v 的值为 1。
            elseif v
                if val~=0&&abs(val-999999.999999)>=10^-6
                    peph.vel(sat,j)=val*k3;
                end
                if base>0&&std>0
                    peph.vst(sat,j)=base^std*k4;
                end%这段代码是在之前的代码的if line(1)=='P'判断条件不成立的情况下执行的,它执行了以下操作:首先,通过判断变量 v 是否为真(非零)来执行接下来的代码块。

%判断 val 不等于 0,并且 val 的绝对值与 999999.999999 的差值大于等于 10 的负 6 次方(即绝对值大于等于 0.000001)。如果条件满足,执行以下操作:
%将变量 val 乘以 k3,并将结果赋值给 peph.vel(sat, j)。peph.vel 是一个数组或矩阵,并且 sat 和 j 用作索引。
%如果 base 大于 0 且 std 大于 0,则执行以下操作:
%将 base 的 std 次方乘以 k4,并将结果赋值给 peph.vst(sat, j)。peph.vst 是一个数组或矩阵,并且 sat 和 j 用作索引。
%简而言之,这段代码的作用是在 v 为真的情况下,根据一些条件对 peph 数据结构的 vel 和 vst 进行赋值操作。如果条件满足,将 val 乘以特定的系数,并赋值给 peph.vel 或 peph.vst。
            end 
        end 
    end
    if v
        if nav.np>size(nav.peph,1)
            nav.peph(nav.np+1:nav.np+NMAX,1)=repmat(gls.peph,NMAX,1);
        end%nav.np:这是一个变量,表示当前位置;nav.peph:这是一个数组或矩阵,存储了位置信息。size(nav.peph,1):这是一个函数,返回 nav.peph 的行数。nav.np < size(nav.peph,1):这是一个条件判断,检查 nav.np 是否小于 nav.peph 的行数。
        nav.peph(nav.np+1)=peph;
        nav.np=nav.np+1;
    end%这段代码的作用是在 v 为真的情况下,根据一些条件将变量 peph 添加到 nav.peph 中的特定位置。如果条件满足,则根据需要扩展 nav.peph 的大小,并将 peph 添加到 nav.peph 中的下一个空闲位置,同时更新 nav.np 的值。
end
fclose(fid);
if nav.np<size(nav.peph,1)
    nav.peph(nav.np+1:end,:)=[];
end%这段代码的目的是将 nav.peph 中超出当前索引范围的部分数据移除。如果 nav.np 较小,导致 nav.peph 中存在多余的行数,则通过删除超出范围的行来保持数据的正确性。

return

1.3精密钟差文件(.clk)

调用readclk()函数

function nav=readclk(nav,opt,fname)
global glc gls
NMAX=10000; nav.pclk=repmat(gls.pclk,NMAX,1);
idx=strfind(fname,glc.sep); fname0=fname(idx(end)+1:end);%这段代码主要是对变量进行赋值操作。它将 gls.pclk 在行方向上复制了 NMAX 次,并将结果赋值给 nav.pclk。然后,通过 strfind 函数找到 fname 中最后一个斜杠的位置,并将斜杠后面的部分赋值给 fname0。
fprintf('Info:reading clk file %s...',fname0);%读取后缀为.clk文件的名字,最终在命令行窗口输出Info:reading obs file wum20464.clk...over
fid=fopen(fname);%代开精密钟差文件

% 读取精密钟差的头文件
while ~feof(fid)
    line=fgetl(fid);
    label=line(61:end);
    if size(line,2)<=60
        continue;
    elseif ~isempty(strfind(label,'RINEX VERSION / TYPE'))
        ver=str2double(line(1:9)); %#示例数据版本为3.0,已经经过对比源文件进行查看
        type=line(21);%根据示例数据类型为'C'
    elseif ~isempty(strfind(label,'END OF HEADER'))
        break;
    end  
end
if type~='C'%type为C的话,那么表示下载的是正确的clk文件的数据,如果type不为C的话,提示错误“该文件不是clock file”
    error('The file %s is not clock file!!!',fname0);
end
mask=set_sysmask(opt.navsys);%这个函数可以用于根据输入参数的不同设置系统屏蔽状态,进而控制系统的行为。

% 读取精密钟差的主体文件
while ~feof(fid)
    buff(1:glc.MAXRNXLEN)=' ';
    line=fgets(fid);
    buff(1:size(line,2))=line;
    if size(buff,2)<8,continue; end
    if ~strcmp(buff(1:2),'AS'),continue;end
    %这段代码的作用是按行读取文件内容,并对读取到的每行进行一些条件判断。它首先将 buff 数组初始化为空格字符,然后使用 fgets 函数逐行读取文件内容,并将其复制到 buff 数组中。接着,它进行一些条件判断,例如判断行的长度是否足够、是否以特定的字符开头等,从而决定是否继续处理该行。
    satid=buff(4:8);
    sat=satid2no(satid);
    [sys,~]=satsys(sat);
    if sys==0,continue;end
    if mask(sys)==0,continue;end
%这段代码提取了行内容中的卫星标识符,并根据卫星标识符获取卫星编号和导航系统类型。然后,根据导航系统类型进行一些条件判断,例如判断导航系统是否被禁用,从而决定是否继续处理该行。
    time=str2time(buff(8:34));%time=str2time(buff(8:34));:将 buff 数组中第 8 到第 34 个元素(即行内容的第 8 到第 34 个字符)作为字符串参数,调用函数 str2time 进行解析和转换,并将转换后的时间结果赋值给变量 time。该行代码的目的是将字符子串解析为时间值。
    clk=str2double(buff(41:59));%clk=str2double(buff(41:59));:将 buff 数组中第 41 到第 59 个元素(即行内容的第 41 到第 59 个字符)作为字符串参数,调用函数 str2double 进行解析和转换,并将转换后的数值结果赋值给变量 clk。该行代码的目的是将字符子串解析为双精度浮点数。
    std=str2double(buff(61:79));%std=str2double(buff(61:79));:将 buff 数组中第 61 到第 79 个元素(即行内容的第 61 到第 79 个字符)作为字符串参数,调用函数 str2double 进行解析和转换,并将转换后的数值结果赋值给变量 std。该行代码的目的是将字符子串解析为双精度浮点数。
    if isnan(clk),clk=0;end
    if isnan(std),std=0;end
    %这段代码的作用是在变量 clk 和 std 的值为 NaN 时,将它们置为 0,以避免计算或使用这些值时出现错误。NaN 是一种特殊的浮点数值,表示不是一个数字。
    if nav.nc<=0%这段代码是用于更新卫星钟差信息的逻辑判断和操作。下面是每行代码的含义:
        nav.nc=nav.nc+1;%if nav.nc<=0:如果变量 nav.nc 小于或等于 0,即当前没有卫星钟差信息,执行下面的操作。
%nav.nc=nav.nc+1;:将变量 nav.nc 增加 1,表示有一个卫星钟差信息。
        nav.pclk(nav.nc).time=time;%nav.pclk(nav.nc).time=time;:将当前时间 time 赋值给 nav.pclk 数组中的 nav.nc 索引的 time 字段。
    elseif abs(timediff(time,nav.pclk(nav.nc).time))>1e-9
        if nav.nc+1>size(nav.pclk,1)
            nav.pclk(nav.nc+1:nav.nc+NMAX)=repmat(gls.pclk,NMAX,1);
        end
%%elseif abs(timediff(time,nav.pclk(nav.nc).time))>1e-9:如果当前时间 time 与 nav.pclk 数组中的 nav.nc 索引的 time 字段之间的时间差值大于 1e-9 秒(即差值超过 1 纳秒),执行下面的操作。
%if nav.nc+1>size(nav.pclk,1):如果 nav.nc+1 大于 nav.pclk 数组的行数(即超过数组的大小),执行下面的操作。
%nav.pclk(nav.nc+1:nav.nc+NMAX)=repmat(gls.pclk,NMAX,1);:将 gls.pclk 数组重复 NMAX 次,并赋值给 nav.pclk 数组中从 nav.nc+1 到 nav.nc+NMAX 索引的位置,即扩展 nav.pclk 数组的大小以容纳更多的卫星钟差信息。
%nav.nc=nav.nc+1;:将 nav.nc 增加 1,表示有一个新的卫星钟差信息。
%nav.pclk(nav.nc).time=time;:将当前时间 time 赋值给 nav.pclk 数组中的 nav.nc 索引的 time 字段。
        nav.nc=nav.nc+1;
        nav.pclk(nav.nc).time=time;%该代码段的作用是更新卫星钟差信息,在 nav.pclk 数组中加入一个新的时间值,并将 nav.nc 的值增加 1。这样就可以在 nav.pclk 数组中持续追踪和存储卫星钟差信息。
    end
    nav.pclk(nav.nc).clk(sat,1)=clk;
    nav.pclk(nav.nc).std(sat,1)=std;%这段代码的作用是将输入的时钟值和标准差赋值给卫星钟差信息数组 nav.pclk 中对应位置的元素。通过 nav.nc 索引获取当前的卫星钟差信息,然后根据 sat 索引指定具体的卫星,将对应的时钟值 clk 和标准差 std 赋值给相应的字段。这样就更新了卫星钟差信息的时钟值和标准差。
end
if nav.nc<size(nav.pclk,1)
    nav.pclk(nav.nc+1:end,:)=[];
end
%该代码段的作用是检查 nav.pclk 数组的大小是否超过 nav.nc 的值(即卫星钟差信息的数量),如果超出,则删除多余的行,以确保数组的大小与 nav.nc 的值相匹配。通过这样的操作,只保留最新的卫星钟差信息,并删除旧的无效信息。
fclose(fid);
fprintf('over\n');
return


在读取精密星历文件的时候主要处理两部分,一部分是精密星历头文件,另外一部分是主体文件。 

1.4天线校正文件(.atx)

调用readatx()函数

function nav=readatx(nav,fname)
global glc gls
freq=0; pcv0=gls.pcv; pcvs=gls.pcvs;
NMAX=10000; pcvs.pcv=repmat(gls.pcv,NMAX,1);
idx=strfind(fname,glc.sep); fname0=fname(idx(end)+1:end);
fprintf('Info:reading atx file %s...',fname0);
fid=fopen(fname);%打开天线文件
%这段代码通过设置变量、重复数组、提取字符串以及打印消息等操作,为读取 ATX 文件做好了准备。最后,使用 fopen 函数打开了文件,并返回文件句柄 fid,可以用于后续的文件读取操作。
while ~feof(fid)
    line=fgets(fid);
    if size(line,2)<=60 || ~isempty(strfind(line(61:end),'COMMENT')),continue;end%找到相关的标签是“COMMENT”。    
    if ~isempty(strfind(line(61:end),'START OF ANTENNA'))
        pcv=pcv0;%如果第61-最后一列中发现有标签“START OF ANTENNA”,将pcv0的值赋给pcv。
    end    
    if ~isempty(strfind(line(61:end),'END OF ANTENNA'))
        if pcvs.n+1>size(pcvs.pcv,1)
            pcvs.pcv(pcvs.n+1:pcvs.n+NMAX)=repmat(gls.pcv,NMAX,1);
        end
        pcvs.pcv(pcvs.n+1)=pcv;
        pcvs.n=pcvs.n+1;
        continue;
    end
    %代码段会检查读取到的 ATX 文件中的行,如果某行包含字符串 “END OF ANTENNA”,则在特定条件下进行数据处理和更新。这些操作包括扩展数组大小、赋值操作和变量的更新。最后,使用 continue 语句跳过当前循环,继续执行下一轮循环。
    %这段代码用于检测并处理读取到的 ATX 文件中的行,如果某行包含字符串 “END OF ANTENNA”,则执行一系列的操作。下面是代码的含义:
    if ~isempty(strfind(line(61:end),'TYPE / SERIAL NO'))%查看标签“TYPE / SERIAL NO”
        pcv.type=line(1:20);%pcv.type 是一个变量,表示天线相位中心变量的类型
        pcv.code=line(21:40);%pcv.code 是一个变量,表示天线的编码(code)
        prn=fix(str2num(pcv.code(2:3)));
        %这行代码对字符串 pcv.code 进行处理,提取其中的第2个和第3个字符,并将其转换为数值类型,然后使用 fix 函数对结果进行向下取整。最后将得到的结果赋值给变量 prn。
        %fix() 是一个MATLAB(或类似语言)中的函数,用于将输入的数值向下取整到最接近的较小整数。
        if ~prn,continue;end 
        if strcmp(pcv.code(4:11),'        ')%pcv.code(4:11):这个索引操作提取了 pcv.code 字符串的第4个到第11个字符,即一个8个字符长的子字符串。' ':这个字符串是由8个空格组成的,用于与 pcv.code(4:11) 的子字符串进行比较。
            pcv.sat=satid2no(pcv.code);%如果 pcv.code(4:11) 的子字符串与8个空格相等,则调用 satid2no() 函数,并将 pcv.code 作为参数传入。satid2no() 函数可能用于根据 pcv.code 获取卫星的编号或其他相关信息,并将其赋值给 pcv.sat 变量
        end
    elseif ~isempty(strfind(line(61:end),'VALID FROM'))%有效起始日期(值得是)
        time=str2time(line(1:43));%将含有“有效起始日期”标签的第一列到43列存储到time中。
        pcv.ts=time; %将time值赋给pcv.ts
        continue;
    elseif ~isempty(strfind(line(61:end),'VALID UNTIL'))%有效截止日期
        time=str2time(line(1:43));%将含有“有效截止日期”标签的第一列到43列存储到time中。
        pcv.te=time; %将time值赋给pcv.te
        continue;
    elseif ~isempty(strfind(line(61:end),'DAZI'))%“DAZI” 代表着差分方位角(Differential Azimuth)。方位角是指某一点相对于参考点的方向角度。在差分GPS中,使用DAZI来表示接收机与参考站之间的方位角差异。
        pcv.dazi=str2num(line(3:8)); %#ok将第3-8列的字符以str2num的形式赋值给pcv.dazi
        continue;
    elseif ~isempty(strfind(line(61:end),'ZEN1 / ZEN2 / DZEN'))%“ZEN1” 和 “ZEN2” 代表测站天顶角(Zenith Angle),即接收机天线指向接收到信号的角度。这些参数用于估计接收机的卫星可见性和观测品质,对于实时运动定位和静态测量都很重要。
        %“DZEN” 指的是测站天顶角的变化。在RTKLIB的解算过程中,由于卫星位置的变化或者天线运动引起的变化,接收机的测站天顶角也会发生变化。“DZEN” 用于表示测站天顶角的变化量。
        pcv.zen1=str2num(line(3:8)); %#ok第3-8列的值以str2num的形式赋值给pcv.zen1
        pcv.zen2=str2num(line(9:14)); %#ok第9-14列的值以str2num的形式赋值给pcv.zen2
        pcv.dzen=str2num(line(15:20)); %#ok第15-20列的值以str2num的形式赋值给pcv.zen3
        continue;
    elseif ~isempty(strfind(line(61:end),'START OF FREQUENCY'))%表示的是开始的频率
        %它检查文本行中是否包含"START OF FREQUENCY"的标识,如果是的话,就表示接下来要处理的是频率信息。
        [f,count]=sscanf(line(5:6),'%d');
        if count<1,continue;end
        [csys,count]=sscanf(line(4),'%c');%“csys” 是一个表示坐标系统的变量 
        if count<1,continue;end
        if     csys=='G'
%如果坐标系统是 ‘G’,则将频率值直接赋给 freq。
            freq=f;
        elseif csys=='R'
%如果坐标系统是 ‘R’,则将频率值加上glc.NFREQ(频率数量)后赋给 freq。
            freq=f+glc.NFREQ;
        elseif csys=='E'%主要是根据频率的特性进行计算
%如果坐标系统是 ‘E’,根据频率值的不同情况进行赋值:
            if     f==1,freq=f+2*glc.NFREQ;
%如果频率值为 1,将其加上 2 乘以 glc.NFREQ 后赋给 freq。
            elseif f==5,freq=2+2*glc.NFREQ;
%如果频率值为 5,将其加上 2 乘以 glc.NFREQ 后再加 2 后赋给 freq。
            elseif f==6,freq=3+2*glc.NFREQ;
%如果频率值为 6,将其加上 2 乘以 glc.NFREQ 后再加 3 后赋给 freq。
            else       ,freq=0;
%其他情况下,将 freq 赋为 0。
            end
        elseif csys=='C'
%如果坐标系统是 ‘C’,则将频率值加上 3 乘以 glc.NFREQ 后赋给 freq。
            freq=f+3*glc.NFREQ; 
        elseif csys=='J'
%如果坐标系统是 ‘J’,根据频率值的不同情况进行赋值:
            if      f<5,freq=f+4*glc.NFREQ;
%如果频率值小于 5,将其加上 4 乘以 glc.NFREQ 后赋给 freq。
            elseif f==5,freq=3+4*glc.NFREQ;
%如果频率值为 5,将其加上 4 乘以 glc.NFREQ 后再加 3 后赋给 freq。
            else       ,freq=0;
%其他情况下,将 freq 赋为 0。
            end
        else
            freq=0;
%如果坐标系统不属于上述情况,则将 freq 赋为 0。
        end%最终,根据不同的坐标系统和频率值,通过计算得到对应的频率索引值 freq。
    elseif ~isempty(strfind(line(61:end),'END OF FREQUENCY'))%表示的是结束的频率
        freq=0;  %此时将频率为0
    elseif ~isempty(strfind(line(61:end),'NORTH / EAST / UP'))%北、东与垂直方向
        %if freq<1||freq>glc.NFREQ,continue;end
        [neu,count]=decodef(line,3);%调用decodef()函数
        if count<3,continue;end
        if freq<1,continue;end
        if pcv.sat~=0%如果卫星不为0的时候
            pcv.off(freq,:)=neu;%将neu值赋给pcv.off()
        else
            pcv.off(freq,:)=[neu(2),neu(1),neu(3)];%其他的话将neu(2)、neu(1)与neu(3)的值赋给pcv.off()
        end
    elseif ~isempty(strfind(line,'NOAZI'))%在句子里面查找NOAZI,找到的话执行下面的操作
        if freq<1,continue;end
        dd=(pcv.zen2-pcv.zen1)/pcv.dzen+1;%其中,pcv.zen2 和 pcv.zen1 是探测器的 Zenith 角度,pcv.dzen 表示 Zenith 角度的间隔。
        if dd~=myRound(dd)||dd<=1
            %fprintf('error');
            continue;
        end
        if pcv.dazi==0
            [val,count]=decodef(line(9:end),fix(dd));%调用decodef()函数
            %decodef() 是一个用于解码字符串并返回浮点数数组的函数。
            if count<=0
                %fprintf('error');
                continue
            elseif count~=fix(dd)
                %fprintf('error');
                continue
            end
            pcv.var(freq,1:count)=val;
        else
            id=fix(360/pcv.dazi)+1;
            %计算 id 的值,该值为 360/pcv.dazi 的取整值加 1。
            for i=1:id
                line=fgets(fid);
                [val,j]=decodef(line(9:end),fix(dd));
                if j<=0,continue
                elseif j~=fix(dd),continue%fix()函数用于取整数部分
                end
                pcv.var(freq,(i-1)*fix(dd)+1:(i-1)*fix(dd)+j)=val;
            end%复制数组:可以使用这个语句将一个数组的值复制到另一个数组的特定位置。
        end%pcv.var(1, 6:9) = val; % 将数组 val 的值复制到 pcv.var 的第一个行中的索引 6 到 9 的元素
    end%更新部分数据:可以使用这个语句将特定位置的元素更新为新的值。
    %pcv.var(2, 3:6) = val; % 将数组 val 的值更新到 pcv.var 的第二行中的索引 3 到 6 的元素
end
fclose(fid);
fprintf('over\n');
if pcvs.n<size(pcvs.pcv,1)%如果 pcvs.n 的值小于 pcvs.pcv 数组的行数(即数组的大小),则执行条件判断内的语句。
    pcvs.pcv(pcvs.n+1:end,:)=[];%在条件判断内部,pcvs.pcv(pcvs.n+1:end,:)=[]; 用于删除 pcvs.pcv 数组中从 pcvs.n+1 行到末尾的所有行。
end
nav.ant_para=pcvs;%pcvs的结果赋值给nav.ant_para里面
return

1.5差分码偏差文件(.DCB)

调用readdcb()函数 

function nav=readdcb(nav,obs,fname)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%only read dcb for GPS or GLONASS(CODE procuct)
%convert CODE product to consistent with CAS product
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
global glc
type=0; DCBPAIR=glc.DCBPAIR;%导入dcbpair的参数
idx=strfind(fname,glc.sep); fname0=fname(idx(end)+1:end);
fprintf('Info:reading DCB file %s...',fname0);%读到该文件的时候,在命令行输出“Info:reading DCB file %s...”
fid=fopen(fname);
%nav.cbias
%双差码偏差参数通常用于补偿不同频率的伪距观测之间的差异。将这个差异转化为以米为单位的数值,可以更准确地对卫星导航系统进行校正。
while ~feof(fid)
    line=fgets(fid);
    if     ~isempty(strfind(line,'DIFFERENTIAL (P1-P2) CODE BIASES')),type=1;
    elseif ~isempty(strfind(line,'DIFFERENTIAL (P1-C1) CODE BIASES')),type=2;
    elseif ~isempty(strfind(line,'DIFFERENTIAL (P2-C2) CODE BIASES')),type=3;
    end%将三个文件p1p2、p1c1与p2c2文件,将三种文件对应不同的类型,第一种类型是type=1;第二种类型是type=2,第三种类型是type=3.
    if type==0,continue;end
    if isempty(line),continue;end
    if line(1)~='G'&&line(1)~='R',continue;end
    buff=strsplit(line);%strsplit() 是一个字符串操作函数,通常用于将一个字符串分割成多个子字符串,并将这些子字符串存储在一个数组中。
    %buff 一般指的是用于存储或处理数据的缓冲区或缓冲器。
    cbias=str2double(line(27:35));%将第27-35列的值以str2double的形式赋值给cbias(abias表示的是载波偏差)。
    %对于接收机来说
    if strcmp(buff(1),'G')||strcmp(buff(1),'R')%如果存储的系统的类型为G或者R的时候。
        if ~isfield(obs,'sta'),continue;end
        if strcmp(buff(1),'G'),j=1;else,j=2;end
        if strcmpi(obs.sta.name,char(buff(2)))
            nav.rbias(j,type)=cbias*1E-9*glc.CLIGHT;%nav.rbias(j,type) = cbias * 1E-9 * glc.CLIGHT:如果上述条件满足,将计算得到的值 cbias 乘以 1E-9(表示1倍 1−910 −9,即纳秒转为秒的缩放因子),再乘以 glc.CLIGHT(光速)并赋值给 nav.rbias(j,type)。
        end%rbias 是一个术语,表示接收机的接收机钟差(Receiver Clock Bias)。
        %这段代码片段的功能是,如果 obs 中有 sta 字段,然后根据 buff 字符串中的第一个字符确定变量 j 的值,最后通过比较字符串 obs.sta.name 与 buff(2) 来决定是否给 nav.rbias(j,type) 赋值。
    else
    %对于卫星来说
        sat=satid2no(char(buff(1)));%调用的是satid2no()函数,该函数用于将卫星的标识符(satid)转换为卫星编号(sats)。
        if sat~=0
            [sys,~]=satsys(sat);%调用的是satsys()函数,输入参数主要包括sat。
            if type==1%如果是第一类型,p1p2的文件。
                dcb_pair='C1W-C2W'; %P1-P2
                %“dcb_pair” 是一个表示双差码偏差(Differential Code Bias)的字符串,例如 ‘C1W-C2W’。
                %在这个字符串中,‘C1W’ 表示的是 P1 码,‘C2W’ 表示的是 P2 码。P1 码和 P2 码都是 GPS 卫星导航的伪距测量中的两个频率。
                if sys==glc.SYS_GPS%如果系统是GPS系统的话
                    for i=1:glc.MAXDCBPAIR%使用for循环遍历双差码偏差参数数组DCBPAIR的每个元素。
                        if strcmp(dcb_pair,DCBPAIR(sys,i)),break;end%在每次循环中,通过使用strcmp函数将dcb_pair与DCBPAIR(sys, i)进行比较。如果它们相等,则执行break语句跳出循环。
                    end
                    %计算导航系统为GPS的卫星的双差码偏差。
                    nav.cbias(sat,i)=cbias*1E-9*glc.CLIGHT;%对于给定的卫星编号sat和双差码偏差参数索引i,将卫星卫星导航系统的dcbs数组中的元素设置为cbias乘以1E-9(表示以纳秒为单位)乘以光速glc.CLIGHT。                    
                elseif sys==glc.SYS_GLO%如果系统是GLO系统话
                    dcb_pair='C1P-C2P'; %P1-P2
                    %“dcb_pair” 是一个表示双差码偏差(Differential Code Bias)的字符串,例如 ‘C1P-C2P’。
                    for i=1:glc.MAXDCBPAIR%%使用for循环遍历双差码偏差参数数组DCBPAIR的每个元素。
                        if strcmp(dcb_pair,DCBPAIR(sys,i)),break;end%在每次循环中,通过使用strcmp函数将dcb_pair与DCBPAIR(sys, i)进行比较。如果它们相等,则执行break语句跳出循环。
                    end
                    %计算导航系统GLO的卫星的双差码偏差
                    nav.cbias(sat,i)=cbias*1E-9*glc.CLIGHT;%;%对于给定的卫星编号sat和双差码偏差参数索引i,将卫星卫星导航系统的dcbs数组中的元素设置为cbias乘以1E-9(表示以纳秒为单位)乘以光速glc.CLIGHT。          
                end
            elseif type==2%如果是p1c1类型的文件的话
                dcb_pair='C1C-C1W'; %C1-P1
                    %“dcb_pair” 是一个表示双差码偏差(Differential Code Bias)的字符串,例如 ‘C1C-C1W’。
                if sys==glc.SYS_GPS%如果系统是GPS系统的话
                    for i=1:glc.MAXDCBPAIR%%%使用for循环遍历双差码偏差参数数组DCBPAIR的每个元素。
                        if strcmp(dcb_pair,DCBPAIR(sys,i)),break;end%在每次循环中,通过使用strcmp函数将dcb_pair与DCBPAIR(sys, i)进行比较。如果它们相等,则执行break语句跳出循环。
                    end
                    %计算导航系统为GPS的卫星的双差码偏差。                    
                    nav.cbias(sat,i)=-cbias*1E-9*glc.CLIGHT;
                    %nav.cbias(sat, i) = -cbias * 1E-9 * glc.CLIGHT; 这一行代码的作用是将导航系统为GPS的卫星的双差码偏差的负值赋值给nav.cbias(sat, i)。
                elseif sys==glc.SYS_GLO%如果系统是GLO系统的话
                    dcb_pair='C1C-C1P'; %C1-P1
                    %“dcb_pair” 是一个表示双差码偏差(Differential Code Bias)的字符串,例如 ‘C1C-C1P’。
                    for i=1:glc.MAXDCBPAIR%%使用for循环遍历双差码偏差参数数组DCBPAIR的每个元素。
                        if strcmp(dcb_pair,DCBPAIR(sys,i)),break;end%%在每次循环中,通过使用strcmp函数将dcb_pair与DCBPAIR(sys, i)进行比较。如果它们相等,则执行break语句跳出循环。
                    end
                    %计算导航系统GLO的卫星的双差码偏差
                    nav.cbias(sat,i)=-cbias*1E-9*glc.CLIGHT; %note the minus sign !
                    %nav.cbias(sat, i) = -cbias * 1E-9 * glc.CLIGHT; 这一行代码的作用是将导航系统为GLO的卫星的双差码偏差的负值赋值给nav.cbias(sat, i)。
                end
            elseif type==3%如果是p2c2类型的文件的话
                dcb_pair='C2W-C2L'; %P2-C2
                %“dcb_pair” 是一个表示双差码偏差(Differential Code Bias)的字符串,例如 ‘C2W-C2L’。
                if sys==glc.SYS_GPS%如果卫星系统为GPS的话
                    for i=1:glc.MAXDCBPAIR%使用for循环遍历双差码偏差参数数组DCBPAIR的每个元素。
                        if strcmp(dcb_pair,DCBPAIR(sys,i)),break;end%在每次循环中,通过使用strcmp函数将dcb_pair与DCBPAIR(sys, i)进行比较。如果它们相等,则执行break语句跳出循环。
                    end
                    %计算卫星系统GPS的双差码偏差
                    nav.cbias(sat,i)=cbias*1E-9*glc.CLIGHT;
                    %在这个代码中,将导航系统为GPS的卫星的双差码偏差赋值给nav.cbias(sat, i)。具体而言,将cbias乘以1E-9(表示以纳秒为单位)乘以光速glc.CLIGHT的值,然后将结果赋给nav.cbias(sat, i)。
                elseif sys==glc.SYS_GLO%如果卫星系统为GLO的话
                    dcb_pair='C2C-C2P'; %C2-P2
               %“dcb_pair” 是一个表示双差码偏差(Differential Code Bias)的字符串,例如 ‘C2C-C2P’。                    
                    for i=1:glc.MAXDCBPAIR%使用for循环遍历双差码偏差参数数组DCBPAIR的每个元素。
                        if strcmp(dcb_pair,DCBPAIR(sys,i)),break;end%在每次循环中,通过使用strcmp函数将dcb_pair与DCBPAIR(sys, i)进行比较。如果它们相等,则执行break语句跳出循环。
                    end
                     %计算导航系统GLO的卫星的双差码偏差
                    nav.cbias(sat,i)=-cbias*1E-9*glc.CLIGHT; %note the minus sign !
                    %将cbias(双差码偏差值)乘以1E-9(表示以纳秒为单位)乘以光速glc.CLIGHT的值,并将结果赋值为nav.cbias(sat, i)的相反数。这样做的目的可能是根据特定的需求或公式要求,将双差码偏差的值取负。
                end
            end
        end
    end
end
fclose(fid);
fprintf('over\n');
return

1.6多系统差分码偏差文件(.BSX)

function nav=readdcb_mgex(nav,opt,obsr,fname)%定义一个名叫readdcb_mgex()函数,输入参数为nav,opt,obsr,fname,输出参数为nav
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%read dcb for MGEX (include GPS GLONASS GALILEO BDS QZSS)
%if CODE_DCB can be used for GPS and GLONASS,don't use CAS_DCB for GPS and
%GLONASS
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%在示例的时候,一般需要的文件是CAS0MGXRAP_20190870000_01D_01D_DCB.BSX
global glc
type=0; time=str2time(opt.ts); DCBPAIR=glc.DCBPAIR;
if time.time==0
    time=obsr.data(1).time;
end
idx=strfind(fname,glc.sep); %这段代码的目的是从字符串fname中提取出文件名(fname0)。具体而言,使用strfind函数在fname中查找glc.sep(可能是分隔符)第一次出现的位置,并将其索引存储在idx中。
fname0=fname(idx(end)+1:end);%然后,通过idx(end)+1,提取出最后一个分隔符的后一个位置作为文件名在fname中的起始位置。最后,使用起始位置和字符串切片操作,将起始位置到字符串末尾的部分提取出来,并存储在fname0中,即提取出了文件名。
fprintf('Info:reading DCB_MGEX file %s...',fname0);%读取DCB_MGEX文件(读到文件的名字)后,在命令行窗口输出“Info:reading DCB_MGEX file %s...”
fid=fopen(fname);%打开DCB_MGEX文件
while ~feof(fid)
    line=fgets(fid);
    if ~isempty(strfind(line,'+BIAS/SOLUTION')),type=1;end %进行循环,如果出现标签“+BIAS/SOLUTION”的时候,type为1
    if ~isempty(strfind(line,'-BIAS/SOLUTION')),break;end%如果出现标签“-BIAS/SOLUTION”的话,结束操作
    if ~type,continue;end%如果没有类型的话,结束操作    
    if ~strcmp(line(2:4),'DSB')||~strcmp(line(16:19),'    '),continue;end
    %如果第2-4列中出现DSB的话,或者第16-19列为空的话('    '),继续操作。
    year =fix(str2num(line(36:39)));%#ok
    %将第36到39列的数据以str2num的形式取整赋值到year上
    doy_s=fix(str2num(line(41:43)));%#ok
    %将第41到43列的数据以str2num的形式取整赋值到doy_s上----开始的年积日
    doy_e=fix(str2num(line(56:58)));%#ok
    %将第56到58列的数据以str2num的形式取整赋值到doy_e上----结束的年积日
    if year<=50,year=year+2000;end
    %如果是年分小于等于50的话,将其值加上2000
    time_s=ydoy2time(year,doy_s); %调用ydoy2time()函数,输入参数为年份以及开始的年积日,输出为开始的时间
    time_e=ydoy2time(year,doy_e);%调用ydoy2time()函数,输入参数为年份以及结束的年积日,输出为结束的时间
    if ~(timediff(time,time_s)>=0&&timediff(time,time_e)<0),continue;end
    %这一行代码的含义是,如果时间 time 不在时间范围 time_s 和 time_e 内(即时间早于 time_s 或晚于等于 time_e),那么就执行 continue,即跳过当前迭代,进入下一次迭代。
    %换句话说,这行代码的作用是忽略不符合时间范围要求的情况,继续处理下一个迭代。
    satid=line(12:14);%satid表示的是卫星编号,从第12列到14列(PRN)
    sat=satid2no(satid);%调用satid2no函数,输入参数为satid,输出为sat
    [sys,prn]=satsys(sat);%调用的是satsys()函数
    dcb_pair=[line(26:28),'-',line(31:33)];%计算双差码偏差,以第一个为例,是将(C1C-C1W)
    cbias=str2num(line(72:92)); %#ok
    %以第一行为例,将第72-92列以str2num的形式赋值给cbias(为-0.9690)。----cbias(双差码偏差值)
    if sys==glc.SYS_GPS%在上面的两个标签之间,如果系统为GPS系统的话
        if ~nav.no_CODE_DCB,continue;end
        %Code Differential Code Bias (简称 CODE_DCB)是卫星导航系统中的一个校准参数,用于修正由于 GPS 和 GLONASS 等系统的信号传播路径中的大气影响引起的误差。
        for i=1:glc.MAXDCBPAIR
            if strcmp(dcb_pair,DCBPAIR(sys,i)),break;end 
        end%%在每次循环中,通过使用strcmp函数将dcb_pair与DCBPAIR(sys, i)进行比较。如果它们相等,则执行break语句跳出循环。
        nav.cbias(sat,i)=cbias*1E-9*glc.CLIGHT;%这行代码将 cbias 乘以 1E-9(即十的负九次方,相当于除以十亿),然后再乘以 glc.CLIGHT,其中 glc.CLIGHT 表示光速。最终的结果赋值给 nav.cbias(sat,i)。
    elseif sys==glc.SYS_GLO%如果系统为GLO的话
        if ~nav.no_CODE_DCB,continue;end%如果 nav.no_CODE_DCB 的值为假(false),即表示码差分码偏差不可用,
        for i=1:glc.MAXDCBPAIR%使用for循环遍历双差码偏差参数数组DCBPAIR的每个元素。
            if strcmp(dcb_pair,DCBPAIR(sys,i)),break;end%在每次循环中,通过使用strcmp函数将dcb_pair与DCBPAIR(sys, i)进行比较。如果它们相等,则执行break语句跳出循环。 
        end
        nav.cbias(sat,i)=cbias*1E-9*glc.CLIGHT;
        %在这个代码中,将导航系统为GPS的卫星的双差码偏差赋值给nav.cbias(sat, i)。具体而言,将cbias乘以1E-9(表示以纳秒为单位)乘以光速glc.CLIGHT的值,然后将结果赋给nav.cbias(sat, i)。        
    elseif sys==glc.SYS_GAL%如果系统为GAL的话
        for i=1:glc.MAXDCBPAIR%使用for循环遍历双差码偏差参数数组DCBPAIR的每个元素。
            if strcmp(dcb_pair,DCBPAIR(sys,i)),break;end%在每次循环中,通过使用strcmp函数将dcb_pair与DCBPAIR(sys, i)进行比较。如果它们相等,则执行break语句跳出循环。
        end
        nav.cbias(sat,i)=cbias*1E-9*glc.CLIGHT;
        %%在这个代码中,将导航系统为GPS的卫星的双差码偏差赋值给nav.cbias(sat, i)。具体而言,将cbias乘以1E-9(表示以纳秒为单位)乘以光速glc.CLIGHT的值,然后将结果赋给nav.cbias(sat, i)。
    elseif sys==glc.SYS_BDS%如果卫星系统是BSD的话
        for i=1:glc.MAXDCBPAIR%使用for循环遍历双差码偏差参数数组DCBPAIR的每个元素。
            if prn>18 %BDS-3%如果prn大于18的话
                if strcmp(dcb_pair,DCBPAIR(sys,i)) 
                    if i==2,i=glc.BD3_C2IC6I;end %#ok
                    break;%如果 dcb_pair 和 DCBPAIR(sys,i) 相等,则在 i 等于 2 的情况下,将 i 赋值为 glc.BD3_C2IC6I,然后跳出当前循环或循环结构
                end 
            else %BDS-2
                if strcmp(dcb_pair,DCBPAIR(sys,i)),break;end%在每次循环中,通过使用strcmp函数将dcb_pair与DCBPAIR(sys, i)进行比较。如果它们相等,则执行break语句跳出循环。 
            end
        end
        nav.cbias(sat,i)=cbias*1E-9*glc.CLIGHT;%cbias为纳秒
        %这段代码将一个浮点数变量 cbias 乘以 1E-9(即 1 除以 10 的 9 次方)和光速值(由常数 glc.CLIGHT 表示),并将结果赋值给 nav.cbias(sat, i)。也就是说,这段代码用于将一个以纳秒为单位的钟差偏差(cbias)转换为以米为单位的钟差偏差,并将结果存储在 nav.cbias 数组的相应位置(sat 和 i 为数组的索引)中。
    elseif sys==glc.SYS_QZS%如果系统是QZSS系统的话
        for i=1:glc.MAXDCBPAIR%使用for循环遍历双差码偏差参数数组DCBPAIR的每个元素。
            if strcmp(dcb_pair,DCBPAIR(sys,i)),break;end %在每次循环中,通过使用strcmp函数将dcb_pair与DCBPAIR(sys, i)进行比较。如果它们相等,则执行break语句跳出循环。 
        end
        nav.cbias(sat,i)=cbias*1E-9*glc.CLIGHT;
        %在这个代码中,将导航系统为GPS的卫星的双差码偏差赋值给nav.cbias(sat, i)。具体而言,将cbias乘以1E-9(表示以纳秒为单位)乘以光速glc.CLIGHT的值,然后将结果赋给nav.cbias(sat, i)。        
    end 
end
fclose(fid);
fprintf('over\n');
return

1.7地球参考框架文件(.ERP)

function nav=readerp(nav,fname)
%定义可readerp()函数,输入的参数为nav与fname,输出的参数书为nav
global glc gls%代码声明了三个全局变量,即 glc、gls 
flag=0; n=0; erp=gls.erp;
idx=strfind(fname,glc.sep); fname0=fname(idx(end)+1:end);%在索引的时候发现.erp的文件名字的时候
fprintf('Info:reading erp file %s...',fname0);%在命令行输出“Info:reading erp file %s...”
fid=fopen(fname);%使用 fopen 函数打开文件.erp(后缀)。

% read data
while ~feof(fid)
    line=fgets(fid,266);
    if ~isempty(strfind(line,'MJD')),flag=1;end%if ~isempty(strfind(line,'MJD')),flag=1;end 判断 line 中是否包含字符串 ‘MJD’。如果包含,则将 flag 置为 1。
    if flag==0,continue;end
    if flag==1
        line=fgets(fid); %#ok<NASGU>
        flag=2; continue;
    end
    if flag==2
        value=str2double(strsplit(line));%将每一列的元素进行存储,村相互到value里面
        %value=str2double(strsplit(line)); 将字符串 line 按空格进行分割,并将每个分割后的字符串转换为数值,并将结果存储在 value 数组中。
        erp.data(n+1).mjd    =value(1);%.mjd:Modified Julian Date(修正朱利安日期),用来表示观测时间。
        % 将 value 数组中的第一个元素赋值给 erp.data 结构体数组的成员 mjd,其中 n+1 为数组的索引。
        erp.data(n+1).xp     =value(2)*1e-6*glc.AS2R;%.xp:地球自转的 X 方向极移,即地球自转轴在国际参考坐标系下相对于地理坐标系的偏移。
        %glc.AS2R 是一个常量,代表角秒转弧度的比例因子
        erp.data(n+1).yp     =value(3)*1e-6*glc.AS2R;%.yp:地球自转的 Y 方向极移,即地球自转轴在国际参考坐标系下相对于地理坐标系的偏移。
        erp.data(n+1).ut1_utc=value(4)*1e-7;%.ut1_utc:UT1 与 UTC 之间的差距,用来校正地球自传的时间单位。
        erp.data(n+1).lod    =value(5)*1e-7;%.lod:地球自转率(Length of Day),表示地球自转的角速度。
        erp.data(n+1).xpr    =value(13)*1e-6*glc.AS2R;%.xpr:极移预测的 X 方向误差。
        erp.data(n+1).ypr    =value(14)*1e-6*glc.AS2R;%.ypr:极移预测的 Y 方向误差。
        n=n+1;
    end
end
fclose(fid);
fprintf('over\n');
erp.n=n;
erp.nmax=n;
nav.erp=erp;
return

1.8坐标时序文件(.blq)

function nav=readblq(nav,obsr,obsb,fname)%定义一个readblq()函数,输入参数有基准站的观测数据、流动站的观测数据、文件名字以及与观测文件相关的一个结构体nav,输出的参数包括nav
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%read ocean tide loading parameter(otlp) for rover and base
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
global glc
idx=strfind(fname,glc.sep); fname0=fname(idx(end)+1:end);
fprintf('Info:reading blq file %s...',fname0);%在命令行输出“Info:reading blq file ocnload.blq...”
ns=0;%ns表示的是卫星的数量
if obsr.n>0,sta(1)=obsr.sta;ns=1;end
if obsb.n>0,sta(2)=obsb.sta;ns=2;end
if ns==0,return;end

for i=1:ns
    fid=fopen(fname);%打开(.blq)文件
    sta_name=upper(sta(i).name);%将测站的名字都转换成大写的形式,赋值给sta_name。
    %upper()函数将字符串中的所有字符转换为大写字母形式,并返回转换后的结果。
    while ~feof(fid)
        line=fgets(fid);
        %line = fgets(fid); 表示从打开的文件中读取一行文本,并将其存储在 line 变量中。
        %每次调用 fgets 函数,它会读取文件中的下一行,并将结果作为一个字符串返回。
        %如果文件中已经没有更多的行可读取,fgets 函数将返回一个空指针或空字符串。
        if ~isempty(strfind(line,'-cmc')),break;end%如果文件中找到“-cmc”的话,结束操作
    end
    while ~feof(fid)
        line=fgets(fid);
        %line = fgets(fid); 表示从打开的文件中读取一行文本,并将其存储在 line 变量中。
        %每次调用 fgets 函数,它会读取文件中的下一行,并将结果作为一个字符串返回。
        %如果文件中已经没有更多的行可读取,fgets 函数将返回一个空指针或空字符串。
        if ~isempty(strfind(line,'$$'))||size(line,2)<=2,continue;end %如果在文件不为空,且找到“$$”的话
        name=upper(line(3:6));%以第一个为例,主要将CEBR转为大写字母
        if isempty(strfind(sta_name,name)),continue;end%如果在文件中找到测站的话
        [otlp,fid,stat]=decode_blqdata(fid);%调用decode_blqdata()函数,输入参数包括fid,输出的为otlp、fid与stat        
        if stat==1%使用条件语句,判断变量 stat 是否等于1。如果条件成立,执行接下来的代码块,否则跳过。
            nav.otlp(:,:,i)=otlp';%将 otlp 的转置值赋给 nav.otlp(:,:,i)。这段代码假设 nav.otlp 是一个三维数组,将 otlp 的转置值放入 nav.otlp 的第 i 个维度。
        end
    end
    fclose(fid);%关闭fid
end
fprintf('over\n');
return

在进行读取数据的时候调用的是decode_blqdata()函数,在该函数中,对将数据以矩阵的形式存储下来。erer

function [otlp,fid,stat]=decode_blqdata(fid)%定义了一个名叫decode_blqdata()函数,主要是用以解决blq文件数据存储问题,输入参数包括fid,输出参数为otlp,fid,stat
stat=0; n=0;
otlp=zeros(6,11);
%将变量 stat 和 n 初始化为0;创建一个大小为 6x11 的全零矩阵,并将其赋给变量 otlp。
while ~feof(fid)
    line=fgets(fid);
    if ~isempty(strfind(line,'$$'))||size(line,2)<=2,continue;end%if ~isempty(strfind(line, '$$')) || size(line, 2) <= 2:如果 line 中包含 $$ 或者 line 的长度小于等于2,则执行 continue;,跳过当前循环的剩余代码。
    v=str2double(strsplit(line));%v = str2double(strsplit(line));:将 line 按空格分割,并将得到的子字符串转换为数值,并存储在向量 v 中
    idx=~isnan(v);
    value=v(idx);
    for i=1:11%刚好是文件的一个测站的数据
        otlp(n+1,i)=value(i);
    end
    n=n+1;
    if n==6
        stat=1;
        return;
    end
end
return

 2.设置文件输出

2.1模式设置(PPP) 

function rtk=initoutfile(rtk,opt,file,obsr)%定义了一个initoutfile()函数,输入参数为rtk、opt(结构体)、文件 以及观测数据,输出参数为rtk
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%Copyright(c) 2020-2025, by Kai Chen, All rights reserved.
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
global glc

if opt.ins.mode==glc.GIMODE_OFF
    if opt.mode==glc.PMODE_SPP
        mode='SPP';
    elseif opt.mode==glc.PMODE_PPP_KINEMA
        mode='PPP_K';
    end
end
%根据模型是什么,选择相应的模式----PPP

2.2路径及结果文件设置

fullname=char(file.obsr);%glc.sep为/分隔符   输出的结构文件的名字是根据观测文件的名字
idx1=find(fullname==glc.sep); idx2=find(fullname=='.');
outfilename=[fullname(idx1(end)+1:idx2(end)-1),'_',mode,'.pos'];%设置输出文件名字

fullpath=which('main.m');%result的路径是与main.m在同一个文件夹里面
[path,~,~]=fileparts(fullpath);
pathname=[path,glc.sep,'result',glc.sep];
rtk.outfile=[pathname,outfilename];%完整的路径

3.设置卫星和接收者的天线参数

% 设置对于卫星和接收者的天线参数
if opt.mode~=glc.PMODE_SPP%首先判断优化模式是否为SPP(Single Point Positioning),如果不是,则进行以下操作。
    nav=L2_L5pcv_copy(nav);%将导航数据(nav)中的L2-L5频段的天线相位中心变量(pcv)拷贝一份(L2_L5pcv_copy(nav)),并同时将观测数据(obsr、obsb)中的站点信息(sta)提取出来。
    if isfield(obsr,'sta'),stas(1)=obsr.sta;end
    if isfield(obsb,'sta'),stas(2)=obsb.sta;end
    time0.time=obsr.data(1,1);time0.sec=obsr.data(1,2);%将观测数据的第一条数据的时间信息(time0)提取出来,包括时间(time0.time)和秒(time0.sec)。
    [nav,opt]=setpcv(time0,opt,nav,nav.ant_para,nav.ant_para,stas);%调用setpcv函数来设置这些天线参数。setpcv函数会在指定的时间(time0)和导航数据(nav)中,根据天线参数(nav.ant_para)设置卫星和接收者的天线参数,并将设置后的天线参数保存在opt结构体中。
end

 3.1调用L2_L5pcv_copy()函数

nav=L2_L5pcv_copy(nav) 这一行代码的作用是创建一个导航数据(nav)的副本,并将副本命名为 L2_L5pcv;L2_L5pcv_copy 函数是 RTKLIB 中的一个函数,它用于复制导航数据的 L2-L5 频段的天线相位中心变量(PCV)参数。这些 PCV 参数描述了卫星和接收机的天线特性,包括天线相位中心、天线相位中心变化随着观测角度的变化等信息。通过调用 L2_L5pcv_copy 函数,可以将导航数据中的 L2-L5 频段的 PCV 参数复制到新的导航数据副本 L2_L5pcv 中。这样做的目的是为了在设置卫星和接收机的天线参数时,使用 L2-L5 频段的 PCV 参数进行计算和处理。

总结起来,nav=L2_L5pcv_copy(nav) 这行代码的作用是复制导航数据的 L2-L5 频段的 PCV 参数,并将副本保存在 L2_L5pcv 中,以备后续使用。

function nav=L2_L5pcv_copy(nav)%定义了一个名叫L2_L5pcv_copy()函数,输入参数为nav,输出参数为nav
%L2_L5pcv_copy() 函数是用于复制 L2 和 L5 相位中心变化 (PCV) 数据的函数。
if nav.ant_para.n==0,return;end%L2_L5pcv_copy() 函数的作用是将 L2 和 L5 频率的相位中心变化(PCV)数据从一个数据结构复制到另一个数据结构中。
for i=1:nav.ant_para.n%定义了一个循环,从 1 到 nav.ant_para.n 进行迭代。这里的 nav.ant_para.n 可能表示接收机天线的个数或者与 L2 和 L5 相位中心变化数据相关的其他参数。
    if norm(nav.ant_para.pcv(i).off(3,:))>0,continue;end%判断第 i 个天线的 off 字段的第 3 行是否大于零。off 可能表示相位中心变化的偏移量。如果大于零,则跳过当前迭代,继续下一个循环迭代
    nav.ant_para.pcv(i).off(3,:)=nav.ant_para.pcv(i).off(2,:);%将第 i 个天线的 off 字段的第 2 行的值赋给第 3 行。这个赋值操作可能是复制 L2 相位中心变化到 L5 相位中心变化。
    nav.ant_para.pcv(i).var(3,:)=nav.ant_para.pcv(i).var(2,:);%将第 i 个天线的 var 字段的第 2 行的值赋给第 3 行。这个赋值操作可能是复制 L2 相位中心变化的方差到 L5 相位中心变化的方差。
end

return

 3.2调用setpcv()函数

[nav,opt]=setpcv(time0,opt,nav,nav.ant_para,nav.ant_para,stas) 这行代码的作用是调用 setpcv 函数来设置卫星和接收机的天线参数,并将结果保存在 nav 和 opt 变量中。

opt.pcvr=repmat(gls.pcv,mode,1);%这行代码的作用是将一个长度为 mode 的向量 gls.pcv 在第一个维度上复制多次,并将结果存储在 opt.pcvr 变量中。
  • repmat 是 MATLAB 中的函数,用于将输入向量或矩阵在指定的维度上进行复制。
  • gls.pcv 是一个原始的向量。
  • mode 是一个指定复制次数的整数值。

通过调用 repmat(gls.pcv,mode,1),我们将 gls.pcv 向量在第一个维度上复制了 mode 次,也就是将其复制了 mode 行。第二个参数 1 表示在第二个维度上不进行复制,即保持原始向量的列数不变。

function mask=set_sysmask(opt)%设置set_sysmask()函数,输入参数opt。
mask(1:5)=0;
%这个函数可以用于根据输入参数的不同设置系统屏蔽状态,进而控制系统的行为。
if ~isempty(strfind(opt,'G')),mask(1)=1;end%如果输入参数 opt 中包含字母 “G”,则将 mask 中的第一个元素设置为 1。
if ~isempty(strfind(opt,'R')),mask(2)=1;end%如果输入参数 opt 中包含字母 “R”,则将 mask 中的第一个元素设置为 2。
if ~isempty(strfind(opt,'E')),mask(3)=1;end%如果输入参数 opt 中包含字母 “E”,则将 mask 中的第一个元素设置为 3。
if ~isempty(strfind(opt,'C')),mask(4)=1;end%如果输入参数 opt 中包含字母 “C”,则将 mask 中的第一个元素设置为 4。
if ~isempty(strfind(opt,'J')),mask(5)=1;end%如果输入参数 opt 中包含字母 “J”,则将 mask 中的第一个元素设置为 5。

return

 获取卫星的编号,卫星的数量,卫星系统的pcvs时间等。

if pcvs.n>0
    for i=1:glc.MAXSAT%最大的卫星数量(1:150)
        [sys,~]=satsys(i);%使用函数 satsys(i) 获取卫星编号 i 对应的系统(如 GPS、GLONASS、Galileo 等)。
        if mask(sys)==0,continue;end
        [pcv,stat]=searchpcv(i,'',time,pcvs);%使用函数 searchpcv 根据卫星编号 i、空字符串 ''、时间 time 和 pcvs(可能是存储卫星天线参数的结构体或变量)来搜索卫星的天线参数。所得的天线参数存储在变量 pcv 中,同时还会返回一个状态 stat。
        if stat==0%如果 stat 的值为 0,表示未找到卫星的天线参数,则执行以下操作:
            id=satno2id(i);%使用函数 satno2id(i) 将卫星编号 i 转换为卫星标识符(通常是卫星的名称或编号)
            nav.pcvs(i)=gls.pcv;%将 gls.pcv 赋值给导航数据 nav 中的 pcvs(表示卫星天线参数),以备后续使用。
            fprintf('Warning:%s,have no antenna parameters!\n',id);%打印警告信息,提示该卫星缺少天线参数。
            continue;
        end
        nav.pcvs(i)=pcv;

 调用satsys()函数

function [sys,prn]=satsys(sat)%定义了一个satsys()函数,该函数输入参数包括sat,输出的参数包括sys,prn。

global glc
sys=0;

if sat<=0||sat>glc.MAXSAT
    sat=0;%如果卫星编号小于等于0或大于最大卫星数glc.MAXSAT,则将sys设置为0,sat设置为0。
elseif sat<=glc.NSATGPS%%%%%%在进行PPP的时候主要是进行的是这一块
    sys=glc.SYS_GPS; %如果卫星编号小于等于GLONASS卫星数glc.NSATGPS,则将sys设置为GPS,sat设置为卫星编号加上最小PRN编号减1。
    sat=sat+glc.MINPRNGPS-1;
elseif (sat-glc.NSATGPS)<=glc.NSATGLO
    sys=glc.SYS_GLO; %如果卫星编号减去GPS卫星数glc.NSATGPS后小于等于GLONASS卫星数glc.NSATGLO,则将sys设置为GLONASS,sat设置为卫星编号减去GPS卫星数再加上最小PRN编号减1。
    sat=(sat-glc.NSATGPS)+glc.MINPRNGLO-1;
elseif (sat-glc.NSATGPS-glc.NSATGLO)<=glc.NSATGAL
    sys=glc.SYS_GAL; %如果卫星编号减去GPS卫星数glc.NSATGPS再减去GLONASS卫星数glc.NSATGLO后小于等于GALILEO卫星数glc.NSATGAL,则将sys设置为GALILEO,sat设置为卫星编号减去GPS卫星数再减去GLONASS卫星数再加上最小PRN编号减1。
    sat=(sat-glc.NSATGPS-glc.NSATGLO)+glc.MINPRNGAL-1;
elseif (sat-glc.NSATGPS-glc.NSATGLO-glc.NSATGAL)<=glc.NSATBDS
    sys=glc.SYS_BDS; %如果卫星编号减去GPS卫星数glc.NSATGPS再减去GLONASS卫星数glc.NSATGLO再减去GALILEO卫星数glc.NSATGAL后小于等于BDS卫星数glc.NSATBDS,则将sys设置为BDS,sat设置为卫星编号减去GPS卫星数再减去GLONASS卫星数再减去GALILEO卫星数再加上最小PRN编号减1。
    sat=(sat-glc.NSATGPS-glc.NSATGLO-glc.NSATGAL)+glc.MINPRNBDS-1;
elseif (sat-glc.NSATGPS-glc.NSATGLO-glc.NSATGAL-glc.NSATBDS)<=glc.NSATQZS
    sys=glc.SYS_QZS; %如果卫星编号减去GPS卫星数glc.NSATGPS再减去GLONASS卫星数glc.NSATGLO再减去GALILEO卫星数glc.NSATGAL再减去BDS卫星数glc.NSATBDS后小于等于QZSS卫星数glc.NSATQZS,则将sys设置为QZSS,sat设置为卫星编号减去GPS卫星数再减去GLONASS卫星数再减去GALILEO卫星数再减去BDS卫星数再加上最小PRN编号减1。
    sat=(sat-glc.NSATGPS-glc.NSATGLO-glc.NSATGAL-glc.NSATBDS)+glc.MINPRNQZS-1;
else
    sat=0;
end

prn=sat;%将sat值赋值给prn(每颗卫星唯一的编码值)。

return

4.数据处理过程

调用gnss_processor()函数

if opt.ins.mode==glc.GIMODE_OFF%根据所选择的模式将进行相应的处理过程
    % gnss
    gnss_processor(rtk,opt,obsr,obsb,nav);%调用 gnss_processor 函数对 GNSS 数据进行处理。
end

 4.1设置输出的进条度

ti=0;
%创建一个名为"GINav"的进度条,并在创建进度条时设置进度条窗口的位置和大小。
hbar=waitbar(0,'Processing...','Name','GINav', 'CreateCancelBtn', 'delete(gcbf);');%代码中的waitbar函数用于创建进度条窗口,第一个参数"0"表示初始进度为0,第二个参数"‘Processing…’“表示在进度条窗口中显示的文本信息为"Processing…”,第三个参数"‘Name’,‘GINav’“表示设置进度条窗口的名称为"GINav”,第四个参数"‘CreateCancelBtn’, ‘delete(gcbf);’"表示为进度条窗口创建一个取消按钮,并设置点击取消按钮时关闭进度条窗口。
H=get(0,'ScreenSize'); w=600; h=450; x=H(3)/2-w/2; y=H(4)/2-h/2; %通过函数get获取屏幕的尺寸,然后计算出进度条窗口的位置和大小,使用figure函数创建一个新的图形窗口,并将图形窗口的位置和大小设置为之前计算得到的值。
hfig=figure;set(gcf,'Position',[x y w h]);%使用set函数将当前图形窗口设置为gcf (get current figure),并将位置和大小设置为之前计算得到的值。

4.2初始化rtk结构

调用initrtk()函数

rtk=initrtk(rtk,opt);
function rtk=initrtk(rtk,opt)%定义一个initrtk()函数,输入参数为rtk与opt输出参数为rtk

global glc
rtk.opt=opt;%将结构体opt赋值给rtk.opt
rtk.opt.ts=str2time(rtk.opt.ts); %将rtk.opt.ts(表示的是开始的时间)以str2time的形式赋值给rtk.opt.ts
rtk.opt.te=str2time(rtk.opt.te);%rtk.opt.te(表示的是结束的时间)以str2time的形式赋值给rtk.opt.te
rtk.mask=set_sysmask(opt.navsys);%设置卫星系统的掩码,用以确定对应卫星系统   
%在进行PPP的时候不进行这一快
if opt.mode<=glc.PMODE_STATIC
    if opt.ionoopt==glc.IONOOPT_IFLC,NF=1;else,NF=opt.nf;end
    if opt.dynamics==1,NP=9;else,NP=3;end
    if opt.ionoopt==glc.IONOOPT_EST,NI=glc.MAXSAT;else,NI=0;end
    if opt.tropopt<glc.TROPOPT_EST,NT=0;elseif opt.tropopt==glc.TROPOPT_EST,NT=2;else,NT=6;end
    if opt.glomodear~=2,NL=0;else,NL=2;end
    if opt.mode<=glc.PMODE_DGNSS,NB=0;else,NB=NF*glc.MAXSAT;end
    
    % 参数的数量
    NR=NP+NI+NT+NL; NX=NR+NB;
    rtk.NF=NF;rtk.NP=NP;rtk.NI=NI;rtk.NT=NT;rtk.NL=NL;rtk.NB=NB;
    
    % index of parameter
    II=NP;ITR=NP+NI;ITB=NP+NI+NT/2;IL=NP+NI+NT;IB=NR;
    rtk.ii=II; rtk.itr=ITR; rtk.itb=ITB; rtk.il=IL; rtk.ib=IB;
    
else%IFLC 方法是在两个或多个频率的载波相位观测值之间构建线性组合,利用它们之间的差异来消除电离层延迟的影响。
    if opt.ionoopt==glc.IONOOPT_IFLC,NF=1;else,NF=opt.nf;end%“NF” 是指导航系统中的频率数量或频段的数量。
    if opt.dynamics==1,NP=9;else,NP=3;end%opt.dynamics 是一个选项变量,用于设置动态模型的处理方式。
    NC=glc.NSYS;%表示支持的卫星数量
    
    % GLONASS 
    if opt.gloicb==0,                 NICB=0;%这是一个变量,用于存储根据 opt.gloicb 的值确定的国际代码偏差类型
    elseif opt.gloicb==glc.GLOICB_LNF,NICB=1;%表示伽利略的国际代码偏差(inter-frequency code bias)类型为线性(linear)。
    else,                             NICB=2;
    end
    
    if opt.tropopt<glc.TROPOPT_EST,NT=0;elseif opt.tropopt==glc.TROPOPT_EST,NT=1;else,NT=3;end%glc.TROPOPT_EST用以在GLONASS系统中估计对流层延迟
    if opt.ionoopt==glc.IONOOPT_EST,NI=glc.MAXSAT;else,NI=0;end
    if opt.nf>=3,ND=1;else,ND=0;end
    
    % 参数的数量
    NR=NP+NC+NICB+NT+NI+ND; NB=NF*glc.MAXSAT; NX=NR+NB;
    rtk.NF=NF;rtk.NP=NP;rtk.NC=NC;rtk.NICB=NICB;rtk.NT=NT;rtk.NI=NI;rtk.ND=ND;rtk.NB=NB;
    
    % 参数的索引
    IC=NP; IICB=NP+NC; IT=NP+NC+NICB; II=NP+NC+NICB+NT; ID=NP+NC+NICB+NT+NI; IB=NR;
    rtk.ic=IC; rtk.iicb=IICB; rtk.it=IT; rtk.ii=II; rtk.id=ID; rtk.ib=IB;
    
end

rtk.nx=NX; rtk.na=NR;%“rtk.nx” 表示状态向量的维度。它用于确定 RTK 过程中所估计的状态量的数量。这些状态量可能包括位置、速度、钟差等信息。    “rtk.na” 表示滤波状态向量的维度。它用于确定滤波器的状态估计向量的尺寸。在滤波过程中,滤波器通过更新状态向量来估计和更新系统的状态,而状态向量是通过测量和预测进行更新的。
rtk.x=zeros(rtk.nx,1);%通过将rtk.x初始化为大小为rtk.nx行1列的零向量,将rtk对象中的x变量初始化为大小为rtk.nx的变量向量。---“x” 是状态估计向量,它包含了定位过程中估计的各个状态量的值。
rtk.P=zeros(rtk.nx,rtk.nx);%通过将rtk.P初始化为大小为rtk.nx行rtk.nx列的零矩阵,将rtk对象中的P变量初始化为大小为rtk.nx的协方差矩阵。---P是状态估计的协方差矩阵,表示各个状态量之间的误差协方差。
rtk.xa=zeros(rtk.na,1);%通过将rtk.xa初始化为大小为rtk.na行1列的零向量,将rtk对象中的xa变量初始化为大小为rtk.na的变量向量。---“xa” 是滤波中的滤波状态向量(滤波状态估计),表示滤波器输出的最优估计状态。
rtk.Pa=zeros(rtk.na,rtk.na);%通过将rtk.Pa初始化为大小为rtk.na行rtk.na列的零矩阵,将rtk对象中的Pa变量初始化为大小为rtk.na的协方差矩阵。---“Pa” 是滤波中的滤波协方差矩阵,表示滤波器输出的状态估计的协方差。

return

4.3设置时间跨度 

 调用timespan()函数

tspan=timespan(rtk,obsr);
function tspan=timespan(rtk,obsr)%定义一个timespan()的函数,输入参数包括流动站的观测数据以及nav,输出参数为tspan

conf_ts=rtk.opt.ts; conf_te=rtk.opt.te;%将接收机开始于结束的时间赋值给conf_ts与conf_te
obs_ts.time=obsr.data(1,1); obs_ts.sec=obsr.data(1,2);%记录观测的开始的时间以及秒
obs_te.time=obsr.data(end,1); obs_te.sec=obsr.data(end,2);%记录观测结束的时间以及秒
dt=obsr.dt;%dt:采样时间间隔(Sampling Time Interval),表示相邻观测数据之间的时间间隔。(例如:第一个历元与第二个历元之间的时间间隔)

if conf_ts.time~=0&&timediff(conf_ts,obs_ts)>=0%首先,检查接收机开始时间(conf_ts)的date部分是否不等于0,并且timediff(conf_ts,obs_ts)的结果大于等于0。
    ts=conf_ts;%如果满足上述条件,说明接收机的开始时间有效且早于或等于观测数据的开始时间,那么将conf_ts赋值给ts。
else%经过右侧可以看到ts为conf_ts(以接收机开始的时间为基准)
    ts=obs_ts;
end

if conf_te.time~=0&&timediff(conf_te,obs_te)<=0%首先,检查接收机结束时间(conf_te)的date部分是否不等于0,并且timediff(conf_ts,obs_ts)的结果小于等于0。
    te=conf_te;%如果满足上述条件,说明接收机的结束时间有效且晚于或等于观测数据的开始时间,那么将conf_te赋值给ts。
else
    te=obs_te;
end

tspan=fix(timediff(te,ts)/dt)+1;%整个表达式的目的是计算时间段(tspan)的总长度。时间段的开始时间为ts,结束时间为te,采样时间间隔为dt。通过对两个时间点之间的时间差进行除法运算,并向下取整得到的结果再加1,可以得到时间段的总长度。

return

 经过上述的操作得到的是tspam为2880,即一整天的观测历元的个数。

 4.4一个历元数据处理

while 1%从第一个历元开始进行相关的处理

    if ti>tspan,break;end
    
    % 搜索接收机接收到的观测数据
    [obsr_,nobs,obsr]=searchobsr(obsr);
    if nobs<0
        str=sprintf('Processing... %.1f%%',100);
        waitbar(ti/tspan,hbar,str);
        break;
    end
    % exclude rover obs排除接收机的观测数据
    [obsr_,nobs]=exclude_sat(obsr_,rtk);
    if nobs==0,continue;end

    if opt.mode>=glc.PMODE_DGNSS&&opt.mode<=glc.PMODE_STATIC
        % search base obs寻找基准站的观测数据
        [obsb_,nobs]=searchobsb(obsb,obsr_(1).time);
        % exclude base obs排除基准站没有必要的的观测数据
        if nobs~=0,[obsb_,~]=exclude_sat(obsb_,rtk);end
    else
        obsb_=NaN;
    end
    
    % solve an epoch保留一个历元的数据(接收机里面的)
    [rtk,~]=gnss_solver(rtk,obsr_,obsb_,nav);
    
    if rtk.sol.stat~=0
        % write solution to output file写出解决后的输出文件路径
        outsol(rtk);
        % kinematic plot通过捕捉和绘制运动路径,可以帮助制作人员更好地理解和规划场景中的动态元素。
        plot_trajectory_kine(hfig,rtk);
    else
        [week,sow]=time2gpst(obsr_(1).time);%将观测时间(obsr_(1).time)转换为 GPS 周数(week)和秒(sow)。
        fprintf('Warning:GPS week = %d sow = %.3f,GNSS unavailable!\n',week,sow);
    end
    
    % update progress bar在程序运行过程中更新显示一个进度条。进度条是一个用于表示任务完成进度的图形化工具,通常以水平条的形式展示。通过更新进度条,可以让用户了解任务的当前进度,并提供视觉上的反馈。
    ti=ti+1;
    str=sprintf('Processing... %.1f%%',100*ti/tspan);
    waitbar(ti/tspan,hbar,str);
     
end
4.4.1调用searchobsr()函数

 调用该部分主要是搜索接收机的观测数据,将其记录并存储起来。

function [obs,nobs,obss]=searchobsr(obss)%定义了searchobsr()函数,用以搜索观测数据,输入参数为obss,输出参数为obs,nobs,obss
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%search rover observations
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
global gls%定义全局变量 gls

if obss.idx>=obss.n%是一个条件判断语句,检查观测数据的当前索引(obss.idx)是否大于等于观测数据的总数目(obss.n)。如果满足条件,说明已经遍历完了所有的观测数据,那么将obs赋值为NaN(不可用的观测数据),nobs赋值为-1,并且返回结果。这个判断是为了防止索引越界错误。
    obs=NaN;nobs=-1;return
end

obss.idx=obss.idx+1;%如果没有索引越界,那么将观测数据的索引加1,用于获取下一个时间点的观测数据。
obs_tmp=obss.data(obss.idx,:);%根据更新后的索引,从观测数据(obss.data)中获取对应索引位置的观测数据,并赋值给obs_tmp变量。

time0=obss.data(:,1)+obss.data(:,2);%这行代码计算观测数据中每个时间点的总时间,将观测数据的时间部分(列1)与秒数部分(列2)相加,得到每个时间点的总时间。
time1=obs_tmp(1)+obs_tmp(2);%通过观测数据的时间部分(obs_tmp(1))与秒数部分(obs_tmp(2))相加,得到待匹配的时间点的总时间。
idx=time0==time1;  pos=find(time0==time1);%将时间0和时间1进行比较,判断是否有时间匹配的情况,即时间0中有哪些时间点与时间1相等。
if any(idx)%如果存在匹配的时间点(即idx中有至少一个为true),则进入该条件判断。
    obs0=obss.data(idx,:);  nobs=size(obs0,1); obss.idx=pos(end);%将匹配到的时间点的观测数据提取出来,并赋值给obs0;获取匹配到的时间点的观测数据的数量;更新观测数据的索引,将索引设置为最后一个匹配到的时间点的索引。
else
    nobs=0;obs=NaN;return;% 将观测数据的数量(nobs)设置为0,表示没有可用的观测数据;将观测数据(obs)设置为NaN,表示观测数据不可用。
end

obs=repmat(gls.obs_tmp,nobs,1);%该代码使用 repmat 函数,将观测数据 obs_tmp 按行复制 nobs 次,列数保持不变(1列)。这样就创建了一个尺寸为 (nobs,列数) 的矩阵,其中每行都是与 obs_tmp 相同的观测数据。
for i=1:nobs
    obs(i).time.time=obs0(i,1);%将 obs0(i,1) 的值赋给 obs(i) 结构体中的 time 字段中的 time 字段。这个字段用于存储观测数据的时间部分。
    obs(i).time.sec=obs0(i,2);%将 obs0(i,2) 的值赋给 obs(i) 结构体中的 time 字段的 sec 字段。该字段用于存储观测数据的秒部分。
    obs(i).sat=obs0(i,3);%将 obs0(i,3) 的值赋给 obs(i) 结构体中的 sat 字段。该字段用于存储卫星的标识符。
    obs(i).P=obs0(i,4:6);%将 obs0(i,4:6) 的值赋给 obs(i) 结构体中的 P 字段。该字段用于存储观测到的伪距数据。
    obs(i).L=obs0(i,7:9);%将 obs0(i,7:9) 的值赋给 obs(i) 结构体中的 L 字段。该字段用于存储观测到的载波相位数据。
    obs(i).D=obs0(i,10:12);%将 obs0(i,10:12) 的值赋给 obs(i) 结构体中的 D 字段。该字段用于存储观测到的多普勒频率偏移数据。
    obs(i).S=obs0(i,13:15);%将 obs0(i,13:15) 的值赋给 obs(i) 结构体中的 S 字段。该字段用于存储观测到的信噪比数据。
    obs(i).LLI=obs0(i,16:18);%将 obs0(i,16:18) 的值赋给 obs(i) 结构体中的 LLI 字段。该字段用于存储载波相位的丢失标志。
    obs(i).code=obs0(i,19:21);%将 obs0(i,19:21) 的值赋给 obs(i) 结构体中的 code 字段。该字段用于存储观测到的码伪距数据。
end

return
4.4.2调用exclude_sat()函数

  调用该部分主要是排除接收机的无效的观测数据,剔出观测值中的码粗茶。

function [obs,nobs]=exclude_sat(obs0,rtk)%定义了一个exclude_sat()函数,输入参数未obs0与rtk,输出参数未obs,nobs
%定义一个全局变量
global gls
nobs0=size(obs0,1); nobs=0; obs=repmat(gls.obs_tmp,nobs0,1);%将尺寸为obs0行,1列的数据存储在nobs0,首次按mobs为0,重复的存储gls.obs_tmp,nobs0,1
ts=rtk.opt.ts; te=rtk.opt.te;%将接收机开始的时间与结束的时间赋值给ts与te
mask=set_sysmask(rtk.opt.navsys);%调用set_sysmaks()函数,可以用于根据输入参数的不同设置系统屏蔽状态,进而控制系统的行为。

for i=1:nobs0%进行一个循环,用以及记录观测数据值(不同观测值类型下对应的观测值)
    
    time=obs0(i).time;
    if ts.time~=0%这是一个条件判断语句,用于判断接收机接收的时间(ts)是否为非零值。如果ts.time不等于0,说明ts已经设置了一个有效的时间值。
        dt=timediff(time,ts);%计算观测时间与ts之间的时间差,将结果赋值给dt变量。这里使用了timediff函数。
        if dt<0,continue;end %如果计算得到的时间差dt小于0,即观测时间早于ts,那么进入下一次循环,继续处理下一个观测数据。这里使用了continue语句。
    end
    if te.time~=0%判断结束时间(te)是否为非零值。如果te.time不等于0,说明te已经设置了一个有效的时间值。
        dt=timediff(time,te);%计算观测时间与te之间的时间差,将结果赋值给dt变量。
        if dt>0,continue;end
    end

    %if obs0(i).sat==4;continue;end    
    [sys,~]=satsys(obs0(i).sat);
    if mask(sys)==0,continue;end
    
    obs(nobs+1)=obs0(i);
    nobs=nobs+1;
end

if nobs==0,obs=NaN;return;end
if nobs<nobs0
    obs(nobs+1:end,:)=[];
end

return

4.4.3调用gnss_solver()函数

该部分主要用以保存用以保存接收机的一个历元的观测数据。

if opt.mode==glc.PMODE_SPP||opt.mode>=glc.PMODE_PPP_KINEMA%判断了opt.mode的值。如果opt.mode等于glc.PMODE_SPP(也就是单点定位)或者opt.mode大于等于glc.PMODE_PPP_KINEMA(即动态PPP定位),则rtk.sol.stat被赋值为glc.SOLQ_NONE(无解定位状态)。
    % 在进行PPP的时候先执行spp,把spp的结果作为首次结果进行卡尔曼滤波进行迭代
    [obsr,nobs]=scan_obs_spp(obsr);%调用scan_obs_spp()函数
    if nobs==0,stat0=0;return;end
    % correct BDS2 multipath error校正北斗2多路径误差
    if ~isempty(strfind(opt.navsys,'C'))
        obsr=bds2mp_corr(rtk,obsr);
    end
end
% standard point positioning标准单点定位
[rtk,stat0]=sppos(rtk,obsr,nav);%调用sppos()函数
if stat0==0,return;end
4.4.3.1调用scan_obs_spp()函数

satposs

4.4.3.2调用sppos()函数
4.4.3.2.1调用satposs()函数

(1)计算卫星位置、时钟偏差、速度

在该部分调用staposs()函数。

时间计算公式:时间=上次时间+负的伪距观测值/光速值

具体代码如下所示。

function t=timeadd(t0,sec)

t0.sec=t0.sec+sec;
tt=floor(t0.sec);%floor()函数向下一位取整。
t.time=t0.time+fix(tt);
t.sec=t0.sec-tt;%在定义的时间上计算秒数。

return

调用ephclk()函数进行卫星钟差的计算

    [dts,stat1]=ephclk(time,obs(i),nav);
    if stat1==0,continue;end

为什么要计算发射时刻的时间?

一:在进行卫星位置计算时,计算发射时刻的时间是为了考虑到信号的传播时间和接收机的接收时间。这是因为卫星的位置是在发射信号时确定的,但信号需要一定的时间才能从卫星传输到接收机。

二:计算发射时刻的时间可以帮助我们在接收到信号后,将信号的传播时间从总接收时间中减去,以获得更准确的卫星位置信息。这样可以更精确地进行卫星定位、导航和定位解算。

三:发射时刻的时间计算还可以用于校正时间方面的误差,例如卫星钟差、接收机钟差等,以确保接收到的信号时间与真实的发射时刻对齐。

总而言之,计算发射时刻的时间是为了纠正信号传播时间和减小定位误差,从而提高卫星定位的精度和准确性。

<1>卫星钟差计算:

首先是通过searcheph_h()函数,能够在星历数据集中查找指定卫星在给定时间点的有效星历数据。该函数可能会使用一些特定的搜索算法或条件来筛选和匹配星历数据。

t0=abs(eph0(:,11)+eph0(:,12)-time.time-time.sec);
idx1=(t0<=tmax&t0<=tmin);
if ~any(idx1),eph_out=NaN;stat=0;return;end
t1=t0(idx1);
eph1=eph0(idx1,:);
idx2=t1==min(t1);
eph_=eph1(idx2,:);
eph2=eph_(end,:);

 代码段的功能是根据时间戳和条件筛选星历数据,并从中选择满足条件的最小时间差值对应的星历数据。

if sys==glc.SYS_GPS||sys==glc.SYS_GAL||sys==glc.SYS_BDS||sys==glc.SYS_QZS
% 如果系统类型是 GPS、Galileo、北斗或者日本 QZSS,则调用 searcheph_h 函数根据给定时间和卫星编号从星历数据结构体 nav.eph 中搜索相应的星历数据,并将结果存储在 eph 中。如果搜索失败,则将 stat0 设置为0,并返回。
    [eph,stat]=searcheph_h(teph,sat,-1,nav.eph);%如果系统类型是 GLONASS,则调用 searchgeph_h 函数根据给定时间和卫星编号从星历数据结构体 nav.geph 中搜索相应的星历数据,并将结果存储在 geph 中。如果搜索失败,则将 stat0 设置为0,并返回。
    if stat==0,stat0=0;return;end%如果系统类型不属于上述任何一种,则将 stat0 设置为0,并直接返回。
    dts=eph2clk(time,eph);%根据所获取的星历数据 eph 或 geph,通过调用 eph2clk 或 geph2clk 函数计算出卫星的钟差值,并将结果存储在 dts 中。

<2>钟差计算公式:钟差 = eph.f0 +eph.f1 * t +eph.f2 * t^2

  • eph.f0 为卫星的零阶钟差补偿常数,表示卫星钟差在 t = 0 时刻的值。
  • eph.f1 为卫星的一阶钟差补偿常数,表示卫星钟差对时间变化的线性响应。
  • eph.f2 为卫星的二阶钟差补偿常数,表示卫星钟差对时间变化的二次响应。
  • t 为观测时刻与卫星星历数据的参考时刻之间的时间差。
function t=eph2clk(time,eph)%定义一个eph2clk()函数,输入的参数包括时间以及eph 是一个包含星历数据的结构体。

t=timediff(time,eph.toc);%通过调用 timediff 函数计算给定时间 time 与星历数据的 toc(时间标记)之间的时间差,并将结果存储在变量 t 中。
for i=1:3
    t=t-(eph.f0+eph.f1*t+eph.f2*t^2);
end%通过一个 for 循环,进行三次钟差修正。在每次循环中,通过计算 eph.f0 + eph.f1 * t + eph.f2 * t^2,将修正的钟差值累加到变量 t 中。

t=eph.f0+eph.f1*t+eph.f2*t^2;%将修正后的钟差值存储在变量 t 中,并返回。

return

<3>校正时间延迟(该部分校正相当于校正一个系统误差,设置阈值)

time=timeadd(time,-dts); %signal transition time

这行代码用于进行信号过渡时间的计算,其中 time 是输入的时间变量,dts 是信号过渡时间的参数。具体而言,这行代码调用了 timeadd() 函数来将 time 减去 dts,以获得信号过渡后的更新时间。

在进行卫星位置计算的时候先调用ephpos()函数,再调用eph2pos()函数,先通过广播星历进行计算,之后再步入peph2pos()函数。

function [sv,stat]=satpos(time,obs,nav,ephopt,sv)%定义satpos()函数,输入参数为time,obs,nav,ephopt,sv,输出参数为sv与stat
%定义全局变量glc
global glc
teph=obs.time; sat=obs.sat;%函数内部声明了变量 teph 和 sat,并将输入的观测时间 obs.time 存储在 teph 中,将输入的卫星编号 obs.sat 存储在 sat 中。
%过 switch 语句对 ephopt 进行判断,根据不同的选项参数进行不同的操作。
switch ephopt
    case glc.EPHOPT_BRDC%当 ephopt 等于 glc.EPHOPT_BRDC 时,表示使用广播星历数据进行计算。调用 ephpos 函数计算卫星位置,将结果存储在 sv 中,并将计算的状态存储在 stat 中。最后,使用 return 关键字结束函数。
        [sv,stat]=ephpos(time,teph,sat,nav,-1,sv); return;
    case glc.EPHOPT_PREC%当 ephopt 等于 glc.EPHOPT_PREC 时,表示使用精密星历数据进行计算。调用 peph2pos 函数计算卫星位置,将结果存储在 sv 中,并将计算的状态存储在 stat 中。最后,使用 return 关键字结束函数。
        [sv,stat]=peph2pos(time,sat,nav,1,sv); return;
    otherwise%其他情况下,将 stat 设置为0,表示计算失败。最后,使用 return 关键字结束函数。
        stat=0;return;
end

通过广播星历计算卫星位置与速度,在该部分调用eph2pos()函数。

 ①输入用于地球引力模型、地球角速度和开普勒方程的求解的多个参数

MU_GPS   =3.9860050E14;     % gravitational constant--GPS系统的地球引力常数         
MU_GAL   =3.986004418E14;   % earth gravitational constant--GAL系统的地球引力常数   
MU_BDS   =3.986004418E14;   % earth gravitational constant--BDS系统的地球引力常数  
OMGE_GAL =7.2921151467E-5;  % earth angular velocity (rad/s)---GAL系统的地球引力常数 
OMGE_BDS =7.292115E-5;      % earth angular velocity (rad/s)---BDS系统的地球角速度(弧度/秒)
RTOL_KEPLER =1E-13;         %开普勒方程求解的相对误差容限
MAX_ITER_KEPLER =30;        %开普勒方程求解的最大迭代次数
SIN_5 =-0.0871557427476582; % sin(-5.0 deg) %-5.0度的正弦值为-0.0871557427476582
COS_5  =0.9961946980917456; % cos(-5.0 deg) %-5.0度的正弦值为0.9961946980917456

 ②计算平近点角值M:

公式为M=eph.M0+(sqrt(mu/(eph.A*eph.A*eph.A))+eph.deln)*tk;

计算卫星运动的平均角速度n:

在这里插入图片描述
计算观测瞬间卫星的平近点角M:

 在这里插入图片描述

 广播星历每2h更新一次,将参考时刻设在中央时刻,外推间隔小于等于1h,而卫星的运行周期为12h左右,采用卫星过近地点时刻来计算时,外推间隔最大有可能达6h,用参考时刻来取代卫星过近地点时刻后,外推间隔将大大减小,也能获得精度较高的结果。

M=eph.M0+(sqrt(mu/(eph.A*eph.A*eph.A))+eph.deln)*tk;

根据上述代码eph.M0表示的 为t0时刻的平近点角,eph.deln表示的是根据卫星运动而进行的摄动改正数值, tk表示的是从参考时间到待计算时间之间的时间间隔。

③计算卫星的偏近点角E:---开普勒方程

公式为E=E-(E-eph.e*sin(E)-M)/(1-eph.e*cos(E))

在这里插入图片描述

n=0; E=M; Ek=0;%%迭代求解开普勒方程
while abs(E-Ek)>RTOL_KEPLER&&n<MAX_ITER_KEPLER
    Ek=E;
    E=E-(E-eph.e*sin(E)-M)/(1-eph.e*cos(E));%%计算偏近点角E的迭代公式
    n=n+1;
end

abs(E-Ek)>RTOL_KEPLER&&n<MAX_ITER_KEPLER用于判断是否继续迭代计算偏近点角的条件。E 是当前偏近点角的值;Ek 是上一次迭代的偏近点角的值;RTOL_KEPLER 是用于判断迭代误差的阈值;n 是当前的迭代次数;MAX_ITER_KEPLER 是最大迭代次数的限制;eph.e:卫星的离心率;M:平近点角。终止条件可以是迭代次数达到最大值或者当前偏近点角与上一次迭代的偏近点角之差小于一个给定的阈值。

④计算真近点角、轨道半径与轨道倾角值

计算真近点角公式:u=atan2(sqrt(1.0-eph.e*eph.e)*sinE,cosE-eph.e)+eph.omg;

eph.e:轨道离心率;E:偏近点角;eph.omg:升交点赤经;eph.A:长半轴;eph.i0:初始轨道倾角;eph.idot:轨道倾角变化率。

计算轨道半径公式:r=eph.A*(1.0-eph.e*cosE)

计算轨道倾角公式:i=eph.i0+eph.idot*tk; 

u=atan2(sqrt(1.0-eph.e*eph.e)*sinE,cosE-eph.e)+eph.omg;
r=eph.A*(1.0-eph.e*cosE); 
i=eph.i0+eph.idot*tk; 

⑤摄动改正后的真近点角、轨道半径与轨道倾角值

sin2u=sin(2.0*u); cos2u=cos(2.0*u);
u=u+eph.cus*sin2u+eph.cuc*cos2u; 
r=r+eph.crs*sin2u+eph.crc*cos2u; 
i=i+eph.cis*sin2u+eph.cic*cos2u; 
x=r*cos(u); y=r*sin(u); cosi=cos(i);

 上述的公式为计算摄动改正后的真近点角u、轨道半径r与轨道倾角值i,以及x与y值。

⑥计算坐标XYZ

 计算升交点赤经公式:O=eph.OMG0+(eph.OMGd-omge)*tk-omge*eph.toes

在上述公式中,  O 表示卫星在轨道上的升交点赤经;eph.OMG0 表示卫星的升交点赤经的初始值;

eph.OMGd 表示卫星的升交点赤经变化率;tk为时间差;omge为地球自转速度;eph.toes表示为星历的参考时间。

通过迭代更新升交点赤经,然后更新x、y与z值,将着三个值存储在rs里面。

    %%用于根据星历数据和其他轨道参数,更新卫星在轨道上的位置信息。
O=eph.OMG0+(eph.OMGd-omge)*tk-omge*eph.toes; 
    sinO=sin(O); cosO=cos(O);
    rs=[x*cosO-y*cosi*sinO; 
        x*sinO+y*cosi*cosO;
        y*sin(i)];

⑦计算与卫星钟差和观测误差

tk=timediff(time,eph.toc);
dts=eph.f0+eph.f1*tk+eph.f2*tk*tk;
dts=dts-2*sqrt(mu*eph.A)*eph.e*sinE/(glc.CLIGHT)^2;
%tk 表示观测时间与星历的参考时间之间的时间差,单位为秒。
%time 表示观测的时间戳。
%eph.toc 表示星历的参考时间,即星历的观测时间。
%dts 是卫星钟差校正项。
%eph.f0、eph.f1 和 eph.f2 是卫星钟差的校正参数。
%mu 是地球的引力常数。
%eph.A 是卫星轨道的半长轴。
%eph.e 是卫星轨道的离心率。
%sinE 是椭圆轨道中的偏近点角的正弦值。
%glc.CLIGHT 是光速。

在上述代码中进行两次卫星钟差的改正,改正后的钟差值为dts。 

计算观测误差(方差):

ura_value=[2.4,3.4,4.85,6.85,9.65,13.65,24.0,48.0,96.0,192.0,384.0,768.0,1536.0,3072.0,6144.0];
ura=ura-1;
var=ura_value(ura+1)^2;

上述代码中ura代表用户距离精度(User Range Accuracy),它是一种用于描述卫星精度的参数。URA通常与GNSS定位中的卫星观测值(伪距或载波相位)相关联。其值越小,表示该卫星的距离测量精度越高,反之则越低,URA值主要用于确定GNSS定位中卫星观测数据的权重或方差。较低的URA值意味着更精确的测量,因此在GNSS定位算法中被赋予更高的权重,对定位结果的影响更大。而较高的URA值说明该卫星的测量结果可能有较大的不确定性,因此在定位算法中被赋予较低的权重。

sv.pos=rs;
sv.dts=dts;
sv.vars=vars;  

在该部分,主要将计算出来xyz值赋予sv.pos;钟差值dts赋予sv.dts;观测误差值vars赋予sv.vars。 

⑧计算卫星速度变化率

sv.vel=(sv1.pos-sv.pos)/tt;

sv.vel 表示卫星的速度向量;sv1.pos 表示卫星在时间 tt 之后的位置;sv.pos 表示卫星的当前位置;tt 表示时间差,用于计算位置和速度的变化率;sv.dtsd 表示卫星钟差的速度。

sv.vel=(sv1.pos-sv.pos)/tt;,可以计算出卫星的速度向量。它是通过卫星在时间差 tt 后的位置与当前位置之差,再除以时间差 tt 得到的。

⑨计算卫星钟差速度变化率

sv.dtsd=(sv1.dts-sv.dts)/tt

 sv.dtsd 表示卫星钟差的速度变化率;sv1.dts 表示卫星在时间 tt 之后的钟差;sv.dts 表示卫星的当前钟差;tt 表示时间差,用于计算钟差的速度变化率。

sv.dtsd=(sv1.dts-sv.dts)/tt;,可以计算出卫星钟差的速度变化率。它是通过卫星在时间差 tt 后的钟差与当前钟差之差,再除以时间差 tt 得到的。

PPP的时候需要调用peph2pos()函数

function [sv,stat]=peph2pos(time,sat,nav,opt,sv)%定义一个peph2pos()函数,输入参数为time,sat,nav,opt,sv,输出参数为sv,stat。
%定义全局变量glc
global glc
stat=1; tt=0.001;%初始化stat为1,tt为0.001
%首先,通过判断变量 sat 是否小于等于0或大于卫星最大数量 glc.MAXSAT,来检查卫星编号是否在有效范围内。如果不在有效范围内,则将变量 stat 赋值为0,表示卫星状态为无效。
if sat<=0||glc.MAXSAT<sat, stat=0;return; end
%如果卫星编号在有效范围内,那么不执行条件语句中的代码,继续执行后续的代码。
%计算卫星位置以及钟差calculate satellite position and clock bias
[pos,dts,vare,varc,stat1]=pephpos(time,sat,nav); %通过调用 pephpos 函数计算给定时间 time 和卫星编号 sat 对应的卫星位置,并将计算结果存储在变量 pos 中。同时,计算得到的钟差和方差分别存储在变量 dts 和 vare 中。变量 varc 则是传入的钟差方差。这部分主要是用于计算卫星的位置
if stat1==0,stat=0;return;end%stat1 等于0,表示计算卫星位置失败,此时将整个计算的状态 stat 设置为0,并直接返回
[dts,varc,stat2]=pephclk(time,sat,nav,dts,varc);%通过调用 pephclk 函数计算给定时间 time 和卫星编号 sat 对应的钟差,并将计算结果存储在变量 dts 中。同时,计算得到的钟差方差存储在变量 varc 中。
if stat2==0,stat=0;return;end%stat2 等于0,表示计算钟差失败,此时将整个计算的状态 stat 设置为0,并直接返回。
%调用 timeadd 函数将给定时间 time 向后微调一个较小的值 tt,并将结果存储在变量 time_ss 中。
time_ss=timeadd(time,tt);
[pos1,dts1,~,~,stat1]=pephpos(time_ss,sat,nav);%pephpos 函数计算微调后的时间 time_ss 和卫星编号 sat 对应的卫星位置,并将计算结果存储在变量 pos1 中。同时,计算得到的微调后的钟差存储在变量 dts1 中。
if stat1==0,stat=0;return;end%如果 stat1 等于0,表示计算卫星位置失败,此时将整个计算的状态 stat 设置为0,并直接返回。
[dts1,~,stat2]=pephclk(time_ss,sat,nav,dts1,0);%调用 pephclk 函数计算微调后的时间 time_ss 和卫星编号 sat 对应的钟差,并将计算结果存储在变量 dts1 中。
if stat2==0,stat=0;return;end%如果 stat2 等于0,表示计算钟差失败,此时将整个计算的状态 stat 设置为0,并直接返回。

%天线相位抵消校正antenna phase offset correction
dant=zeros(3,1);%定义了一个大小为3x1的零向量 dant。
if opt==1 && isfield(nav,'pcvs')%通过条件判断语句,判断选项参数 opt 是否等于1,并且星历数据结构体 nav 是否包含成员变量 pcvs。
    dant=satantoff(time,pos,sat,nav);%调用 satantoff 函数,传入给定时间 time、卫星位置 pos、卫星编号 sat 和星历数据结构体 nav,计算天线相位抵消的校正量,并将计算结果存储在变量 dant 中。
end

%计算卫星速度与钟偏
vel=(pos1-pos)/tt;%计算卫星的速度,通过将微调后的卫星位置 pos1 与原始卫星位置 pos 相减,再除以微调时间 tt。

%相对论效应--计算相对论效应对钟差的修正。
if dts~=0%判断钟差 dts 是否不等于0,进行条件判断
    dtsd=(dts1-dts)/tt;%dtsd 是指钟差的变化率,即钟差的一阶导数。在代码中,通过计算微调后的钟差 dts1 和原始钟差 dts 的差值,并除以微调时间 tt,得到钟差的变化率 dtsd
    dts=dts-2*dot(pos,vel)/glc.CLIGHT/glc.CLIGHT;%修正钟差 dts,通过将原始钟差 dts 减去位置矢量 pos 与速度矢量 vel 的点积乘以2,再除以光速的平方 glc.CLIGHT 的平方。
else%钟差的变化率在卫星导航系统中非常重要,因为它描述了时钟的稳定性和变化速率。通过考虑钟差的变化率,可以更准确地估计卫星的位置和时间信息。相对论效应是导致钟差的变化的重要因素之一,在代码中通过计算位置矢量 pos 与速度矢量 vel 的点积乘以2,再除以光速的平方,来修正钟差。
    dts=0; dtsd=0;
end
vars=vare+varc;%vars 是指钟差变化的组合变量,通过将钟差的误差项 vare 和钟差变化项 varc 相加得到。
%sv.pos 表示卫星的位置矢量,通过将原始卫星位置 pos 和位置误差项 dant 相加得到。
sv.pos=pos+dant; sv.vel=vel; %sv.vel 表示卫星的速度矢量,等于原始卫星速度 vel。
sv.dts=dts;      sv.dtsd=dtsd;%sv.dts 表示卫星的钟差,等于原始钟差 dts     %sv.dtsd 表示钟差的变化率,即钟差的一阶导数,等于之前计算得到的 dtsd。
sv.vars=vars;    sv.svh=0;%sv.vars 表示钟差变化的组合变量,等于之前计算得到的 vars。
%sv.svh 表示精度标志,等于0,表示未进行任何精度修改。
return

(1)计算卫星的位置

调用的是pephpos()函数

function [satpos,satclk,vare,varc,stat]=pephpos(time,sat,nav)%定义一个pephpos()函数
%定义全局变量glc
global glc
stat=1; norder=10; %norder 被赋值为10,表示多项式拟合的阶数。
tdiff=zeros(norder+1,1); p=zeros(3,norder+1);% 被初始化为一个 (norder+1) 行1列的全零列向量    %p 被初始化为一个3行 (norder+1) 列的全零矩阵。
satpos=zeros(3,1); s=zeros(3,1); satclk=0;%satpos 被初始化为一个3行1列的全零列向量。
varc=0;vare=0;%s 被初始化为一个3行1列的全零列向量。
%判断变量 nav.np 是否小于 norder,或者判断当前时间与 nav.peph(1).time 的时间差是否小于-900秒(即当前时间早于 nav.peph(1).time 超过900秒),或者判断当前时间与 nav.peph(end).time 的时间差是否大于900秒(即当前时间晚于 nav.peph(end).time 超过900秒)。
if nav.np<norder||timediff(time,nav.peph(1).time)<-900||...
        timediff(time,nav.peph(end).time)>900
    stat=0; return;
end

%二分查找算法(Binary Search)
i=0;
j=nav.np-1;%首先,定义变量 i 并赋值为0,定义变量 j 并赋值为 nav.np-1,其中 nav.np 表示导航数据的总数减1。
while i<j
    k=fix((i+j)/2);%在循环中,计算中间位置的索引 k,通过取整函数 fix 将 (i+j) 除以2 的结果赋值给 k。
    if timediff(nav.peph(k+1).time,time)<0%判断 nav.peph(k+1).time 与 time 的时间差是否小于0,如果成立,则更新 i 的值为 k+1,表示查找范围的起始位置右移一位。
        i=k+1;
    else
        j=k;%如果判断不成立,则更新 j 的值为 k,表示查找范围的结束位置左移一位。
    end
end

if i<=0,index=0;  else,index=i-1;  end
index=index+1;

idx=index-norder/2; %start of fitting interval
if idx<1,idx=1;  elseif idx+norder>nav.np,idx=nav.np-norder;  end%%接着,计算 idx 的初始值,即 index - norder/2,其中 norder 是多项式拟合的阶数。

nt=1;
for j=0:norder
    tdiff(nt)=timediff(nav.peph(idx+j).time,time); %time difference
    nt=nt+1;
    if dot(nav.peph(idx+j).pos(sat,1:3),nav.peph(idx+j).pos(sat,1:3))<=0%如果 idx + norder 大于 nav.np,则将 idx 赋值为 nav.np - norder,以确保索引不超过 nav.np - norder。
        stat=0; return;
    end
end

for j=0:norder
    pos=nav.peph(idx+j).pos(sat,:);
    %在每次循环中,首先获取 nav.peph(idx+j).pos(sat,:),其中 idx+j 表示当前索引位置,sat 表示卫星的编号,pos 是卫星在当前索引位置的位置向量。
    %地球自转修正操作
    sinl=sin(glc.OMGE*tdiff(j+1));
    cosl=cos(glc.OMGE*tdiff(j+1)); 
    %执行地球自转的修正操作,即计算 sinl=sin(glc.OMGE*tdiff(j+1)) 和 cosl=cos(glc.OMGE*tdiff(j+1)),其中 tdiff(j+1) 表示时间差。
    p(1,j+1)=cosl*pos(1)-sinl*pos(2);%p(1,j+1) = cosl*pos(1) - sinl*pos(2),表示修正后的 X 坐标;
    p(2,j+1)=sinl*pos(1)+cosl*pos(2);%p(2,j+1) = sinl*pos(1) + cosl*pos(2),表示修正后的 Y 坐标;
    p(3,j+1)=pos(3);%p(3,j+1) = pos(3),表示不进行修正的 Z 坐标。
    %通过这个循环,可以计算得到拟合区间内卫星位置的修正值,并存储在矩阵 p 中的相应位置。
end

%使用 Neville’s 算法实现了多项式插值:
for i=1:3
    satpos(i,1)=polyinter(tdiff,p(i,:)); %调用 polyinter 函数进行多项式插值,其中 tdiff 是时间差数组,p(i,:) 是相应的位置数组,表示在不同时间点对应的位置。
end%polyinter 函数的作用是根据给定的时间差数组和位置数组,使用 Neville’s 算法进行多项式插值,并返回插值结果。在这里,将插值结果赋值给 satpos(i,1),表示获取插值后的卫星位置。
%通过这个循环,可以对每个坐标轴(X、Y、Z)分别进行多项式插值,并将插值后的卫星位置保存在 satpos 矩阵中的相应列。

for i=1:3%通过循环计算了x、y、z三个坐标轴上的误差标准差。其中,nav.peph(index).std(sat,i) 表示卫星 index 的第 i 维误差标准差,索引从1到3。这些标准差值分别保存在 s(1)、s(2)、s(3) 中。
    s(i)=nav.peph(index).std(sat,i);
end
std=sqrt(dot(s,s)); %通过 sqrt(dot(s,s)) 计算误差标准差的平方和的平方根,得到了 std 的值,表示由精密星历造成的误差。
if tdiff(1)>0 
    std=std+(5E-7*tdiff(1)^2)/2; %如果 tdiff(1) 大于0,说明最早的时间差为正,使用公式 std=std+(5E-7*tdiff(1)^2)/2 计算由拟合造成的误差,并累计到 std 上。
elseif tdiff(end)<0
    std=std+(5E-7*tdiff(end)^2)/2;%如果 tdiff(end) 小于0,说明最晚的时间差为负,同样使用公式 std=std+(5E-7*tdiff(end)^2)/2 计算由拟合造成的误差,并累计到 std上。
end
vare=std^2;%通过 vare=std^2 计算得到卫星位置的方差,并存储在 vare 变量中。

%对时钟进行线性插值的操作
t0=timediff(time,nav.peph(index).time);%通过 timediff 函数计算了当前时间 time 与 nav.peph(index).time 和 nav.peph(index+1).time 的时间差,分别保存在 t0 和 t1 中。
t1=timediff(time,nav.peph(index+1).time);
c0=nav.peph(index).pos(sat,4);
c1=nav.peph(index+1).pos(sat,4);
%从 nav.peph(index) 和 nav.peph(index+1) 中获取了卫星时钟的值,即 nav.peph(index).pos(sat,4) 和 nav.peph(index+1).pos(sat,4),分别保存在 c0 和 c1 中。
if t0<=0%首先,检查时间差 t0 是否小于等于0。如果是,说明当前时间在 nav.peph(index) 的时间之前,所以将时钟值设为 c0,即 satclk = c0。
    satclk=c0;
    if satclk~=0%如果 satclk 不等于0,根据公式 varc=(nav.peph(index).std(sat,4)*glc.CLIGHT-1E-3*t0)^2 计算方差值 varc。其中,nav.peph(index).std(sat,4) 表示卫星时钟误差标准差,glc.CLIGHT 是常量光速,1E-3*t0 表示根据时间差 t0 估计的时钟差。方差 varc 的计算是为了考虑时钟拟合误差。
        varc=(nav.peph(index).std(sat,4)*glc.CLIGHT-1E-3*t0)^2;
    end
elseif t1>=0
    satclk=c1;%检查时间差 t1 是否大于等于0。如果是,说明当前时间在 nav.peph(index+1) 的时间之后,所以将时钟值设为 c1,即 satclk = c1。
    if satclk~=0%如果 satclk 不等于0,根据公式 varc=(nav.peph(index+1).std(sat,4)*glc.CLIGHT+1E-3*t1)^2 计算方差值 varc。其中,nav.peph(index+1).std(sat,4) 表示卫星时钟误差标准差,glc.CLIGHT 是常量光速,1E-3*t1 表示根据时间差 t1 估计的时钟差。方差 varc 的计算考虑了时钟拟合误差。
        varc=(nav.peph(index+1).std(sat,4)*glc.CLIGHT+1E-3*t1)^2;
    end
elseif c0~=0 && c1~=0%否则,时间差既不小于等于0,也不大于等于0,即位于 nav.peph(index) 和 nav.peph(index+1) 的时间范围之间。
    satclk=(c1*t0-c0*t1)/(t0-t1);%检查 c0 和 c1 是否均不为0,如果是,根据插值公式 satclk=(c1*t0-c0*t1)/(t0-t1) 计算插值得到的时钟值 satclk。
    if abs(t0)-abs(t1)>0%然后,通过比较绝对值的大小,选择 t0 或 t1 的绝对值较大的那个时间差对应的卫星时钟误差标准差,计算方差值。
        varc=(nav.peph(index+1).std(sat,4)*glc.CLIGHT+1E-3*abs(t1))^2;%如果 abs(t0)-abs(t1)>0,则根据公式 varc=(nav.peph(index+1).std(sat,4)*glc.CLIGHT+1E-3*abs(t1))^2 计算方差。
    else
        varc=(nav.peph(index).std(sat,4)*glc.CLIGHT+1E-3*abs(t0))^2;%根据公式 varc=(nav.peph(index).std(sat,4)*glc.CLIGHT+1E-3*abs(t0))^2 计算方差。
    end
else%如果上述情况都不满足,即 c0 和 c1 中至少有一个为0。这表示无法进行插值,所以将时钟值 satclk 和方差值 varc 均设为0。
    satclk=0;
    varc=0;
end

return

使用使用 Neville’s 算法实现了多项式插值

调用plolyinter()函数

function out=polyinter(x,y)%函数的输入参数为x和y,分别是时间差数组和位置数组。
%首先,获取时间差数组x的大小n。
n=size(x,1);
%然后,通过两层循环进行迭代计算。
for j=1:n-1%外层循环(j=1到n-1)控制插值多项式的阶数。
    for i=0:n-j-1%内层循环(i=0到n-j-1)逐步计算每个插值节点的值,并更新位置数组y的值。
        y(i+1)=(x(i+j+1)*y(i+1)-x(i+1)*y(i+1+1))/(x(i+j+1)-x(i+1));
    end %根据Neville’s算法公式,用x(i+j+1)和y(i+1)、x(i+1)和y(i+1+1)之间的差值进行插值计算,更新y(i+1)的值。
end
%最后,将计算得到的插值结果赋值给变量out,即out=y(1)。
out=y(1);

return
 (2)计算卫星钟差

调用pephclk()函数

function [satclk0,varc0,stat]=pephclk(time,sat,nav,satclk0,varc0)%定义pephclk()函数
%全局变量glc
global glc
stat=1;%初始化stat为1
%如果导航数据的数量小于2(也就是说导航数据的个数少于2个),则返回。这个条件判断了导航数据的数量是否足够进行插值计算。
if nav.nc<2||timediff(time,nav.peph(1).time)<-900||...%如果当前时间与第一个导航数据的时间之差小于 -900 秒(也就是说当前时间比第一个导航数据的时间提前了至少 900 秒),则返回。这个条件判断了当前时间是否过早,超出了可靠的插值范围。
        timediff(time,nav.peph(end).time)>900%如果当前时间与最后一个导航数据的时间之差大于 900 秒(也就是说当前时间比最后一个导航数据的时间晚了至少 900 秒),则返回。这个条件判断了当前时间是否过晚,超出了可靠的插值范围
    return;
end%插值计算与判断

%实现了二分搜索算法,用于在时间序列中找到与给定时间最接近的导航数据点的索引。
i=0; j=nav.nc-1;%初始时,将变量 i 设为0,将变量 j 设为导航数据的数量 nav.nc-1。
while i<j
    k=fix((i+j)/2);%,通过判断给定时间 time 与索引 k+1 对应的时间点的时间差 timediff(nav.pclk(k+1).time,time) 的符号来更新搜索的范围。
    if timediff(nav.pclk(k+1).time,time)<0%如果时间差小于0,说明给定时间 time 在索引 k+1 对应的时间点之后,即较大的时间段,将 i 更新为 k+1。
        i=k+1;
    else
        j=k;%否则,说明给定时间 time 在索引 k+1 对应的时间点之前,即较小的时间段,将 j 更新为 k。
    end
end

if i<=0,idx=0; else,idx=i-1; end
idx=idx+1;%将 idx 的值增加1,得到最终的最接近给定时间的导航数据点的索引。

%实现了对时钟进行线性插值的操作,并计算了插值得到的时钟值 satclk 和相应的方差值 varc。
t0=timediff(time,nav.pclk(idx).time);%通过 timediff 函数计算了当前时间 time 与索引为 idx 的导航数据点的时间差,保存在 t0 中,同时计算了当前时间与索引为 idx+1 的导航数据点的时间差,保存在 t1 中。
t1=timediff(time,nav.pclk(idx+1).time);
c0=nav.pclk(idx).clk(sat);
c1=nav.pclk(idx+1).clk(sat);
%从索引为 idx 的导航数据点中获取了卫星时钟的值 c0,从索引为 idx+1 的导航数据点中获取了卫星时钟的值 c1。
if t0<=0
    satclk=c0;%如果 t0 <= 0,说明给定时间在索引为 idx 的导航数据点之前或恰好等于该点的时间,将时钟值 satclk 设为 c0。
    if satclk==0,stat=0;return;end%如果 satclk 等于0,说明无法进行插值,将 stat 设为0,通过 return 提前返回。否则,根据公式 (nav.pclk(idx).std(sat)*glc.CLIGHT-1E-3*t0)^2 计算方差值 varc。
    varc=(nav.pclk(idx).std(sat)*glc.CLIGHT-1E-3*t0)^2;
elseif t1>=0
    satclk=c1;%如果 t1 >= 0,说明给定时间在索引为 idx+1 的导航数据点之后或恰好等于该点的时间,将时钟值 satclk 设为 c1。
    if satclk==0,stat=0;return;end%如果 satclk 等于0,说明无法进行插值,将 stat 设为0,通过 return 提前返回。否则,根据公式 (nav.pclk(idx+1).std(sat)*glc.CLIGHT+1E-3*t1)^2 计算方差值 varc。
    varc=(nav.pclk(idx+1).std(sat)*glc.CLIGHT+1E-3*t1)^2;
elseif c0~=0 && c1~=0%判断 c0 和 c1 是否均不为0,如果是,根据插值公式 satclk=(c1*t0-c0*t1)/(t0-t1) 计算插值得到的时钟值 satclk。
    satclk=(c1*t0-c0*t1)/(t0-t1);
    if abs(t0)-abs(t1)>0%如果 abs(t0)-abs(t1) > 0,则根据公式 (nav.pclk(idx+1).std(sat)*glc.CLIGHT+1E-3*abs(t1))^2 计算方差。
        varc=(nav.pclk(idx+1).std(sat)*glc.CLIGHT+1E-3*abs(t1))^2;
    else%否则,根据公式 (nav.pclk(idx).std(sat)*glc.CLIGHT+1E-3*abs(t0))^2 计算方差。
        varc=(nav.pclk(idx).std(sat)*glc.CLIGHT+1E-3*abs(t0))^2;
    end
else
    stat=0; return;%如果上述情况都不满足,即 c0 和 c1 中至少有一个为0,则说明无法进行插值,将 stat 设为0,通过 return 提前返回。
end

if satclk~=0
    satclk0=satclk;
    varc0=varc;
end

return

 (3)函数计算给定时间、卫星位置、卫星编号和导航数据的天线相对偏移量。

function dant=satantoff(time,rs,sat,nav)%定义satantoff()函数,输入参数为me,rs,sat,nav,输出参数为dant--偏移量
%定义全局变量glc
global glc
j=1;k=2;
lam=nav.lam(sat,:);%lam 是一个包含卫星所属系统的波长的数组。不同的系统和频率有不同的波长,通过索引 j 和 k 来获取相应的波长。
pcv=nav.pcvs(sat);%pcv 是一个包含卫星的天线相对偏移量的结构体数组,其中包含了不同频率的偏移量值
erpv=zeros(5,1);%erpv 是一个包含了地球旋转参数的零向量,用于计算太阳和月亮位置的时候使用。具体来说,它表示了地球的自转参数,包括倾角、经度、纬度、地球自转速率等参数。

% ECEF 是地心地固坐标系,可以通过计算得到给定时刻太阳和月亮的 ECEF(地心地固坐标系下的坐标)位置。
[rsun,~,~]=sunmoonpos(gpst2utc(time),erpv);
%通过调用 sunmoonpos 函数计算给定时间的太阳和月亮的 ECEF 坐标。太阳和月亮的坐标通过调用 gpst2utc 函数,将 GPST 时间转换为 UTC 时间,并通过设置 erpv 为零向量来计算。函数返回太阳的 ECEF 坐标 rsun。
%ECI” 代表地心惯性坐标系(Earth-Centered Inertial Coordinate System),而 “ECEF” 代表地心地固坐标系(Earth-Centered, Earth-Fixed Coordinate System)。
ez=-rs/norm(rs);%计算地心惯性坐标系中的单位向量 ez。这可以通过将卫星位置向量 rs 归一化(除以其模长)得到。
r=rsun-rs;%计算太阳位置 rsun 和卫星位置 rs 之间的向量 r。首先,通过计算太阳位置向量 rsun,可以使用其他算法(如 sunmoonpos)来获得。然后,将太阳位置向量 rsun 减去卫星位置向量 rs 来计算矢量 r。
es=r/norm(r);%计算 ECEF 坐标系中的 y 轴单位向量 ey。这可以通过将矢量 ez 和 r 进行叉积运算,并将结果归一化来获得。
r=cross(ez,es);
ey=r/norm(r);
ex=cross(ey,ez);%计算 ECEF 坐标系中的 x 轴单位向量 ex。这可以通过将矢量 ey 和 ez 进行叉积运算,并将结果归一化来获得。
M=[ex,ey,ez];%将 ex、ey 和 ez 组合成一个转换矩阵 M。所得矩阵 M 表示从 ECI 到 ECEF 的线性变换。

%“计算天线相对偏移量” 指的是计算天线的位置相对于接收机位置的偏移量。天线相对偏移量是一个向量,描述了天线相对于接收机的位置差异。这个偏移量可以用来校正 GNSS 接收机接收的卫星信号的到达时间,以更准确地计算定位结果。
[sys,~]=satsys(sat);
%if glc.NFREQ>=3&&sys==glc.SYS_GAL,k=3;end
if glc.NFREQ<2||lam(j)==0||lam(k)==0,return;end
%gamma 是一个常量,表示波长之比的平方。它的计算方式是卫星系统中第 k 频率波长的平方除以第 j 频率波长的平方。
gamma=lam(k)^2/lam(j)^2;
C1=gamma/(gamma-1);%C1 的计算方式是将 gamma 除以 gamma-1。这个常量在计算天线相对偏移量时用于加权计算。它在单频点情况下产生一个加权系数,用于将频率相对偏移量转换为天线相对偏移量。
C2=-1/(gamma-1);%C2 的计算方式是将 -1 除以 gamma-1。类似于 C1,C2 也用于加权计算,但是负号表明它会以相反的符号应用于频率相对偏移量。

if sys==glc.SYS_GPS%如果 sys 是 GPS 系统 (glc.SYS_GPS),则将 j 设置为 1,k 设置为 2。
    j=1;k=2;
elseif sys==glc.SYS_GLO%如果 sys 是 GLONASS 系统 (glc.SYS_GLO),则将 j 设置为 1+glc.NFREQ,k 设置为 2+glc.NFREQ。
    j=1+glc.NFREQ; k=2+glc.NFREQ;
elseif sys==glc.SYS_GAL%如果 sys 是 GALILEO 系统 (glc.SYS_GAL),则将 j 设置为 1+2*glc.NFREQ,k 设置为 2+2*glc.NFREQ。
    j=1+2*glc.NFREQ; k=2+2*glc.NFREQ;
elseif sys==glc.SYS_BDS%如果 sys 是 BeiDou 系统 (glc.SYS_BDS),则将 j 设置为 1+3*glc.NFREQ,k 设置为 2+3*glc.NFREQ。
    j=1+3*glc.NFREQ; k=2+3*glc.NFREQ;
elseif sys==glc.SYS_QZS%如果 sys 是 QZSS 系统 (glc.SYS_QZS),则将 j 设置为 1+4*glc.NFREQ,k 设置为 2+4*glc.NFREQ。
    j=1+4*glc.NFREQ; k=2+4*glc.NFREQ;
end%根据不同卫星系统的波段配置,使用不同的索引来获取相应的波长,以便后续计算相关的天线相对偏移量。

%计算了iono-free线性组合(iono-free linear combination)的天线相对偏移量。
dant1=M*pcv.off(j,:)';%首先,使用转换矩阵 M 将频率 j 的天线相对偏移量向量 pcv.off(j,:) 进行线性变换,得到 dant1。
dant2=M*pcv.off(k,:)';%使用转换矩阵 M 将频率 k 的天线相对偏移量向量 pcv.off(k,:) 进行线性变换,得到 dant2。
dant=C1*dant1+C2*dant2;%将 dant1 和 dant2 分别乘以常量 C1 和 C2,并将两个结果相加得到最终的天线相对偏移量 dant。

return

4.4.3.2.2调用estpos()函数

①计算残差、测量模型和权重矩阵

在该部分调用的

是rescode()函数。

 [v,H,P,vsat,azel,resp,nv,ns]=rescode(iter,obs,nav,sv,xr0,opt)
 %残差 v、设计矩阵 H、协方差矩阵 P、可见卫星数 ns、有效卫星数 nv

<1>坐标系转换(BLH---->XYZ)

地心地固坐标系转换为大地经纬度坐标系

while abs(z-zk)>1E-4
    zk=z;
    sinp=z/sqrt(r2+z*z);
    v=RE_WGS84/sqrt(1.0-e2*sinp*sinp);
    z=r(3)+v*e2*sinp;
end

if r2>1E-12
    pos(1)=atan(z/sqrt(r2));
    pos(2)=atan2(r(2),r(1));
else
    if r(3)>0
        pos(1)=pi/2;
    else
        pos(1)=-pi/2;
    end
    pos(2)=0;
end
pos(3)=sqrt(r2+z*z)-v;

将 pos=ecef2pos(rr);:调用 ecef2pos 函数,并将rr向量作为参数传入。这个函数的作用是将以地心地固坐标系表示的位置转换为经纬度坐标系中的位置。

伪距编码偏差校正

    [pr,Vmea]=prange(obs(i),nav,opt,azel(i,:),iter);
    if pr==0,continue;end
    if abs(pr)<1e7||abs(pr)>5e7,continue;end

 码偏差校正:将获得的码偏差估计值应用于伪距观测值,以校正由于码偏差引起的误差。校正过程将对每个卫星的伪距观测值进行调整,以减小码偏差带来的影响。

排除不必要卫星

 stat=satexclude(obs(i).sat,Vars,sv(i).svh,opt);

 计算电离层延迟

该部分调用iono_cor()函数,在进行计算电离层延迟的时候使用的是Klobuchar模型:Klobuchar模型是一种由全球卫星导航系统(GNSS)提供的电离层延迟模型。该模型基于GNSS卫星的导航电文消息中包含的参数,如电离层的全球电离层地形模型(Global Ionospheric Maps,GIM)数据和对流层延迟查找表等,用于估计电离层延迟。

    iono_err=iono_klbc(time,pos,azel,nav.ion_gps);
    iono_var=(0.5*iono_err).^2;

 time:时间信息,用于观测电离层延迟的时间点;pos:接收机的位置信息,用于确定接收机的地理位置坐标;azel:接收机的方位角和仰角信息,用于指定接收机的指向;nav.ion_gps:导航数据中包含的GPS系统的电离层参数。

iono_err的计算:iono_err = iono_klbc(time, pos, azel, nav.ion_gps):调用iono_klbc函数,根据给定的时间、位置、方位角和仰角以及GPS电离层参数,计算电离层的误差(iono_err)。

iono_var的计算:iono_var = (0.5 * iono_err).^2:将电离层误差的一半(0.5 * iono_err)进行平方运算得到电离层误差的方差(iono_var)。

计算对流层延迟

该部分调用trop_cor()函数,在进行对流层延迟的时候使用的是Saastamoinen模型:这是最常用的对流层延迟模型之一。Saastamoinen模型基于大气湿度和温度分布,通过计算信号在对流层中传播时的路径长度以及折射率差异来估计对流层延迟的大小。

elseif opt==glc.TROPOPT_SAAS %Saastamoinen model
    trop_err=trop_saa(pos,azel,0.7); %humi=0.7
    trop_var=(0.3./(sin(azel(2))+0.1)).^2;
else

 trop_err的计算:trop_err = trop_saa(pos, azel, 0.7):调用trop_saa函数,根据接收机的位置信息(pos)、方位角和仰角(azel)以及相对湿度(0.7),计算对流层误差(trop_err)。Saastamoinen模型是一种经典的对流层延迟模型,用于估计卫星信号传播过程中由于大气折射引起的延迟。

trop_var的计算:trop_var = (0.3./(sin(azel(2))+0.1)).^2:该式子计算了对流层误差的方差(trop_var)。这里使用了方位角和仰角(azel)来确定对流层延迟方差的大小,具体计算是将0.3除以(仰角的正弦值加上0.1),然后对结果进行平方。

伪距残差

 % 伪距残差
    v(nv+1)=pr-(r+dtr-glc.CLIGHT*dts+ionoerr+troperr);

代码的目的是通过将伪距观测值和相关修正项(钟差、电离层延迟、对流层延迟等)相减,计算出伪距的残差(观测值与预测值之间的差异)。这个残差可以用于定位算法中的伪距残差最小化问题,以提高GNSS定位的精度。

伪距残差(pseudo-range residual)的观测矩阵H(H矩阵)

H(nv+1,:)=[-LOS,1,0,0,0,0];
    if     sys==glc.SYS_GLO,v(nv+1)=v(nv+1)-x0(5);H(nv+1,5)=1;mask(2)=1;
    elseif sys==glc.SYS_GAL,v(nv+1)=v(nv+1)-x0(6);H(nv+1,6)=1;mask(3)=1;
    elseif sys==glc.SYS_BDS,v(nv+1)=v(nv+1)-x0(7);H(nv+1,7)=1;mask(4)=1;
    elseif sys==glc.SYS_QZS,v(nv+1)=v(nv+1)-x0(8);H(nv+1,8)=1;mask(5)=1;
    else                   ,                                  mask(1)=1;
    end

上述代码是根据系统类型,在H矩阵中更新相应的行、列和伪距残差,以及mask向量中的元素。这些更新是为了在定位算法中准确地建立观测矩阵和伪距残差方程,以进一步进行GNSS定位。

方差矩阵

在该代码中调用的是varerr_spp()函数。

varr=opt.err(1)^2*(opt.err(2)^2+opt.err(3)^2/sin(el));%opt.err(1):表示观测误差的第一个元素。;opt.err(2):表示观测误差的第二个元素;opt.err(3):表示观测误差的第三个元素;el:方位角和仰角的仰角分量;varr:观测误差的方差。
var=fact^2*varr;%fact:表示一个系数或缩放因子。
    VARr=varerr_spp(opt,azel(i,2),sys);
    var(nv+1,nv+1)=VARr+Vars+Viono+Vtrop+Vmea;

VARr:表示接收机单点定位误差的方差(variance)。这个方差根据函数varerr_spp()的调用和其他参数进行计算。var:表示方差矩阵、(nv+1, nv+1):表示方差矩阵var的第(nv+1, nv+1)个元素,也就是方阵中的对角线元素。

上述代码的目的是将VARr(接收机单点定位误差的方差)与Vars(状态估计误差的方差)、Viono(电离层延迟误差的方差)、Vtrop(对流层延迟误差的方差)和Vmea(观测噪声的方差)相加,并将其结果赋值给方差矩阵var的对角线元素(var(nv+1, nv+1))。

记录和验证卫星观测数据以及对残差进行分析

   vsat(i)=1;  resp(i)=v(nv+1,1);  idx(nv+1)=i;

vsat(i)=1:将变量vsat的第i个元素赋值为1。通常用于表示第i个卫星的可见性,1表示可见,0表示不可见;resp(i)=v(nv+1,1):将变量resp的第i个元素赋值为v的第(nv+1,1)个元素的值。变量v可能是一个数组或矩阵,而resp可能是记录相应响应值的变量;idx(nv+1)=i:将变量idx的第(nv+1)个元素赋值为i。变量idx通常用于存储索引或标识符,此处用于记录对应数据或状态的索引。

权重矩阵

for i=1:nv
    P(i,i)=var(i,i)^-1;
end

这段代码的含义是将协方差矩阵(var)的对角线元素的倒数赋值给P矩阵的对角线元素。具体解释如下,for i=1:nv:通过循环迭代变量i的值从1到nv,用于遍历协方差矩阵的对角线;P(i,i)=var(i,i)^-1:将P矩阵的第(i,i)个元素赋值为协方差矩阵var中对应位置元素的倒数。这里的var矩阵可能表示GNSS定位中的观测噪声协方差矩阵,P矩阵一般表示卡尔曼滤波中的状态估计协方差矩阵。将协方差矩阵的对角线元素的倒数赋值给P矩阵的对角线元素是为了计算状态估计值的权重,权重的倒数与协方差成正比。

该代码的目的是根据协方差矩阵的对角线元素,计算状态估计协方差矩阵P的逆。这在卡尔曼滤波等应用中非常常见,通过计算逆矩阵或伪逆可以获得状态变量的权重,进而影响状态估计的精度和可靠性。

②最小二乘法

function [x,VAR]=least_square(v,H,P)

%normal vector
N = (H'*P*H);%N = (H'*P*H);:计算法方程的normal matrix,即 H 矩阵的转置乘以观测协方差矩阵 P 再乘以 H 矩阵。


%cumpute unknown parameter
x = (N^-1)*H'*P*v;%根据最小二乘法的思想,计算未知参数的估计值 x。这里通过将法方程进行求逆,然后与 H 矩阵的转置乘以观测协方差矩阵 P 再乘以观测量 v 相乘来得到参数估计值。

%convariance of parameter
VAR = N^-1;%计算参数的协方差矩阵,即法方程的逆矩阵。这里直接将法方程的逆矩阵作为参数的协方差矩阵。

return

使用最小二乘法可以优化参数,通过最小化观测数据与参数估计值之间的残差平方和,找到最优的参数估计解,以此得到优化后的增量dx和参数的协方差矩阵Q。

4.4.3.3调用scan_obs_ppp()函数
function [obs,nobs]=scan_obs_ppp(obsr)
%一个用于对PPP(精密点位置)观测数据进行扫描和筛选的函数。输入参数obsr是一个包含观测数据的结构体数组。函数将对输入的每一个观测数据进行以下操作:
global gls
nobs0=size(obsr,1); nobs=0; k=2;
obs=repmat(gls.obs_tmp,nobs0,1);

for i=1:nobs0
    %sat=obsr(i).sat;
    %[sys,~]=satsys(sat);
    %if sys==glc.SYS_GAL,k=3;else,k=2;end
    if obsr(i).L(1)==0||obsr(i).L(k)==0,continue;end%检查第一个频率(L1)和第二个频率(L2或E5a)的载波相位观测值(obsr(i).L(1)和obsr(i).L(k))是否都非零,如果其中任意一个为零,则跳过该观测数据。
    if abs(obsr(i).P(1)-obsr(i).P(k))>=200,continue;end
    %检查第一个频率(L1)和第二个频率(L2或E5a)的伪距观测值(obsr(i).P(1)和obsr(i).P(k))的差值是否超过200米,如果超过,则跳过该观测数据。
    obs(nobs+1)=obsr(i);%如果通过了上述两个条件的筛选,则将该观测数据存入输出的观测数据数组obs中,并增加有效观测数据的计数器nobs。
    nobs=nobs+1;
end

if nobs==0,obs=NaN;return;end
if nobs<nobs0%函数会判断有效观测数据的数量nobs,如果为零,则将输出的观测数据数组obs设置为NaN;如果有效观测数据数量小于输入观测数据数量,则将多余的观测数据删除。
    obs(nobs+1:end,:)=[];
end

return
4.4.3.4调用clkrepair()函数
function  [rtk,obsr]=clkrepair(rtk,obsr,nav)%用于修复接收机钟差跳变问题(仅针对 GPS 系统),并更新观测数据。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%repair receiver jump(only for GPS)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
global glc%函数首先定义了一些全局变量和局部变量。然后,对每一个观测数据进行以下操作:
delta0=0; delta1=0; validGPS=0; cjGPS=0; validobs=zeros(32,1);
nobs=size(obsr,1); obs_rcr=rtk.obs_rcr;

for i=1:nobs
    sat=obsr(i).sat;
    if sat>glc.MAXPRNGPS,continue;end%获取卫星编号(sat),如果卫星编号大于最大 GPS 卫星编号(glc.MAXPRNGPS),则跳过该观测数据。
    lam=nav.lam(sat,:);%获取对应的波长(lam)
    %检查观测数据的伪距和相位观测值是否都非零,如果其中任意一个为零,则跳过该观测数据。
    if obsr(i).P(1)*obsr(i).P(2)*obsr(i).L(1)*obsr(i).L(2)==0,continue;end
    if obs_rcr(sat,1)*obs_rcr(sat,2)*obs_rcr(sat,3)*obs_rcr(sat,4)==0%检查之前记录的接收机观测值修正量(obs_rcr)是否都非零,如果其中任意一个为零,则跳过该观测数据。
        continue;
    end
    %增加有效 GPS 观测数据的计数器(validGPS)。
    validGPS=validGPS+1;
    
    d1=obsr(i).P(1)-obs_rcr(sat,1);
    d2=obsr(i).P(2)-obs_rcr(sat,2);
    d3=(obsr(i).L(1)-obs_rcr(sat,3))*lam(1);
    d4=(obsr(i).L(2)-obs_rcr(sat,4))*lam(2);
    %计算接收机时钟跳变修正量(delta0和delta1)。
    if abs(d1-d3)>290000 % ms clock jump
        delta0=delta0+(d1-d3);
        delta1=delta1+(d2-d4);
        cjGPS=cjGPS+1;
    end
end
%如果时钟跳变计数器(cjGPS)不为零,并且与有效 GPS 观测数据数目相等,则进行如下操作:
if cjGPS~=0&&cjGPS==validGPS
    d1=delta0/cjGPS;%计算平均时钟跳变修正量(d1和d2)。
    d2=delta1/cjGPS; %#ok
    
%     CJ_F1=0; 
%     CJ_F2=0;
    CJ_F1=d1/glc.CLIGHT*1000;
    CJ_F2=myRound(CJ_F1);%计算不同单位下的时钟跳变修正量(CJ_F1和CJ_F2)。
    
    if abs(CJ_F1-CJ_F2)<2.5e-2%如果两种不同单位下的时钟跳变修正量差值小于2.5e-2,则将时钟跳变修正量添加到接收机时钟跳变记录中(rtk.clkjump)。
        rtk.clkjump=rtk.clkjump+fix(CJ_F2);
    end
end
%对每一颗卫星进行如下操作
for i=1:nobs
    sat=obsr(i).sat;%获取卫星编号(sat)。
    if sat>glc.MAXPRNGPS,continue;end% 如果卫星编号大于最大 GPS 卫星编号(glc.MAXPRNGPS),则跳过该观测数据。
    validobs(sat)=1;
    %标记该卫星的观测数据为有效(validobs)。
    rtk.obs_rcr(sat,1)=obsr(i).P(1);% 将观测数据的伪距和相位观测值更新到接收机观测值修正量中(rtk.obs_rcr)。
    rtk.obs_rcr(sat,2)=obsr(i).P(2);
    rtk.obs_rcr(sat,3)=obsr(i).L(1);
    rtk.obs_rcr(sat,4)=obsr(i).L(2);
    %计算接收机时钟跳变修正量对应的距离修正量(dclk1和dclk2)。
    dclk1=rtk.clkjump*glc.CLIGHT/1000;
    dclk2=rtk.clkjump*glc.CLIGHT/1000;
    
    % 修正相位观测值,将接收机时钟跳变修正量添加到相位观测值中。
    if obsr(i).L(1)~=0,obsr(i).L(1)=obsr(i).L(1)+dclk1/lam(1);end
    if obsr(i).L(2)~=0,obsr(i).L(2)=obsr(i).L(2)+dclk2/lam(2);end   
    
end
%对于未被标记为有效的卫星,将接收机观测值修正量设置为零。
for i=1:glc.MAXPRNGPS
    if validobs(i)==0
        rtk.obs_rcr(i,1)=0;
        rtk.obs_rcr(i,2)=0;
        rtk.obs_rcr(i,3)=0;
        rtk.obs_rcr(i,4)=0;
    end
end

return

4.4.3.5调用pppos()函数
function [rtk,stat]=pppos(rtk,obs,nav)%是一个用于进行精密点定位(PPS)的函数。函数的输入参数包括::RTK 控制结构体obs:观测数据nav:导航数据,输出参数为rtk:更新后的 RTK 控制结构体,stat状态(0: 错误,1: 正常)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%% precise point positioning %%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%input:  rtk - rtk control structrtk
%        obs - observations
%        nav - navigation message
%output: rtk - rtk control struct
%        stat - state (0:error 1:ok)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

global glc%获取观测数据的数量nobs。设置迭代的最大次数MAXITER为8。初始化迭代次数iter为1。初始化状态stat为0(表示错误)。
nobs=size(obs,1); MAXITER=8; iter=1; stat=0;
exc=zeros(nobs,1); dr=zeros(3,1);
%创建一个大小为nobs的全零向量exc,用于记录是否排除某些观测数据。创建一个大小为3的全零列向量dr,用于存储位置增量。
% initialize rtk.sat.fix
for i=1:glc.MAXSAT
    for j=1:rtk.opt.nf
        rtk.sat(i).fix(j)=0;
    end
end%通过两个嵌套的循环,将RTK结构体中的rtk.sat.fix初始化为全零。该变量用于记录卫星的固定解状态,rtk.opt.nf表示频率的数量。

% debug tracing
% fprintf('\n \n \n');
% fprintf('time= %d',obs(1).time.time);fprintf('\n');
% fprintf('before time update');
% printx_ppp(rtk.x,rtk);
% printP(rtk.P,rtk);

% 通过调用udstate_ppp函数对RTK状态进行时间更新。
rtk=udstate_ppp(rtk,obs,nav);

% debug tracing
% fprintf('after time update');
% printx_ppp(rtk.x,rtk);
% printP(rtk.P,rtk);

% 计算卫星的位置、钟差、速度和钟漂,并存储在变量sv中。
sv=satposs(obs,nav,rtk.opt.sateph);

% exclude measurements of eclipsing satellite (block IIA)如果配置中启用了排除遮挡的卫星测量选项,则通过调用testeclipse函数排除受遮挡的卫星测量。
if rtk.opt.posopt(4)==1
    sv=testeclipse(obs,nav,sv);
end

% 如果启用了地球潮汐改正的选项,则计算地球潮汐改正量,并存储在变量dr中。
if rtk.opt.tidecorr==1
    dr=tidedisp(gpst2utc(obs(1).time),rtk.sol.pos,7,nav.erp,nav.otlp);
end


while iter<=MAXITER
    
    % 在每次迭代中,首先计算观测残差,测量矩阵和测量噪声矩阵。然后,通过调用ppp_res函数计算观测残差,同时排除异常值。
    [v,H,R,~,exc,nv,rtk]=ppp_res(0,rtk.x,rtk,obs,nav,sv,dr,exc);
    if nv==0,break;end
    
    % debug tracing
%     printv(v);
%     printH(H);
%     printR(R);

    % 进行测量更新,通过调用Kfilter_h函数,更新状态估计和状态协方差矩阵。
    [X,P,stat_tmp]=Kfilter_h(v,H,R,rtk.x,rtk.P);
    if stat_tmp==0
        [week,sow]=time2gpst(obs(1).time);
        fprintf('Warning:GPS week = %d sow = %.3f,filter error!\n',week,sow);
        stat=0;break;
    end
    
    % debug tracing
%     fprintf('after measurement update');
%     printx_ppp(X,rtk);
%     printP(P,rtk);
    
    % calculate posteriori residuals,validate the solution
    [~,~,~,~,exc,stat,rtk]=ppp_res(iter,X,rtk,obs,nav,sv,dr,exc);
    iter=iter+1;
    
    if stat==1%如果验证解成功(状态标志stat=1),则退出迭代,并更新状态估计和状态协方差矩阵。
        rtk.x=X; rtk.P=P;
        break;
    end
    
end

if iter>MAXITER%如果迭代次数超过了最大迭代次数,输出警告信息。
    [week,sow]=time2gpst(obs(1).time);
    fprintf('Warning:GPS week=%d sow=%.3f, ppp iteration overflows',week,sow);
end

if stat==1%如果解是有效的(状态标志stat=1),则更新解。
    % PPP ambiguity resolution (Not supported for the time being)
    
    % update solution
    rtk=update_stat(rtk,obs,glc.SOLQ_PPP);

    % hold fixed ambiguity (Not supported for the time being)
    
end

return

4.4.3.5.1调用udstate_ppp()函数
function rtk=udstate_ppp(rtk,obs,nav)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% update the state parameters (PPP mode)
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

global glc

% 调用 udpos_ppp 函数更新位置参数
rtk=udpos_ppp(rtk);

% update clock(include GLONASS icb)调用 udclk_ppp 函数更新时钟参数,这包括 GLONASS 的 ICB(钟差改正偏差)
rtk=udclk_ppp(rtk);

% 调用 udtrop_ppp 函数来更新对流层参数。
if rtk.opt.tropopt==glc.TROPOPT_EST||rtk.opt.tropopt==glc.TROPOPT_ESTG
    rtk=udtrop_ppp(rtk);
end

% 调用 udiono_ppp 函数来更新电离层参数。
if rtk.opt.ionoopt==glc.IONOOPT_EST
    rtk=udiono_ppp(rtk,obs,nav);
end

% 如果配置了支持 L5 频率,并且观测到了 L5 信号,那么通过调用 uddcb_ppp 函数来更新 L5 接收机 DCB(差分代码偏差)参数。
if rtk.opt.nf>=3
    rtk=uddcb_ppp(rtk);
end

% 调用 udamb_ppp 函数来更新模糊度参数
rtk=udamb_ppp(rtk,obs,nav);

return

(1)调用udpos_ppp()函数

function rtk=udpos_ppp(rtk)% PPP 定位中的位置参数更新函数 udpos_ppp(),输入参数为rtk,输出参数为更新后的rtk。
%定义全局变量glc
global glc
VAR_POS=60^2; VAR_VEL=10^2; VAR_ACC=10^2;
%代码定义了全局变量和一些参数,如位置的方差、速度的方差和加速度的方差。
% 第一个历元
if sqrt(dot(rtk.x(1:3),rtk.x(1:3)))<=0
    for i=1:3
        rtk=initx(rtk,rtk.sol.pos(i),VAR_POS,i);
    end%在本次中 rtk.opt.dynamics=0,不开启PPP动态定位
    if rtk.opt.dynamics==1%对于第一个历元,如果接收机的位置状态为零,那么初始化位置状态和方差。如果 PPP 动态定位选项开启,则同时初始化速度状态和方差。
        for i=1:3
            rtk=initx(rtk,rtk.sol.vel(i),VAR_VEL,3+i);
        end
        for i=1:3
            rtk=initx(rtk,1e-6,VAR_ACC,6+i);
        end
    end
end

% 对于 PPP 静态模式,根据设定的 PPP 静态定位误差标准差和历元时间,更新状态协方差矩阵。
if rtk.opt.mode==glc.PMODE_PPP_STATIC%%选择这个
    for i=1:3
        rtk.P(i,i)=rtk.P(i,i)+(rtk.opt.prn(6))^2*abs(rtk.tt);
    end
    return;
end

% 然后,对于动态定位但不考虑动力学的情况,只更新位置状态和方差。
if rtk.opt.dynamics==0
    for i=1:3
        rtk=initx(rtk,rtk.sol.pos(i),VAR_POS,i);
    end
    return;
end

% 生成有效状态的索引并存储在 ix 中。
nx=1;
for i=1:rtk.nx
    if rtk.x(i)~=0&&rtk.P(i,i)>0
        ix(nx)=i;
        nx=nx+1;
    end
end
nx=nx-1;
if nx<=9,return;end

% 生成位置/速度/加速度的状态转移矩阵 F,并将初始状态和方差存储在矩阵 x 和矩阵 P 中
F=eye(nx); x=zeros(nx,1); P=zeros(nx,nx);
for i=1:6
    F(i,i+3)=rtk.tt;
end
for i=1:3
    F(i,i+6)=rtk.tt^2*0.5;
end
for i=1:nx
    x(i)=rtk.x(ix(i));
    for j=1:nx
        P(i,j)=rtk.P(ix(i),ix(j));
    end
end

xp=F*x;
P=F*P*F';
%通过状态转移矩阵更新状态,并计算更新后的状态方差。
for i=1:nx
    rtk.x(ix(i))=xp(i);
    for j=1:nx
        rtk.P(ix(i),ix(j))=P(i,j);
    end
end

% 添加过程噪声到加速度的方差,并更新状态协方差矩阵。
Q(1,1)=rtk.opt.prn(4)^2*abs(rtk.tt);
Q(2,2)=rtk.opt.prn(4)^2*abs(rtk.tt);
Q(3,3)=rtk.opt.prn(5)^2*abs(rtk.tt);
[~,Cne]=xyz2blh(x(1:3));
Qv=Cne'*Q*Cne;

for i=1:3
    for j=1:3
        rtk.P(i+6,j+6)=rtk.P(i+6,j+6)+Qv(i,j);
    end
end

return

(2)调用udclk_ppp()函数

(3)调用udtrop_ppp()函数

function rtk=udtrop_ppp(rtk)%定义了一个udtrop_ppp()函数,用于更新对流层模型相关的参数,输入参数为rtk,输出参数为更新后的rtk

global glc
VAR_GRA=0.01^2; azel=[0,pi/2];%代码定义了全局变量和一些参数,如重力异常的方差和测量方向角(方位角和仰角)。
%根据接收机IT值(整数时间)判断是否需要初始化对流层状态和方差。如果IT值对应的状态为零,则根据接收机当前位置和测量方向角计算对流层延迟和方差,并进行初始化。
if rtk.x(rtk.it+1)==0
    pos=ecef2pos(rtk.sol.pos);%ecef2pos 是一个函数,用于将地心地固坐标(ECEF)转换为经纬度和海拔高度的大地坐标。
    [ztd,var]=trop_mops(rtk.sol.time,pos,azel); %trop_mops 是一个函数,用于计算大气延迟中的对流层延迟。
    rtk=initx(rtk,ztd,var,rtk.it+1);%rtk.sol.time 是接收机的当前历元时间,pos 是接收机的大地坐标(经度、纬度、海拔高度),azel 是接收机到卫星的方位角和仰角。
    if rtk.opt.tropopt==glc.TROPOPT_ESTG%接下来,如果使用估计对流层参数(ESTG)的选项,则对流层延迟和方差也需要进行初始化;trop_mops 的返回值是一个包含两个元素的向量 [ztd, var]。ztd 表示大气延迟中的对流层延迟(Zenith Troposphere Delay),var 表示对流层延迟的方差。
        rtk=initx(rtk,1e-6,VAR_GRA,rtk.it+2);
        rtk=initx(rtk,1e-6,VAR_GRA,rtk.it+3);
    end%如果对流层参数已经初始化过,则根据设定的对流层延迟误差标准差和历元时间,更新对流层延迟的方差。
else%最后,如果使用估计对流层参数的选项,则进一步更新方位角和仰角的方差。
    rtk.P(rtk.it+1,rtk.it+1)=rtk.P(rtk.it+1,rtk.it+1)+rtk.opt.prn(3)^2*abs(rtk.tt);
    if rtk.opt.tropopt==glc.TROPOPT_ESTG
        rtk.P(rtk.it+2,rtk.it+2)=rtk.P(rtk.it+2,rtk.it+2)+(rtk.opt.prn(3)*0.1)^2*abs(rtk.tt);
        rtk.P(rtk.it+3,rtk.it+3)=rtk.P(rtk.it+3,rtk.it+3)+(rtk.opt.prn(3)*0.1)^2*abs(rtk.tt);
    end
end

return

①调用ecef2pos()函数

ecef2pos 是一个函数,用于将地心地固坐标(ECEF)转换为经纬度和海拔高度的大地坐标。

function pos=ecef2pos(r)
%一个函数 ecef2pos,用于将地心地固坐标(ECEF)转换为经纬度和海拔高度的大地坐标。
FE_WGS84=1.0/298.257223563; RE_WGS84=6378137; e2=FE_WGS84*(2.0-FE_WGS84);%代码定义了一些常数,如地球椭球体参数和计算过程中需要使用的变量。
r2=dot(r(1:2),r(1:2));
v=RE_WGS84;
z=r(2);
zk=0;

while abs(z-zk)>1E-4%代码通过迭代计算的方式,根据地心地固坐标的 X、Y、Z 分量来估计大地坐标的经度、纬度和海拔高度。
    zk=z;
    sinp=z/sqrt(r2+z*z);
    v=RE_WGS84/sqrt(1.0-e2*sinp*sinp);
    z=r(3)+v*e2*sinp;
end
%迭代的过程是根据椭球体几何关系以及近似的方法进行的。具体来说,代码通过迭代计算大地坐标的纬度 pos(1) 和经度 pos(2),以及中间变量 v。最后,通过计算海拔高度 pos(3)。
if r2>1E-12
    pos(1)=atan(z/sqrt(r2));
    pos(2)=atan2(r(2),r(1));
else
    if r(3)>0
        pos(1)=pi/2;
    else
        pos(1)=-pi/2;
    end
    pos(2)=0;
end
pos(3)=sqrt(r2+z*z)-v;
%这段代码是实现地心地固坐标到大地坐标转换的算法,将三维空间中的位置表示转换为经度、纬度和海拔高度表示,以便于后续的处理和使用。
return

②调用trop_mops()函数

function [trop_delay,var]=trop_mops(time,pos,azel)%函数的输入包括观测时间 time、接收机的位置 pos(经度、纬度和海拔高度)以及卫星的方位角和仰角 azel。
%定义了一个函数 trop_mops,用于计算大气延迟中的对流层延迟。
k1=77.604;k2=382000;rd=287.054;gm=9.784;g=9.80665;%首先,代码定义了一些常数和变量。k1、k2 是常数,rd 是气体常数,gm 和 g 是重力常数。
persistent pos_ zh zw
sinel=sin(azel(2)); h=pos(3);
%代码根据输入参数进行条件判断,如果接收机的海拔高度超出范围或仰角为零,或者缓存的位置信息与当前位置信息不一致,那么直接返回对流层延迟为零。
if isempty(pos_),pos_=zeros(3,1);end
if isempty(zh),zh=0;end
if isempty(zh),zh=0;end

if pos(3)<-100||pos(3)>10000||azel(2)==0
    trop_delay=0;
    var=0;
    return;
end
%接下来,如果满足条件,则根据大气模型和地球的几何关系计算出对流层延迟。其中,通过调用 getmet 函数获取大气廓线参数,然后根据公式计算出对流层延迟的变化和映射函数。最后,计算出对流层延迟和方差。
if zh==0||abs(pos(1)-pos_(1))>1e-7||abs(pos(2)-pos_(2))>1e-7||abs(pos(3)-pos_(3))>1
    met=getmet(pos(1)*180/pi);
    if pos(1)>=0
        tmp=28;
    else
        tmp=211;
    end
    doy=time2doy(time);
    c=cos(2*pi*(doy-tmp)/365.25);
    for i=1:5
        met(i)=met(i)-met(i+5)*c;
    end
    zh=1E-6*k1*rd*met(1)/gm;
    zw=1E-6*k2*rd/(gm*(met(5)+1.0)-met(4)*rd)*met(3)/met(2);
    zh=zh*(1.0-met(4)*h/met(2))^(g/(rd*met(4)));
    zw=zw*(1.0-met(4)*h/met(2))^((met(5)+1.0)*g/(rd*met(4))-1.0);
    for i=1:3
        pos_(i)=pos(1);
    end
end
%函数返回对流层延迟 trop_delay 和方差 var。
m=1.001/sqrt(0.002001+sinel*sinel); %mapping function of GCAT model
trop_delay=(zh+zw)*m;
var=0.12*0.12*m*m;
%这段代码实现了 MOPS 对流层模型的计算,根据接收机的位置和观测信息,估计大气延迟中的对流层延迟和方差。
return
    
    

在该部分调用getmet()函数,主要是getmet 是一个函数,用于获取大气廓线参数,这些大气廓线参数在后续的计算中用于估计大气延迟的影响,进而对 GNSS 接收机的观测数据进行修正和处理。

function met=getmet(lat)
%定义了一个函数 getmet,用于根据给定的纬度信息获取大气廓线参数。
%lat=15,30,45,60,75    lat 是传入的纬度信息,单位是度。
metprm= [1013.25,299.65,26.31,6.30E-3,2.77,  0.00, 0.00,0.00,0.00E-3,0.00;
         1017.25,294.15,21.79,6.05E-3,3.15, -3.75, 7.00,8.85,0.25E-3,0.33;
         1015.75,283.15,11.66,5.58E-3,2.57, -2.25,11.00,7.24,0.32E-3,0.46;
         1011.75,272.15, 6.78,5.39E-3,1.81, -1.75,15.00,5.36,0.81E-3,0.74;
         1013.00,263.65, 4.11,4.53E-3,1.55, -0.50,14.50,3.39,0.62E-3,0.30];
   %代码中首先定义了一个矩阵 metprm,其中包含了不同纬度下的大气廓线参数,包括气压、温度、湿度等。  
lat=abs(lat);
%代码根据给定的纬度信息,判断其与标准纬度区间的关系,然后根据线性插值的方法计算得到对应纬度下的大气廓线参数。
if lat<=15%如果给定的纬度小于等于 15 度,则直接取最低纬度下的大气廓线参数。
    for i=1:10
        met(i)=metprm(1,i);
    end
elseif lat>=75%如果给定的纬度大于等于 75 度,则直接取最高纬度下的大气廓线参数。
    for i=1:10
        met(i)=metprm(5,i);
    end
else%对于其他情况,代码通过计算插值权重 a,然后根据权重将两个相邻纬度下的大气廓线参数进行插值得到对应纬度下的参数。
    j=fix(lat/15);
    a=(lat-j*15)/15;
    for i=1:10
        met(i)=(1-a)*metprm(j,i)+a*metprm(j+1,i);
    end
end%这段代码根据给定的纬度信息,在预先定义好的大气廓线参数矩阵中查询或计算对应纬度下的大气廓线参数,并返回结果供后续使用。

(4)调用udamb_ppp()函数

function rtk=udamb_ppp(rtk,obs,nav)%用以解决模糊度更新的问题
%PPP(精密单点定位)算法中的状态更新步骤
global glc %函数的输入包括 rtk(接收机状态和观测数据处理结果)、obs(接收机观测数据)和nav(导航电文)。
clk_jump=0; dantr=zeros(3,1);dants=zeros(3,1);phw=0; 
nobs=size(obs,1); MAXSAT=glc.MAXSAT; VAR_BIAS=60^2;%代码中首先定义了一些常量和变量。MAXSAT 是最大卫星数,VAR_BIAS 是模糊度的方差。

%代码处理了一些和观测数据相关的判断和操作。首先,根据用户设置判断是否存在时钟跳变,并更新状态。然后,对32颗卫星及其多频率进行初始化。
if rtk.opt.posopt(6)==1%rtk.opt.posopt 是一个包含不同定位选项的向量。rtk.opt.posopt(6) 表示其中的第六个选项,用于判断是否启用了时钟跳变检测功能。
    [~,sow]=time2gpst(obs(1).time);%如果 rtk.opt.posopt(6) 的值为 1,表示启用了时钟跳变检测功能。代码通过调用 time2gpst 函数将观测数据的时间转换为 GPS 周内秒(sow)的形式,并将结果存储在 sow 变量中。
    tmp=fix(floor(sow*10+0.5));
    if rem(tmp,864000)==0,clk_jump=1;end%通过计算 tmp 对 864000 取模,如果结果为 0,则表示存在时钟跳变,将 clk_jump 变量的值设置为 1,表示时钟跳变已发生。
end
%这段代码用于将状态结构体 rtk 中的 sat 成员的 slip 字段全部设置为0。
for i=1:glc.MAXSAT%glc.MAXSAT 是卫星的最大数量,rtk.opt.nf 是观测频率的数量。
    for j=1:rtk.opt.nf%代码使用两层的循环结构,外层循环遍历所有卫星,内层循环遍历所有观测频率。对于每个卫星和观测频率,将 rtk.sat(i).slip(j) 设置为0,即将指定卫星和观测频率下的 slip 值重置为0。
        rtk.sat(i).slip(j)=0;
    end
end%这个操作用于在状态更新之前,将之前可能存在的卫星周跳标记 (slip) 清零,以便后续的状态更新算法进行正确的处理。
	
%detslip_LLI_ppp 的函数,用于通过 LLI(Loss of Lock Indicator)来检测周跳。
rtk=detslip_LLI_ppp(rtk,obs);%函数的输入参数包括 rtk(接收机状态和观测数据处理结果)和 obs(接收机观测数据)。
%该函数的作用是根据观测数据中的 LLI 信息,检测并修复可能发生的周跳,即接收机失锁的情况。
%detect cycle slip by geometry-free phase jump
rtk=detslip_gf_ppp(rtk,obs,nav);%该函数的作用是通过计算几何无偏组合的相位差,并检测可能发生的周跳。

%detect slip by Melbourne-Wubbena linear combination jump
rtk=detslip_mw_ppp(rtk,obs,nav);%调用了名为 detslip_mw_ppp 的函数,用于通过墨尔本-沃本纳线性组合的跃变来检测周跳。
%总的来说,这段代码调用了一个函数来使用墨尔本-沃本纳线性组合的跃变来检测周跳,以便进行后续的修复和处理。
%用于更新状态和协方差矩阵。每次循环更新的是第 f 个观测频率的状态和协方差矩阵。具体的更新操作可能需要根据上下文进行进一步的分析,在当前给出的代码片段中无法确定具体的更新步骤。
if rtk.opt.ionoopt==glc.IONOOPT_IFLC,nf=1;else,nf=rtk.opt.nf;end
for f=1:nf
    
    % 通过重置整数模糊度以及重置失去观测数据的卫星计数器来处理状态向量和协方差矩阵。
    for i=1:glc.MAXSAT%循环遍历 1 到 glc.MAXSAT,对于每颗卫星执行以下操作:
        rtk.sat(i).outc(f)=rtk.sat(i).outc(f)+1;%对于当前观测频率 f,将卫星的观测失效计数器 rtk.sat(i).outc(f) 增加1。
        if rtk.sat(i).outc(f)>rtk.opt.maxout||rtk.opt.modear==glc.ARMODE_INST||clk_jump==1%如果观测失效计数器超过了规定的最大失效数 rtk.opt.maxout,或者卫星处于瞬时模糊度固定模式 glc.ARMODE_INST,或者钟跳值为1,则执行以下操作:
            rtk.x(rtk.ib+(f-1)*MAXSAT+i)=0;%将状态向量中与该卫星对应的整数模糊度置为0。
            rtk.P(rtk.ib+(f-1)*MAXSAT+i,:)=0;%将协方差矩阵中与该卫星相关的行和列都置为0。
            rtk.P(:,rtk.ib+(f-1)*MAXSAT+i)=0;
            %rtk=initx(rtk,0,0,rtk.ib+(f-1)*MAXSAT+i);
        end
    end
    
    % 用码和相位比较方法来估计近似模糊度。
    k=0;offset=0;bias=zeros(nobs,1);slip=zeros(nobs,1);%定义了一些变量:k、offset、bias 和 slip。其中,k 和 offset 初始化为0,bias 和 slip 是长度为 nobs 的零向量。
    for i=1:nobs%通过一个循环遍历 1 到 nobs,对于每个观测数据执行以下操作:
        sat=obs(i).sat;%获取观测数据中的卫星编号。
        j=rtk.ib+(f-1)*MAXSAT+sat;%根据卫星编号计算状态向量中对应的索引值 j。
        [L,P,Lc,Pc]=corr_meas(rtk,obs(i),nav,dantr,dants,phw);%调用 corr_meas 函数计算相关的测量量,包括载波相位差分 L 和码测量差分 P,以及载波相位噪声和码噪声的线性组合 Lc 和 Pc。
        bias(i)=0;%初始化 bias(i) 为0。
        if rtk.opt.ionoopt==glc.IONOOPT_IFLC
            bias(i)=Lc-Pc;%如果 rtk.opt.ionoopt 等于 glc.IONOOPT_IFLC,则计算 bias(i) 为 Lc - Pc,并检查卫星的周跳情况。
            slip(i)=(rtk.sat(sat).slip(1)||rtk.sat(sat).slip(2)); 
        elseif L(f)~=0&&P(f)~=0
            slip(i)=rtk.sat(sat).slip(f);%否则,根据载波相位差分 L、码差分 P 和其他相关参数计算 bias(i) 的近似值。
            [sys,~]=satsys(obs(i).sat);%#ok
            %if sys==glc.SYS_GAL,kk=3;else,kk=2;end
            kk=2;
            lam=nav.lam(sat,:);%如果状态向量中对应的整数模糊度为0,或者卫星存在周跳情况,或者 bias(i) 为0,则继续下一次循环。
            if obs(i).P(1)==0||obs(i).P(kk)==0||lam(1)==0||lam(kk)==0||lam(f)==0, continue;end
            ion=(obs(i).P(1)-obs(i).P(kk))/(1-(lam(kk)/lam(1))^2);
            bias(i)=L(f)-P(f)+2*ion*(lam(f)/lam(1))^2;
        end%更新 offset,将 bias(i) - rtk.x(j) 加入到 offset 中。
        if rtk.x(j)==0||slip(i)||bias(i)==0,continue;end
        offset=offset+(bias(i)-rtk.x(j));
        k=k+1;
    end%增加计数器 k。
    
    % 这段代码用于校正相位偏差的偏移量,以确保相位和代码之间的相干性。
    if k>=2&&abs(offset/k)>0.0005*glc.CLIGHT%首先,代码判断如果计数器 k 大于等于2,并且偏移量的绝对值除以 k 的结果大于 0.0005 * glc.CLIGHT(光速的千分之五),则执行以下操作:
        for i=1:MAXSAT%根据卫星编号计算状态向量中对应的索引值 j。
            j=rtk.ib+(f-1)*MAXSAT+i;
            if rtk.x(j)~=0%如果状态向量中的值不为0,则将该状态值加上 offset/k,以校正相位偏差的偏移量。
                rtk.x(j)=rtk.x(j)+offset/k;
            end
        end
    end
    %这段代码用于校正相位偏差的偏移量,如果在估计近似模糊度时发现偏移量超过了阈值,就会对状态向量中对应的卫星进行校正以保持相位和代码之间的一致性。这有助于提高定位精度。
    for i=1:nobs%通过一个循环遍历 1 到 nobs,对于每个观测数据执行以下操作:
        sat=obs(i).sat;
        j=rtk.ib+(f-1)*MAXSAT+sat;%更新协方差矩阵中 P(j,j) 的值,该值为原始值加上 rtk.opt.prn(1)^2 乘以时间差的绝对值。其中,rtk.opt.prn(1) 是配置参数,rtk.tt 是时
        rtk.P(j,j)=rtk.P(j,j)+rtk.opt.prn(1)^2*abs(rtk.tt);
        if bias(i)==0||(rtk.x(j)~=0&&~slip(i)),continue;end%如果 bias(i) 等于0 或者 (rtk.x(j) != 0 且 ~slip(i)),则继续下一次循环
       %总的来说,这段代码在检测到周跳或满足特定条件时,对整数模糊度进行重新初始化。重新初始化的过程中,协方差矩阵中的对应元素也会进行更新。这有助于确保整数模糊度的正确性和稳定性。
        %  %调用 initx 函数进行整数模糊度的重新初始化,该函数的参数包括整数模糊度的偏差值 bias(i)、方差 VAR_BIAS 和卫星对应的索引值 j。
        rtk=initx(rtk,bias(i),VAR_BIAS,j);
    end
    
end

return;

①调用detslip_LLI_ppp()函数

函数会遍历观测数据中的每颗卫星,在每颗卫星的每个观测频率上检查 LLI 是否存在失锁情况。如果检测到失锁,函数会将 rtk.sat(i).slip(j) 标记为 1,表示在第 i 颗卫星的第 j 个观测频率上发生了周跳。

function rtk=detslip_LLI_ppp(rtk,obs)
%用于检测载波相位周跳的函数。
nobs=size(obs,1);%首先,函数根据观测数据的数量确定了 nobs。
for i=1:nobs%然后,通过嵌套的循环,遍历观测数据中的每一个数据点。
    for j=1:rtk.opt.nf%对于每个数据点,再遍历接收机配置的所有频率。
        if obs(i).L(j)==0||~bitand(obs(i).LLI(j),3),continue;end%如果载波相位 obs(i).L(j) 等于0,或者 obs(i).LLI(j) 的二进制与运算结果不等于3,表示该数据点没有发生载波相位周跳,跳过继续检查下一个数据点。
        rtk.sat(obs(i).sat).slip(j)=1;%如果上述条件不满足,说明载波相位周跳发生了,将 rtk.sat(obs(i).sat).slip(j) 设置为1,表示该卫星在该频率上发生了周跳。
    end%至此,遍历完所有的观测数据点和频率。
end
%函数返回更新后的 rtk 结构体。
return

②调用detslip_gf_ppp()函数

函数会遍历观测数据中的每颗卫星,在每颗卫星的每个观测频率上计算几何无偏组合的相位差,并与预先定义的阈值进行比较。如果相位差超过阈值,即发生了相位跃变,函数会将 rtk.sat(i).slip(j) 标记为 1,表示在第 i 颗卫星的第 j 个观测频率上发生了周跳。

function rtk=detslip_gf_ppp(rtk,obs,nav)
%这是一个用于检测几何自由度周跳的函数,定义detslip_gf_ppp()函数,gf组合
nobs=size(obs,1);

for i=1:nobs%在每次循环中,调用 gfmeas 函数计算几何自由度测量值 g1。如果 g1 等于0,表示没有进行有效的几何自由度测量,跳过继续检查下一个数据点。
    g1=gfmeas(obs(i),nav);
    if g1==0,continue;end
    g0=rtk.sat(obs(i).sat).gf;%接着,获取上一次的几何自由度测量值 g0。
    rtk.sat(obs(i).sat).gf=g1;%将当前的几何自由度测量值 g1 存储到 rtk.sat(obs(i).sat).gf 中。
    if g0~=0&&abs(g1-g0)>rtk.opt.csthres(1)%如果上一次的几何自由度测量值 g0 不等于0,并且当前测量值与上一次测量值的差的绝对值大于接收机配置的几何自由度周跳阈值 rtk.opt.csthres(1),则表示发生了几何自由度周跳。
        for j=1:rtk.opt.nf
            tmp=rtk.sat(obs(i).sat).slip(j);%在这种情况下,遍历接收机配置的所有频率,并将 rtk.sat(obs(i).sat).slip(j) 的对应位设置为1,表示在该卫星上的该频率发生了周跳。
            rtk.sat(obs(i).sat).slip(j)=bitor(tmp,1);
        end
    end
end

return


%用于计算几何自由度测量值的函数。
function gf=gfmeas(obs,nav)
global glc %#ok%函数根据卫星编号获取导航系统中对应的载波波长 lam。全局变量 glc 用于存储全局常量。
lam=nav.lam(obs.sat,:);

[sys,~]=satsys(obs.sat); %#ok
% if sys==glc.SYS_GAL,k=3;else,k=2;end
k=2;
%如果 lam(1) 或者 lam(k) 或者 obs.L(1) 或者 obs.L(k) 的值为0,表示无效的观测数据,将 gf 置为0 并返回。
if lam(1)==0||lam(k)==0||obs.L(1)==0||obs.L(k)==0
    gf=0; return;
end%最后,根据公式 gf = lam(1)*obs.L(1) - lam(k)*obs.L(k) 计算几何自由度测量值,并返回。
gf=lam(1)*obs.L(1)-lam(k)*obs.L(k);

return;




③调用detslip_mw_ppp()函数

函数会遍历观测数据中的每颗卫星,在每颗卫星的每个观测频率上计算墨尔本-沃本纳线性组合的相位跃变,并与预先定义的阈值进行比较。如果相位跃变超出阈值,就表示发生了周跳,函数会将 rtk.sat(i).slip(j) 设置为1,表示在第 i 颗卫星的第 j 个观测频率上出现了周跳。

④调用corr_meas())函数

计算测量值的函数,包括载波相位和伪距的修正。

function [L,P,Lc,Pc]=corr_meas(rtk,obs,nav,dantr,dants,phw)%计算测量值的函数,包括载波相位和伪距的修正。
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% SNR test not surpport
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%

global glc
lam=nav.lam(obs.sat,:);
L=zeros(glc.NFREQ,1);P=zeros(glc.NFREQ,1);Lc=0;Pc=0;
%然后,初始化载波相位 L、伪距 P、带载波相位的组合 Lc 和带伪距的组合 Pc。
for i=1:glc.NFREQ%通过一个循环遍历接收机配置的所有频率。
    L(i)=0; P(i)=0;
    if lam(i)==0||obs.L(i)==0||obs.P(i)==0,continue;end%如果波长 lam(i) 或者载波相位 obs.L(i) 或者伪距 obs.P(i) 的值为0,表示无效的观测数据,跳过继续检查下一个频率。
    
    %计算载波相位的修正值,包括天线相位中心和相位滞后的校正,以及相位风向校正
    L(i)=obs.L(i)*lam(i)-dants(i)-dantr(i)-phw*lam(i);
    P(i)=obs.P(i)       -dants(i)-dantr(i);
    %计算伪距的修正值,包括天线相位中心和相位滞后的校正。
end

% 进行电离层延迟的修正。
[cbias,~]=getdcb(nav,obs,rtk.opt);%通过 getdcb 函数获取测站和卫星的钟差偏差 cbias,并将其应用于伪距观测
for i=1:glc.NFREQ
    if P(i)~=0,P(i)=P(i)-cbias(i);end
end
C1= lam(2)^2/(lam(2)^2-lam(1)^2);
C2=-lam(1)^2/(lam(2)^2-lam(1)^2);
%根据公式计算带载波相位的组合值 Lc 和带伪距的组合值 Pc。
%IFLC measurements
if L(1)~=0&&L(2)~=0,Lc=C1*L(1)+C2*L(2);end
if P(1)~=0&&P(2)~=0,Pc=C1*P(1)+C2*P(2);end
%总的来说,这个函数用于根据观测数据、导航数据、天线相位中心和相位滞后的修正值、相位风向校正以及电离层延迟进行修正后的测量值计算。
return


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值