Skip to content

Commit

Permalink
Added better support for HR AquadoppProfiler metadata. Simplified the…
Browse files Browse the repository at this point in the history
… way Status uint8 is read (in particular for orientation information). Same with other uint16 similar data.
  • Loading branch information
ggalibert committed May 19, 2017
1 parent 49c6fa2 commit b66f4e6
Show file tree
Hide file tree
Showing 4 changed files with 98 additions and 31 deletions.
53 changes: 44 additions & 9 deletions Parser/aquadoppProfilerParse.m
Original file line number Diff line number Diff line change
Expand Up @@ -64,9 +64,29 @@
if isfield(structures, 'Id42')
% this is a HR profiler velocity data
profilerType = 'Id42';
if ~strfind(hardware.instrumentType,'HR')
fprintf('%s\n', ['Warning : ' filename ' HR PROFILER instrumentType does not match Id42 sector type data']);
end
else
% this is a plain profiler velocity data
profilerType = 'Id33';
if strfind(hardware.instrumentType,'HR')
fprintf('%s\n', ['Warning : ' filename ' AQUADOPP PROFILER instrumentType does not match Id33 sector type data']);
end

end

% still to be implemented
value = bin2dec(num2str(bitget(user.TimCtrlReg, 7:-1:6)));
switch value
case 0
user.TimCtrlReg_PowerLevel_ = 'HIGH';
case 1
user.TimCtrlReg_PowerLevel_ = 'HIGH-';
case 2
user.TimCtrlReg_PowerLevel_ = 'LOW+';
case 3
user.TimCtrlReg_PowerLevel_ = 'LOW';
end

velocityProcessed = false;
Expand Down Expand Up @@ -102,6 +122,15 @@
cellSize: ...
blankDist + (ncells-1) * cellSize)';

%
velocityScaling = 1;
if bitget(user(1).Mode, 5) == 1
velocityScaling = 0.1;
end
if strfind(hardware(1).instrumentType, 'HR_PROFILER')
sampleRate = double(512 / user(1).T5);
end

% Note this is actually the distance between the ADCP's transducers and the
% middle of each cell
% See http://www.nortek-bv.nl/en/knowledge-center/forum/current-profilers-and-current-meters/579860330
Expand Down Expand Up @@ -163,18 +192,18 @@
roll = roll / 10.0;
pressure = pressure / 1000.0;
temperature = temperature / 100.0;
velocity1 = velocity1 / 1000.0;
velocity2 = velocity2 / 1000.0;
velocity3 = velocity3 / 1000.0;
velocity1 = velocity1 * velocityScaling / 1000.0;
velocity2 = velocity2 * velocityScaling / 1000.0;
velocity3 = velocity3 * velocityScaling / 1000.0;

if velocityProcessed
% velocity has been processed
% velocities / 1000.0 (mm/s -> m/s) assuming earth coordinates
% 20*log10(sig2noise) (counts -> dB)
% direction / 100.0 (0.01 deg -> deg)
velocity1 = velocity1Proc / 1000.0; % we update the velocity
velocity2 = velocity2Proc / 1000.0;
velocity3 = velocity3Proc / 1000.0;
velocity1 = velocity1Proc * velocityScaling / 1000.0; % we update the velocity
velocity2 = velocity2Proc * velocityScaling / 1000.0;
velocity3 = velocity3Proc * velocityScaling / 1000.0;
sig2noise1(sig2noise1==0) = NaN;
sig2noise2(sig2noise2==0) = NaN;
sig2noise3(sig2noise3==0) = NaN;
Expand All @@ -189,16 +218,22 @@
verticalDist = verticalDist / 1000.0; % since verticalDist is uint16, max value gives 65m but distance along beams can go up to 170m...???
end

if strfind(hardware.instrumentType, 'HR')
instrument_model = 'HR Aquadopp Profiler';
else
instrument_model = 'Aquadopp Profiler';
end

sample_data = struct;

sample_data.toolbox_input_file = filename;
sample_data.meta.featureType = ''; % strictly this dataset cannot be described as timeSeriesProfile since it also includes timeSeries data like TEMP
sample_data.meta.head = head;
sample_data.meta.hardware = hardware;
sample_data.meta.user = user;
sample_data.meta.binSize = cellSize;
sample_data.meta.instrument_make = 'Nortek';
sample_data.meta.instrument_model = 'Aquadopp Profiler';
sample_data.meta.instrument_model = instrument_model;
sample_data.meta.instrument_serial_no = hardware.SerialNo;
sample_data.meta.instrument_firmware = hardware.FWversion;
sample_data.meta.instrument_sample_interval = median(diff(time*24*3600));
Expand All @@ -207,7 +242,7 @@
sample_data.meta.beam_to_xyz_transform = head.TransformationMatrix;

% add dimensions with their data mapped
adcpOrientations = bin2dec(status(:, end));
adcpOrientations = single(bitget(status, 1, 'uint8'));
adcpOrientation = mode(adcpOrientations); % hopefully the most frequent value reflects the orientation when deployed
height = distance;
if adcpOrientation == 1
Expand Down
2 changes: 1 addition & 1 deletion Parser/awacParse.m
Original file line number Diff line number Diff line change
Expand Up @@ -208,7 +208,7 @@
sample_data.meta.beam_to_xyz_transform = head.TransformationMatrix;

% add dimensions with their data mapped
adcpOrientations = bin2dec(status(:, end));
adcpOrientations = single(bitget(status,1,'uint8'));
adcpOrientation = mode(adcpOrientations); % hopefully the most frequent value reflects the orientation when deployed
height = distance;
if adcpOrientation == 1
Expand Down
2 changes: 1 addition & 1 deletion Parser/continentalParse.m
Original file line number Diff line number Diff line change
Expand Up @@ -209,7 +209,7 @@
sample_data.meta.beam_to_xyz_transform = head.TransformationMatrix;

% add dimensions with their data mapped
adcpOrientations = bin2dec(status(:, end));
adcpOrientations = single(bitget(status,1,'uint8'));
adcpOrientation = mode(adcpOrientations); % hopefully the most frequent value reflects the orientation when deployed
height = distance;
if adcpOrientation == 1
Expand Down
72 changes: 52 additions & 20 deletions Parser/readParadoppBinary.m
Original file line number Diff line number Diff line change
Expand Up @@ -335,7 +335,10 @@
SerialNo(SerialNo == 0) = 32; % replace 0 by 32: code for whitespace
SerialNo = char(SerialNo);
block = data(:, 19:30); % uint16
% bytes 30-41 are free
% bytes 30-41 are free, but
% data(idx+30:idx+31) == (103,103) if HR
Spare = data(:, 31:42);

FWversion = data(:, 43:46);
FWversion(FWversion == 0) = 32; % replace 0 by 32: code for whitespace
FWversion = char(FWversion);
Expand All @@ -349,7 +352,7 @@
PICversion = blocks(4:8:end);
HWrevision = blocks(5:8:end);
RecSize = blocks(6:8:end);
Status = blocks(7:8:end);
Status = uint16(blocks(7:8:end));
Checksum = blocks(8:8:end);

if nRecords > 1
Expand All @@ -370,6 +373,31 @@
SerialNo = strtrim(SerialNo);
FWversion = strtrim(FWversion);

% safety check that if instrument type is HR then the returned
% structure should contain Id42 sectors.
instrumentType = 'UNKNOWN';
if any(strfind(SerialNo, 'VNO'))
instrumentType = 'VECTRINO';
elseif any(strfind(SerialNo, 'VEC'))
instrumentType = 'VECTOR';
elseif any(strfind(SerialNo, 'AQD'))
%https://github.com/pjrusello/Nortek-Binary-Ready-Utilities/blob/master/NortekDataStructure.py
%hrFlag == '\x67\x67', hex 0x67 = dec 103
if Spare(1, 1) == 103 && Spare(1, 2) == 103
instrumentType = 'HR_PROFILER';
else
instrumentType = 'AQUADOPP_PROFILER';
end
elseif any(strfind(SerialNo, 'WPR'))
instrumentType = 'AWAC';
end

if nRecords > 1
nChar = length(instrumentType);
instrumentType = repmat(instrumentType, nRecords, 1);
instrumentType = mat2cell(instrumentType, ones(1, nRecords), nChar);
end

sect = struct('Sync', Sync, ...
'Id', Id, ...
'Size', Size, ...
Expand All @@ -381,7 +409,8 @@
'PICversion', PICversion, ...
'HWrevision', HWrevision, ...
'RecSize', RecSize, ...
'Status', Status);
'Status', Status, ...
'instrumentType', instrumentType);

end

Expand Down Expand Up @@ -555,8 +584,8 @@
NPings = blocks(7:43:end);
AvgInterval = blocks(8:43:end);
NBeams = blocks(9:43:end);
TimCtrlReg = blocks(10:43:end);
PwrCtrlReg = blocks(11:43:end);
TimCtrlReg = uint16(blocks(10:43:end));
PwrCtrlReg = uint16(blocks(11:43:end));
A1_1 = blocks(12:43:end);
B0_1 = blocks(13:43:end);
B1_1 = blocks(14:43:end);
Expand All @@ -566,12 +595,12 @@
BinLength = blocks(18:43:end);
MeasInterval = blocks(19:43:end);
WrapMode = blocks(20:43:end);
Mode = dec2bin(blocks(21:43:end), 8);
Mode = uint16(blocks(21:43:end));
AdjSoundSpeed = blocks(22:43:end);
NSampDiag = blocks(23:43:end);
NBeamsCellDiag = blocks(24:43:end);
NPingsDiag = blocks(25:43:end);
ModeTest = blocks(26:43:end);
ModeTest = uint16(blocks(26:43:end));
AnalnAddr = blocks(27:43:end);
SWVersion = blocks(28:43:end);
WMMode = blocks(29:43:end);
Expand Down Expand Up @@ -716,7 +745,7 @@

PressureMSB = data(:, 25); % uint8
% 8 bits status code http://cs.nortek.no/scripts/customer.fcgi?_sf=0&custSessionKey=&customerLang=en&noCookies=true&action=viewKbEntry&id=7
Status = dec2bin(bytecast(data(:, 26), 'L', 'uint8', cpuEndianness), 8)';
Status = uint8(data(:, 26));

PressureLSW = data(:, 27:28); % uint16
% !!! temperature and velocity can be negative
Expand Down Expand Up @@ -759,7 +788,7 @@
Time = num2cell(Time);
Error = num2cell(Error);
PressureMSB = num2cell(PressureMSB);
Status = mat2cell(Status, 8, ones(1, nRecords))';
Status = num2cell(Status);
PressureLSW = num2cell(PressureLSW);
Checksum = num2cell(Checksum);
Analn1 = num2cell(Analn1);
Expand Down Expand Up @@ -1059,7 +1088,7 @@

Error = bytecast(data(:, 23), 'L', 'int8', cpuEndianness);
% 8 bits status code http://cs.nortek.no/scripts/customer.fcgi?_sf=0&custSessionKey=&customerLang=en&noCookies=true&action=viewKbEntry&id=7
Status = dec2bin(bytecast(data(:, 24), 'L', 'uint8', cpuEndianness), 8)';
Status = uint8(data(:, 24));
Analn = data(:, 25:26); % uint16

Checksum = data(:, 27:28); % uint16
Expand All @@ -1084,7 +1113,7 @@
Size = num2cell(Size);
Time = num2cell(Time);
Error = num2cell(Error);
Status = mat2cell(Status, 8, ones(1, nRecords))';
Status = num2cell(Status);
Analn = num2cell(Analn);
Checksum = num2cell(Checksum);
Size = num2cell(Size);
Expand Down Expand Up @@ -1134,7 +1163,7 @@

PressureMSB = bytecast(data(:, 25), 'L', 'uint8', cpuEndianness); % uint8
% 8 bits status code http://cs.nortek.no/scripts/customer.fcgi?_sf=0&custSessionKey=&customerLang=en&noCookies=true&action=viewKbEntry&id=7
Status = dec2bin(bytecast(data(:, 26), 'L', 'uint8', cpuEndianness), 8)';
Status = uint8(data(:, 26));
PressureLSW = data(:, 27:28); % uint16
Temperature = data(:, 29:30); % int16

Expand Down Expand Up @@ -1196,7 +1225,7 @@
Time = num2cell(Time);
Error = num2cell(Error);
PressureMSB = num2cell(PressureMSB);
Status = mat2cell(Status, 8, ones(1, nRecords))';
Status = num2cell(Status);
PressureLSW = num2cell(PressureLSW);
Temperature = num2cell(Temperature);
Checksum = num2cell(Checksum);
Expand Down Expand Up @@ -1256,7 +1285,7 @@
% !!! Heading, pitch and roll can be negative
block3 = data(:, 19:24); % int16
PressureMSB = data(:, 25); % uint8
% byte 25 is a fill byte
Status = uint8(data(:, 26));
PressureLSW = data(:, 27:28); % uint16
Temperature = data(:, 29:30); % int16
block4 = data(:, 31:34); % uint16
Expand Down Expand Up @@ -1356,6 +1385,7 @@
Size = num2cell(Size);
Time = num2cell(Time);
PressureMSB = num2cell(PressureMSB);
Status = num2cell(Status);
PressureLSW = num2cell(PressureLSW);
Temperature = num2cell(Temperature);
Beams = num2cell(Beams);
Expand Down Expand Up @@ -1389,6 +1419,7 @@
'Size', Size, ...
'Time', Time, ...
'PressureMSB', PressureMSB, ...
'Status', Status, ...
'PressureLSW', PressureLSW, ...
'Temperature', Temperature, ...
'Beams', Beams, ...
Expand Down Expand Up @@ -1448,7 +1479,7 @@
Roll = block(:, 3);
PressureMSB = bytecast(data(:, 25), 'L', 'uint8', cpuEndianness); % uint8
% 8 bits status code http://cs.nortek.no/scripts/customer.fcgi?_sf=0&custSessionKey=&customerLang=en&noCookies=true&action=viewKbEntry&id=7
Status = dec2bin(bytecast(data(:, 26), 'L', 'uint8', cpuEndianness), 8)';
Status = uint8(data(:, 26));
PressureLSW = bytecast(reshape(data(:, 27:28)', [], 1), 'L', 'uint16', cpuEndianness); % uint16
Temperature = bytecast(reshape(data(:, 29:30)', [], 1), 'L', 'int16', cpuEndianness); % int16
% bytes 30-117 are spare
Expand Down Expand Up @@ -1499,7 +1530,7 @@
Pitch = num2cell(Pitch);
Roll = num2cell(Roll);
PressureMSB = num2cell(PressureMSB);
Status = mat2cell(Status, 8, ones(1, nRecords))';
Status = num2cell(Status);
PressureLSW = num2cell(PressureLSW);
Temperature = num2cell(Temperature);
Vel1 = mat2cell(Vel1, nCells, ones(1, nRecords))';
Expand Down Expand Up @@ -1858,7 +1889,7 @@

function sect = readContinental(data, cpuEndianness)
%READCONTINENTAL Reads a Continental Data section.
% Id=0x42, Continental Data
% Id=0x24, Continental Data
% SYSTEM INTEGRATOR MANUAL (Dec 2014) pg 50
% structure is same as awac velocity profile data
sect = readAwacVelocityProfile(data, cpuEndianness);
Expand All @@ -1868,7 +1899,7 @@
function sect = readVectrinoVelocityHeader(data, cpuEndianness)
%READVECTRINOVELOCITYHEADER Reads a Vectrino velocity data header section
% (pg 42 of system integrator manual).
% Id=0x12, Vectrino velocity data header
% Id=0x50, Vectrino velocity data header
% SYSTEM INTEGRATOR MANUAL (Dec 2014) pg 57-58

nRecords = size(data, 1);
Expand Down Expand Up @@ -2012,7 +2043,8 @@
% v = velocity scaling (0 = mm/s, 1 = 0.1mm/s)
% ccc = #cells -1
% bb = #beams -1
Status = dec2bin(bytecast(data(:, 3), 'L', 'uint8', cpuEndianness), 8)';
% is 'e' bit0 or bit7?
Status = uint8(data(:, 3));

Count = data(:, 4);

Expand Down Expand Up @@ -2043,7 +2075,7 @@
if nRecords > 1
Sync = num2cell(Sync);
Id = num2cell(Id);
Status = mat2cell(Status, 8, ones(1, nRecords))';
Status = num2cell(Status);
Count = num2cell(Count);
Vel1 = num2cell(Vel1);
Vel2 = num2cell(Vel2);
Expand Down

0 comments on commit b66f4e6

Please sign in to comment.