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.