├── README.md ├── readRinex302.m └── readRinexNav.m /README.md: -------------------------------------------------------------------------------- 1 | # RINEX-reader 2 | containes MatLab RINEX 3.02 reader 3 | 4 | This function will read RINEX 3.02 multi constellation files and generate an output Matrix with all the information. 5 | Functions require: 6 | str2doubleq: a fast converter from string to double http://fr.mathworks.com/matlabcentral/fileexchange/28893-fast-string-to-double-conversion 7 | 8 | date2gpst: conversor from date (year month day hour minute second) to GPS time of week 9 | 10 | -------------------------------------------------------------------------------- /readRinex302.m: -------------------------------------------------------------------------------- 1 | 2 | function [XYZ_station,obs,observablesHeader,measurementsInterval]=readRinex302(filePath) 3 | %% This function opens RINEX 3.02 observation files. 4 | % Follows RINEX 3.02 standard. Reads Multiconstellation observables and 5 | % generates an output matrix 6 | 7 | %%% ------ Input--- %%%%%%%%%% 8 | % 9 | % filePath : path to the RINEX observables file 10 | % 11 | %%% ------ Output--- %%%%%%%%%% 12 | % 13 | % XYZ_station: ECEF coordinates of reference station or point (estimated by receiver) 14 | % 15 | % observablesHeader: Cell array containing information of observables for 16 | % each constellation. to look for GPS information type 17 | % observablesHeader{'G'} 18 | % 19 | % obs: Matrix containing observables {'week' 'epoch' 'flag' 'prn' 'C1C' 'D1C' 'S1C'} 20 | % Different for each constellation. 21 | % 22 | % This functions uses functions str2doubleq for quick conversion from 23 | % string to double. It also uses function Date2GPSTime to convert a date to 24 | % TOW. 25 | 26 | 'Loading observables...' 27 | idFile = fopen (filePath); 28 | 29 | generalHeader = {'week', 'epoch', 'flag', 'prn'}; 30 | 31 | %Initialzie values 32 | measurementsInterval = -1; 33 | 34 | %% Read header 35 | while (true) 36 | 37 | line = fgetl(idFile); %get line 38 | splitLine = strsplit(line); %Line splited by spaces 39 | 40 | if strfind(line,'APPROX POSITION XYZ') % Receiver aprox position 41 | XYZ_station=real(str2doubleq(line(1:60))); 42 | 43 | 44 | 45 | elseif ~isempty(strfind(line,'SYS / # / OBS TYPES')) % Observation types for the different constellations (C1C, D1 and S1 only ) 46 | constellation = line(1); 47 | if constellation == 'G' 48 | hasGps = 1; 49 | elseif constellation == 'R' 50 | hasGlonass = 1; 51 | elseif constellation == 'C' 52 | hasBeidou = 1; 53 | end 54 | 55 | nObservables = str2doubleq(line(2:7)); % Number of observables 56 | observables = splitLine(3:end - 7); % Take the observables only (Not the text regions) 57 | observables = [generalHeader, observables]; % Append the header, as the data will be ordered like specified in obsrvables now. 58 | 59 | if nObservables >13 %Two line case 60 | line2 = fgetl(idFile); 61 | splitLine2 = strsplit(line2); 62 | observables = [observables, splitLine2(2:end - 7) ]; 63 | end 64 | 65 | observablesHeader{uint8(constellation)} = observables; % Contains all the observables for the constellations. 66 | %use constellation letter for indexation 67 | 68 | elseif strfind(line,'INTERVAL') 69 | measurementsInterval=str2doubleq(line(5:10)); % Measurement intervals (Default 1) 70 | 71 | 72 | elseif strfind(line,'END OF HEADER'); 73 | break; % End of header loop 74 | end 75 | end 76 | 77 | 78 | 79 | 80 | if measurementsInterval == -1 %If itnerval not set interval = 1 81 | measurementsInterval = 1; 82 | end 83 | %% Read body 84 | 85 | obs = []; % Output matrix 86 | epoch = 0; % Epoch counter 87 | nObs = 1; 88 | 89 | while(~feof(idFile)) % Until end of file 90 | line = fgetl(idFile); % Get line 91 | splitLine = strsplit(line); % Split line by spaces 92 | 93 | if strfind(line, '>') % New epoch 94 | epoch = epoch + 1; 95 | %Read time 96 | year = str2doubleq(splitLine(2)); 97 | month = str2doubleq(splitLine(3)); 98 | day = str2doubleq(splitLine(4)); 99 | hour = str2doubleq(splitLine(5)); 100 | minute = str2doubleq(splitLine(6)); 101 | second = str2doubleq(splitLine(7)); 102 | time = [year, month, day, hour, minute, second]; 103 | time=real(time); 104 | [tow,gpsWeek]=Date2GPSTime(time(1),time(2),time(3),time(4)+time(5)/60+time(6)/3600); %Transform date to seconds of week 105 | 106 | currentEpoch = tow; % Output 107 | currentSatellites = str2doubleq(splitLine(9)); % Satellite information 108 | currentFlag = str2doubleq(splitLine(8)); % flag (use/not use) 109 | 110 | else 111 | error 'Loading not correct, satellites skiped' % Simple check, it should never jump if using the right rinex version 112 | end 113 | 114 | if currentSatellites == 0 115 | 'No satellites in epoch' 116 | end 117 | 118 | for i = 1:real(currentSatellites) % Read the epoch satellites 119 | line = fgetl(idFile); 120 | constellation = line(1); % First character indicates de constellation 121 | prn = str2doubleq ([line(2) line(3)]); % Satellites PRN number 122 | 123 | nObservables = cellfun('length',observablesHeader(uint8(constellation))) - 4; %The header also includes things that are not measurements 124 | measurementsPosition = (4:16:16*nObservables+4); %Vector containing the columns of the measurements. Each 16 columns theres a measurement 125 | 126 | if measurementsPosition(end) > length(line) 127 | measurementsPosition(end) = length(line); %Correction of a wierd bug 128 | end 129 | 130 | measurementsValue = zeros(1,nObservables); %Initialize vector to store data 131 | for m = 1:nObservables % Number of observables in the line (Generally 3) 132 | value = line(measurementsPosition(m):measurementsPosition(m+1)); % Column position of measurement. Measurements take 16 columns 133 | measurementsValue(m) = str2doubleq(value); % convert string to double 134 | end 135 | 136 | measurementsValue = real(measurementsValue); % output of str2doubleq is imaginary 137 | if measurementsValue(1) == 0 % if PSR value equals 0 138 | continue; % Skip line (Satellite has no information on L1) 139 | end 140 | switch constellation %Asign constellation based on first char of line 141 | 142 | case 'G' %GPS 143 | prn = prn+1000; 144 | case 'R' 145 | prn = prn+2000; 146 | case 'S' 147 | prn = prn+3000; 148 | case 'E' 149 | prn = prn+4000; 150 | case 'C' 151 | prn = prn+5000; 152 | otherwise 153 | error 'Unrecognized constellation' %Probably 'J' for QZSS 154 | end 155 | 156 | data = [gpsWeek, currentEpoch,currentFlag,prn,measurementsValue]; % store data 157 | obs{nObs} = real(data); 158 | nObs= nObs+1; 159 | end 160 | 161 | 162 | end 163 | 164 | %Convert cell array to matrix. This is necesary to adapt to the rest of the 165 | %alogrithm. Might give problems when different constellations have more 166 | %observables. 167 | obs = cell2mat(obs'); 168 | 169 | 'Observables loaded' 170 | fclose(idFile); -------------------------------------------------------------------------------- /readRinexNav.m: -------------------------------------------------------------------------------- 1 | function [ outputEphemeris] = readRinexNav( filePath ) 2 | %readRinexNav Reads a mixed RINEX navigation file *.nav and returns the 3 | %loaded ephemeris for each constellation 4 | % Reads Keplerian and Cartesian type ephemeris coming from RINEX 3.02 5 | % Files can be downlaoded from here: ftp://cddis.gsfc.nasa.gov/gnss/data/campaign/mgex/daily/rinex3/2015/ 6 | % Download in *.p format and convert to .nav using rtklib 7 | 8 | %%%%%-------Input 9 | % fileName = File adress 10 | 11 | %%%%%------- Output 12 | % outputEphemeris = Class containing the ephemeris for each 13 | % constellation 14 | 15 | 16 | 'Loading ephemeris...' 17 | endOfHeader = 0; 18 | 19 | navFile = fopen(filePath); 20 | 21 | %Read header 22 | while (~endOfHeader) 23 | line = fgetl(navFile); 24 | lineSplit = strsplit(line); 25 | 26 | if strfind(line,'RINEX VERSION') 27 | Version = lineSplit(2); 28 | if ~strcmp(Version,'3.02') 29 | error 'Not the correct version, should be 3.02' 30 | end 31 | 32 | 33 | elseif strfind(line,'DATE') 34 | date = lineSplit(3); 35 | year = str2doubleq(date{1,1}(1:4)); 36 | month = str2doubleq(date{1,1}(5:6)); 37 | day = str2doubleq(date{1,1}(7:8)); 38 | DOY=Date2DayOfYear(real(year),real(month),real(day)); 39 | elseif strfind(line,'IONOSPHERIC CORR') 40 | if strcmp(lineSplit(1), 'GPSA') 41 | ionoAlpha = str2doubleq(lineSplit(2:5)); 42 | elseif strcmp(lineSplit(1), 'GPSB') 43 | ionoBeta = str2doubleq(lineSplit(2:5)); 44 | end 45 | elseif strfind (line,'LEAP SECONDS') 46 | leapSeconds = str2doubleq(lineSplit(2)); 47 | elseif strfind(line,'END OF HEADER') 48 | endOfHeader = 1; 49 | end 50 | end 51 | 52 | %Pointer line set at the end of the header. 53 | ionosphericParameters = [ionoAlpha; ionoBeta]; 54 | 55 | 56 | %read body 57 | 58 | gpsEphemeris = []; 59 | glonassEphemeris = []; 60 | beidouEphemeris = []; 61 | 62 | keplerArray = zeros(22,1); %Vector containing Keplerian elements type ephemeris (GPS, Beidou, Galileo) 63 | cartesianArray = zeros(19,1); %Vector containing Cartesian type ephemeris (GLONASS, SBAS) 64 | while ~feof(navFile) 65 | line = fgetl(navFile); 66 | lineSplit = strsplit(line); 67 | 68 | constellation = line(1); 69 | if ischar(constellation) %New Ephemeris 70 | switch constellation 71 | case {'G', 'C'} %If the ephemeris is ether for GPS or Beidou, store Keplerian elements 72 | 73 | %%Read All of the ephemeris 74 | svprn = str2doubleq([line(2), line(3)]); 75 | af0 = str2doubleq(lineSplit(end-2)); %Read from end because of 1 digit prn 76 | af1 = str2doubleq(lineSplit(end-1)); 77 | af2 = str2doubleq(lineSplit(end)); 78 | 79 | lineSplit = strsplit(fgetl(navFile)); % 80 | IODE = str2doubleq(lineSplit(2)); 81 | crs = str2doubleq(lineSplit(3)); 82 | deltan = str2doubleq(lineSplit(4)); 83 | M0 = str2doubleq(lineSplit(5)); 84 | 85 | lineSplit = strsplit(fgetl(navFile)); % 86 | cuc = str2doubleq(lineSplit(2)); 87 | ecc = str2doubleq(lineSplit(3)); 88 | cus = str2doubleq(lineSplit(4)); 89 | roota = str2doubleq(lineSplit(5)); 90 | 91 | lineSplit = strsplit(fgetl(navFile)); 92 | toe = str2doubleq(lineSplit(2)); 93 | cic = str2doubleq(lineSplit(3)); 94 | Omega0 = str2doubleq(lineSplit(4)); 95 | cis = str2doubleq(lineSplit(5)); 96 | 97 | lineSplit = strsplit(fgetl(navFile)); % 98 | i0 = str2doubleq(lineSplit(2)); 99 | crc = str2doubleq(lineSplit(3)); 100 | omega = str2doubleq(lineSplit(4)); 101 | Omegadot = str2doubleq(lineSplit(5)); 102 | 103 | lineSplit = strsplit(fgetl(navFile)); % 104 | idot = str2doubleq(lineSplit(2)); 105 | CodesOnL2 = str2doubleq(lineSplit(3)); 106 | week_toe = str2doubleq(lineSplit(4)); 107 | L2Pflag = str2doubleq(lineSplit(5)); 108 | 109 | lineSplit = strsplit(fgetl(navFile)); % 110 | SVaccuracy = str2doubleq(lineSplit(2)); 111 | SVhealth = str2doubleq(lineSplit(3)); 112 | tgd = str2doubleq(lineSplit(4)); 113 | IODC = str2doubleq(lineSplit(5)); 114 | 115 | lineSplit = strsplit(fgetl(navFile)); 116 | transmissionTime = str2doubleq(lineSplit(2)); 117 | fitInterval = str2doubleq(lineSplit(3)); 118 | 119 | %Conversion to the format required by function 120 | %sat_coordinates_XYZ 121 | keplerArray(1) = svprn; 122 | keplerArray(2) = af2; 123 | keplerArray(3) = M0; 124 | keplerArray(4) = roota; 125 | keplerArray(5) = deltan; 126 | keplerArray(6) = ecc; 127 | keplerArray(7) = omega; 128 | keplerArray(8) = cuc; 129 | keplerArray(9) = cus; 130 | keplerArray(10) = crc; 131 | keplerArray(11) = crs; 132 | keplerArray(12) = i0; 133 | keplerArray(13) = idot; 134 | keplerArray(14) = cic; 135 | keplerArray(15) = cis; 136 | keplerArray(16) = Omega0; 137 | keplerArray(17) = Omegadot; 138 | keplerArray(18) = toe; 139 | keplerArray(19) = af0; 140 | keplerArray(20) = af1; 141 | keplerArray(21) = toe; 142 | keplerArray(22) = tgd; 143 | 144 | if constellation == 'G' 145 | gpsEphemeris = [gpsEphemeris keplerArray]; 146 | elseif constellation == 'C' 147 | beidouEphemeris = [beidouEphemeris keplerArray]; 148 | else 149 | error 'Unknown constellation' 150 | %Should never reach this point, as there is a case 151 | %above. 152 | end 153 | 154 | case 'R' %Also SBAS case 155 | slot_sv=str2doubleq(line(2:3)); 156 | %Time of Emision 157 | ToE(1)=str2doubleq(lineSplit(end-8)); %Star from the end to avoid problems with 1 digit prn 158 | ToE(2)=str2doubleq(lineSplit(end-7)); 159 | ToE(3)=str2doubleq(lineSplit(end-6)); 160 | ToE(4)=str2doubleq(lineSplit(end-5)); 161 | ToE(5)=str2doubleq(lineSplit(end-4)); 162 | ToE(6)=str2doubleq(lineSplit(end-3)); 163 | ToE = real(ToE); 164 | [toe,week]=Date2GPSTime(ToE(1),ToE(2),ToE(3),ToE(4)+ToE(5)/60+ToE(6)/3600); 165 | sv_clock_bias=str2doubleq(lineSplit(end-2)); 166 | sv_rel_freq_bias=str2doubleq(lineSplit(end-1)); 167 | m_f_t=str2doubleq(lineSplit(end)); 168 | 169 | lineSplit = strsplit(fgetl(navFile));%%% 170 | X=str2doubleq(lineSplit(2)); 171 | Xdot=str2doubleq(lineSplit(3)); 172 | Xacc=str2doubleq(lineSplit(4)); 173 | health=str2doubleq(lineSplit(5)); 174 | 175 | lineSplit = strsplit(fgetl(navFile));%%% 176 | Y=str2doubleq(lineSplit(2)); 177 | Ydot=str2doubleq(lineSplit(3)); 178 | Yacc=str2doubleq(lineSplit(4)); 179 | freq_num=str2doubleq(lineSplit(5)); 180 | 181 | lineSplit = strsplit(fgetl(navFile));%%% 182 | Z=str2doubleq(lineSplit(2)); 183 | Zdot=str2doubleq(lineSplit(3)); 184 | Zacc=str2doubleq(lineSplit(4)); 185 | age_oper_info=str2doubleq(lineSplit(5)); 186 | 187 | cartesianArray(1)=slot_sv; 188 | cartesianArray(2)=toe; 189 | cartesianArray(3)=sv_clock_bias; 190 | cartesianArray(4)=sv_rel_freq_bias; 191 | cartesianArray(5)=m_f_t; 192 | cartesianArray(6)=X; 193 | cartesianArray(7)=Xdot; 194 | cartesianArray(8)=Xacc; 195 | cartesianArray(9)=health; 196 | cartesianArray(10)=Y; 197 | cartesianArray(11)=Ydot; 198 | cartesianArray(12)=Yacc; 199 | cartesianArray(13)=freq_num; 200 | cartesianArray(14)=Z; 201 | cartesianArray(15)=Zdot; 202 | cartesianArray(16)=Zacc; 203 | cartesianArray(17)=age_oper_info; 204 | cartesianArray(18)=1; 205 | cartesianArray(19)=week; 206 | 207 | if constellation == 'R' 208 | glonassEphemeris = [glonassEphemeris, cartesianArray]; 209 | elseif constellation == 'S' 210 | 211 | 212 | end 213 | 214 | otherwise 215 | %error 'Unknown constellation' 216 | 217 | 218 | end 219 | 220 | else 221 | error ('Wrong counting. New ephemeris expected.') 222 | end 223 | 224 | end 225 | 226 | % Construct output 227 | outputEphemeris.glonassEphemeris = real(glonassEphemeris); 228 | outputEphemeris.gpsEphemeris = real(gpsEphemeris); 229 | outputEphemeris.beidouEphemeris = real(beidouEphemeris); 230 | outputEphemeris.ionosphericParameters = real(ionosphericParameters); 231 | outputEphemeris.DOY = real(DOY); 232 | outputEphemeris.leapSeconds = real(leapSeconds); 233 | 234 | 235 | fclose(navFile); 236 | 'Ephemeris loaded correctly' 237 | 238 | 239 | end 240 | --------------------------------------------------------------------------------