diff --git a/RDI_PD0_IO.pl b/RDI_PD0_IO.pl --- a/RDI_PD0_IO.pl +++ b/RDI_PD0_IO.pl @@ -1,12 +1,12 @@ #====================================================================== -# R D I _ B B _ R E A D . P L +# R D I _ P D 0 _ I O . P L # doc: Sat Jan 18 14:54:43 2003 -# dlm: Sat Jul 30 18:34:46 2016 +# dlm: Tue Mar 7 12:07:29 2017 # (c) 2003 A.M. Thurnherr -# uE-Info: 402 62 NIL 0 0 72 10 2 4 NIL ofnI +# uE-Info: 1250 39 NIL 0 0 72 0 2 4 NIL ofnI #====================================================================== -# Read RDI BroadBand Binary Data Files (*.[0-9][0-9][0-9]) +# Read RDI PD0 binary data files (*.[0-9][0-9][0-9]) # HISTORY: # Jan 18, 2003: - incepted aboard the Aurora Australis (KAOS) @@ -78,6 +78,12 @@ # Feb 29, 2016: - LEAP DAY: actually got BT data patching to work # Jul 30, 2016: - BUG: incomplete last ensemble with garbage content was returned on reading # WH300 data +# Aug 5, 2016: - cosmetics +# Aug 23, 2016: - added &clearEns() +# Nov 9, 2016: - made WBRhdr() return undef on "empty" files +# Nov 18, 2016: - BUG: ensNo was not reported correctly in format errors +# Nov 23, 2016: - no longer set pitch/roll/heading to undef in clearEns() +# Mar 7, 2016: - renamed round() to stop clashing with ANTSLIB # FIRMWARE VERSIONS: # It appears that different firmware versions generate different file @@ -375,7 +381,7 @@ my($fn,$dta) = @_; $WBRcfn = $fn; open(WBRF,$WBRcfn) || die("$WBRcfn: $!"); - WBRhdr($dta); + WBRhdr($dta) || die("$WBRcfn: Insufficient data\n"); } sub WBRhdr($) @@ -389,14 +395,14 @@ #-------------------- skip_initial_trash(); - sysread(WBRF,$buf,6) == 6 || die("$WBRcfn: $!"); + sysread(WBRF,$buf,6) == 6 || return undef; ($hid,$did,$dta->{ENSEMBLE_BYTES},$dummy,$dta->{NUMBER_OF_DATA_TYPES}) = unpack('CCvCC',$buf); $hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header (hid)",$hid,0)); $did == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header (did)",$did,0)); - $start_ens = sysseek(WBRF,$dta->{ENSEMBLE_BYTES}-6+2,1) || die("$WBRcfn: $!"); - sysread(WBRF,$buf,6) == 6 || die("$WBRcfn: $!"); + $start_ens = sysseek(WBRF,$dta->{ENSEMBLE_BYTES}-6+2,1) || return undef; + sysread(WBRF,$buf,6) == 6 || return undef; ($hid,$did,$dta->{ENSEMBLE_BYTES},$dummy,$dta->{NUMBER_OF_DATA_TYPES}) = unpack('CCvCC',$buf); $hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header (hid2)",$hid,0)); @@ -643,8 +649,8 @@ { my($fn,$dta) = @_; $WBRcfn = $fn; - open(WBRF,$WBRcfn) || die("$WBRcfn: $!"); - WBRhdr($dta); + open(WBRF,$WBRcfn) || die("$WBRcfn: $!\n"); + WBRhdr($dta) || die("$WBRcfn: Insufficient Data\n"); WBRens($dta->{N_BINS},$dta->{FIXED_LEADER_BYTES}, \@{$dta->{ENSEMBLE}}); print(STDERR "$WBRcfn: $BIT_errors built-in-test errors\n") @@ -670,7 +676,7 @@ sysseek(WBRF,$start_ens,0) || die("$WBRcfn: $!"); sysread(WBRF,$buf,6) == 6 || last; ($hid,$did,$ens_length,$dummy,$ndt) = unpack('CCvCC',$buf); - $hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header",$hid,0)); + $hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header",$hid,defined($ensNo)?$ensNo+1:0)); ${$E}[$ens]->{DATA_SOURCE_ID} = $did; if ($did == 0x7f) { ${$E}[$ens]->{PRODUCER} = 'TRDI ADCP'; @@ -698,26 +704,31 @@ # final ensemble. sysseek(WBRF,$start_ens,0) || die("$WBRcfn: $!"); - unless ((sysread(WBRF,$buf,$ens_length) == $ens_length) && + unless ((sysread(WBRF,$buf,$ens_length) == $ens_length) && # incomplete ensemble (sysread(WBRF,$cs,2) == 2)) { pop(@{$E}); last; } - pop(@{$E}),last unless (unpack('%16C*',$buf) == unpack('v',$cs)); + unless (unpack('%16C*',$buf) == unpack('v',$cs)) { # bad checksum + pop(@{$E}); + last; +# next; # using this might make the code work + } # for files with isolated bad ensembles #------------------------------ # Variable Leader #------------------------------ + my($lastEns) = $ensNo; sysseek(WBRF,$start_ens+$WBRofs[1],0) || die("$WBRcfn: $!"); sysread(WBRF,$buf,4) == 4 || die("$WBRcfn: $!"); - ($id,$ensNo) = unpack("vv",$buf); + ($id,$ensNo) = unpack("vv",$buf); # only lower two bytes!!! $id == 0x0080 || - die(sprintf($FmtErr,$WBRcfn,"Variable Leader",$id,$ensNo+1)); + die(sprintf($FmtErr,$WBRcfn,"Variable Leader",$id,$ensNo + ($lastEns - ($lastEns & 0xFFFF)))); - if ($fixed_leader_bytes==42 || $fixed_leader_bytes==58) { # BB150 & Explorer DVL + if ($fixed_leader_bytes==42 || $fixed_leader_bytes==58) { # BB150 & Explorer DVL sysread(WBRF,$buf,7) == 7 || die("$WBRcfn: $!"); (${$E}[$ens]->{YEAR},${$E}[$ens]->{MONTH}, ${$E}[$ens]->{DAY},${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE}, @@ -854,7 +865,7 @@ ($id,@dta) = unpack("vv$ndata",$buf); $id == 0x0100 || - die(sprintf($FmtErr,$WBRcfn,"Velocity Data",$id,$ens)); + die(sprintf($FmtErr,$WBRcfn,"Velocity Data",$id,$ensNo)); for ($i=0,$bin=0; $bin<$nbins; $bin++) { for ($beam=0; $beam<4; $beam++,$i++) { @@ -873,7 +884,7 @@ ($id,@dta) = unpack("vC$ndata",$buf); $id == 0x0200 || - die(sprintf($FmtErr,$WBRcfn,"Correlation Data",$id,$ens)); + die(sprintf($FmtErr,$WBRcfn,"Correlation Data",$id,$ensNo)); for ($i=0,$bin=0; $bin<$nbins; $bin++) { for ($beam=0; $beam<4; $beam++,$i++) { @@ -891,7 +902,7 @@ ($id,@dta) = unpack("vC$ndata",$buf); $id == 0x0300 || - die(sprintf($FmtErr,$WBRcfn,"Echo Intensity",$id,$ens)); + die(sprintf($FmtErr,$WBRcfn,"Echo Intensity",$id,$ensNo)); for ($i=0,$bin=0; $bin<$nbins; $bin++) { for ($beam=0; $beam<4; $beam++,$i++) { @@ -908,7 +919,7 @@ ($id,@dta) = unpack("vC$ndata",$buf); $id == 0x0400 || - die(sprintf($FmtErr,$WBRcfn,"Percent-Good Data",$id,$ens)); + die(sprintf($FmtErr,$WBRcfn,"Percent-Good Data",$id,$ensNo)); for ($i=0,$bin=0; $bin<$nbins; $bin++) { # printf(STDERR "%-GOOD($bin): "); @@ -1028,7 +1039,7 @@ WBPens($dta->{N_BINS},$dta->{FIXED_LEADER_BYTES},$dta); } -sub round(@) +sub _round(@) { return $_[0] >= 0 ? int($_[0] + 0.5) : int($_[0] - 0.5); @@ -1039,7 +1050,7 @@ { my($nbins,$fixed_leader_bytes,$dta) = @_; my($start_ens,$B1,$B2,$B3,$B4,$I,$id,$bin,$beam,$buf,$dummy,@dta,$i,$cs,@WBPofs); - my($ens,$ensNo,$dayStart,$ens_length,$hid,$ndt); + my($ens,$dayStart,$ens_length,$hid,$ndt); for ($ens=$start_ens=0; $ens<=$#{$dta->{ENSEMBLE}}; $ens++,$start_ens+=$ens_length+2) { @@ -1100,24 +1111,24 @@ sysseek(WBPF,$start_ens+$WBPofs[1]+14,0) || die("$WBPcfn: $!"); # jump to SPEED_OF_SOUND - $dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH} = round($dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH}*10); + $dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH} = _round($dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH}*10); #--------------------------------- # NB: IMP allows for missing value #--------------------------------- $dta->{ENSEMBLE}[$ens]->{HEADING} = defined($dta->{ENSEMBLE}[$ens]->{HEADING}) - ? round($dta->{ENSEMBLE}[$ens]->{HEADING}*100) + ? _round($dta->{ENSEMBLE}[$ens]->{HEADING}*100) : 0xF000; $dta->{ENSEMBLE}[$ens]->{PITCH} = defined($dta->{ENSEMBLE}[$ens]->{PITCH}) - ? unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{PITCH}*100))) + ? unpack('S',pack('s',_round($dta->{ENSEMBLE}[$ens]->{PITCH}*100))) : 0x8000; $dta->{ENSEMBLE}[$ens]->{ROLL} = defined($dta->{ENSEMBLE}[$ens]->{ROLL}) - ? unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{ROLL}*100))) + ? unpack('S',pack('s',_round($dta->{ENSEMBLE}[$ens]->{ROLL}*100))) : 0x8000; $dta->{ENSEMBLE}[$ens]->{TEMPERATURE} = - unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{TEMPERATURE}*100))); + unpack('S',pack('s',_round($dta->{ENSEMBLE}[$ens]->{TEMPERATURE}*100))); $buf = pack('vvvvvvv', $dta->{ENSEMBLE}[$ens]->{SPEED_OF_SOUND}, @@ -1137,7 +1148,7 @@ for ($bin=0; $bin<$nbins; $bin++) { for ($beam=0; $beam<4; $beam++) { $dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam] = defined($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam]) - ? round($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam]*1000) + ? _round($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam]*1000) : 0x8000; $buf = pack('v',unpack('S',pack('s',$dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam]))); my($nw) = syswrite(WBPF,$buf,2); @@ -1202,7 +1213,7 @@ unless ($nxt == $ndt) { # BT found sysseek(WBPF,14,1) || die("$WBPcfn: $!"); # skip BT config for ($beam=0; $beam<4; $beam++) { # BT range low bytes (2 per beam) - $buf = pack('v',round($dta->{ENSEMBLE}[$ens]->{BT_RANGE}[$beam] * 100) & 0xFFFF); + $buf = pack('v',_round($dta->{ENSEMBLE}[$ens]->{BT_RANGE}[$beam] * 100) & 0xFFFF); my($nw) = syswrite(WBPF,$buf,2); $nw == 2 || die("$WBPcfn: $nw bytes written ($!)"); } @@ -1210,7 +1221,7 @@ for ($beam=0; $beam<4; $beam++) { # BT velocities $buf = pack('v',unpack('S',pack('s', defined($dta->{ENSEMBLE}[$ens]->{BT_VELOCITY}[$beam]) - ? round($dta->{ENSEMBLE}[$ens]->{BT_VELOCITY}[$beam]*1000) + ? _round($dta->{ENSEMBLE}[$ens]->{BT_VELOCITY}[$beam]*1000) : 0x8000))); my($nw) = syswrite(WBPF,$buf,2); $nw == 2 || die("$WBPcfn: $nw bytes written ($!)"); @@ -1236,7 +1247,7 @@ sysseek(WBPF,33,1) || die("$WBPcfn: $!"); # BT range high bytes (1 per beam) for ($beam=0; $beam<4; $beam++) { - $buf = pack('C',(round($dta->{ENSEMBLE}[$ens]->{BT_RANGE}[$beam]*100) & 0xFF0000) >> 16); + $buf = pack('C',(_round($dta->{ENSEMBLE}[$ens]->{BT_RANGE}[$beam]*100) & 0xFF0000) >> 16); my($nw) = syswrite(WBPF,$buf,1); $nw == 1 || die("$WBPcfn: $nw bytes written ($!)"); } @@ -1257,4 +1268,40 @@ } # ens loop } +#---------------------------------------------------------------------- +# &clearEns(^data,ens-index) +# - undefine all velocities in ensemble, including BT +# - this is required for the LDEO_IX software, +# which does not recognize missing attitude values +# - set percent good to zero +# - this is done for consistency +# - DO NOT undef heading, pitch and roll +# - the LDEO software does not recognize missing attitude vals +# and, therefore, misinterprets those +# - while this should not matter because all the velocities are +# also deleted, it was found that setting only the heading to +# undef'd and leaving pitch and roll unchanged causes +# significant errors in GPS velocity referencing! This +# must be a bug +# - also, if attitudes are undef'd the LDEO software +# cannto determine the instrument offset from pitch/roll +# and the pitch/roll DL vs UL plots are bogus +#---------------------------------------------------------------------- + +sub clearEns($$) +{ + my($dta,$ens) = @_; + croak("clearEns: ens-index $ens out of range\n") + unless ($ens>=0 && $ens<=$#{$dta->{ENSEMBLE}}); + for (my($bin)=0; $bin<$dta->{N_BINS}; $bin++) { + undef(@{$dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin]}); + @{$dta->{ENSEMBLE}[$ens]->{PERCENT_GOOD}[$bin]} = (0,0,0,0); + } + undef(@{$dta->{ENSEMBLE}[$ens]->{BT_VELOCITY}}); + @{$dta->{ENSEMBLE}[$ens]->{BT_PERCENT_GOOD}} = (0,0,0,0); +# undef($dta->{ENSEMBLE}[$ens]->{HEADING}); +# undef($dta->{ENSEMBLE}[$ens]->{PITCH}); +# undef($dta->{ENSEMBLE}[$ens]->{ROLL}); +} + 1; # return true for all the world to see