From 686429dba2bb2c2f5f00a9de1a2711ff6c6b5134 Mon Sep 17 00:00:00 2001 From: Pierre Sakic Date: Thu, 11 Jun 2026 17:45:36 +0200 Subject: [PATCH 1/3] (re)add read-spotgins (v2 & v3) --- CODE/etc/rawformats.conf | 4 +- CODE/matlab/readfmtdata.m | 2 +- CODE/matlab/readfmtdata_gnss.m | 97 ++++++++++++++++++++++++++++------ 3 files changed, 84 insertions(+), 19 deletions(-) diff --git a/CODE/etc/rawformats.conf b/CODE/etc/rawformats.conf index 5755fa24..34d189e5 100644 --- a/CODE/etc/rawformats.conf +++ b/CODE/etc/rawformats.conf @@ -22,8 +22,8 @@ winston|EARTHWORM|EarthWorm Winston Wave Server data request||host:port gipsy|GNSS|JPL GIPSY-OASIS .tdp file|ANTENNA,RECEIVER,XYZ|fullpath of root directory containing YYYY/FID/*.tdp files gipsyx|GNSS|JPL GipsyX .tdp file|ANTENNA,RECEIVER,XYZ|fullpath of root directory containing YYYY/FID/*.tdp files globkval|GNSS|MIT GAMIT/GLOBK VAL file||fullpath of directory containing the .VAL file -spotgins-enu-v2|GNSS|SPOTGINS solutions - version 2 (<2025-08)||fullpath of file(s) with bash wildcard facilities, possible $FID, or URL to single file -spotgins-ippp|GNSS|SPOTGINS IPPP time series||fullpath of file(s) with bash wildcard facilities, possible $FID, or URL to single file +spotgins-enu|GNSS|SPOTGINS ENU solutions - v2&3||fullpath of file(s) with bash wildcard facilities, possible $FID, or URL to single file +spotgins-ippp|GNSS|SPOTGINS IPPP time series (ITES)||fullpath of file(s) with bash wildcard facilities, possible $FID, or URL to single file gamit-pos|GNSS|MIT GAMIT/GLOBL POS time series||fullpath of file(s) with bash wildcard facilities, possible $FID, or URL to single file pbogps-pos|GNSS|PBO GPS POS time series||fullpath of file(s) with bash wildcard facilities, possible $FID, or URL to single file usgs-rneu|GNSS|USGS RNEU text file||fullpath of file(s) with bash wildcard facilities diff --git a/CODE/matlab/readfmtdata.m b/CODE/matlab/readfmtdata.m index 57399a7d..22122889 100644 --- a/CODE/matlab/readfmtdata.m +++ b/CODE/matlab/readfmtdata.m @@ -69,7 +69,7 @@ case {'miniseed','seedlink','arclink','combined','fdsnws-dataselect'} D(n) = readfmtdata_miniseed(WO,P,N(n),F); - case {'globkval','gipsy','gipsyx','gipsy-tdp','usgs-rneu','ies-neu','ogc-neu','ingv-gps','sbe37-ascii','spotgins-enu-v2','spotgins-ippp','gamit-pos','pbogps-pos'} + case {'globkval','gipsy','gipsyx','gipsy-tdp','usgs-rneu','ies-neu','ogc-neu','ingv-gps','sbe37-ascii','spotgins-enu','spotgins-ippp','gamit-pos','pbogps-pos'} D(n) = readfmtdata_gnss(WO,P,N(n),F); case {'hyp71sum2k','fdsnws-event','scevtlog-xml'} diff --git a/CODE/matlab/readfmtdata_gnss.m b/CODE/matlab/readfmtdata_gnss.m index 4912f8af..e8ce6611 100644 --- a/CODE/matlab/readfmtdata_gnss.m +++ b/CODE/matlab/readfmtdata_gnss.m @@ -40,6 +40,13 @@ % data format: jjjjj.jj E N V dE dN dV yyyymmddhhmmss yyyy.yyyyyyyyy % node calibration: no .CLB file or 4 components (East, North, Up) in meters and (Orbit) % +% format 'spotgins-enu' +% type: SPOTGINS solutions - supports v2 and v3 formats (auto-detection) +% filename/url: P.RAWDATA (use $FID to point the right file/url) +% data format v2: jjjjj.jj E N V dE dN dV yyyymmddhhmmss yyyy.yyyyyyyyy +% data format v3: MJD DispEast DispNorth DispUp SigmaEast SigmaNorth SigmaUp CorrEN CorrEU CorrNU yyyy-mm-ddTHH:MM:SS DecimalYear Const Flag DateOfExe GinsVersion PrairieVersion +% node calibration: no .CLB file or 4 components (East, North, Up) in meters and (Orbit)READFMTDATA_GNSS subfunction of readfmtdata.m +% % format 'spotgins-ippp' % type: GINS IPPP solutions % filename/url: P.RAWDATA (use $FID to point the right file/url) @@ -306,19 +313,66 @@ end %D.ITRF_YEAR = 'ITRF08'; - % ----------------------------------------------------------------------------- -case 'spotgins-enu-v2' - % format exemple - %#jjjjj.jjjjjjjj _____E _____N _____U ____dE ____dN ____dU yyyymmddHHMMSS yyyy.yyyyyyy Const Dateofexe GinsVersion - % 52670.83876160 0.055822 0.051638 0.005578 0.001263 0.001163 0.004899 20030131200749 2003.0844898 G 250404_185253 VALIDE_24_2 - % 52671.50195600 0.057207 0.054240 -0.004722 0.000705 0.000619 0.002600 20030201120249 2003.0863067 G 250404_185253 VALIDE_24_2 - +case 'spotgins-enu' + % Supports both v2 and v3 SPOTGINS formats + % + % v2 format example: + %#jjjjj.jjjjjjjj _____E _____N _____U ____dE ____dN ____dU yyyymmddHHMMSS yyyy.yyyyyyy Const Dateofexe GinsVersion + % 52670.83876160 0.055822 0.051638 0.005578 0.001263 0.001163 0.004899 20030131200749 2003.0844898 G 250404_185253 VALIDE_24_2 + % 52671.50195600 0.057207 0.054240 -0.004722 0.000705 0.000619 0.002600 20030201120249 2003.0863067 G 250404_185253 VALIDE_24_2 + % + % v3 format example: + %#MJD DispEast DispNorth DispUp SigmaEast SigmaNorth SigmaUp CorrEN CorrEU CorrNU yyyy-mm-ddTHH:MM:SS DecimalYear Const Flag DateOfExe GinsVersion PrairieVersion + % 51668.5 0.080276 -2.058358 0.009854 0.000312 0.000439 0.001339 -0.028963 -0.085824 -0.011884 2000-05-04T12:00:00 2000.340164 G 0 250910_120313 25_1 v56 + % 51669.5 0.077154 -2.057207 0.005923 0.000257 0.000371 0.001109 -0.017412 -0.060937 -0.124317 2000-05-05T12:00:00 2000.342896 G 0 250910_120313 25_1 v56 + fdat = sprintf('%s/%s.dat',F.ptmp,N.ID); wosystem(sprintf('rm -f %s',fdat),P); + + % Detect format version from first file + format_version = ''; + if ~isempty(F.raw) + first_raw = F.raw{1}; + if strncmpi('http',first_raw,4) + [s,header] = wosystem(sprintf('curl -s -S "%s" | head -20',first_raw),P); + else + [s,header] = wosystem(sprintf('head -20 %s',first_raw),P); + end + if s == 0 + if ~isempty(strfind(header,'SPOTGINS SOLUTION [POSITION] v3')) || ~isempty(strfind(header,'MJD DispEast')) + format_version = 'v3'; + elseif ~isempty(strfind(header,'SPOTGINS SOLUTION [POSITION] v2')) || ~isempty(strfind(header,'jjjjj.jjjjjjjj')) + format_version = 'v2'; + else + % Try to detect from data columns (fallback method) + if strncmpi('http',first_raw,4) + [s,sample] = wosystem(sprintf('curl -s -S "%s" | grep -v "^#" | head -1',first_raw),P); + else + [s,sample] = wosystem(sprintf('grep -v "^#" %s | head -1',first_raw),P); + end + if s == 0 && ~isempty(sample) + cols = length(strsplit(strtrim(sample))); + if cols >= 17 % v3 has 17+ columns + format_version = 'v3'; + elseif cols >= 11 % v2 has 11+ columns + format_version = 'v2'; + end + end + end + end + end + + if isempty(format_version) + format_version = 'v2'; % default fallback + fprintf('%s: ** INFO ** Could not detect SPOTGINS format version, assuming v2.\n',wofun); + else + fprintf('%s: ** INFO ** Detected SPOTGINS format %s.\n',wofun,format_version); + end + for a = 1:length(F.raw) fraw = F.raw{a}; - cmd0 = sprintf('awk ''/^[^#]/ {print}'' >> %s',fdat); % removes header lines + cmd0 = sprintf('awk ''/^[^#]/ {print}'' >> %s',fdat); % removes header lines if strncmpi('http',fraw,4) s = wosystem(sprintf('curl -s -S "%s" | %s',fraw,cmd0),P); if s ~= 0 @@ -331,20 +385,31 @@ fprintf('%s: ** WARNING ** Raw data "%s" not found.\n',wofun,fraw); end end - - - % load the file + + % load the file if exist(fdat,'file') dd = dlmread(fdat); else dd = []; end + if ~isempty(dd) - t = dd(:,1) + 678941.5007; % converts MJD to datenum - d = [dd(:,2:4),zeros(size(dd,1),1)]; % North(mm),East(mm),Up(mm) => E(m),N(m),U(m),Orbit - e = dd(:,5:7); + switch format_version + case 'v3' + % v3 format: MJD DispEast DispNorth DispUp SigmaEast SigmaNorth SigmaUp ... + t = dd(:,1) + 678941.5007; % converts MJD to datenum + d = [dd(:,2:4),zeros(size(dd,1),1)]; % DispEast,DispNorth,DispUp,Orbit => E(m),N(m),U(m),Orbit + e = dd(:,5:7); % SigmaEast,SigmaNorth,SigmaUp + + case 'v2' + % v2 format: jjjjj.jj E N U dE dN dU ... + t = dd(:,1) + 678941.5007; % converts MJD to datenum + d = [dd(:,2:4),zeros(size(dd,1),1)]; % E,N,U,Orbit => E(m),N(m),U(m),Orbit + e = dd(:,5:7); % dE,dN,dU + end + e(e Date: Thu, 11 Jun 2026 19:16:32 +0200 Subject: [PATCH 2/3] add read_rtklib --- CODE/matlab/readfmtdata_gnss.m | 97 +++++++++++++++ CODE/matlab/test_readfmtdata_gnss_rtklib.m | 130 +++++++++++++++++++++ 2 files changed, 227 insertions(+) create mode 100644 CODE/matlab/test_readfmtdata_gnss_rtklib.m diff --git a/CODE/matlab/readfmtdata_gnss.m b/CODE/matlab/readfmtdata_gnss.m index e8ce6611..051135e2 100644 --- a/CODE/matlab/readfmtdata_gnss.m +++ b/CODE/matlab/readfmtdata_gnss.m @@ -83,6 +83,16 @@ % data format: ascii % node calibration: no .CLB file or 4 components (East, North, Up) in meters and (Orbit) % +% format 'rtklib' +% type: RTKLIB solution file (ENU baseline, FLH absolute, or XYZ ECEF) +% filename/url: P.RAWDATA (use $FID to point the right file/url) +% data format: yyyy/mm/dd HH:MM:SS.sss a b c Q ns s_a s_b s_c sdAB sdBC sdAC age ratio +% header lines start with %%; coordinate type auto-detected from header keywords +% ENU: e-baseline(m) n-baseline(m) u-baseline(m) +% FLH: latitude(deg) longitude(deg) height(m) - converted to UTM +% XYZ: x-ecef(m) y-ecef(m) z-ecef(m) - converted to UTM +% node calibration: no .CLB file or 4 components (East, North, Up) in meters and (Orbit) +% % % Authors: François Beauducel and Jean-Bernard de Chabalier, WEBOBS/IPGP % Created: 2016-07-10, in Yogyakarta (Indonesia) @@ -641,6 +651,93 @@ e = []; end +% ----------------------------------------------------------------------------- +case 'rtklib' + % RTKLIB solution file + % Header lines start with %. Coordinate type auto-detected from header keywords: + % 'e-baseline' => ENU, 'x-ecef' => XYZ, 'latitude' => FLH (default) + % Data format: yyyy/mm/dd HH:MM:SS.sss a b c Q ns s_a s_b s_c sdAB sdBC sdAC age ratio + + fdat = sprintf('%s/%s.dat',F.ptmp,N.ID); + wosystem(sprintf('rm -f %s',fdat),P); + + % detect coordinate type from file header + initype = 'FLH'; % RTKLIB default output is FLH + if ~isempty(F.raw) + fraw = F.raw{1}; + if strncmpi('http',fraw,4) + [~,hdr] = wosystem(sprintf('curl -s -S "%s" | head -30',fraw),P); + else + [~,hdr] = wosystem(sprintf('head -30 "%s"',fraw),P); + end + % Be more robust: check multiple keyword variants + if ~isempty(strfind(lower(hdr),'x-ecef')) || ~isempty(strfind(lower(hdr),'y-ecef')) || ~isempty(strfind(lower(hdr),'z-ecef')) + initype = 'XYZ'; + elseif ~isempty(strfind(lower(hdr),'e-baseline')) || ~isempty(strfind(lower(hdr),'n-baseline')) + initype = 'ENU'; + elseif ~isempty(strfind(lower(hdr),'latitude')) || ~isempty(strfind(lower(hdr),'longitude')) + initype = 'FLH'; + end + end + fprintf('%s: ** INFO ** RTKLIB coordinate type: %s\n',wofun,initype); + + % extract data: convert 'yyyy/mm/dd HH:MM:SS.sss' date/time to 6 numeric columns + % resulting columns: y m d H M S a b c Q ns s_a s_b s_c sdAB sdBC sdAC age ratio + for a = 1:length(F.raw) + fraw = F.raw{a}; + cmd0 = sprintf(['awk ''/^[^%%]/{split($1,d,"/");split($2,t,":");' ... + 'print d[1],d[2],d[3],t[1],t[2],t[3],$3,$4,$5,$6,$7,$8,$9,$10,$11,$12,$13,$14,$15}'' >> %s'],fdat); + if strncmpi('http',fraw,4) + s = wosystem(sprintf('curl -s -S "%s" | %s',fraw,cmd0),P); + if s ~= 0 + break; + end + else + s = wosystem(sprintf('cat "%s" | %s',fraw,cmd0),P); + end + if s ~= 0 + fprintf('%s: ** WARNING ** Raw data "%s" not found.\n',wofun,fraw); + end + end + + % load the file + % columns: 1=year 2=month 3=day 4=hour 5=min 6=sec 7=a 8=b 9=c + % 10=Q 11=ns 12=s_a 13=s_b 14=s_c 15=sdAB 16=sdBC 17=sdAC 18=age 19=ratio + if exist(fdat,'file') + dd = load(fdat); + else + dd = []; + end + if ~isempty(dd) + t = datenum(dd(:,1),dd(:,2),dd(:,3),dd(:,4),dd(:,5),dd(:,6)); + switch initype + case 'ENU' + % e-baseline(m), n-baseline(m), u-baseline(m) + % sigma columns: s_a=sde, s_b=sdn, s_c=sdu + d = [dd(:,7),dd(:,8),dd(:,9),zeros(size(dd,1),1)]; % E,N,U,Orbit + e = [dd(:,12),dd(:,13),dd(:,14)]; % sde,sdn,sdu + case 'FLH' + % latitude(deg), longitude(deg), height(m) - convert to UTM + % sigma columns: s_a=sdn, s_b=sde, s_c=sdu (N before E in RTKLIB FLH output) + [E_utm,N_utm] = ll2utm(dd(:,7),dd(:,8)); + d = [E_utm(:),N_utm(:),dd(:,9),zeros(size(dd,1),1)]; % E_UTM,N_UTM,h,Orbit + e = [dd(:,13),dd(:,12),dd(:,14)]; % sde(=s_b),sdn(=s_a),sdu + case 'XYZ' + % x-ecef(m), y-ecef(m), z-ecef(m) - convert to UTM + % sigma columns: s_a=sdx, s_b=sdy, s_c=sdz + [enu_xyz,e_xyz] = cart2utm(dd(:,7:9),dd(:,12:14)); + d = [enu_xyz,zeros(size(dd,1),1)]; % E,N,U,Orbit + e = e_xyz; + end + e(e 0); + + if all_finite_t + fprintf('[PASS] All timestamps are finite\n'); + else + fprintf('[FAIL] Some timestamps are NaN/Inf\n'); + end + + if all_finite_d + fprintf('[PASS] All position data are finite\n'); + else + fprintf('[FAIL] Some position data are NaN/Inf\n'); + end + + if all_finite_e && all_positive_e + fprintf('[PASS] All error values are finite and positive\n'); + else + fprintf('[FAIL] Some error values invalid\n'); + end + + if size(D.d,2) == 4 && size(D.e,2) == 3 + fprintf('[PASS] Output dimensions correct: D.d is 900×4, D.e is 900×3\n'); + else + fprintf('[FAIL] Output dimensions wrong\n'); + end + + fprintf('\n==============================================================\n'); + fprintf(' SUCCESS: rtklib format is working in readfmtdata_gnss!\n'); + fprintf('==============================================================\n\n'); + +catch err + fprintf('ERROR in readfmtdata_gnss:\n'); + fprintf(' %s\n', err.message); + fprintf('\nStack:\n'); + for i = 1:length(err.stack) + fprintf(' %s (line %d)\n', err.stack(i).name, err.stack(i).line); + end + + % Cleanup + system(sprintf('rm -rf "%s"', F.ptmp)); + error('Test failed'); +end + +% Cleanup +system(sprintf('rm -rf "%s"', F.ptmp)); + +fprintf('Test complete.\n'); From a01fbe7ca1a9282f86fa44478509527ba5d8bd3f Mon Sep 17 00:00:00 2001 From: Pierre Sakic Date: Thu, 11 Jun 2026 19:20:54 +0200 Subject: [PATCH 3/3] add rtklib format support to rawformats.conf and update readfmtdata_gnss function --- CODE/etc/rawformats.conf | 1 + CODE/matlab/readfmtdata.m | 2 +- CODE/matlab/test_readfmtdata_gnss_rtklib.m | 130 --------------------- 3 files changed, 2 insertions(+), 131 deletions(-) delete mode 100644 CODE/matlab/test_readfmtdata_gnss_rtklib.m diff --git a/CODE/etc/rawformats.conf b/CODE/etc/rawformats.conf index 34d189e5..f42b11f4 100644 --- a/CODE/etc/rawformats.conf +++ b/CODE/etc/rawformats.conf @@ -43,3 +43,4 @@ sbe37-ascii|ASCII|sbe37 OBP text file|DATA_ERROR,DATA_DECIMATE|fullpath of file( mc3|WO|MainCourante database||MC3 name mat-file|WO|Matlab MAT-file|T,D,E|fullpath of .mat file genform|WO|GENFORM database||FORM name| +rtklib|GNSS|RTKLIB solution file||fullpath of file(s) with bash wildcard facilities, possible $FID, or URL to single file diff --git a/CODE/matlab/readfmtdata.m b/CODE/matlab/readfmtdata.m index 22122889..582eb8a4 100644 --- a/CODE/matlab/readfmtdata.m +++ b/CODE/matlab/readfmtdata.m @@ -69,7 +69,7 @@ case {'miniseed','seedlink','arclink','combined','fdsnws-dataselect'} D(n) = readfmtdata_miniseed(WO,P,N(n),F); - case {'globkval','gipsy','gipsyx','gipsy-tdp','usgs-rneu','ies-neu','ogc-neu','ingv-gps','sbe37-ascii','spotgins-enu','spotgins-ippp','gamit-pos','pbogps-pos'} + case {'globkval','gipsy','gipsyx','gipsy-tdp','usgs-rneu','ies-neu','ogc-neu','ingv-gps','sbe37-ascii','spotgins-enu','spotgins-ippp','gamit-pos','pbogps-pos','rtklib'} D(n) = readfmtdata_gnss(WO,P,N(n),F); case {'hyp71sum2k','fdsnws-event','scevtlog-xml'} diff --git a/CODE/matlab/test_readfmtdata_gnss_rtklib.m b/CODE/matlab/test_readfmtdata_gnss_rtklib.m deleted file mode 100644 index 7ff295a9..00000000 --- a/CODE/matlab/test_readfmtdata_gnss_rtklib.m +++ /dev/null @@ -1,130 +0,0 @@ -%TEST_READFMTDATA_GNSS_RTKLIB Test the readfmtdata_gnss function with rtklib format -% -% Simulates a WebObs configuration with RTKLIB data -% -% Usage: -% /usr/bin/octave --no-gui test_readfmtdata_gnss_rtklib.m - -fprintf('\n==============================================================\n'); -fprintf(' WebObs readfmtdata_gnss – rtklib integration test\n'); -fprintf('==============================================================\n\n'); - -% Setup paths -here = fileparts(mfilename('fullpath')); -addpath(here); - -% Create mock objects matching WebObs structure -% -% The real function expects: -% readfmtdata_gnss(WO, P, N, F) -% where: -% P = process structure -% N = node structure -% F = options structure - -% Create minimal mock structures -P = struct(); -P.TZ = 0; % Timezone offset - -N = struct(); -N.ID = 'TEST01'; -N.FID = 'BOMG'; -N.UTC_DATA = 0; % No UTC offset for this test -% CLB with nx=5 to skip calib() call (nx must be != 4) -N.CLB = struct('nx', 5, 'nm', {{'E','N','U','Orbit'}}, 'un', {{'m','m','m',''}}); - -F = struct(); -F.fmt = 'rtklib'; -F.raw = {'/home/sakic/aaa_FOURBI/OVPF_static-start_ULT_BOMG_B593_2026_065_0030.out'}; -F.ptmp = tempname(); % Temporary directory -mkdir(F.ptmp); -F.datelim = [NaN NaN]; % No date limits - -fprintf('Setup:\n'); -fprintf(' Process: %s\n', P.TZ); -fprintf(' Node ID: %s (FID=%s)\n', N.ID, N.FID); -fprintf(' Format: %s\n', F.fmt); -fprintf(' Raw data: %s\n', F.raw{1}); -fprintf(' Temp dir: %s\n\n', F.ptmp); - -% Call the real function -fprintf('--- Calling readfmtdata_gnss(WO, P, N, F) ---\n\n'); -try - D = readfmtdata_gnss([], P, N, F); - - fprintf('SUCCESS!\n\n'); - fprintf('Output structure D:\n'); - fprintf(' D.t: %d×1 timestamps (datenum)\n', length(D.t)); - fprintf(' D.d: %d×4 data matrix [E N U Orbit] (meters)\n', size(D.d,1)); - fprintf(' D.e: %d×3 error matrix [sE sN sU] (meters)\n', size(D.e,1)); - fprintf(' D.CLB: calibration structure\n\n'); - - % Detailed inspection - fprintf('First 5 data points:\n'); - fprintf(' Time (datenum): %.8f to %.8f\n', D.t(1), D.t(5)); - fprintf(' East (m): %.2f to %.2f\n', D.d(1,1), D.d(5,1)); - fprintf(' North (m): %.2f to %.2f\n', D.d(1,2), D.d(5,2)); - fprintf(' Height (m): %.2f to %.2f\n', D.d(1,3), D.d(5,3)); - fprintf(' East sigma (m): %.6f to %.6f\n', D.e(1,1), D.e(5,1)); - fprintf(' North sigma (m): %.6f to %.6f\n', D.e(1,2), D.e(5,2)); - fprintf(' Height sigma (m): %.6f to %.6f\n', D.e(1,3), D.e(5,3)); - - fprintf('\nLast 5 data points:\n'); - fprintf(' Time (datenum): %.8f to %.8f\n', D.t(end-4), D.t(end)); - fprintf(' East (m): %.2f to %.2f\n', D.d(end-4,1), D.d(end,1)); - fprintf(' North (m): %.2f to %.2f\n', D.d(end-4,2), D.d(end,2)); - fprintf(' Height (m): %.2f to %.2f\n', D.d(end-4,3), D.d(end,3)); - - % Sanity checks - fprintf('\n--- Sanity checks ---\n'); - - all_finite_t = all(isfinite(D.t)); - all_finite_d = all(isfinite(D.d(:))); - all_finite_e = all(isfinite(D.e(:))); - all_positive_e = all(D.e(:) > 0); - - if all_finite_t - fprintf('[PASS] All timestamps are finite\n'); - else - fprintf('[FAIL] Some timestamps are NaN/Inf\n'); - end - - if all_finite_d - fprintf('[PASS] All position data are finite\n'); - else - fprintf('[FAIL] Some position data are NaN/Inf\n'); - end - - if all_finite_e && all_positive_e - fprintf('[PASS] All error values are finite and positive\n'); - else - fprintf('[FAIL] Some error values invalid\n'); - end - - if size(D.d,2) == 4 && size(D.e,2) == 3 - fprintf('[PASS] Output dimensions correct: D.d is 900×4, D.e is 900×3\n'); - else - fprintf('[FAIL] Output dimensions wrong\n'); - end - - fprintf('\n==============================================================\n'); - fprintf(' SUCCESS: rtklib format is working in readfmtdata_gnss!\n'); - fprintf('==============================================================\n\n'); - -catch err - fprintf('ERROR in readfmtdata_gnss:\n'); - fprintf(' %s\n', err.message); - fprintf('\nStack:\n'); - for i = 1:length(err.stack) - fprintf(' %s (line %d)\n', err.stack(i).name, err.stack(i).line); - end - - % Cleanup - system(sprintf('rm -rf "%s"', F.ptmp)); - error('Test failed'); -end - -% Cleanup -system(sprintf('rm -rf "%s"', F.ptmp)); - -fprintf('Test complete.\n');