草庐IT

利用广播星历解算北斗卫星位置及精度分析

晚晚晚 2023-05-08 原文

利用星历数据解算北斗卫星位置

网上已经有了比较多关于如何利用播发的广播星历来解算卫星位置的blog,此文章的目的是为了记录一下学习成果的同时回馈一下。(毕竟看过很多blog了,但是从来没写过),我在文中用到的数据是我处理过的,只保留了北斗的数据,如果直接用rinex格式下的星历文件,同样可以按照相同的步骤进行求解,不过在数据处理方面有所不同

在实现之前首先得下载好广播星历文件并且导入

下载的网址就比较多了,比如说武汉IGS数据中心,广播星历和精密星历都能下载。

下面是具体实现

1.首先对参数初始化

代码目前没有做交互,也没有采用循环(这些都比较容易在后期实现)所以在一开始只能选定一个卫星号prn,并且只能人为修改prn号来更换卫星的选择。在观测时间的选择上,我所读取的广播星历数据的起始时间为BDT 783周259200s,所以我选取的初始观测时间为259200s。计算卫星位置的数量为可以自己选择,由于我下载的精密星历同一卫星仅有95个数据,所以我设定为95个。卫星的时间间隔我选择的是900s,也即15mins。(与精密星历播发数据相匹配方便精度检验)。

clc;
close;
clear;

%1. 读取下载好的广播星历数据
Data_bro=importdata("Nfile-new.csv");

%2.参数初始化
prn=07;             %卫星号 
t=259200;           %观测起始时间
number=95;          %设定计算位置点的数量(当gap=900时,number应小于95,精密星历中只有95条数据)
gap=900;            %时间上的间隔(单位为s)
flag=0;             %选择是否播放动画(flag=0时不播放,flag=1时播放)

2.计算卫星位置

计算卫星位置之前首先要对星历数据进行选择,选择星历要进行两步处理,第一是在星历文件中找到与所设定卫星号prn相同的星历数据,第二步是在第一步的结果中选取当前观测时刻内依旧有效的精度最高的卫星星历数据,由于我们是非实时解算,所以我们可以选取与观测时刻时间间隔最小的星历数据作为我们解算位置所用的数据。也就是说最终选取得到的结果是针对单一卫星在某时刻播发的一条星历数据

%3.计算卫星位置
for i=1:number      
    t=t+gap;    %每隔gap观测一次
    broadEph_tar = select_eph(t,prn,Data_bro.data);   %选星历
    [Xk(i),Yk(i),Zk(i)] = cal_coordinate(t,prn,broadEph_tar);
end

其中select_eph函数为我设立的选取星历的函数,cal_coordinate为我计算卫星位置的函数。(其实可以把两个函数二合一)其代码如下
select_eph函数:

function broadEph_tar = select_eph(t,prn,Broad_eph)

%1.选择prn相对应的所有星历数据
result_pre=[];
num=1;
for k=1:length(Broad_eph)
    if Broad_eph(k,1)==prn     
        result_pre(num,1)=num;
        result_pre(num,2)=k;
        num=num+1;
    end
end

%2.选择与观测时间相近且已经播发的星历数据  
delta_t=[];
%从对应的广播星历中找到与观测时间最相近的星历数据
for k=1:size(result_pre,1)
    delta_t(k)=t-Broad_eph(result_pre(k,2),3);
    %使用在有效期内的星历数据,将尚未播发的星历数据剔除
    if delta_t(k)<0
        delta_t(k)=1e8;
    end
end
%找到最近播发的星历文件及在数据中所排位置eph_tar,返回所找到的星历文件
[Min,c]=min(delta_t);
eph_tar=result_pre(c,2);
broadEph_tar=Broad_eph(eph_tar,:);
end

cal_coordinate函数:(由于每个人对数据的处理可能不一样,我在下面的代码中省去了我将数据由data_broadEph(也就是所选星历)中读取出来的部分),函数中主要给出的是具体的计算步骤,其实也比较简单。其中有一个对卫星状态的判断,上官网直接看中国卫星导航系统管理办公室测试评估研究中心

function [Xk,Yk,Zk] = cal_coordinate(t,prn,data_broadEph)
%1.解算所用常数
miu=3.986004418e14;
Omega_Dote=7.2921150e-5;

%2.计算轨道半长轴A及卫星平均角速度n0
A=sqrt_A^2;
n0=sqrt(miu/A^3);

%3.计算时间差
% toc=toc_week*3600*24*7+toc_second;
% toe=toe_week*3600*24*7+toe_second;
toe=toe_second;
tk=t-toe;
% if tk>302400
%     tk=tk-604800;
% elseif tk<-302400
%     tk=tk+604800;
% end

%4.改正平均角速度n0
n=n0+delta_n;

%5.计算平近点角
Mk=M0+n*tk;

%6.迭代计算偏近点角
%对开普勒方程进行迭代得到三阶近似式
E0=Mk+e*sin(Mk)+e^2*sin(Mk)*cos(Mk)+0.5*e^3*sin(Mk)*(3*(cos(Mk))^2-1);
% E0=Mk;
E1=E0+e*sin(E0);
while abs(E1-E0)>1e-10
    E0=E1;
    E1=Mk+e*sin(E0);
    delta=abs(E1-E0);
end
Ek=E1;

%7.计算纬度幅角
% vk_sin=sqrt(1-e^2)*sin(Ek)/(1-e*cos(Ek));
% vk_cos=cos(Ek)-e/(1-e*cos(Ek));
vk=2*atan2(sqrt((1+e)/(1-e))*tan(Ek/2),1);
phi_k=vk+omega;

%8.计算纬度幅角、径向、轨道倾角改正项
delta_uk=Cus*sin(2*phi_k)+Cuc*cos(2*phi_k);
delta_rk=Crs*sin(2*phi_k)+Crc*cos(2*phi_k);
delta_ik=Cis*sin(2*phi_k)+Cic*cos(2*phi_k);

%9.改正纬度幅角、径向、轨道倾角
uk=phi_k+delta_uk;
rk=A*(1-e*cos(Ek))+delta_rk;
ik=i0+Idot*tk+delta_ik;

%10.计算卫星再轨道平面内的坐标
xk=rk*cos(uk);
yk=rk*sin(uk);

%% 计算卫星在BDCS坐标系下的坐标
% 1.首先对卫星状态进行判断
%如果卫星为为非正常状态(在轨实验/在轨测试)则不返回卫星位置
prn_abnormal=[31,56,57,18];
prn_Geo=[1,2,3,4,5,59,69];
% if ismember(prn,prn_abnormal)==1
%     return
if ismember(prn,prn_Geo)==1   %GEO
    %(1)计算历元升交点经度(惯性系)
    Omega_k=Omega0+OmegaDot*tk-Omega_Dote*toe;
    %(2)计算GEO卫星在自定义坐标系中的坐标
    XGk=xk*cos(Omega_k)-yk*cos(ik)*sin(Omega_k);
    YGk=xk*sin(Omega_k)+yk*cos(ik)*cos(Omega_k);
    ZGk=yk*sin(ik);
    %(3)计算GEO卫星在BDCS中的坐标
    Xk=cos(Omega_Dote*tk)*XGk+sin(Omega_Dote*tk)*cos(-5/180*pi)*YGk+sin(Omega_Dote*tk)*sin(-5/180*pi)*ZGk;
    Yk=-sin(Omega_Dote*tk)*XGk+cos(Omega_Dote*tk)*cos(-5/180*pi)*YGk+cos(Omega_Dote*tk)*sin(-5/180*pi)*ZGk;
    Zk=-sin(-5/180*pi)*YGk+cos(-5/180*pi)*ZGk;
else
    %计算MEO/IGSO卫星坐标
    Omega_k=(Omega0+(OmegaDot-Omega_Dote)*tk-Omega_Dote*toe);   %计算升交点经度(地固系)
    Xk=xk*cos(Omega_k)-yk*cos(ik)*sin(Omega_k);
    Yk=xk*sin(Omega_k)+yk*cos(ik)*cos(Omega_k);
    Zk=yk*sin(ik);
end

3.绘制卫星星下点轨迹

首先要将卫星的坐标在大地坐标系下表示,在转换之后要将经纬度由弧度制转换为角度制。其中的绘制动图是为了更好的展示星下点轨迹而增添的一个功能,可以一个一个点逐点将星下点轨迹绘制出来,可以让大家知道星下点的起始点。

%4. 绘制卫星星下点轨迹
%4.1 转换坐标 
pos=[Xk;Yk;Zk]';
% plot3(pos(:,1),pos(:,2),pos(:,3));  grid on
for i=1:length(pos)
    [B(i),L(i),H(i)] = xyz2blh(Xk(i),Yk(i),Zk(i));   %将空间直角坐标转换成大地坐标
end
B=B'*180/pi;
L=L'*180/pi;
h = geoshow('landareas.shp', 'FaceColor', [0.5 0.8 0.3]);  %导入世界地图
hold on;    grid on;
plot(L,B);
%4.2 绘制动图
if flag==1
    at = animatedline('Color','b','Marker','*','MarkerSize',3);
%     avi = VideoWriter('orbit.avi');
%     open(avi);
    Mo=moviein(length(pos));
    for k=1:length(pos)
        addpoints(at,L(k),B(k));
        Mo(k)=getframe;
    end
    drawnow;
    movie(Mo);
%     close(avi);
end

4.读入精密星历计算精度

这一步比较简单,首先对时间间隔进行一个判断,如果间隔为15分钟才会读取精密星历,来计算精度。

if gap==900    %如果时间间隔为900s也即15分钟,才导入精密星历进行误差计算
    Data_pre=importdata("SP3.mat");
    Data_pre=Data_pre(:,1:4);        %只保留卫星坐标
    
    %1.根据所定prn寻找符合的精密星历数据
    if prn<10
        PRN="PC"+"0"+num2str(prn);
    else
        PRN="PC"+num2str(prn);
    end
    k=[];
    num=0;
    for i=1:length(Data_pre)        %找到PRN相匹配的卫星
        if Data_pre{i,1}==PRN
            num=num+1;
            k(num)=i;
        end
    end
    
    PreciseEph=Data_pre(k(2:end),2:4);   %由于未观测起始时间的卫星所以剔除第一个数据
    PreciseEph=cell2mat(PreciseEph);
    error=pos-PreciseEph(1:length(pos),:)*1000;     %精密星历中的坐标数据单位为KM
    error_mean=mean(error);
    
    %2. 绘制图像
    figure;hold on;
    plot(1:length(error),error(:,1));
    plot(1:length(error),error(:,2));
    plot(1:length(error),error(:,3));
    grid on;
    legend("X坐标误差","Y坐标误差","Z坐标误差");
    ylabel("误差大小(m)");
end


误差图可以看到,由本程序实现的卫星位置计算,精度在米级,误差在5m以内,比较正常,说明上诉解算流程基本正确。
到这里基本上就实现了我们的目的,希望能给大家带来一定的帮助!如果想要通过卫星位置的解算进一步实现用户位置的解算,可以阅读我的另一篇文章

有关利用广播星历解算北斗卫星位置及精度分析的更多相关文章

  1. [工业相机] 分辨率、精度和公差之间的关系 - 2

    📢博客主页:https://blog.csdn.net/weixin_43197380📢欢迎点赞👍收藏⭐留言📝如有错误敬请指正!📢本文由Loewen丶原创,首发于CSDN,转载注明出处🙉📢现在的付出,都会是一种沉淀,只为让你成为更好的人✨文章预览:一.分辨率(Resolution)1、工业相机的分辨率是如何定义的?2、工业相机的分辨率是如何选择的?二.精度(Accuracy)1、像素精度(PixelAccuracy)2、定位精度和重复定位精度(RepeatPrecision)三.公差(Tolerance)四.课后作业(Post-ClassExercises)视觉行业的初学者,甚至是做了1~2年

  2. ruby - 正则表达式在哪个位置失败? - 2

    我需要一个非常简单的字符串验证器来显示第一个符号与所需格式不对应的位置。我想使用正则表达式,但在这种情况下,我必须找到与表达式相对应的字符串停止的位置,但我找不到可以做到这一点的方法。(这一定是一种相当简单的方法……也许没有?)例如,如果我有正则表达式:/^Q+E+R+$/带字符串:"QQQQEEE2ER"期望的结果应该是7 最佳答案 一个想法:你可以做的是标记你的模式并用可选的嵌套捕获组编写它:^(Q+(E+(R+($)?)?)?)?然后你只需要计算你获得的捕获组的数量就可以知道正则表达式引擎在模式中停止的位置,你可以确定匹配结束

  3. ruby-on-rails - ruby on rails 模型验证中的浮点精度 - 2

    我正在尝试使用正则表达式验证美元金额:^[0-9]+\.[0-9]{2}$这工作正常,但每当用户提交表单并且美元金额以0(零)结尾时,ruby(或rails?)将0砍掉。所以500.00变成500.0,因此正则表达式验证失败。有没有办法让ruby​​/rails保持用户输入的格式,而不管尾随零? 最佳答案 我假设您的美元金额是小数类型。因此,用户在字段中输入的任何值在保存到数据库之前都会从字符串转换为适当的类型。验证适用于已转换为数字类型的值,因此在您的情况下,正则表达式并不是真正合适的验证过滤器。不过,您有几种可能性可以解决这个问

  4. ruby - 下载位置 Selenium-webdriver Cucumber Chrome - 2

    我将Cucumber与Ruby结合使用。通过Selenium-Webdriver在Chrome中运行测试时,我想将下载位置更改为测试文件夹而不是用户下载文件夹。我当前的chrome驱动程序是这样设置的:Capybara.default_driver=:seleniumCapybara.register_driver:seleniumdo|app|Capybara::Selenium::Driver.new(app,:browser=>:chrome,desired_capabilities:{'chromeOptions'=>{'args'=>%w{window-size=1920,1

  5. ruby - Heroku production.log 文件位置 - 2

    我想在heroku.com上查看我的应用程序日志的内容,所以我关注了thisexcellentadvice并拥有我所有的日志内容。但是我现在很想知道我的日志文件实际在哪里,因为“log/production.log”似乎是空的:C:\>herokuconsoleRubyconsoleforajpbrevx.heroku.com>>files=Dir.glob("*")=>["public","tmp","spec","Rakefile","doc","config.ru","app","config","lib","README","Gemfile.lock","vendor","sc

  6. ruby - 在 Ruby 中查找多个正则表达式匹配的模式和位置 - 2

    这应该是一个简单的问题,但我找不到任何相关信息。给定一个Ruby中的正则表达式,对于每个匹配项,我需要检索匹配的模式$1、$2,但我还需要匹配位置。我知道=~运算符为我提供了第一个匹配项的位置,而string.scan(/regex/)为我提供了所有匹配模式。如果可能,我需要在同一步骤中获得两个结果。 最佳答案 MatchDatastring.scan(regex)do$1#Patternatfirstposition$2#Patternatsecondposition$~.offset(1)#Startingandendingpo

  7. ruby-on-rails - 尝试打开 .gitignore 以在文本编辑器中对其进行编辑,但在 OS X Mountain Lion 上找不到文件位置 - 2

    我使用“newapp_name”创建了一个新的Rails应用程序,我正在尝试编辑.gitignore文件,但在我的应用程序文件夹中找不到它。我在哪里可以找到它?我安装了Git。 最佳答案 .gitignore位于项目的root中,而不是app子目录中。首先打开终端并进入您的目录。您需要使用ls-a来显示stash文件。然后使用打开.gitignore 关于ruby-on-rails-尝试打开.gitignore以在文本编辑器中对其进行编辑,但在OSXMountainLion上找不到文件位

  8. ruby-on-rails - 在 Rails 中存储(结构化)配置数据的位置 - 2

    对于我正在编写的Rails3应用程序,我正在考虑从本地文件系统上的XML、YAML或JSON文件中读取一些配置数据。重点是:我应该把这些文件放在哪里?Rails应用程序中是否有用于存储此类内容的默认位置?附带说明一下,我的应用程序部署在Heroku上。 最佳答案 我经常做的是:如果文件是通用配置文件:我在目录/config中创建一个YAML文件,每个环境有一个上层key如果我为每个环境(大项目)创建一个文件:我为每个环境创建一个YAML并将它们存储在/config/environments/然后我在加载YAML的地方创建了一个初始化

  9. Ruby:数组中的下一个/上一个值,循环数组,数组位置 - 2

    假设我有一个没有特定顺序的随机数数组。假设这些是参加马拉松比赛的人的ID#,他们按照完成的顺序添加到数组中,例如:race1=[8,102,67,58,91,16,27]race2=[51,31,7,15,99,58,22]这是一个简化且有些做作的示例,但我认为它传达了基本思想。现在有几个问题:首先,我如何获得特定条目之前和之后的ID?假设我正在查看运行者58,我想知道谁在他之前和之后完成了比赛。race1,runner58:previousfinisher=67,nextfinisher=91race2,runner58:previousfinisher=99,nextfinishe

  10. ruby-on-rails - 在 Rails 中向 Integer 类添加方法的最佳位置在哪里? - 2

    在Rails中向整数类添加方法的最佳位置在哪里?我想添加一个to_meters和to_miles方法。 最佳答案 如果您决心使用数字(或整数等)类来进行单位转换,那么至少要在逻辑上做到这一点,并具有一些实际值(value)。首先,创建一个Unit类,用于存储单位类型(米、英尺、肘等)和创建时的值。然后向Numeric添加一堆方法,这些方法对应于单元可以具有的有效值:这些方法将返回一个单元对象,其类型记录为方法名称。Unit类将支持一组to_*方法,这些方法将转换为具有相应单位值的另一种单位类型。这样,您可以执行以下命令:>>x=47

随机推荐