|
|
function [xyzM,dtsvS] = GpsEph2Xyz(gpsEph,gpsTime) |
|
|
%[xyzM,dtsvS] = GpsEph2Xyz(gpsEph,gpsTime) |
|
|
% Calculate sv coordinates, in ECEF frame, at ttx = gpsTime |
|
|
% |
|
|
% Inputs: |
|
|
% gpsEph: vector of GPS ephemeris structures, as defined in ReadRinexNav.m |
|
|
% |
|
|
% gpsTime = [gpsWeek, ttxSec]: GPS time at time of transmission, ttx |
|
|
% ttx = trx - PR/c - dtsvS, where trx is time of reception (receiver clock), |
|
|
% dtsvS is the satellite clock error (seconds), can be computed in advance |
|
|
% using Eph2Dtsv.m or iterating this function: gps time = sat time - dtsvS |
|
|
% gpsWeek, ttxSec must be vectors of length(gpsEph), |
|
|
% |
|
|
% outputs: |
|
|
% xyzM = [i,j,k] matrix of coordinates of satellites (ecef meters) |
|
|
% dtsvS = vector of satellite clock error (seconds) |
|
|
% The row dimension of xyzM, dtsvS = length(gpsEph) |
|
|
% |
|
|
% xyzM = sat positions at time ttxSec, in terms of ecef coords at the same time |
|
|
% Use FlightTimeCorrection.m to get xyzM & v in ecef coords at time of reception |
|
|
% |
|
|
% See IS-GPS-200 for details of data |
|
|
|
|
|
%Author: Frank van Diggelen |
|
|
%Open Source code for processing Android GNSS Measurements |
|
|
|
|
|
xyzM=[]; dtsvS=[]; |
|
|
|
|
|
[bOk,gpsEph,gpsWeek,ttxSec] = CheckGpsEphInputs(gpsEph,gpsTime); |
|
|
if ~bOk |
|
|
return |
|
|
end |
|
|
p=length(gpsEph); |
|
|
%Now we are done checking and manipulating the inputs |
|
|
% the time vectors: gpsWeek, ttxSec are the same length as gpsEph |
|
|
%------------------------------------------------------------------------------- |
|
|
|
|
|
%set fitIntervalSeconds |
|
|
fitIntervalHours = [gpsEph.Fit_interval]'; |
|
|
%Rinex says "Zero if not known", so adjust for zeros |
|
|
fitIntervalHours(fitIntervalHours == 0) = 2; |
|
|
fitIntervalSeconds = fitIntervalHours*3600; |
|
|
|
|
|
%Extract variables from gpsEph, into column vectors |
|
|
%orbit variable names follow RINEX 2.1 Table A4 |
|
|
%clock variables af0, af1, af2 follow IS GPS 200 |
|
|
TGD = [gpsEph.TGD]'; |
|
|
Toc = [gpsEph.Toc]'; |
|
|
af2 = [gpsEph.af2]'; |
|
|
af1 = [gpsEph.af1]'; |
|
|
af0 = [gpsEph.af0]'; |
|
|
Crs = [gpsEph.Crs]'; |
|
|
Delta_n = [gpsEph.Delta_n]'; |
|
|
M0 = [gpsEph.M0]'; |
|
|
Cuc = [gpsEph.Cuc]'; |
|
|
e = [gpsEph.e]'; |
|
|
Cus = [gpsEph.Cus]'; |
|
|
Asqrt = [gpsEph.Asqrt]'; |
|
|
Toe = [gpsEph.Toe]'; |
|
|
Cic = [gpsEph.Cic]'; |
|
|
OMEGA = [gpsEph.OMEGA]'; |
|
|
Cis = [gpsEph.Cis]'; |
|
|
i0 = [gpsEph.i0]'; |
|
|
Crc = [gpsEph.Crc]'; |
|
|
omega = [gpsEph.omega]'; |
|
|
OMEGA_DOT=[gpsEph.OMEGA_DOT]'; |
|
|
IDOT = [gpsEph.IDOT]'; |
|
|
ephGpsWeek = [gpsEph.GPS_Week]'; |
|
|
|
|
|
%Calculate dependent variables ------------------------------------------------- |
|
|
|
|
|
%Time since time of applicability accounting for weeks and therefore rollovers |
|
|
%subtract weeks first, to avoid precision errors: |
|
|
tk =(gpsWeek-ephGpsWeek)*GpsConstants.WEEKSEC + (ttxSec-Toe); |
|
|
|
|
|
I = find(abs(tk)>fitIntervalSeconds); |
|
|
if ~isempty(I) |
|
|
numTimes = length(I); |
|
|
fprintf(sprintf('WARNING in GpsEph2Xyz.m, %d times outside fit interval.',... |
|
|
numTimes)); |
|
|
end |
|
|
|
|
|
A = Asqrt.^2; %semi-major axis of orbit |
|
|
n0=sqrt(GpsConstants.mu./(A.^3)); %Computed mean motion (rad/sec) |
|
|
n=n0+Delta_n; %Corrected Mean Motion |
|
|
h = sqrt(A.*(1-e.^2).*GpsConstants.mu); |
|
|
Mk=M0+n.*tk; %Mean Anomaly |
|
|
Ek=Kepler(Mk,e); %Solve Kepler's equation for eccentric anomaly |
|
|
|
|
|
%Calculate satellite clock bias (See ICD-GPS-200 20.3.3.3.3.1) |
|
|
%subtract weeks first, to avoid precision errors: |
|
|
dt =(gpsWeek-ephGpsWeek)*GpsConstants.WEEKSEC + (ttxSec-Toc); |
|
|
|
|
|
%Calculate satellite clock bias |
|
|
sin_Ek=sin(Ek); |
|
|
cos_Ek=cos(Ek); |
|
|
dtsvS = af0 + af1.*dt + af2.*(dt.^2) + ... |
|
|
GpsConstants.FREL.*e.*Asqrt.*sin_Ek -TGD; |
|
|
|
|
|
%true anomaly: |
|
|
vk=atan2(sqrt(1-e.^2).*sin_Ek./(1-e.*cos_Ek),(cos_Ek-e)./(1-e.*cos_Ek)); |
|
|
Phik=vk + omega; %Argument of latitude |
|
|
|
|
|
sin_2Phik=sin(2*Phik); |
|
|
cos_2Phik=cos(2*Phik); |
|
|
% The next three terms are the second harmonic perturbations |
|
|
duk = Cus.*sin_2Phik + Cuc.*cos_2Phik; %Argument of latitude correction |
|
|
drk = Crc.*cos_2Phik + Crs.*sin_2Phik; %Radius Correction |
|
|
dik = Cic.*cos_2Phik + Cis.*sin_2Phik; %Correction to Inclination |
|
|
|
|
|
uk = Phik + duk; %Corrected argument of latitude |
|
|
rk = A.*((1-e.^2)./(1+e.*cos(vk))) + drk; %Corrected radius |
|
|
ik = i0 + IDOT.*tk + dik; %Corrected inclination |
|
|
|
|
|
sin_uk=sin(uk); |
|
|
cos_uk=cos(uk); |
|
|
xkp = rk.*cos_uk; % Position in orbital plane |
|
|
ykp = rk.*sin_uk; % Position in orbital plane |
|
|
|
|
|
% Wk = corrected longitude of ascending node, |
|
|
Wk = OMEGA + (OMEGA_DOT - GpsConstants.WE).*tk - GpsConstants.WE*[gpsEph.Toe]'; |
|
|
|
|
|
%for dtflight, see FlightTimeCorrection.m |
|
|
sin_Wk = sin(Wk); |
|
|
cos_Wk = cos(Wk); |
|
|
|
|
|
xyzM=zeros(p,3); |
|
|
% The matrix xyzM contains the ECEF coordinates of position |
|
|
sin_ik=sin(ik); |
|
|
cos_ik=cos(ik); |
|
|
xyzM(:,1)=xkp.*cos_Wk-ykp.*cos_ik.*sin_Wk; |
|
|
xyzM(:,2)=xkp.*sin_Wk+ykp.*cos_ik.*cos_Wk; |
|
|
xyzM(:,3)=ykp.*sin_ik; |
|
|
|
|
|
end %end of function GpsEph2Xyz |
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%% |
|
|
|
|
|
% Copyright 2016 Google Inc. |
|
|
% |
|
|
% Licensed under the Apache License, Version 2.0 (the "License"); |
|
|
% you may not use this file except in compliance with the License. |
|
|
% You may obtain a copy of the License at |
|
|
% |
|
|
% http://www.apache.org/licenses/LICENSE-2.0 |
|
|
% |
|
|
% Unless required by applicable law or agreed to in writing, software |
|
|
% distributed under the License is distributed on an "AS IS" BASIS, |
|
|
% WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. |
|
|
% See the License for the specific language governing permissions and |
|
|
% limitations under the License. |
|
|
|
|
|
|
|
|
|