V7.1
authorA.M. Thurnherr <athurnherr@yahoo.com>
Tue, 27 Nov 2018 12:58:21 -0500
changeset 36 04e8cb4f8073
parent 35 d3f6ca34c4ea
child 37 b24d11f7dfc4
V7.1
.lsfit.poly
ANTSlib
HISTORY
INDEX
ants.pl
antsio.pl
libCPT.pl
libIMP.pl
libLADCP.pl
libRDI_Coords.pl
libSBE.pl
libconv.pl
libfuns.pl
libvec.pl
--- a/.lsfit.poly
+++ b/.lsfit.poly
@@ -1,9 +1,9 @@
 #======================================================================
 #                    . L S F I T . P O L Y 
 #                    doc: Wed Feb 24 09:40:06 1999
-#                    dlm: Thu Jan 10 16:47:06 2013
+#                    dlm: Sun May 13 08:25:37 2018
 #                    (c) 1999 A.M. Thurnherr
-#                    uE-Info: 118 16 NIL 0 0 72 2 2 4 NIL ofnI
+#                    uE-Info: 114 36 NIL 0 0 72 2 2 4 NIL ofnI
 #======================================================================
 
 # What you need to provide if you wanna fit a different
@@ -27,6 +27,7 @@
 #	Jul 28, 2006: - Version 3.3 [HISTORY]
 #	Sep 19, 2011: - moved part of the usage code into init() to allow use in [pgram]
 #	Jan 10, 2013: - added extremum output when fitting parabola (-o 2)
+#	May 13, 2018: - BUG: replaced opt_o with modelNFit in &modelCleanup()
 
 #++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 #
@@ -110,7 +111,7 @@
 
 sub modelCleanup() 
 {
-	return unless ($opt_o == 2);		# calculate loc of extremum on parabolic fits
+	return unless ($0 eq 'lsfit' && $modelNFit == 3);		# calculate loc of extremum on parabolic fits with lsfit only
 
 	my($extX) = -$A[2] / (2 * $A[3]);
 	if ($A[3] > 0) {
old mode 100755
new mode 100644
--- a/HISTORY
+++ b/HISTORY
@@ -1,9 +1,9 @@
 #======================================================================
 #                    H I S T O R Y 
 #                    doc: Thu May  7 13:12:05 2015
-#                    dlm: Sat Dec 23 16:20:34 2017
+#                    dlm: Tue Nov 27 12:57:11 2018
 #                    (c) 2015 A.M. Thurnherr
-#                    uE-Info: 10 11 NIL 0 0 70 0 2 4 NIL ofnI
+#                    uE-Info: 184 51 NIL 0 0 70 0 2 4 NIL ofnI
 #======================================================================
 
 May  7, 2015:
@@ -154,3 +154,33 @@
 	- improvements to [libALEC.pl]
 	- removed ambiguous date warning from [libconv.pl]
 
+Dec 23, 2017:
+	- published V7.0
+
+----------------------------------------------------------------------
+
+Mar 3 - Apr 23, 2018:
+	- multiple improvements to [libSBE.pl]
+
+Mar 28, 2018: 
+	- added &loadInstrumentTransformation() to [libRDI_coords.pl]
+
+Apr 23, 2018:
+	- bugfix in [antsio.pl]
+
+Apr 25, 2018:
+	- added eps_VKE() to [libLADCP.pl]
+
+May 13, 2018:
+	- bugfix in [.lsfit.poly]
+
+May 22, 2018: 
+	- added NMEA2dec_time() to [libconv.pl]
+
+May 22 - Jun 9, 2018:
+	- multiple improvements to [libIMP.pl]
+
+Nov 27, 2018:
+	- update version number in [ants.pl] [.hg/hgrc]
+	- updated HISTORY
+	- published V7.1
old mode 100755
new mode 100644
--- a/ants.pl
+++ b/ants.pl
@@ -2,9 +2,9 @@
 #======================================================================
 #                    A N T S . P L 
 #                    doc: Fri Jun 19 14:01:06 1998
-#                    dlm: Fri Dec  8 13:11:21 2017
+#                    dlm: Tue Nov 27 12:57:36 2018
 #                    (c) 1998 A.M. Thurnherr
-#                    uE-Info: 31 20 NIL 0 0 72 2 2 4 NIL ofnI
+#                    uE-Info: 27 60 NIL 0 0 72 2 2 4 NIL ofnI
 #======================================================================
 
 # HISTORY:
@@ -24,11 +24,12 @@
 #  Mar 12, 2017: - updated to V6.8 (for LADCP_w 1.3 release)
 #  Nov 20, 2017: - updated to V6.9 (for DT KVH software)
 #  Dec  8, 2017: - updated to V7.0 (to avoid absolute-path symlink)
+#  Nov 27, 2018: - updaetd to V7.1 (for LADCP_w 1.4 release)
 
 exec($ENV{ANTS_PERL},$0,@ARGV),die("$ENV{ANTS_PERL}: $!")
     if (defined($ENV{ANTS_PERL}) && $^X ne $ENV{ANTS_PERL});
 
-$antsLibVersion = 7.0;
+$antsLibVersion = 7.1;
 
 die(sprintf("$0: obsolete library V%.1f; V%.1f required\n",
 	$antsLibVersion,$antsMinLibVersion))
--- a/antsio.pl
+++ b/antsio.pl
@@ -2,9 +2,9 @@
 #======================================================================
 #                    A N T S I O . P L 
 #                    doc: Fri Jun 19 19:22:51 1998
-#                    dlm: Wed Apr  5 13:45:32 2017
+#                    dlm: Mon Apr 23 14:20:58 2018
 #                    (c) 1998 A.M. Thurnherr
-#                    uE-Info: 215 83 NIL 0 0 70 2 2 4 NIL ofnI
+#                    uE-Info: 216 82 NIL 0 0 70 2 2 4 NIL ofnI
 #======================================================================
 
 # HISTORY:
@@ -213,6 +213,7 @@
 #	Sep 13, 2016: - modified &antsAddParams to make more flexible
 #	Mar 10, 2017: - BUG: antsCheckDeps() used ctime instead of mtime!!!
 #	Apr  5, 2017: - BUG: stale file mtime dependency info was not printed correctly
+#	Apr 23, 2018: - BUG: @antsLayout was not kept up-to-date when layout-changes are allowed
 
 # GENERAL NOTES:
 #	- %P was named without an ants-prefix because associative arrays
@@ -486,10 +487,12 @@
 
 		# DONE WITH HEADER PARSING
 		
+		# Handle Layout changes:
+		#	- only allow when $antsAllowEmbeddedLayoutChange is set
+		#	- ensure that antsLayout always contains up-to-date Layout
 		croak("$0: embedded layout change when reading file $ARGV <@antsLayout> -> <@Layout>")
 			if (!$antsAllowEmbeddedLayoutChange && @Layout && @antsLayout && ("@Layout" ne "@antsLayout"));
-
-		@antsLayout = @Layout unless (@antsLayout);
+		@antsLayout = @Layout if (@Layout);
 
 		$P{RECNO} = -1 unless defined($P{RECNO});	# set pseudo %PARAMs
 		$P{LINENO} = -1 unless defined($P{LINENO});
--- a/libCPT.pl
+++ b/libCPT.pl
@@ -1,9 +1,9 @@
 #======================================================================
 #                    L I B C P T . P L 
 #                    doc: Wed Nov 15 12:28:49 2000
-#                    dlm: Fri May  9 11:40:01 2008
+#                    dlm: Mon May 14 21:29:00 2018
 #                    (c) 2000 A.M. Thurnherr
-#                    uE-Info: 25 31 NIL 0 0 72 2 2 4 NIL ofnI
+#                    uE-Info: 75 58 NIL 0 0 72 2 2 4 NIL ofnI
 #======================================================================
 
 # HISTORY:
@@ -23,6 +23,9 @@
 #	Aug 16, 2006: - BUG: last level was returned on value < first level
 #	May  9, 2008: - adapted to GMT 4.3 (see also IMPLEMENTATION NOTES
 #					in [mkCPT])
+#	Mar 26, 2018: - BUG: fg colors could not be set?!?!?!?! (both F and B set bg color)
+#				  - implemented color scaling for input files with rgb vals 0-1
+#	May 14, 2016: - added input file check
 
 #----------------------------------------------------------------------
 # CPT File Parsing
@@ -65,10 +68,11 @@
 		if ($f[0] eq 'B') {
 			$CPT{bg_R} = $f[1]; $CPT{bg_G} = $f[2]; $CPT{bg_B} = $f[3];
 		} elsif ($f[0] eq 'F') {
-			$CPT{bg_R} = $f[1]; $CPT{bg_G} = $f[2]; $CPT{bg_B} = $f[3];
+			$CPT{fg_R} = $f[1]; $CPT{fg_G} = $f[2]; $CPT{fg_B} = $f[3];
 		} elsif ($f[0] eq 'N') {
 			$CPT{nan_R} = $f[1]; $CPT{nan_G} = $f[2]; $CPT{nan_B} = $f[3];
 		} else {
+			croak("$0: format error - 7 fields expected on line: $_") unless ($#f >= 7);
 			$CPT{from_z}[$CPT{levels}] = $f[0];
 			$CPT{from_R}[$CPT{levels}] = $f[1];
 			$CPT{from_G}[$CPT{levels}] = $f[2];
@@ -82,7 +86,27 @@
     }
     $CPT{color_model} = 'RGB' unless defined($CPT{color_model});
     croak("$0: color model $CPT{color_model} not implemented\n")
-    	unless ($CPT{color_model} =~ '\+?RGB' || $CPT{color_model} =~ '\+?HSV');
+    	unless ($CPT{color_model} =~ '\+?[Rr][Gg][Bb]' || $CPT{color_model} =~ '\+?[Hh][Ss][Vv]');
+
+	if ($CPT{from_R}[0]>=0 && $CPT{from_R}[0]<=1 &&								# colors in 0-1 range
+		$CPT{from_G}[0]>=0 && $CPT{from_G}[0]<=1 &&
+		$CPT{from_B}[0]>=0 && $CPT{from_B}[0]<=1 &&
+    	$CPT{from_R}[$CPT{levels}-1]>=0 && $CPT{from_R}[$CPT{levels}-1]<=1 &&
+		$CPT{from_G}[$CPT{levels}-1]>=0 && $CPT{from_G}[$CPT{levels}-1]<=1 &&
+		$CPT{from_B}[$CPT{levels}-1]>=0 && $CPT{from_B}[$CPT{levels}-1]<=1) {
+			$CPT{bg_R} = round(255 * $CPT{bg_R}); $CPT{bg_G} = round(255 * $CPT{bg_G}); $CPT{bg_B} = round(255 * $CPT{bg_B});
+			$CPT{fg_R} = round(255 * $CPT{fg_R}); $CPT{fg_G} = round(255 * $CPT{fg_G}); $CPT{fg_B} = round(255 * $CPT{fg_B});
+			$CPT{nan_R} = round(255 * $CPT{nan_R}); $CPT{nan_G} = round(255 * $CPT{nan_G}); $CPT{nan_B} = round(255 * $CPT{nan_B});
+			for (my($i)=0; $i<$CPT{levels}; $i++) {
+				$CPT{from_R}[$i] = round(255 * $CPT{from_R}[$i]);
+				$CPT{from_G}[$i] = round(255 * $CPT{from_G}[$i]);
+				$CPT{from_B}[$i] = round(255 * $CPT{from_B}[$i]);
+				$CPT{to_R}[$i] = round(255 * $CPT{to_R}[$i]);
+				$CPT{to_G}[$i] = round(255 * $CPT{to_G}[$i]);
+				$CPT{to_B}[$i] = round(255 * $CPT{to_B}[$i]);
+			}
+	}
+
 	return %CPT;
 }
 		
--- a/libIMP.pl
+++ b/libIMP.pl
@@ -1,9 +1,9 @@
 #======================================================================
 #                    L I B I M P . P L 
 #                    doc: Tue Nov 26 21:59:40 2013
-#                    dlm: Fri Dec  8 13:44:41 2017
+#                    dlm: Sat Jun  9 12:07:15 2018
 #                    (c) 2017 A.M. Thurnherr
-#                    uE-Info: 42 73 NIL 0 0 70 2 2 4 NIL ofnI
+#                    uE-Info: 52 109 NIL 0 0 70 2 2 4 NIL ofnI
 #======================================================================
 
 # HISTORY:
@@ -40,6 +40,16 @@
 #	Nov 20, 2017: - major code cleanup
 #	Nov 22, 2017: - replaced "IMP" output in routines used by KVH by "IMU"
 #	Dec  8, 2017: - replaced remaing "IMP" output (e.g. in plot) by "IMU"
+#	May 22, 2018: - added data trimming to rot_vec
+#	May 23, 2018: - added horizontal field strength to mag calib plot
+#				  - added support for S/N 8 board inside UL WH300 (neg_piro == 2)
+#	May 24, 2018: - continued working (coord_trans == 2)
+#	May 25, 2018: - continued working
+#	May 30, 2018: - BUG: trimming did not re-calculate elapsed time
+#	Jun  5, 2018: - BUG: on -c main magnetometer and accelerometer vectors were
+#						 modified twice
+#	Jun  7, 2018: - relaxed definition of -e
+#	Jun  9, 2018: - BUG: some "edge" data (beyond the valid profile) were bogus (does not matter in practice)
 
 #----------------------------------------------------------------------
 # gRef() library
@@ -75,67 +85,98 @@
 	} else {
 		GMT_psbasemap('-Bg1a.1f.01:"X Magnetic Field [Gauss]":/g1a0.1f0.01:"Y Magnetic Field [Gauss]":WeSn');
 	}
-    GMT_unitcoords();																# sensor info
-	if ($sensor_info ne '') {
-	    GMT_pstext('-F+f12,Helvetica,blue+jTR -N');
-    	printf(GMT "0.98 0.98 $sensor_info\n");
-    }
-    GMT_pstext('-F+f14,Helvetica,blue+jTL -N');
+    GMT_unitcoords();																# horizontal field strength
+    GMT_pstext('-F+f12,Helvetica,blue+jTR -N');
+   	printf(GMT "0.98 0.98 HF = %.2f Gauss\n",$HF_mag);
+   	
+   	printf(GMT "0.98 0.94 $sensor_info\n")											# sensor info
+		if ($sensor_info ne '');
+
+    GMT_pstext('-F+f14,Helvetica,blue+jTL -N');										# profile id
     printf(GMT "0.01 1.06 $P{profile_id}\n");
 	GMT_end();
 }
 
-sub rot_vecs($) 																	# rotate & output IMU vector data 
+sub rot_vecs(@) 																	# rotate & output IMU vector data 
 {
-	my($neg_piro) = @_;																# negate KVH pitch/roll data
+	my($coord_trans,$min_elapsed,$max_elapsed,$plot_milapsed,$plot_malapsed) = @_;		# negate KVH pitch/roll data if first arg set to 1
+	$min_elapsed = 0 unless defined($min_elapsed);
+	$max_elapsed = 9e99 unless defined($max_elapsed);
+	$plot_milapsed = $min_elapsed unless defined($plot_milapsed);
+	$plot_malapsed = $max_elapsed unless defined($plot_malapsed);
+
 	while (&antsIn()) {
+		next if ($ants_[0][$elapsedF] < $min_elapsed);								# trim data
+		last if ($ants_[0][$elapsedF] > $max_elapsed);
+		
 		my($cpiro) = -1;															# current pitch/roll accelerometer
 		my(@R); 																	# rotation matrix
 		for (my($i)=0; $i<@vecs; $i++) {											# rotate vector data
 			if ($piro[$i][0] != $cpiro) {											# next sensor chip
 				$cpiro = $piro[$i][0];
-				my($pitch) = atan2($ants_[0][$vecs[$cpiro][0]], 					# eqn 25 from Freescale AN3461
-								   sqrt($ants_[0][$vecs[$cpiro][1]]**2+$ants_[0][$vecs[$cpiro][2]]**2));    
-				my($roll)  = atan2($ants_[0][$vecs[$cpiro][1]], 					# eqn 26
-								   $ants_[0][$vecs[$cpiro][2]]);
-				if ($neg_piro) {
+
+				my($accX) = $ants_[0][$vecs[$cpiro][0]];
+				my($accY) = $ants_[0][$vecs[$cpiro][1]];
+				my($accZ) = $ants_[0][$vecs[$cpiro][2]];
+
+				if ($coord_trans == 2) {											# S/N 8 inside UL WH300
+					$accY *= -1; $accZ *= -1;
+				}
+				
+				my($roll)  = atan2($accY,$accZ); 									# eqn 25 from Freescale AN3461
+				my($pitch) = atan2($accX,sqrt($accY**2+$accZ**2));     				# eqn 26 from <Freescale AN3461
+				if ($coord_trans == 1) {											# KVH
 					$pitch *= -1;
 					$roll  *= -1;
-                }								   
+                }
 				$ants_[0][$piro[$i][1]] = deg($pitch);								# add pitch/roll to data
 				$ants_[0][$piro[$i][2]] = deg($roll);
+
 				my($sp) = sin($pitch); my($cp) = cos($pitch);						# define rotation matrix
 				my($sr) = sin($roll);  my($cr) = cos($roll);
 				@R = ([ $cp,	 0,   -$sp	  ],
 					  [-$sp*$sr, $cr, -$cp*$sr],
 					  [ $sp*$cr, $sr,  $cp*$cr]);
 			}
-			my($newX) = ($ants_[0][$vecs[$i][0]]-$bias[$i][0]) * $R[0][0] +
-						($ants_[0][$vecs[$i][1]]-$bias[$i][1]) * $R[0][1] +
-						($ants_[0][$vecs[$i][2]]-$bias[$i][2]) * $R[0][2];
-			my($newY) = ($ants_[0][$vecs[$i][0]]-$bias[$i][0]) * $R[1][0] +
-						($ants_[0][$vecs[$i][1]]-$bias[$i][1]) * $R[1][1] +
-						($ants_[0][$vecs[$i][2]]-$bias[$i][2]) * $R[1][2];
-			my($newZ) = ($ants_[0][$vecs[$i][0]]-$bias[$i][0]) * $R[2][0] +
-						($ants_[0][$vecs[$i][1]]-$bias[$i][1]) * $R[2][1] +
-						($ants_[0][$vecs[$i][2]]-$bias[$i][2]) * $R[2][2];
-			$ants_[0][$vecs[$i][0]] = $newX;
-			$ants_[0][$vecs[$i][1]] = $newY;
-			$ants_[0][$vecs[$i][2]] = $newZ;
+			my($xval) = $ants_[0][$vecs[$i][0]];
+			my($yval) = $ants_[0][$vecs[$i][1]];
+			my($zval) = $ants_[0][$vecs[$i][2]];
+			
+			if ($coord_trans == 2) {												# S/N 8 inside UL WH300
+				$yval *= -1; $zval *= -1;
+			}
+			
+			$ants_[0][$vecs[$i][0]] = ($xval-$bias[$i][0]) * $R[0][0] +
+									  ($yval-$bias[$i][1]) * $R[0][1] +
+									  ($zval-$bias[$i][2]) * $R[0][2];
+			$ants_[0][$vecs[$i][1]] = ($xval-$bias[$i][0]) * $R[1][0] +
+			  						  ($yval-$bias[$i][1]) * $R[1][1] +
+									  ($zval-$bias[$i][2]) * $R[1][2];
+			$ants_[0][$vecs[$i][2]] = ($xval-$bias[$i][0]) * $R[2][0] +
+									  ($yval-$bias[$i][1]) * $R[2][1] +
+									  ($zval-$bias[$i][2]) * $R[2][2];
 		}
 	
 		my($magX) = $ants_[0][$magXF];
 		my($magY) = $ants_[0][$magYF];
 		my($magZ) = $ants_[0][$magZF];
+		my($accX) = $ants_[0][$accXF];
+		my($accY) = $ants_[0][$accYF];
+		my($accZ) = $ants_[0][$accZF];
+
 		my($HF)   = sqrt($magX**2+$magY**2);
 		my($valid)= ($HF >= $minfac*$HF_mag) && ($HF <= $maxfac*$HF_mag);
 		my($hdg)  = $valid ? mag_heading($magX,$magY) : nan;
-		&antsOut($ants_[0][$elapsedF],$ants_[0][$tempF],
+
+		&antsOut($ants_[0][$elapsedF]-$min_elapsed,$ants_[0][$tempF],
 				 RDI_pitch($ants_[0][$pitchF],$ants_[0][$rollF]),$ants_[0][$rollF],
-				 $hdg,$ants_[0][$accXF],$ants_[0][$accYF],$ants_[0][$accZF],
-				 $magX,$magY,$magZ,vel_u($HF,$hdg),vel_v($HF,$hdg),$valid);
+				 $hdg,$accX,$accY,$accZ,$magX,$magY,$magZ,
+				 vel_u($HF,$hdg),vel_v($HF,$hdg),$valid);
+
 		pl_mag_calib_plot($valid,$magX,$magY)
-			if defined($P{profile_id});
+			if defined($P{profile_id}) &&
+				($ants_[0][$elapsedF] >= $plot_milapsed) &&
+				($ants_[0][$elapsedF] <= $plot_malapsed);
 	}
 }
 
@@ -414,7 +455,7 @@
 	} else {
 		my($dhist_binsize,$dhist_min_pirom,$dhist_min_mfrac) = split(/,/,$opt_e);
 		croak("$0: cannot decode -e $opt_e\n")
-			unless ($dhist_binsize > 0 && $dhist_min_pirom > 0 && $dhist_min_mfrac > 0);
+			unless ($dhist_binsize > 0 && $dhist_min_pirom > 0 && $dhist_min_mfrac >= 0);
 	
 		my(@dhist); my($nhist) = my($modeFreq) = 0;
 		for (my($ens)=$LADCP_begin; $ens<=$LADCP_end; $ens++) {
@@ -638,15 +679,18 @@
 
 	for (my($ens)=0; $ens<=$#{$LADCP{ENSEMBLE}}; $ens++) {
 		my($r) = int(($LADCP{ENSEMBLE}[$ens]->{ELAPSED_TIME} + $IMP{TIME_LAG} - $ants_[0][$elapsedF]) / $IMP{DT});
-		if ($r<0 || $r>$#ants_) {
+#		print(STDERR "$r\[$ens\,$LADCP{ENSEMBLE}[$ens]->{NUMBER}] = int(($LADCP{ENSEMBLE}[$ens]->{ELAPSED_TIME} + $IMP{TIME_LAG} - $ants_[0][$elapsedF]) / $IMP{DT});\n");
+		if ($r<0 || $r>$#ants_) {												# ensemble beyond limits of IMU data
 			my(@out);
-			$out[$elapsedF] = $LADCP{ENSEMBLE}[$ens]->{ELAPSED_TIME} + $IMP{TIME_LAG};
-			$out[$L_elapsedF] = $LADCP{ENSEMBLE}[$ens]->{ELAPSED_TIME};
-			$out[$L_ensF]		= $LADCP{ENSEMBLE}[$ens]->{NUMBER};
-			$out[$dcF]		= ($ens <= $LADCP_bottom);
+			if ($ens >= $LADCP_begin && $ens <= $LADCP_end) {
+				$out[$elapsedF] 	= $LADCP{ENSEMBLE}[$ens]->{ELAPSED_TIME} + $IMP{TIME_LAG};
+				$out[$L_elapsedF] 	= $LADCP{ENSEMBLE}[$ens]->{ELAPSED_TIME};
+			}
+			$out[$L_ensF]			= $LADCP{ENSEMBLE}[$ens]->{NUMBER};
+			$out[$dcF]				= ($ens <= $LADCP_bottom);
 			&antsOut(@out);
-		} elsif ($ens < $LADCP_begin || $ens > $LADCP_end) {
-			$ants_[$r][$L_elapsedF] = $LADCP{ENSEMBLE}[$ens]->{ELAPSED_TIME};
+		} elsif ($ens < $LADCP_begin || $ens > $LADCP_end) {					# pre deplyment or post recovery
+			$ants_[$r][$L_elapsedF] = undef;
 			$ants_[$r][$L_ensF] 	= $LADCP{ENSEMBLE}[$ens]->{NUMBER};
 			$ants_[$r][$L_pitchF]	= undef;
 			$ants_[$r][$L_rollF]	= undef;
--- a/libLADCP.pl
+++ b/libLADCP.pl
@@ -1,9 +1,9 @@
 #======================================================================
 #                    L I B L A D C P . P L 
 #                    doc: Wed Jun  1 20:38:19 2011
-#                    dlm: Mon May 18 09:49:19 2015
+#                    dlm: Wed Apr 25 17:41:36 2018
 #                    (c) 2011 A.M. Thurnherr
-#                    uE-Info: 49 12 NIL 0 0 70 2 2 4 NIL ofnI
+#                    uE-Info: 46 27 NIL 0 0 70 2 2 4 NIL ofnI
 #======================================================================
 
 # HISTORY:
@@ -23,11 +23,32 @@
 #	Jun 26. 2013: - added T_w_z()
 #				  - added parameter checks to processing-specific corrections
 #	May 18, 2015: - added pulse length to T_w() and T_w_z()
+#	Apr 25, 2018: - added eps_VKE() parameterization
 
 require "$ANTS/libvec.pl";
 require "$ANTS/libfuns.pl";
 
 #------------------------------------------------------------------------------
+# VKE parameterization for epsilon
+#
+# NOTES:
+#	- see Thurnherr et al. (GRL 2015)
+#	- calculate eps from p0
+#	- optional second argument allows free choice of parameterization constant
+#	- default value is from paper, which is slightly lower than the current value
+#	  used in [LADCP_VKE], which applies the parameterization only to spectra
+#	  passing a few tests
+#------------------------------------------------------------------------------
+
+sub eps_VKE(@)
+{
+    my($p0,$c) =
+        &antsFunUsage(-1,'.','<p0[m^2/s^2/(rad/m)]> [c[0.021 [1/sqrt(s)]]]',@_);
+	$c = 0.021 unless defined($c);
+    return numberp($p0) ? ($p0 / $c) ** 2 : nan;
+}
+
+#------------------------------------------------------------------------------
 # Spectral corrections for LADCP data
 #
 # NOTES:
@@ -35,7 +56,6 @@
 #	- to correct, multiply power densities (or power, I think) with corrections
 #	- apply to down-/up-cast data only
 #------------------------------------------------------------------------------
-
 #----------------------------------------------------------------------
 # 1. Corrections for individual data acquisition and processing steps
 #----------------------------------------------------------------------
--- a/libRDI_Coords.pl
+++ b/libRDI_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: Mon Nov 27 07:13:25 2017
+#                    dlm: Wed Mar 28 12:30:12 2018
 #                    (c) 2003 A.M. Thurnherr
-#                    uE-Info: 58 62 NIL 0 0 72 10 2 4 NIL ofnI
+#                    uE-Info: 109 22 NIL 0 0 72 10 2 4 NIL ofnI
 #======================================================================
 
 # RDI Workhorse Coordinate Transformations
@@ -56,6 +56,7 @@
 #	Oct 12, 2017: - documentation
 #	Nov 26, 2017: - BUG: velBeamtoBPEarth() did not respect missing values
 #	Nov 27, 2017: - BUG: numbersp() from [antslib.pl] was used
+#	Mar 28, 2018: - added &loadInstrumentTransformation()
 
 use strict;
 use POSIX;
@@ -74,7 +75,15 @@
 $RDI_Coords::beamTransformation = 'LHR90';	# set to 'RDI' to use 1st order transformations from RDI manual
 
 #----------------------------------------------------------------------
-# beam to earth transformation 
+# beam to earth transformation
+#	- loadInstrumentTransformation(filename) loads a file that contains the
+#	  output from the PS3 command, which includes the instrument transformation
+#	  matrix as follows:
+#	Instrument Transformation Matrix (Down):    Q14:
+#	  1.4689   -1.4682    0.0030   -0.0035       24067  -24055      49     -58
+#	 -0.0036    0.0029   -1.4664    1.4673         -59      48  -24025   24041
+#	  0.2658    0.2661    0.2661    0.2657        4355    4359    4359    4354
+#	  1.0373    1.0382   -1.0385   -1.0373       16995   17010  -17015  -16995
 #----------------------------------------------------------------------
 
 $RDI_Coords::threeBeam_1 = 0;			# stats from velBeamToInstrument
@@ -88,6 +97,35 @@
 { # STATIC SCOPE
 	my(@B2I);
 
+	sub loadInstrumentTransformation($)
+	{
+		die("loadInstrumentTransformation(): B2I matrix already defined\n")
+			if (@B2I);
+		open(ITF,$_[0]) || die("$_[0]: $!\n");
+		my($row) = 0;
+		while (<ITF>) {
+			if ($row == 0) {
+				next unless m{^Instrument Transformation Matrix \(Down\):};
+				$row = 1;
+			} elsif ($row <= 4) {
+				my(@vals) = split;
+				die("$_[0]: cannot decode row #$row of Instrument Transformation Matrix\n")
+					unless (@vals == 8);
+				for (my($i)=0; $i<4; $i++) {
+					die("$_[0]: cannot decode row #$row of Instrument Transformation Matrix\n")
+						unless numberp($vals[$i]);
+					$B2I[$row-1][$i] = $vals[$i];
+				}
+				$row++;
+			} else {
+				last;
+			}
+		}
+		die("$_[0]: cannot decode Instrument Transformation Matrix (row = $row)\n")
+			unless ($row == 5);
+		close(ITF);
+	}
+
 	sub velBeamToInstrument(@)
 	{
 		my($ADCP,$ens,$v1,$v2,$v3,$v4) = @_;
@@ -134,22 +172,21 @@
 	}
 } # STATIC SCOPE
 
-#----------------------------------------------------------------------
+#--------------------------------------------------------------------------------------------------------------
 # velInstrumentToEarth(\%ADCP,ens,v1,v2,v3,v4) => (u,v,w,e)
 #	- $RDI_Coords::beamTransformation = 'LHR90'
 #		- from Lohrmann, Hackett & Roet (J. Tech., 1990)
 #		- eq A1 maps to RDI matrix M (sec 5.6) with
 #			alpha = roll
 #			beta = gimball_pitch
-#			psi = calculation_pitch
-#			psi = asin{sin(beta) cos(alpha) / sqrt[1- sin(alpha)^2 sin(beta)^2]}
+#			psi (pitch used for calculation) =  asin{sin(beta) cos(alpha) / sqrt[1- sin(alpha)^2 sin(beta)^2]}
 #		- (I only checked for 0 heading, but this is sufficient)
 #	- $RDI_Coords::beamTransformation = 'RDI'
 #		- default prior to LADCP_w V1.3
 #		- from RDI manual
 #		- 99% accurate for p/r<8deg
 #			=> 1cm/s error for 1m/s winch speed!
-#----------------------------------------------------------------------
+#--------------------------------------------------------------------------------------------------------------
 
 { # STATIC SCOPE
 	my($hdg,$pitch,$roll,@I2E);
old mode 100755
new mode 100644
--- a/libSBE.pl
+++ b/libSBE.pl
@@ -1,9 +1,9 @@
 #======================================================================
 #                    L I B S B E . P L 
 #                    doc: Mon Nov  3 12:42:14 2014
-#                    dlm: Fri Mar 10 09:46:42 2017
+#                    dlm: Mon Apr 23 21:03:27 2018
 #                    (c) 2014 A.M. Thurnherr
-#                    uE-Info: 20 55 NIL 0 0 72 2 2 4 NIL ofnI
+#                    uE-Info: 25 105 NIL 0 0 72 2 2 4 NIL ofnI
 #======================================================================
 
 # HISTORY:
@@ -18,6 +18,11 @@
 #				  - added $libSBE_quiet to suppress diagnostic messages
 #	May 31, 2016: - made successfully decoding lat/lon optional
 #	Mar 10, 2017: - made lat/lon decoding more flexible
+#	Mar  3, 2018: - adapted SBE37 fields (multiple changes)
+#				  - added default field name for sound speed (sspd)
+#	Mar  8, 2018: - BUG: SBE_parseHeader() did not correctly detect missing lat/lon
+#				  - suppressed warnings in SBE_parseHeader()
+#	Apr 23, 2018: - BUG: header lat/lon was incorrectly parsed when there was no spaced before hemisphere
 
 #----------------------------------------------------------------------
 # fname_SBE2std($)
@@ -30,13 +35,15 @@
 
 	return 'lat' 		if /^lat/;
 	return 'lon' 		if /^lon/;
-	return 'press'		if /^prDM/;
+	return 'press'		if /^pr[dD]M/;
+	return 'sspd'		if /^sv[dD]M/;
 	return 'depth'		if /^depSM/;
 	return 'O2' 		if /^sbeox0/;
 	return 'alt_O2' 	if /^sbeox1/;
 	return 'salin' 		if /^sal00/;
 	return 'alt_salin' 	if /^sal11/;
 	return 'elapsed'	if /^timeS/;
+	return 'time_jday'	if /^timeJV2/;
 	return 'sigma0' 	if /^sigma.*00/;
 	return 'alt_sigma0' if /^sigma.*11/;
 	return 'rho0' 		if /^density00/;
@@ -90,24 +97,24 @@
 		return 'alt_theta0';
 	}
 
-	if (m{^c0S/m}) {										# conductivity with different units
+	if (m{^c0S/m} || m{^cond0S/m}) {										# conductivity with different units
 		return undef
 			if defined($P{'cond.unit'}) && ($P{'cond.unit'} ne 'S/m');
 		&antsAddParams('cond.unit','S/m');
 		return 'cond';
-	} elsif (m{^c0mS/cm}) {
+	} elsif (m{^c0mS/cm} || m{^cond0mS/cm}) {
 		return undef
 			if defined($P{'cond.unit'}) && ($P{'cond.unit'} ne 'mS/cm');
 		&antsAddParams('cond.unit','mS/cm');
 		return 'cond';
 	}
 		
-	if (m{^c1S/m}) {
+	if (m{^c1S/m} || m{^cond1S/m}) {
 		return undef
 			if defined($P{'cond.unit'}) && ($P{'cond.unit'} ne 'S/m');
 		&antsAddParams('cond.unit','S/m');
 		return 'alt_cond';
-	} elsif (m{^c1mS/cm}) {
+	} elsif (m{^c1mS/cm} || m{^cond1mS/cm}) {
 		return undef
 			if defined($P{'cond.unit'}) && ($P{'cond.unit'} ne 'mS/cm');
 		&antsAddParams('cond.unit','mS/cm');
@@ -162,21 +169,21 @@
 		&antsAddParams('ITS',68); $P{ITS} = 68;
 	}
 
-	if (m{^c0S/m}) {										# conductivity with different units
+	if (m{^c0S/m} || m{^cond0S/m}) {										# conductivity with different units
 		return undef
 			if defined($P{'cond.unit'}) && ($P{'cond.unit'} ne 'S/m');
 		&antsAddParams('cond.unit','S/m');
-	} elsif (m{^c0mS/cm}) {
+	} elsif (m{^c0mS/cm} || m{^cond0mS/cm}) {
 		return undef
 			if defined($P{'cond.unit'}) && ($P{'cond.unit'} ne 'mS/cm');
 		&antsAddParams('cond.unit','mS/cm');
 	}
 		
-	if (m{^c1S/m}) {
+	if (m{^c1S/m} || m{^cond1S/m}) {
 		return undef
 			if defined($P{'cond.unit'}) && ($P{'cond.unit'} ne 'S/m');
 		&antsAddParams('cond.unit','S/m');
-	} elsif (m{^c1mS/cm}) {
+	} elsif (m{^c1mS/cm} || m{^cond1mS/cm}) {
 		return undef
 			if defined($P{'cond.unit'}) && ($P{'cond.unit'} ne 'mS/cm');
 		&antsAddParams('cond.unit','mS/cm');
@@ -268,28 +275,30 @@
 			if ($hdr =~ /Date\s*:\s*(.*)/);
 	
 		if (($hdr =~ /Latitude\s*[:=]\s*/) && !defined($lat)) {
-			($deg,$min,$NS) = split(/\s+/,$');
+#			($deg,$min,$NS) = split(/\s+/,$');
+			($deg,$min,$NS) = ($' =~ m{([^\s]+)\s+(\d+\.\d*)\s*([NS])});
 			if ($NS eq 'N' || $NS eq 'S') {
 				$lat = $deg + $min/60;
 				$lat *= -1 if ($NS eq 'S');
-			} elsif (!defined($NS) && abs($deg)<=90 && ($min >= 0) && ($min <= 60)) {
+			} elsif (!defined($NS) && defined($deg) && abs($deg)<=90 && ($min >= 0) && ($min <= 60)) {
 				$lat = $deg + $min/60;
 			} else {
-				print(STDERR "$0: WARNING: cannot decode latitude ($')\n");
+#				print(STDERR "$0: WARNING: cannot decode latitude ($')\n");
 				$lat = nan;
 			}
 			&antsAddParams('lat',$lat);
 			next;
 		}
 		if (($hdr =~ /Longitude\s*[:=]\s*/) && !defined($lon)) {
-			($deg,$min,$EW) = split(/\s+/,$');
+#			($deg,$min,$EW) = split(/\s+/,$');
+			($deg,$min,$EW) = ($' =~ m{([^\s]+)\s+(\d+\.\d*)\s*([EW])});
 			if ($EW eq 'E' || $EW eq 'W') {
 				$lon = $deg + $min/60;
 				$lon *= -1 if ($EW eq 'W');
-			} elsif (!defined($EW) && abs($deg)<=360 && ($min >= 0) && ($min <= 60)) {
+			} elsif (!defined($EW) && defined($deg) && abs($deg)<=360 && ($min >= 0) && ($min <= 60)) {
 				$lon = $deg + $min/60;
 			} else {
-				print(STDERR "$0: WARNING: cannot decode longitude ($')\n");
+#				print(STDERR "$0: WARNING: cannot decode longitude ($')\n");
 				$lon= nan;
 			}
 			&antsAddParams('lon',$lon);
--- a/libconv.pl
+++ b/libconv.pl
@@ -1,9 +1,9 @@
 #======================================================================
 #                    L I B C O N V . P L 
 #                    doc: Sat Dec  4 13:03:49 1999
-#                    dlm: Mon Dec 18 14:27:19 2017
+#                    dlm: Tue May 22 11:19:54 2018
 #                    (c) 1999 A.M. Thurnherr
-#                    uE-Info: 67 36 NIL 0 0 70 2 2 4 NIL ofnI
+#                    uE-Info: 68 41 NIL 0 0 70 2 2 4 NIL ofnI
 #======================================================================
 
 # HISTORY:
@@ -65,6 +65,7 @@
 #	Jan 27, 2017: - BUG: dayNo() numeric month could have leading/trailing whitespace
 #	Jul  6, 2017: - BUG: date conversion routines did not parse 1/5/12 correctly
 #	Dec 18, 2017: - removed ambiguous-date warning
+#	May 22, 2018: - added NMEA2dec_time()
 
 require "$ANTS/libEOS83.pl";                        # &sigma()
 require "$ANTS/libPOSIX.pl";                        # &floor()
@@ -187,6 +188,16 @@
 # String to Decimal Time Conversion
 #----------------------------------------------------------------------
 
+sub NMEA2dec_time(@)
+{
+	my($NMEA_string,$epoch) = &antsFunUsage(-1,'.','<NMEA string>[, epoch]',@_);
+
+	# Mar 17 2018 01:23:09
+	my($month,$day,$year,$time) = split(/\s+/,$NMEA_string);
+	$epoch = $year unless defined($epoch);
+	return dayNo($year,$month,$day,$epoch) + frac_day(split(':',$time));
+}
+
 { my($date_fmt); 
 
 	sub str2dec_time(@) 									# heuristic
--- a/libfuns.pl
+++ b/libfuns.pl
@@ -1,9 +1,9 @@
 #======================================================================
 #                    L I B F U N S . P L 
 #                    doc: Wed Mar 24 11:49:13 1999
-#                    dlm: Thu Jun  4 17:56:37 2015
+#                    dlm: Fri May 11 11:40:05 2018
 #                    (c) 1999 A.M. Thurnherr
-#                    uE-Info: 306 13 NIL 0 0 72 2 2 4 NIL ofnI
+#                    uE-Info: 31 77 NIL 0 0 70 2 2 4 NIL ofnI
 #======================================================================
 
 # HISTORY:
@@ -16,10 +16,24 @@
 #	Sep  7, 2012: - added acosh()
 #	Jun  4, 2015: - added gaussRand()
 #			 	  - made normal() more efficient
+#	May 11, 2018: - added Nsq()
 
 require	"$ANTS/libvec.pl";								# rad()
 
 #----------------------------------------------------------------------
+# Buoyancy-Freuquency Squared
+#	- based on signed buoyancy frequency => propagate sign
+#----------------------------------------------------------------------
+
+{ my(@fc);
+	sub Nsq(@)
+	{
+		my($N) = &antsFunUsage(1,'.','[(signed) buoyancy frequency]',\@fc,'N',@_);
+		return ($N < 0) ? -($N**2) : $N**2;
+	}
+}
+
+#----------------------------------------------------------------------
 # gaussians/normal distribution
 #----------------------------------------------------------------------
 
--- a/libvec.pl
+++ b/libvec.pl
@@ -1,9 +1,9 @@
 #======================================================================
-#                    . . / L I B / L I B V E C . P L 
+#                    L I B V E C . P L 
 #                    doc: Sat Mar 20 12:50:32 1999
-#                    dlm: Wed Nov 15 18:30:55 2017
+#                    dlm: Thu May 24 21:51:20 2018
 #                    (c) 1999 A.M. Thurnherr
-#                    uE-Info: 44 70 NIL 0 0 70 2 2 4 NIL ofnI
+#                    uE-Info: 170 0 NIL 0 0 70 2 2 4 NIL ofnI
 #======================================================================
 
 # HISTORY: