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.