From b9858dde2fce8b7e5c7e2ed5582b9f380cb102e1 Mon Sep 17 00:00:00 2001 From: evacougnon Date: Thu, 28 Apr 2022 15:04:01 +1000 Subject: [PATCH] refactor: signatureParse 1. moved functions in +Nortek/ including tests and description 2. Fix regex in read_header_key.m linked to #758 3. Include Signature100 case and include error message when the SIgnature is not supported 4. updated signatureParse description as it can read both .ad2cp and .mat --- Parser/+Nortek/read_nortek_header_key.m | 58 ++++++++++ Parser/+Nortek/transfer_matrix.m | 43 +++++++ Parser/signatureParse.m | 142 +++--------------------- test/Parser/testSignature.m | 8 ++ 4 files changed, 123 insertions(+), 128 deletions(-) create mode 100644 Parser/+Nortek/read_nortek_header_key.m create mode 100644 Parser/+Nortek/transfer_matrix.m diff --git a/Parser/+Nortek/read_nortek_header_key.m b/Parser/+Nortek/read_nortek_header_key.m new file mode 100644 index 000000000..047819fe4 --- /dev/null +++ b/Parser/+Nortek/read_nortek_header_key.m @@ -0,0 +1,58 @@ +function [value] = read_nortek_header_key(hstr,mode,key,vtype) +% function value = read_nortek_header_key(hstr,mode,key,vtype) +% +% Read a nortek value from a `key` name +% within a `mode` line from the header string `hstr`. +% The type of the variable is defined by `vtype`. +% See example. +% +% Inputs: +% +% hstr - the header string +% mode- the name of the mode or the first string in the line +% key - the name of the key +% vtype - the textscan type of the value [Optional] +% - default: 'float' +% +% +% Outputs: +% +% value - a single value +% +% Example: +% +% hstr = 'GETAVG1,ABC="CBA",MIAVG=600,ERR=0.00e-10'; +% [value] = read_nortek_header_key(hstr,'GETAVG1','MIAVG','int'); +% assert(value==600) +% [value] = read_nortek_header_key(hstr,'GETAVG1','ABC','str'); +% assert(value=='CBA') +% [value] = read_nortek_header_key(hstr,'GETAVG1','ERR','float'); +% assert(value==0.00e-10) +% +% author: hugo.oliveira@utas.edu.au +% +narginchk(4,4) + +if strcmpi(vtype,'float') + mtype = '-?[\d.]+(?:[eE][-?+?\d+]\d+)?'; + mfun = @str2double; +elseif strcmpi(vtype,'integer') || strcmpi(vtype,'int') + mtype = '\d+'; + mfun = @str2double; +else + mtype = '".*?"'; + mfun = @(x) strrep(x,'"',''); +end + +%header lines always start with command,key0=value0,key1=value1,... +re_match = ['(?(' mode '))' '(.*?)' key '={1}' '(?(' mtype '))']; +data = regexpi(hstr,re_match,'names'); + +if ~isempty(data) + value = mfun(data.value); +else + error('Could not find key %s with type %s',key,vtype); +end + +end + diff --git a/Parser/+Nortek/transfer_matrix.m b/Parser/+Nortek/transfer_matrix.m new file mode 100644 index 000000000..9d139075a --- /dev/null +++ b/Parser/+Nortek/transfer_matrix.m @@ -0,0 +1,43 @@ +function [Beam2xyz] = transfer_matrix(iA0_Header) +% function [Beam2xyz] = transfer_matrix(iA0_Header) +% +% get transfer function from adcp config command GETXFAVG +% +% Input: +% iA0_Header - the header string +% +% Output: +% Beam2xyz - transfer matrix to use to convert between ENU and beam +% +% Example +% +% +% + +narginchk(1,1) + +r = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','ROWS','int'); +Beam2xyz = zeros(r,r); + +Beam2xyz(1,1) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M11','float'); +Beam2xyz(1,2) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M12','float'); +Beam2xyz(1,3) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M13','float'); +Beam2xyz(2,1) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M21','float'); +Beam2xyz(2,2) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M22','float'); +Beam2xyz(2,3) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M23','float'); +Beam2xyz(3,1) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M31','float'); +Beam2xyz(3,2) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M32','float'); +Beam2xyz(3,3) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M33','float'); + +if r==4 + Beam2xyz(1,4) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M14','float'); + Beam2xyz(2,4) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M24','float'); + Beam2xyz(3,4) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M34','float'); + Beam2xyz(4,1) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M41','float'); + Beam2xyz(4,2) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M42','float'); + Beam2xyz(4,3) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M43','float'); + Beam2xyz(4,4) = Nortek.read_nortek_header_key(iA0_Header,'GETXFAVG','M44','float'); +end + +end + diff --git a/Parser/signatureParse.m b/Parser/signatureParse.m index 1043751cc..e71023b4b 100644 --- a/Parser/signatureParse.m +++ b/Parser/signatureParse.m @@ -1,11 +1,12 @@ function sample_data = signatureParse( filename, tMode ) %SIGNATUREPARSE Parses ADCP data from a raw Nortek Signature -% binary (.ad2cp) file. +% binary (.ad2cp) file or a .mat that has extracted from the +% Nortek instrument software(faster). % % % Inputs: % filename - Cell array containing the name of the raw signature -% file to parse. +% file to parse (either .ad2cp or .mat). % tMode - Toolbox data type mode. % % Outputs: @@ -60,9 +61,9 @@ % this is a string data record if structures.(acquisitionMode{iA0}).Data.Id == 16 || structures.(acquisitionMode{iA0}).Data.Id == 18 iA0_Header = structures.(acquisitionMode{iA0}).Data.String; - instrumentModel = read_header_key(iA0_Header,'ID','STR','string'); - magDec = read_header_key(iA0_Header,'GETUSER','DECL','float'); - Beam2xyz = TransferMatrix(iA0_Header); + instrumentModel = Nortek.read_nortek_header_key(iA0_Header,'ID','STR','string'); + magDec = Nortek.read_nortek_header_key(iA0_Header,'GETUSER','DECL','float'); + Beam2xyz = Nortek.transfer_matrix(iA0_Header); structures = rmfield(structures, acquisitionMode{iA0}); acquisitionMode(iA0) = []; end @@ -342,7 +343,7 @@ data = struct; nDataset = size(acquisitionMode, 2); - nBeams = 4; % default + nBeams = 4; % default -- WHY IS THIS NEEDED - I don't think it is needed due to l.354 nBeams = blah for i=1:nDataset data.(acquisitionMode{1, i}).Time = structures.Data.([acquisitionMode{1, i} 'Time']); @@ -634,7 +635,6 @@ diffTimeInSec = diff(data.(acquisitionMode{i}).Time*24*3600); - % look for most frequents modes Ms = unique(round(diffTimeInSec*100)/100); % unique() sorts in order of most frequent @@ -665,8 +665,14 @@ sample_data{i}.meta.beam_angle = 20; case 'Signature55' sample_data{i}.meta.beam_angle = 20; - otherwise % Signature500 and Signature1000 + case 'Signature100' + sample_data{i}.meta.beam_angle = 20; + case 'Signature500' + sample_data{i}.meta.beam_angle = 25; + case 'Signature1000' sample_data{i}.meta.beam_angle = 25; + otherwise % send error message + error('Signature not supported'); end if data.(acquisitionMode{i}).isVelocityData switch lower(ext) @@ -873,123 +879,3 @@ end -%----------------------------------------------------------------- -% get transfer function from adcp config command GETXFAVG -% regexp doesn't like the last parameter on the line as it runs into the -% next line. -% ie M33=-0.3547GETUSER,POFF=9.50,.. -%------------------------------------------------------------------ -function [Beam2xyz] = TransferMatrix(iA0_Header) - r = read_header_key(iA0_Header,'GETXFAVG','ROWS','int'); - Beam2xyz = zeros(r,r); - - Beam2xyz(1,1) = read_header_key(iA0_Header,'GETXFAVG','M11','float'); - Beam2xyz(1,2) = read_header_key(iA0_Header,'GETXFAVG','M12','float'); - Beam2xyz(1,3) = read_header_key(iA0_Header,'GETXFAVG','M13','float'); - Beam2xyz(2,1) = read_header_key(iA0_Header,'GETXFAVG','M21','float'); - Beam2xyz(2,2) = read_header_key(iA0_Header,'GETXFAVG','M22','float'); - Beam2xyz(2,3) = read_header_key(iA0_Header,'GETXFAVG','M23','float'); - Beam2xyz(3,1) = read_header_key(iA0_Header,'GETXFAVG','M31','float'); - Beam2xyz(3,2) = read_header_key(iA0_Header,'GETXFAVG','M32','float'); - if r==3 - Beam2xyz(3,3) = read_header_key2(iA0_Header,'M33'); - else - Beam2xyz(3,3) = read_header_key(iA0_Header,'GETXFAVG','M33','float'); - end - - if r==4 - Beam2xyz(1,4) = read_header_key(iA0_Header,'GETXFAVG','M14','float'); - Beam2xyz(2,4) = read_header_key(iA0_Header,'GETXFAVG','M24','float'); - Beam2xyz(3,4) = read_header_key(iA0_Header,'GETXFAVG','M34','float'); - - Beam2xyz(4,1) = read_header_key(iA0_Header,'GETXFAVG','M41','float'); - Beam2xyz(4,2) = read_header_key(iA0_Header,'GETXFAVG','M42','float'); - Beam2xyz(4,3) = read_header_key(iA0_Header,'GETXFAVG','M43','float'); - Beam2xyz(4,4) = read_header_key2(iA0_Header,'M44'); - end -end - -%-------------------------------------------------------------- -function [x] = read_header_key2(header,key) - - mode='GETXFAVG'; - - mtype = '-?[\d.^\D]+'; - re_match = ['(?(' mode '))' '(.*?)' key '={1}' '(?(' mtype ')),']; - data = regexpi(header,re_match,'names'); - - % '-0.3547GETUSER,POFF=9.50' - aa = strsplit(data.value, ','); - s = char(aa(1)); - ss = ''; - for i=1:length(s) - c = s(i); - if c=='-' || c=='.' || ~isempty(str2num(c)) - ss = [ss c]; - end - end - - x = str2double(ss); -end - - - -%---------------------------------------------------------------- -function [value] = read_header_key(hstr,mode,key,vtype) -% function value = read_header_key(hstr,mode,key,vtype) -% -% Read a nortek value from a `key` name -% within a `mode` line from the header string `hstr`. -% The type of the variable is defined by `vtype`. -% See example. -% -% Inputs: -% -% hstr - the header string -% mode- the name of the mode or the first string in the line -% key - the name of the key -% vtype - the textscan type of the value [Optional] -% - default: 'float' -% -% -% Outputs: -% -% value - a single value -% -% Example: -% -% hstr = 'GETAVG1,ABC="CBA",MIAVG=600,ERR=0.00e-10'; -% [value] = read_nortek_key(hstr,'GETAVG1','MIAVG','int'); -% assert(value==600) -% [value] = read_nortek_key(hstr,'GETAVG1','ABC','str'); -% assert(value==600) -% [value] = read_nortek_key(hstr,'GETAVG1','ERR','float'); -% assert(value==600) -% -% author: hugo.oliveira@utas.edu.au -% -narginchk(4,4) - -if strcmpi(vtype,'float') - mtype = '-?[\d.]+(?:[eE][-?+?\d+]\d+)?'; - mfun = @str2double; -elseif strcmpi(vtype,'integer') || strcmpi(vtype,'int') - mtype = '\d+'; - mfun = @str2double; -else - mtype = '".*?"'; - mfun = @(x) strrep(x,'"',''); -end - -%header lines always start with command,key0=value0,key1=value1,... -re_match = ['(?(' mode '))' '(.*?)' key '={1}' '(?(' mtype ')),']; -data = regexpi(hstr,re_match,'names'); - -if ~isempty(data) - value = mfun(data.value); -else - error('Could not find key %s with type %s',key,vtype); -end - -end - diff --git a/test/Parser/testSignature.m b/test/Parser/testSignature.m index 003f4becb..2a186f059 100644 --- a/test/Parser/testSignature.m +++ b/test/Parser/testSignature.m @@ -8,6 +8,7 @@ properties (TestParameter) mode = {'timeSeries'}; +% s55_file = files2namestruct(rdir([toolboxRootPath 'data/testfiles/Nortek/signature_55/v000'])); s250_file = files2namestruct(rdir([toolboxRootPath 'data/testfiles/Nortek/signature_250/v000'])); s500_file = files2namestruct(rdir([toolboxRootPath 'data/testfiles/Nortek/signature_500/v000'])); s1000_file = files2namestruct(rdir([toolboxRootPath 'data/testfiles/Nortek/signature_1000/v000'])); @@ -16,6 +17,13 @@ methods (Test) +% function testReadSignature250(~, s55_file, mode) +% data = signatureParse({s55_file},mode); +% assert(strcmp(data{1}.meta.instrument_model,'Signature55')); +% assert(strcmp(data{1}.meta.instrument_make,'Nortek')); +% assert(data{1}.meta.beam_angle==20); +% end + function testReadSignature250(~, s250_file, mode) data = signatureParse({s250_file},mode); assert(strcmp(data{1}.meta.instrument_model,'Signature250'));