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; |
|