|
|
|
|
function [gpsEph,iono] = ReadRinexNav(fileName)
|
|
|
|
|
% [gpsEph,iono] = ReadRinexNav(fileName)
|
|
|
|
|
%
|
|
|
|
|
% Read GPS ephemeris and iono data from an ASCII formatted RINEX 2.10 Nav file.
|
|
|
|
|
% Input:
|
|
|
|
|
% fileName - string containing name of RINEX formatted navigation data file
|
|
|
|
|
% Output:
|
|
|
|
|
% gpsEph: vector of ephemeris data, each element is an ephemeris structure
|
|
|
|
|
% structure order and orbit variable names follow RINEX 2.1 Table A4
|
|
|
|
|
% clock variable names af0, af1, af2 follow IS GPS 200
|
|
|
|
|
% gpsEph(i).PRN % SV PRN number
|
|
|
|
|
% gpsEph(i).Toc % Time of clock (seconds)
|
|
|
|
|
% gpsEph(i).af0 % SV clock bias (seconds)
|
|
|
|
|
% gpsEph(i).af1 % SV clock drift (sec/sec)
|
|
|
|
|
% gpsEph(i).af2 % SV clock drift rate (sec/sec2)
|
|
|
|
|
% gpsEph(i).IODE % Issue of data, ephemeris
|
|
|
|
|
% gpsEph(i).Crs % Sine harmonic correction to orbit radius (meters)
|
|
|
|
|
% gpsEph(i).Delta_n % Mean motion difference from computed value (radians/sec)
|
|
|
|
|
% gpsEph(i).M0 % Mean anomaly at reference time (radians)
|
|
|
|
|
% gpsEph(i).Cuc % Cosine harmonic correction to argument of lat (radians)
|
|
|
|
|
% gpsEph(i).e % Eccentricity (dimensionless)
|
|
|
|
|
% gpsEph(i).Cus % Sine harmonic correction to argument of latitude (radians)
|
|
|
|
|
% gpsEph(i).Asqrt % Square root of semi-major axis (meters^1/2)
|
|
|
|
|
% gpsEph(i).Toe % Reference time of ephemeris (seconds)
|
|
|
|
|
% gpsEph(i).Cic % Cosine harmonic correction to angle of inclination (radians)
|
|
|
|
|
% gpsEph(i).OMEGA % Longitude of ascending node at weekly epoch (radians)
|
|
|
|
|
% gpsEph(i).Cis % Sine harmonic correction to angle of inclination (radians)
|
|
|
|
|
% gpsEph(i).i0 % Inclination angle at reference time (radians)
|
|
|
|
|
% gpsEph(i).Crc % Cosine harmonic correction to the orbit radius (meters)
|
|
|
|
|
% gpsEph(i).omega % Argument of perigee (radians)
|
|
|
|
|
% gpsEph(i).OMEGA_DOT% Rate of right ascension (radians/sec)
|
|
|
|
|
% gpsEph(i).IDOT % Rate of inclination angle (radians/sec)
|
|
|
|
|
% gpsEph(i).codeL2 % codes on L2 channel
|
|
|
|
|
% gpsEph(i).GPS_Week % GPS week (to go with Toe), (NOT Mod 1024)
|
|
|
|
|
% gpsEph(i).L2Pdata % L2 P data flag
|
|
|
|
|
% gpsEph(i).accuracy % SV user range accuracy (meters)
|
|
|
|
|
% gpsEph(i).health % Satellite health
|
|
|
|
|
% gpsEph(i).TGD % Group delay (seconds)
|
|
|
|
|
% gpsEph(i).IODC % Issue of Data, Clock
|
|
|
|
|
% gpsEph(i).ttx % Transmission time of message (seconds)
|
|
|
|
|
% gpsEph(i).Fit_interval %fit interval (hours), zero if not known
|
|
|
|
|
%
|
|
|
|
|
% iono: ionospheric parameter structure
|
|
|
|
|
% iono.alpha = [alpha0, alpha1, alpha2, alpha3]
|
|
|
|
|
% iono.beta = [ beta0, beta1, beta2, beta3]
|
|
|
|
|
% if iono data is not present in the Rinex file, iono is returned empty.
|
|
|
|
|
|
|
|
|
|
fidEph = fopen(fileName);
|
|
|
|
|
[numEph,numHdrLines] = countEph(fidEph);
|
|
|
|
|
|
|
|
|
|
%Now read from the begining again, looking for iono parameters
|
|
|
|
|
frewind(fidEph);
|
|
|
|
|
iono = readIono(fidEph,numHdrLines);
|
|
|
|
|
|
|
|
|
|
%initialize ephemeris structure array:
|
|
|
|
|
gpsEph = InitializeGpsEph;
|
|
|
|
|
gpsEph = repmat(gpsEph,1,numEph);
|
|
|
|
|
|
|
|
|
|
%now read each ephemeris into gpsEph(j)
|
|
|
|
|
%RINEX defines the format in terms of numbers of characters, so that's how we
|
|
|
|
|
%read it, e.g. "gpsEph(j).PRN = str2num(line(1:2));" and so on
|
|
|
|
|
for j = 1:numEph
|
|
|
|
|
line = fgetl(fidEph);
|
|
|
|
|
gpsEph(j).PRN = str2num(line(1:2));
|
|
|
|
|
%NOTE: we use str2num, not str2double, since str2num handles 'D' for exponent
|
|
|
|
|
|
|
|
|
|
%% get Toc (Rinex gives this as UTC time yy,mm,dd,hh,mm,ss)
|
|
|
|
|
year = str2num(line(3:6));
|
|
|
|
|
%convert year to a 4-digit year, this code is good to the year 2080.
|
|
|
|
|
%From 2080 RINEX 2.1 is ambiguous and shouldnt be used, because is has a
|
|
|
|
|
%2-digit year, and 100 years will have passed since the GPS Epoch.
|
|
|
|
|
if year < 80,
|
|
|
|
|
year = 2000+year;
|
|
|
|
|
else
|
|
|
|
|
year = 1900+year;
|
|
|
|
|
end
|
|
|
|
|
month = str2num(line(7:9));
|
|
|
|
|
day = str2num(line(10:12));
|
|
|
|
|
hour = str2num(line(13:15));
|
|
|
|
|
minute = str2num(line(16:18));
|
|
|
|
|
second = str2num(line(19:22));
|
|
|
|
|
%convert Toc to gpsTime
|
|
|
|
|
gpsTime = Utc2Gps([year,month,day,hour,minute,second]);
|
|
|
|
|
gpsEph(j).Toc = gpsTime(2);
|
|
|
|
|
%% get all other parameters
|
|
|
|
|
gpsEph(j).af0 = str2num(line(23:41));
|
|
|
|
|
gpsEph(j).af1 = str2num(line(42:60));
|
|
|
|
|
gpsEph(j).af2 = str2num(line(61:79));
|
|
|
|
|
|
|
|
|
|
line = fgetl(fidEph);
|
|
|
|
|
gpsEph(j).IODE = str2num(line(4:22));
|
|
|
|
|
gpsEph(j).Crs = str2num(line(23:41));
|
|
|
|
|
gpsEph(j).Delta_n = str2num(line(42:60));
|
|
|
|
|
gpsEph(j).M0 = str2num(line(61:79));
|
|
|
|
|
|
|
|
|
|
line = fgetl(fidEph);
|
|
|
|
|
gpsEph(j).Cuc = str2num(line(4:22));
|
|
|
|
|
gpsEph(j).e = str2num(line(23:41));
|
|
|
|
|
gpsEph(j).Cus = str2num(line(42:60));
|
|
|
|
|
gpsEph(j).Asqrt = str2num(line(61:79));
|
|
|
|
|
|
|
|
|
|
line=fgetl(fidEph);
|
|
|
|
|
gpsEph(j).Toe = str2num(line(4:22));
|
|
|
|
|
gpsEph(j).Cic = str2num(line(23:41));
|
|
|
|
|
gpsEph(j).OMEGA = str2num(line(42:60));
|
|
|
|
|
gpsEph(j).Cis = str2num(line(61:79));
|
|
|
|
|
|
|
|
|
|
line = fgetl(fidEph);
|
|
|
|
|
gpsEph(j).i0 = str2num(line(4:22));
|
|
|
|
|
gpsEph(j).Crc = str2num(line(23:41));
|
|
|
|
|
gpsEph(j).omega = str2num(line(42:60));
|
|
|
|
|
gpsEph(j).OMEGA_DOT = str2num(line(61:79));
|
|
|
|
|
|
|
|
|
|
line = fgetl(fidEph);
|
|
|
|
|
gpsEph(j).IDOT = str2num(line(4:22));
|
|
|
|
|
gpsEph(j).codeL2 = str2num(line(23:41));
|
|
|
|
|
gpsEph(j).GPS_Week = str2num(line(42:60));
|
|
|
|
|
gpsEph(j).L2Pdata = str2num(line(61:79));
|
|
|
|
|
|
|
|
|
|
line = fgetl(fidEph);
|
|
|
|
|
gpsEph(j).accuracy = str2num(line(4:22));
|
|
|
|
|
gpsEph(j).health = str2num(line(23:41));
|
|
|
|
|
gpsEph(j).TGD = str2num(line(42:60));
|
|
|
|
|
gpsEph(j).IODC = str2num(line(61:79));
|
|
|
|
|
|
|
|
|
|
line = fgetl(fidEph);
|
|
|
|
|
gpsEph(j).ttx = str2num(line(4:22));
|
|
|
|
|
gpsEph(j).Fit_interval = str2num(line(23:41));
|
|
|
|
|
end
|
|
|
|
|
fclose(fidEph);
|
|
|
|
|
|
|
|
|
|
end %end of function ReadRinexNav
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
|
|
|
|
function [numEph,numHdrLines] = countEph(fidEph,fileName)
|
|
|
|
|
%utility function for ReadRinexNav
|
|
|
|
|
%Read past the header, and then read to the end, counting ephemerides:
|
|
|
|
|
numHdrLines = 0;
|
|
|
|
|
bFoundHeader = false;
|
|
|
|
|
while ~bFoundHeader %Read past the header
|
|
|
|
|
numHdrLines = numHdrLines+1;
|
|
|
|
|
line = fgetl(fidEph);
|
|
|
|
|
if ~ischar(line), break, end
|
|
|
|
|
k = strfind(line,'END OF HEADER');
|
|
|
|
|
if ~isempty(k),
|
|
|
|
|
bFoundHeader = true;
|
|
|
|
|
break
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
if ~bFoundHeader
|
|
|
|
|
error('Error reading file: %s\nExpected RINEX header not found',fileName);
|
|
|
|
|
end
|
|
|
|
|
%Now read to the end of the file
|
|
|
|
|
numEph = -1;
|
|
|
|
|
while 1
|
|
|
|
|
numEph = numEph+1;
|
|
|
|
|
line = fgetl(fidEph);
|
|
|
|
|
if line == -1,
|
|
|
|
|
break;
|
|
|
|
|
elseif length(line)~=79
|
|
|
|
|
%use this opportunity to check line is the right length
|
|
|
|
|
%because in the rest of ReadRinexNav we depend on line being this length
|
|
|
|
|
error('Incorrect line length encountered in RINEX file');
|
|
|
|
|
end
|
|
|
|
|
end;
|
|
|
|
|
%check that we read the expected number of lines:
|
|
|
|
|
if rem(numEph,8)~=0
|
|
|
|
|
error('Number of nav lines in %s should be divisible by 8',fileName);
|
|
|
|
|
end
|
|
|
|
|
numEph = numEph/8; %8 lines per ephemeris
|
|
|
|
|
|
|
|
|
|
end %end of function countEph
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
|
|
|
|
function iono = readIono(fidEph,numHdrLines)
|
|
|
|
|
%utility function to read thru the header lines, and find iono parameters
|
|
|
|
|
|
|
|
|
|
iono = []; %return empty if iono not found
|
|
|
|
|
bIonoAlpha=false; bIonoBeta=false;
|
|
|
|
|
|
|
|
|
|
for i = 1:numHdrLines,
|
|
|
|
|
line = fgetl(fidEph);
|
|
|
|
|
% Look for iono parameters, and read them in
|
|
|
|
|
if ~isempty(strfind(line,'ION ALPHA')) %line contains iono alpha parameters
|
|
|
|
|
ii = strfind(line,'ION ALPHA');
|
|
|
|
|
iono.alpha=str2num(line(1:ii-1));
|
|
|
|
|
%If we have 4 parameters then we have the complete iono alpha
|
|
|
|
|
bIonoAlpha = (length(iono.alpha)==4);
|
|
|
|
|
end
|
|
|
|
|
if ~isempty(strfind(line,'ION BETA'))%line contains the iono beta parameters
|
|
|
|
|
ii = strfind(line,'ION BETA');
|
|
|
|
|
iono.beta=str2num(line(1:ii-1));
|
|
|
|
|
%If we have 4 parameters then we have the complete iono beta
|
|
|
|
|
bIonoBeta = (length(iono.beta)==4);
|
|
|
|
|
end
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
if ~(bIonoAlpha && bIonoBeta)
|
|
|
|
|
%if we didn't get both alpha and beta iono correctly, then return empty iono
|
|
|
|
|
iono=[];
|
|
|
|
|
end
|
|
|
|
|
|
|
|
|
|
end %end of function readIono
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
function gpsEph = InitializeGpsEph
|
|
|
|
|
%utility function to initialize the ephemeris structure
|
|
|
|
|
gpsEph.PRN = 0;
|
|
|
|
|
gpsEph.Toc = 0;
|
|
|
|
|
gpsEph.af0 = 0;
|
|
|
|
|
gpsEph.af1 = 0;
|
|
|
|
|
gpsEph.af2 = 0;
|
|
|
|
|
gpsEph.IODE = 0;
|
|
|
|
|
gpsEph.Crs = 0;
|
|
|
|
|
gpsEph.Delta_n = 0;
|
|
|
|
|
gpsEph.M0 = 0;
|
|
|
|
|
gpsEph.Cuc = 0;
|
|
|
|
|
gpsEph.e = 0;
|
|
|
|
|
gpsEph.Cus = 0;
|
|
|
|
|
gpsEph.Asqrt = 0;
|
|
|
|
|
gpsEph.Toe = 0;
|
|
|
|
|
gpsEph.Cic = 0;
|
|
|
|
|
gpsEph.OMEGA = 0;
|
|
|
|
|
gpsEph.Cis = 0;
|
|
|
|
|
gpsEph.i0 = 0;
|
|
|
|
|
gpsEph.Crc = 0;
|
|
|
|
|
gpsEph.omega = 0;
|
|
|
|
|
gpsEph.OMEGA_DOT = 0;
|
|
|
|
|
gpsEph.IDOT = 0;
|
|
|
|
|
gpsEph.codeL2 = 0;
|
|
|
|
|
gpsEph.GPS_Week = 0;
|
|
|
|
|
gpsEph.L2Pdata = 0;
|
|
|
|
|
gpsEph.accuracy = 0;
|
|
|
|
|
gpsEph.health = 0;
|
|
|
|
|
gpsEph.TGD = 0;
|
|
|
|
|
gpsEph.IODC = 0;
|
|
|
|
|
gpsEph.ttx = 0;
|
|
|
|
|
gpsEph.Fit_interval= 0;
|
|
|
|
|
|
|
|
|
|
end %end of function InitializeEph
|
|
|
|
|
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
% 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.
|