pre Tampa
authorA.M. Thurnherr <athurnherr@yahoo.com>
Tue, 02 Feb 2016 14:53:59 +0000
changeset 31 b6ca27a1d19c
parent 30 184133e916be
child 32 7155adf61d77
pre Tampa
RDI_Coords.pl
RDI_PD0_IO.pl
RDI_Utils.pl
editPD0
listBins
listHdr
--- a/RDI_Coords.pl
+++ b/RDI_Coords.pl
@@ -1,9 +1,9 @@
 #======================================================================
 #                    R D I _ C O O R D S . P L 
 #                    doc: Sun Jan 19 17:57:53 2003
-#                    dlm: Tue Jan  5 13:56:55 2016
+#                    dlm: Sun Jan 31 12:42:43 2016
 #                    (c) 2003 A.M. Thurnherr
-#                    uE-Info: 185 37 NIL 0 0 72 0 2 4 NIL ofnI
+#                    uE-Info: 185 0 NIL 0 0 72 0 2 4 NIL ofnI
 #======================================================================
 
 # RDI Workhorse Coordinate Transformations
@@ -40,6 +40,7 @@
 #				  - removed some old debug statements
 #				  - removed unused code from &velBeamToBPInstrument
 #	Jan  5, 2016: - added &velEarthToInstrument(@), &velInstrumentToBeam(@)
+#	Jan  9, 2016: - added &velEarthToBeam(), &velBeamToEarth()
 
 use strict;
 use POSIX;
@@ -170,7 +171,8 @@
 		my($dta,$ens,$u,$v,$w,$ev) = @_;
 
 		unless (@E2I) {
-			$hdg   = $dta->{ENSEMBLE}[$ens]->{HEADING} - $dta->{HEADING_BIAS} if defined($dta->{ENSEMBLE}[$ens]->{HEADING});
+			$hdg = $dta->{ENSEMBLE}[$ens]->{HEADING} - $dta->{HEADING_BIAS} 
+				if defined($dta->{ENSEMBLE}[$ens]->{HEADING});
 			$pitch = $dta->{ENSEMBLE}[$ens]->{PITCH};
 			$roll  = $dta->{ENSEMBLE}[$ens]->{ROLL};
 			my($rad_gimbal_pitch) = atan(tan(rad($pitch)) * cos(rad($roll)));
@@ -179,12 +181,15 @@
 			my($sp,$cp) = (sin($rad_gimbal_pitch),cos($rad_gimbal_pitch));
 			my($sr,$cr) = (sin(rad($roll)),	cos(rad($roll)));
 			@E2I = $dta->{ENSEMBLE}[$ens]->{XDUCER_FACING_UP}
-				 ? ([$ch*-$cr+$sh*$sp*-$sr,	 $ch*$sp*-$sr-$sh*-$cr,	$cp*-$sr],
+				 ? (
+					[$ch*-$cr+$sh*$sp*-$sr,	 $ch*$sp*-$sr-$sh*-$cr,	$cp*-$sr],
 				    [$sh*$cp,				 $ch*$cp,				$sp		],
-				    [$ch*-$sr-$sh*$sp*-$cr,	-$sh*-$sr-$ch*$sp*-$cr,	$cp*-$cr])
-				 : ([$ch*$cr+$sh*$sp*$sr,	 $ch*$sp*$sr-$sh*$cr,	$cp*$sr	],
+				    [$ch*-$sr-$sh*$sp*-$cr,	-$sh*-$sr-$ch*$sp*-$cr,	$cp*-$cr]
+				 ) : (
+					[$ch*$cr+$sh*$sp*$sr,	 $ch*$sp*$sr-$sh*$cr,	$cp*$sr	],
 				    [$sh*$cp,				 $ch*$cp,				$sp		],
-				    [$ch*$sr-$sh*$sp*$cr,	-$sh*$sr-$ch*$sp*$cr,	$cp*$cr	]);
+				    [$ch*$sr-$sh*$sp*$cr,	-$sh*$sr-$ch*$sp*$cr,	$cp*$cr	]
+				 );
 		}
 
 		return defined($dta->{ENSEMBLE}[$ens]->{HEADING})
@@ -229,6 +234,17 @@
 	}
 } # STATIC SCOPE
 
+#----------------------------------------------------------------------
+# velEarthToBeam() combines velEarthToInstrument and velInstrumentToBeam
+#----------------------------------------------------------------------
+
+sub velEarthToBeam(@)
+{
+	my($dta,$ens,$u,$v,$w,$ev) = @_;
+	return velInstrumentToBeam($dta,
+				velEarthToInstrument($dta,$ens,$u,$v,$w,$ev));
+}
+
 #======================================================================
 # velBeamToBPEarth(@) calculates the vertical- and horizontal vels
 # from the two beam pairs separately. Note that (w1+w2)/2 is 
--- a/RDI_PD0_IO.pl
+++ b/RDI_PD0_IO.pl
@@ -1,9 +1,9 @@
 #======================================================================
 #                    R D I _ P D 0 _ I O . P L 
 #                    doc: Sat Jan 18 14:54:43 2003
-#                    dlm: Sat Jan  9 13:22:46 2016
+#                    dlm: Sat Jan  9 17:57:01 2016
 #                    (c) 2003 A.M. Thurnherr
-#                    uE-Info: 70 34 NIL 0 0 72 2 2 4 NIL ofnI
+#                    uE-Info: 73 64 NIL 0 0 72 10 2 4 NIL ofnI
 #======================================================================
 
 # Read RDI BroadBand Binary Data Files (*.[0-9][0-9][0-9])
@@ -66,8 +66,11 @@
 #	Oct  2, 2015: - added &skip_initial_trash()
 #	Dec 18, 2015: - added most data types to WBPofs()
 #				  - BUG: WBPens() requires round() for scaled values
-#	Jan  9, 2016: - BUG: WBRhdr() did not set DATA_SOURCE_ID
+#	Jan  9, 2016: - removed system() from writeData()
+#				  - BUG: WBRhdr() did not set DATA_SOURCE_ID
 #				  - added PRODUCER
+#				  - BUG: writeData() did not work correctly for ECOGIG OC26 moored data (spaces in filename?)
+#				  - added support for patching coordinate system
 
 # FIRMWARE VERSIONS:
 #	It appears that different firmware versions generate different file
@@ -92,7 +95,7 @@
 #			- PITCH & ROLL can be missing (0x8000 badval as in velocities)
 #			- HEADING can be missing (0xF000 badval, as 0x8000 is valid 327.68 heading)
 #
-#	- DATA_SOURCE_ID = 0xB0 					produced by editPD0
+#	- DATA_SOURCE_ID = 0xE0 					produced by editPD0
 
 # NOTES:
 #	- RDI stores data in VAX/Intel byte order (little endian)
@@ -333,6 +336,8 @@
 		($dta) = unpack('C',$buf);
 		if ($dta == 0x7f) {
 			$found++;
+		} elsif ($found==1 && ($dta==0xE0 || ($dta&0xF0==0xA0 && $dta&0x0F<8))) {
+			$found++;
 		} elsif ($found == 0) {
 			$skipped++;
 		} else {
@@ -379,12 +384,12 @@
 	$dta->{DATA_SOURCE_ID} = $did;
 	if ($did == 0x7f) {
 		$dta->{PRODUCER} = 'TRDI ADCP';
-	} elsif ($did&0xF0 == 0xA0) {
-		$dta->{PRODUCER} = 'IMP+LADCP';
-	} elsif ($did&0xF0 == 0xB0) {
-		$dta->{PRODUCER} = 'editPD0';
+	} elsif (($did&0xF0) == 0xA0) {
+		$dta->{PRODUCER} = 'IMP+LADCP (Thurnherr software)';
+	} elsif (($did&0xF0) == 0xE0) {
+		$dta->{PRODUCER} = 'editPD0 (Thurnherr software)';
 	} else {
-		$dta->{PRODUCER} = 'unknown';
+		$dta->{PRODUCER} = sprintf('unknown (0x%02X)');
 	}
 
 	printf(STDERR "WARNING: unexpected number of data types (%d)\n",
@@ -652,7 +657,7 @@
 			${$E}[$ens]->{PRODUCER} = 'TRDI ADCP';
 		} elsif ($did&0xF0 == 0xA0) {
 			${$E}[$ens]->{PRODUCER} = 'IMP+LADCP (Thurnherr software)';
-		} elsif ($did&0xF0 == 0xB0) {
+		} elsif ($did&0xF0 == 0xE0) {
 			${$E}[$ens]->{PRODUCER} = 'editPD0 (Thurnherr software)';
 		} else {
 			${$E}[$ens]->{PRODUCER} = 'unknown';
@@ -985,13 +990,24 @@
 	my($fn,$dta) = @_;
 
 	die("writeData() needs \$WBRcfn from previous readData()")
-		unless (-r $WBRcfn);
-	$WBPcfn = $fn;
-	system("cp $WBRcfn $WBPcfn");
+		unless (length($WBRcfn) > 0);
+
+    sysseek(WBRF,0,0) || die("$WBRcfn: $!");						# rewind input file
+	$WBPcfn = $fn;													# set patch file name for error messages
+	open(WBPF,"+>$WBPcfn") || die("$WBPcfn: $!");					# open patch file for r/w
 
-	open(WBPF,"+<$WBPcfn") || die("$WBPcfn: $!");
-    WBPens($dta->{N_BINS},$dta->{FIXED_LEADER_BYTES},
-	                   \@{$dta->{ENSEMBLE}});
+	while (1) {														# copy input file to patch file
+		my($buf);
+		my($nread) = sysread(WBRF,$buf,100*1024);
+		die("$WBRcfn: $!\n") if ($nread < 0);
+		last if ($nread == 0);
+		my($nwritten) = syswrite(WBPF,$buf,100*1024);
+		die("$WBPcfn: $! ($nwritten of $nread written)\n")
+			unless ($nwritten = $nread);
+	}
+    sysseek(WBPF,0,0) || die("$WBPcfn: $!");						# rewind patch file
+
+    WBPens($dta->{N_BINS},$dta->{FIXED_LEADER_BYTES},$dta);
 }
 
 sub round(@)
@@ -1003,11 +1019,11 @@
 
 sub WBPens($$$)
 {
-	my($nbins,$fixed_leader_bytes,$E) = @_;
+	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);
 
-	for ($ens=$start_ens=0; $ens<=$#{$E}; $ens++,$start_ens+=$ens_length+2) {
+	for ($ens=$start_ens=0; $ens<=$#{$dta->{ENSEMBLE}}; $ens++,$start_ens+=$ens_length+2) {
 
 		#------------------------------
 		# Patch Header (Data Source Id)
@@ -1018,7 +1034,7 @@
 		($hid) = unpack('C',$buf);
 		$hid == 0x7f || die(sprintf($FmtErr,$WBPcfn,"Header",$hid,$ens));
 
-		$buf = pack('C',${$E}[$ens]->{DATA_SOURCE_ID});
+		$buf = pack('C',$dta->{ENSEMBLE}[$ens]->{DATA_SOURCE_ID});
 		my($nw) = syswrite(WBPF,$buf,1);
 		$nw == 1 || die("$WBPcfn: $nw bytes written ($!)");
 
@@ -1030,44 +1046,55 @@
 		sysread(WBPF,$buf,2*$ndt) == 2*$ndt || die("$WBPcfn: $!");
 		@WBPofs = unpack("v$ndt",$buf);
 		$fixed_leader_bytes = $WBPofs[1] - $WBPofs[0];
+
+		#--------------------
+		# Fixed Leader
+		#--------------------
 	
+		sysseek(WBPF,$start_ens+$WBPofs[0]+25,0) || die("$WBPcfn: $!");		# jump to EX/Coord-Transform
+		sysread(WBPF,$buf,1) == 1 || die("$WBPcfn: $!");
+		my($EX) = unpack('C',$buf);
+		if ($dta->{BEAM_COORDINATES}) {
+			$EX &= ~0x18;
+		} elsif ($dta->{EARTH_COORDINATES}) {
+			$EX |= 0x18;
+		} else {
+			die("$WBPcfn: only beam- and earth coordinates are supported (implementation restriction)\n");
+		}
+		$buf = pack('C',$EX);		
+		sysseek(WBPF,$start_ens+$WBPofs[0]+25,0) || die("$WBPcfn: $!");
+		syswrite(WBPF,$buf,1) == 1 || die("$WBPcfn: $!");
+
 		#------------------------------
 		# Variable Leader
 		#------------------------------
-	
-		sysseek(WBPF,$start_ens+$WBPofs[1]+12,0) || die("$WBPcfn: $!");
+
+		sysseek(WBPF,$start_ens+$WBPofs[1]+14,0) || die("$WBPcfn: $!");		# jump to SPEED_OF_SOUND
 		
-		${$E}[$ens]->{XDUCER_DEPTH} = round(${$E}[$ens]->{XDUCER_DEPTH}*10);
+		$dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH} = round($dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH}*10);
 
 		#-----------------------------
 		# IMP allows for missing value
 		#-----------------------------
 
-		${$E}[$ens]->{HEADING} = defined(${$E}[$ens]->{HEADING})
-							   ? round(${$E}[$ens]->{HEADING}*100)
+		$dta->{ENSEMBLE}[$ens]->{HEADING} = defined($dta->{ENSEMBLE}[$ens]->{HEADING})
+							   ? round($dta->{ENSEMBLE}[$ens]->{HEADING}*100)
 							   : 0xF000;
-		${$E}[$ens]->{PITCH} = defined(${$E}[$ens]->{PITCH})
-							 ? unpack('S',pack('s',round(${$E}[$ens]->{PITCH}*100)))
+		$dta->{ENSEMBLE}[$ens]->{PITCH} = defined($dta->{ENSEMBLE}[$ens]->{PITCH})
+							 ? unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{PITCH}*100)))
 							 : 0x8000;
-		${$E}[$ens]->{ROLL} = defined(${$E}[$ens]->{ROLL})
-						    ? unpack('S',pack('s',round(${$E}[$ens]->{ROLL}*100)))
+		$dta->{ENSEMBLE}[$ens]->{ROLL} = defined($dta->{ENSEMBLE}[$ens]->{ROLL})
+						    ? unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{ROLL}*100)))
 						    : 0x8000;
 
-		${$E}[$ens]->{TEMPERATURE} =
-			unpack('S',pack('s',round(${$E}[$ens]->{TEMPERATURE}*100)));
-
-		sysseek(WBPF,2,1);			# skip built-in test which reads as 0 but is usually undef		
-									# this was found not to matter, but there is no reason to edit
-#		my($b1);					# this field
-#		sysread(WBPF,$b1,14);
-#		sysseek(WBPF,-14,1);
-#		my($sos,$xd,$hdg,$pit,$rol,$sal,$tem) = unpack('vvvvvvv',$b1);
+		$dta->{ENSEMBLE}[$ens]->{TEMPERATURE} =
+			unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{TEMPERATURE}*100)));
 
 		$buf = pack('vvvvvvv',
-			 ${$E}[$ens]->{SPEED_OF_SOUND},
-			 ${$E}[$ens]->{XDUCER_DEPTH},${$E}[$ens]->{HEADING},
-			 ${$E}[$ens]->{PITCH},${$E}[$ens]->{ROLL},
-			 ${$E}[$ens]->{SALINITY},${$E}[$ens]->{TEMPERATURE});
+			 $dta->{ENSEMBLE}[$ens]->{SPEED_OF_SOUND},
+			 $dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH},$dta->{ENSEMBLE}[$ens]->{HEADING},
+			 $dta->{ENSEMBLE}[$ens]->{PITCH},$dta->{ENSEMBLE}[$ens]->{ROLL},
+			 $dta->{ENSEMBLE}[$ens]->{SALINITY},$dta->{ENSEMBLE}[$ens]->{TEMPERATURE});
 
 		my($nw) = syswrite(WBPF,$buf,14);
 		$nw == 14 || die("$WBPcfn: $nw bytes written ($!)");
@@ -1080,10 +1107,10 @@
 		sysseek(WBPF,$start_ens+$WBPofs[2]+2,0) || die("$WBRcfn: $!");	# skip velocity data id (assume it is correct)
 		for ($bin=0; $bin<$nbins; $bin++) {
 			for ($beam=0; $beam<4; $beam++) {
-				${$E}[$ens]->{VELOCITY}[$bin][$beam] = defined(${$E}[$ens]->{VELOCITY}[$bin][$beam])
-							   						 ? round(${$E}[$ens]->{VELOCITY}[$bin][$beam]*1000)
+				$dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam] = defined($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam])
+							   						 ? round($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam]*1000)
 							   						 : 0x8000;
-				$buf = pack('v',unpack('S',pack('s',${$E}[$ens]->{VELOCITY}[$bin][$beam])));
+				$buf = pack('v',unpack('S',pack('s',$dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam])));
 				my($nw) = syswrite(WBPF,$buf,2);
 				$nw == 2 || die("$WBPcfn: $nw bytes written ($!)");
 			}
@@ -1096,7 +1123,7 @@
 		sysseek(WBPF,$start_ens+$WBPofs[3]+2,0) || die("$WBRcfn: $!");
 		for ($bin=0; $bin<$nbins; $bin++) {
 			for ($beam=0; $beam<4; $beam++) {
-				$buf = pack('C',${$E}[$ens]->{CORRELATION}[$bin][$beam]);
+				$buf = pack('C',$dta->{ENSEMBLE}[$ens]->{CORRELATION}[$bin][$beam]);
 				my($nw) = syswrite(WBPF,$buf,1);
 				$nw == 1 || die("$WBPcfn: $nw bytes written ($!)");
 			}
@@ -1110,7 +1137,7 @@
 
 		for ($bin=0; $bin<$nbins; $bin++) {
 			for ($beam=0; $beam<4; $beam++) {
-				$buf = pack('C',${$E}[$ens]->{ECHO_AMPLITUDE}[$bin][$beam]);
+				$buf = pack('C',$dta->{ENSEMBLE}[$ens]->{ECHO_AMPLITUDE}[$bin][$beam]);
 				my($nw) = syswrite(WBPF,$buf,1);
 				$nw == 1 || die("$WBPcfn: $nw bytes written ($!)");
 			}
@@ -1124,7 +1151,7 @@
 
 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
 			for ($beam=0; $beam<4; $beam++,$i++) {
-				$buf = pack('C',${$E}[$ens]->{PERCENT_GOOD}[$bin][$beam]);
+				$buf = pack('C',$dta->{ENSEMBLE}[$ens]->{PERCENT_GOOD}[$bin][$beam]);
 				my($nw) = syswrite(WBPF,$buf,1);
 				$nw == 1 || die("$WBPcfn: $nw bytes written ($!)");
 			}
--- a/RDI_Utils.pl
+++ b/RDI_Utils.pl
@@ -1,9 +1,9 @@
 #======================================================================
 #                    R D I _ U T I L S . P L 
 #                    doc: Wed Feb 12 10:21:32 2003
-#                    dlm: Sun Mar 22 10:19:08 2015
+#                    dlm: Sat Jan  9 16:36:52 2016
 #                    (c) 2003 A.M. Thurnherr
-#                    uE-Info: 494 98 NIL 0 0 72 0 2 4 NIL ofnI
+#                    uE-Info: 55 41 NIL 0 0 72 0 2 4 NIL ofnI
 #======================================================================
 
 # miscellaneous RDI-specific utilities
@@ -51,6 +51,8 @@
 #			      - Earth coord beam-pair warning removed
 #	May 29, 2014: - removed unused code (disabled warning) from ref_lr_w
 #	Mar 22, 2015: - BUG: mk_prof could bomb because of division-by-zero in return statement
+#	Jan  9, 2016: - renamed ref_lr_w to mk_prof_ref_lr_w because the old name conflicts
+#				    with a sub in LADCP_w
 
 use strict;
 
@@ -263,7 +265,7 @@
 
 # calculate reference-layer vertical and incident velocities
 
-sub ref_lr_w($$$$$$$)
+sub mk_prof_ref_lr_w($$$$$$$)
 {
 	my($dta,$ens,$rl_b0,$rl_b1,$min_corr,$max_e,$min_pctg) = @_;
 	my($i,@n,@bn,@v,@vi,@vel,@veli,@bv,@w);
@@ -422,7 +424,7 @@
 		filterEnsemble($dta,$e)
 			if (defined($filter) &&
 				$dta->{ENSEMBLE}[$e]->{PERCENT_GOOD}[0][0] > 0);
-		ref_lr_w($dta,$e,$lr_b0,$lr_b1,$min_corr,$max_e,$min_pctg);	# ref. layer w
+		mk_prof_ref_lr_w($dta,$e,$lr_b0,$lr_b1,$min_corr,$max_e,$min_pctg);	# ref. layer w
 	
 		if (defined($firstgood)) {
 			$dta->{ENSEMBLE}[$e]->{ELAPSED_TIME} =			# time since start
--- a/editPD0
+++ b/editPD0
@@ -2,56 +2,91 @@
 #======================================================================
 #                    E D I T P D 0 
 #                    doc: Mon Nov 25 20:24:31 2013
-#                    dlm: Fri Dec 18 20:56:45 2015
+#                    dlm: Sat Jan  9 20:07:59 2016
 #                    (c) 2013 A.M. Thurnherr
-#                    uE-Info: 104 1 NIL 0 0 72 2 2 4 NIL ofnI
+#                    uE-Info: 128 0 NIL 0 0 72 2 2 4 NIL ofnI
 #======================================================================
 
 # edit RDI PD0 file, e.g. to replace pitch/roll/heading with external values
 
+# NOTES:
+#
+#	- editing instructions can be provided either in an editing file (primarily
+#	  for ensemble-specific editing), or with the -x option on the command line
+#	  (only or editing applied to all ensembles)
+#
+#	- Data-Editing Library:
+#		p(<pitch>)				set pitch value (RDI not gimbal pitch) of current ensemble
+#		r(<roll>)				set roll alue value of current ensemble
+#		h(<heading>)			set heading alue value of current ensemble
+#
+#		swap_beams(<b1>,<b2>)	swap data from beams b1 and b2
+#								input in beam coords required
+#								beam rotation is equivalent to 3 consecutive beam swaps
+#
+#		earth2beam()			transform beam to earth coordinates
+#								does not handle bin-remapping
+#								input in beam coords required
+#
+#	- -x notes:
+#		- multiple perl expressions can be combined with ,
+#
+#	- Edit File Syntax:
+#		- # comments ignored
+#		- empty lines ignored
+#       - [space] <ensemble-number|*> <space> <perl-expr>
+#		- Examples:
+#       	162     p(3), r(4), h(3.14)
+
 # HISTORY:
-#	Nov 25, 2013: - created
-#	Dec 18, 2015: - added switch_beams()
-#				  - added -x
+#   Nov 25, 2013: - created
+#   Dec 18, 2015: - added switch_beams()
+#                 - added -x
+#	Jan  9, 2016: - renamed switch_beams() to swap_beams()
+#				  - wrote documentation
+#				  - change output data-source ID from 0x7F to 0xE0
+#				  - updated getopts to current perl version
+#				  - adapted to [ADCP_tools_lib.pl]
 
-$0 =~ m{(.*)/[^/]+}; 
-require "$1/RDI_PD0_IO.pl";
-require "getopts.pl";
+use Getopt::Std;
+
+($ADCP_TOOLS) = ($0 =~ m{(.*/)[^/]+});
+$ADCP_tools_minVersion = 1.4; 
+require "$ADCP_TOOLS/ADCP_tools_lib.pl";
 
 $USAGE = "$0 @ARGV";
 die("Usage: $0 " .
-	'-e) <edit-file> | -x) <expr> ' .
-	"<input file> <output file>\n")
-		unless (&Getopts('e:x:') && @ARGV == 2);
+    '-e) <edit-file> | -x) <expr> ' .
+    "<input file> <output file>\n")
+        unless (&getopts('e:x:') && @ARGV == 2);
 
 die("$0: -e <edit-file> or -x <expr> required\n")
-	unless (defined($opt_x) || -r $opt_e);
+    unless (defined($opt_x) || -r $opt_e);
 
-print(STDERR "Reading $ARGV[0]...");				# read data
+print(STDERR "Reading $ARGV[0]...");                # read data
 readData($ARGV[0],\%dta);
 print(STDERR "done\n");
 
 #----------------------------------------------------------------------
 
-print(STDERR "Editing Data...");				
+print(STDERR "Editing Data...");                
 
 #--------------------------------------------------
-# INTERFACE
-#	- example <edit_file> entry for external attitude data
-#		162     p(3), r(4), h(3.14)
-#	- example <edit_file> entry for beam switching
-#		*		switch_beams(3,4)
+# Data Editing Library
 #--------------------------------------------------
 
-sub p($) { $dta{ENSEMBLE}[$e]->{PITCH} = $_[0]; }
-sub r($) { $dta{ENSEMBLE}[$e]->{ROLL} = $_[0]; }
-sub h($) { $dta{ENSEMBLE}[$e]->{HEADING} = $_[0]; }
+sub p($) { $dta{ENSEMBLE}[$e]->{PITCH} = $_[0]; return 1; }
+sub r($) { $dta{ENSEMBLE}[$e]->{ROLL} = $_[0]; return 1; }
+sub h($) { $dta{ENSEMBLE}[$e]->{HEADING} = $_[0]; return 1;}
 
-sub switch_beams($$)
+sub swap_beams($$)
 {
 	my($b1,$b2) = @_;
 
-#	print(STDERR "\n entering switch_beams($b1,$b2) for ens = $e...");
+#	print(STDERR "\n entering swap_beams($b1,$b2) for ens = $e...");
+
+	die("$ARGV[0]: beam-coordinate data required\n")
+		unless ($dta{BEAM_COORDINATES});
 
 	for (my($bin)=0; $bin<$dta{N_BINS}; $bin++) {
 		my($tmp) = $dta{ENSEMBLE}[$e]->{VELOCITY}[$bin][$b1-1];
@@ -70,15 +105,36 @@
 		$dta{ENSEMBLE}[$e]->{PERCENT_GOOD}[$bin][$b1-1] = $dta{ENSEMBLE}[$e]->{PERCENT_GOOD}[$bin][$b2-1];
 		$dta{ENSEMBLE}[$e]->{PERCENT_GOOD}[$bin][$b2-1] = $tmp;
 	}
+	return 1;
+}
 
-	return 1;
+
+{ my($checked);
+
+	sub earth2beam()
+	{
+		unless ($checked) {
+			die("$ARGV[0]: earth-coordinate data required\n")
+				unless ($dta{EARTH_COORDINATES});
+			$dta{BEAM_COORDINATES} = 1; undef($dta{EARTH_COORDINATES});
+			$checked = 1;
+		}
+	    
+		for (my($bin)=0; $bin<$dta{N_BINS}; $bin++) {
+			@{$dta{ENSEMBLE}[$e]->{VELOCITY}[$bin]} =
+				velEarthToBeam(\%dta,$e,@{$dta{ENSEMBLE}[$e]->{VELOCITY}[$bin]});
+		}
+	
+		return 1;
+	}
+
 }
 
 #--------------------------------------------------
 # Main Routine
 #--------------------------------------------------
 
-if (defined($opt_x)) {
+if (defined($opt_x)) {															# edit instructions on the command line
 	push(@EE,'*');
 	my($id) = ($opt_x =~ m/^([A-Z]+)\s/);										# e.g. PITCH, ROLL, HEADING
 	$opt_x = sprintf('$dta{ENSEMBLE}[$e]->{%s}',$id)
@@ -86,7 +142,7 @@
 	push(@EX,$opt_x);
 }		
 
-if (defined($opt_e)) {
+if (defined($opt_e)) {															# edit instructions in edit file
 	open(EF,$opt_e) || die("$opt_e: $!\n");
 	while (<EF>) {
 		s/\#.*//;
@@ -104,9 +160,8 @@
 }
 
 for (local($e)=my($eei)=0; $e<@{$dta{ENSEMBLE}}; $e++) {						# local() needed for p(), r(), h()
-#	print(STDERR "\n\@ens=$EE[$eei]: $EX[$eei]\n");
+	$dta{ENSEMBLE}[$e]->{DATA_SOURCE_ID} = 0xE0;								# mark all ensembles
 	if ($EE[$eei] eq '*' || $EE[$eei] == $dta{ENSEMBLE}[$e]->{NUMBER}) {		# match => edit
-#		print(STDERR "\n\@ens=$EE[$eei]: $EX[$eei]");
 		eval($EX[$eei]) || die("$@ while executing <$EX[$eei]>\n");
 	} elsif ($EE[$eei] > $dta{ENSEMBLE}[$e]->{NUMBER}) {						# next edit later in file => skip
 		next;
--- a/listBins
+++ b/listBins
@@ -2,9 +2,9 @@
 #======================================================================
 #                    L I S T B I N S 
 #                    doc: Fri Aug 25 15:57:05 2006
-#                    dlm: Wed Jan  6 16:08:54 2016
+#                    dlm: Sun Jan 31 12:43:28 2016
 #                    (c) 2006 A.M. Thurnherr
-#                    uE-Info: 153 28 NIL 0 0 72 10 2 4 NIL ofnI
+#                    uE-Info: 340 0 NIL 0 0 72 10 2 4 NIL ofnI
 #======================================================================
 
 # Split data file into per-bin time series.
@@ -329,6 +329,15 @@
 				next;
 			}
 		} else { 															# Earth coordinates
+
+			my(@iVels) = &velEarthToInstrument(\%dta,$e,@{$dta{ENSEMBLE}[$e]->{VELOCITY}[$b]});
+			my(@eVels) = &velInstrumentToEarth(\%dta,$e,@iVels);
+#			printf(STDERR "err($e,$b) = %g,%g/%g,%g/%g,%g/%g,%g\n",
+#												$dta{ENSEMBLE}[$e]->{VELOCITY}[$b][0],$iVels[0],
+#												$dta{ENSEMBLE}[$e]->{VELOCITY}[$b][1],$iVels[1],
+#												$dta{ENSEMBLE}[$e]->{VELOCITY}[$b][2],$iVels[2],
+#												$dta{ENSEMBLE}[$e]->{VELOCITY}[$b][3],$iVels[3]);
+
 			@{$dta{ENSEMBLE}[$e]->{BEAM_VELOCITY}[$b]} =					# calculate beam velocities
 				velInstrumentToBeam(\%dta,
 					&velEarthToInstrument(\%dta,$e,@{$dta{ENSEMBLE}[$e]->{VELOCITY}[$b]}));
--- a/listHdr
+++ b/listHdr
@@ -2,9 +2,9 @@
 #======================================================================
 #                    L I S T H D R 
 #                    doc: Sat Jan 18 18:41:49 2003
-#                    dlm: Sat Jan  9 17:03:16 2016
+#                    dlm: Sat Jan  9 17:16:01 2016
 #                    (c) 2003 A.M. Thurnherr
-#                    uE-Info: 41 0 NIL 0 0 72 10 2 4 NIL ofnI
+#                    uE-Info: 41 32 NIL 0 0 72 10 2 4 NIL ofnI
 #======================================================================
 
 # Print useful info from the RDI BB header
@@ -38,11 +38,13 @@
 #	Jan  9, 2016: - added support for PRODUCER data field
 #				  - updated getopts to current perl version
 #				  - updated IO library name
+#				  - adapted to [ADCP_tools_lib.pl]
 
 use Getopt::Std;
 
-$0 =~ m{(.*/)[^/]+};
-require "$1RDI_PD0_IO.pl";
+($ADCP_TOOLS) = ($0 =~ m{(.*/)[^/]+});
+$ADCP_tools_minVersion = 1.4; 
+require "$ADCP_TOOLS/ADCP_tools_lib.pl";
 
 die("Usage: $0 [-s)ummary] <PD0 file[...]>\n")
     unless (&getopts('s') && @ARGV);
@@ -72,7 +74,7 @@
 	shift;
 	print("    Instrument Characteristics:\n");
 
-	printf("\tPRODUCER\t\t= %s\n",$hdr{PRODUCER});
+	printf("\tPRODUCER\t\t\t= %s\n",$hdr{PRODUCER});
 	if (defined($hdr{SERIAL_NUMBER})) {
 		printf("\tINSTRUMENT\t\t\t= %s #%d\n",$hdr{INSTRUMENT_TYPE},$hdr{SERIAL_NUMBER});
     } else {