RDI_PD0_IO.pl
changeset 37 40d85448debf
parent 36 515b06dae59c
child 39 3bddaa514ef5
--- 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