WorkhorseUtils.pl
changeset 1 a3b6a908dec5
parent 0 229a0d72d2ab
child 2 065ea9ce12fc
equal deleted inserted replaced
0:229a0d72d2ab 1:a3b6a908dec5
     1 #======================================================================
       
     2 #                    W O R K H O R S E U T I L S . P L 
       
     3 #                    doc: Wed Feb 12 10:21:32 2003
       
     4 #                    dlm: Sun May 23 16:32:37 2010
       
     5 #                    (c) 2003 A.M. Thurnherr
       
     6 #                    uE-Info: 142 42 NIL 0 0 72 2 2 4 NIL ofnI
       
     7 #======================================================================
       
     8 
       
     9 # miscellaneous Workhorse-specific utilities
       
    10 
       
    11 # History:
       
    12 #	Feb 12, 2003: - created
       
    13 #	Feb 14, 2003: - added check for short (bad) data files
       
    14 #	Feb 26, 2004: - added Earth-coordinate support
       
    15 #				  - added ensure_BT_RANGE()
       
    16 #	Mar 17, 2004: - set bad BT ranges to undef in ensure_BT_RANGE
       
    17 #				  - calc mean/stddev in ensure_BT_RANGE
       
    18 #	Mar 20, 2004: - BUG: find_seabed() could bomb when not enough
       
    19 #					bottom guesses passed the mode_width test
       
    20 #	Mar 30, 2004: - added &soundSpeed()
       
    21 #	Nov  8, 2005: - WATER_DEPTH => Z_BT
       
    22 #	May 23, 2010: - Z* -> DEPTH*
       
    23 
       
    24 use strict;
       
    25 
       
    26 #======================================================================
       
    27 # fake_BT_RANGE(dta ptr)
       
    28 #======================================================================
       
    29 
       
    30 # During cruise NBP0204 it was found that one of Visbeck's RDIs consistently
       
    31 # returns zero as the bottom-track range, even thought the BT velocities
       
    32 # are good. This functions calculates the ranges if they are missing.
       
    33 
       
    34 sub cBTR($$$)
       
    35 {
       
    36 	my($d,$e,$b) = @_;
       
    37 	my($maxamp) = -9e99;
       
    38 	my($maxi);
       
    39 
       
    40 	for (my($i)=0; $i<$d->{N_BINS}; $i++) {
       
    41 		next unless ($d->{ENSEMBLE}[$e]->{ECHO_AMPLITUDE}[$i][$b] > $maxamp);
       
    42 		$maxamp = $d->{ENSEMBLE}[$e]->{ECHO_AMPLITUDE}[$i][$b];
       
    43 		$maxi = $i;
       
    44 	}
       
    45 	$d->{ENSEMBLE}[$e]->{BT_RANGE}[$b] =
       
    46 		$d->{DISTANCE_TO_BIN1_CENTER} + $maxi * $d->{BIN_LENGTH};
       
    47 }
       
    48 
       
    49 sub ensure_BT_RANGE($)
       
    50 {
       
    51 	my($d) = @_;
       
    52 	for (my($e)=0; $e<=$#{$d->{ENSEMBLE}}; $e++) {
       
    53 		my($sum) = my($n) = 0;
       
    54 		if (defined($d->{ENSEMBLE}[$e]->{BT_VELOCITY}[0])) {
       
    55 			for (my($b)=0; $b<4; $b++) {
       
    56 				cBTR($d,$e,$b)
       
    57 					unless defined($d->{ENSEMBLE}[$e]->{BT_RANGE}[$b]);
       
    58 				$sum += $d->{ENSEMBLE}[$e]->{BT_RANGE}[$b]; $n++;
       
    59 			}
       
    60 		} else {
       
    61 			for (my($b)=0; $b<4; $b++) {
       
    62 				$d->{ENSEMBLE}[$e]->{BT_RANGE}[$b] = undef;
       
    63 			}
       
    64 		}
       
    65 		$d->{ENSEMBLE}[$e]->{BT_MEAN_RANGE} = $sum/$n if ($n == 4);
       
    66 	}
       
    67 }
       
    68 
       
    69 #======================================================================
       
    70 # (seabed depth, stddev) = find_seabed(dta ptr, btm ensno, coord flag)
       
    71 #======================================================================
       
    72 
       
    73 # NOTE FOR YOYOS:
       
    74 #	- this routine only detects the BT around the depeest depth!
       
    75 #	- this is on purpose, because it is used for [listBT]
       
    76 
       
    77 # This is a PAIN:
       
    78 # 	if the instrument is too close to the bottom, the BT_RANGE
       
    79 #	readings are all out; the only solution is to have a sufficiently
       
    80 #	large search width (around the max(depth) ensemble) so that
       
    81 #	a part of the up (oops, I forgot to finish this comment one year
       
    82 #	ago during A0304 and now I don't understand it any more :-)
       
    83 
       
    84 my($search_width) = 200;	# # of ensembles around bottom to search
       
    85 my($mode_width) = 10;		# max range of bottom around mode
       
    86 my($z_offset) = 10000;		# shift z to ensure +ve array indices
       
    87 
       
    88 sub find_seabed($$$)
       
    89 {
       
    90 	my($d,$be,$beamCoords) = @_;
       
    91 	my($i,$dd,$sd,$nd);
       
    92 	my(@guesses);
       
    93 
       
    94 	return undef unless ($be-$search_width >= 0 &&
       
    95 						 $be+$search_width <= $#{$d->{ENSEMBLE}});
       
    96 	for ($i=$be-$search_width; $i<=$be+$search_width; $i++) {
       
    97 		next unless (defined($d->{ENSEMBLE}[$i]->{BT_RANGE}[0]) &&
       
    98 					 defined($d->{ENSEMBLE}[$i]->{BT_RANGE}[1]) &&
       
    99 					 defined($d->{ENSEMBLE}[$i]->{BT_RANGE}[2]) &&
       
   100 					 defined($d->{ENSEMBLE}[$i]->{BT_RANGE}[3]));
       
   101 		my(@BT) = $beamCoords
       
   102 				? velInstrumentToEarth($d,$i,
       
   103 					velBeamToInstrument($d,
       
   104 						@{$d->{ENSEMBLE}[$i]->{BT_VELOCITY}}))
       
   105 				: velApplyHdgBias($d,$i,@{$d->{ENSEMBLE}[$i]->{BT_VELOCITY}});
       
   106 		next unless (abs($BT[3]) < 0.05);
       
   107 		$d->{ENSEMBLE}[$i]->{DEPTH_BT} =
       
   108 		$d->{ENSEMBLE}[$i]->{DEPTH_BT} =
       
   109 			 $d->{ENSEMBLE}[$i]->{BT_RANGE}[0]/4 +
       
   110 			 $d->{ENSEMBLE}[$i]->{BT_RANGE}[1]/4 +
       
   111  			 $d->{ENSEMBLE}[$i]->{BT_RANGE}[2]/4 +
       
   112 			 $d->{ENSEMBLE}[$i]->{BT_RANGE}[3]/4;
       
   113 		$d->{ENSEMBLE}[$i]->{DEPTH_BT} *= -1
       
   114 			if ($d->{ENSEMBLE}[$i]->{XDUCER_FACING_UP});
       
   115 		$d->{ENSEMBLE}[$i]->{DEPTH_BT} += $d->{ENSEMBLE}[$i]->{DEPTH};
       
   116 		$guesses[int($d->{ENSEMBLE}[$i]->{DEPTH_BT})+$z_offset]++;
       
   117 		$nd++;
       
   118 	}
       
   119 	return undef unless ($nd>5);
       
   120 
       
   121 	my($mode,$nmax);
       
   122 	for ($i=0; $i<=$#guesses; $i++) {			# find mode
       
   123 		$nmax=$guesses[$i],$mode=$i-$z_offset
       
   124 			if ($guesses[$i] > $nmax);
       
   125 	}
       
   126 
       
   127 	$nd = 0;
       
   128 	for ($i=$be-$search_width; $i<=$be+$search_width; $i++) {
       
   129 		next unless defined($d->{ENSEMBLE}[$i]->{DEPTH_BT});
       
   130 		if (abs($d->{ENSEMBLE}[$i]->{DEPTH_BT}-$mode) <= $mode_width) {
       
   131 			$dd += $d->{ENSEMBLE}[$i]->{DEPTH_BT};
       
   132 			$nd++;
       
   133 		} else {
       
   134 			$d->{ENSEMBLE}[$i]->{DEPTH_BT} = undef;
       
   135 		}
       
   136 	}
       
   137 	return undef unless ($nd >= 2);
       
   138 
       
   139 	$dd /= $nd;
       
   140 	for ($i=$be-$search_width; $i<=$be+$search_width; $i++) {
       
   141 		next unless defined($d->{ENSEMBLE}[$i]->{DEPTH_BT});
       
   142 		$sd += ($d->{ENSEMBLE}[$i]->{DEPTH_BT}-$dd)**2;
       
   143 	}
       
   144 
       
   145 	return ($dd, sqrt($sd/($nd-1)));
       
   146 }
       
   147 
       
   148 #======================================================================
       
   149 # c = soundSpeed()
       
   150 #======================================================================
       
   151 
       
   152 # Taken from the RDI BroadBand primer manual. The reference given there
       
   153 # is Urick (1983).
       
   154 
       
   155 sub soundSpeed($$$)
       
   156 {
       
   157 	my($salin,$temp,$depth) = @_;
       
   158 	return 1449.2 + 4.6*$temp -0.055*$temp**2  + 0.00029*$temp**3 +
       
   159 				(1.34 - 0.01*$temp) * ($salin - 35) + 0.016*$depth;
       
   160 }
       
   161 
       
   162 1;