77 # - BUG: post-recovery rotations were always zero |
77 # - BUG: post-recovery rotations were always zero |
78 # Sep 9, 2011: - BUG: range calculation for Earth coordinate data included bins without |
78 # Sep 9, 2011: - BUG: range calculation for Earth coordinate data included bins without |
79 # valid velocities |
79 # valid velocities |
80 # Sep 21, 2010: - added %rms_heave_acceleration |
80 # Sep 21, 2010: - added %rms_heave_acceleration |
81 # Apr 12, 2013: - added -p |
81 # Apr 12, 2013: - added -p |
|
82 # May 10, 2013: - BUG: mkProfile bombed when ADCP file is truncated at deepest location |
|
83 # May 14, 2013: - added heading to output |
|
84 # - added err_vel to output |
|
85 # - finally removed -d/-g |
82 |
86 |
83 # NOTES: |
87 # NOTES: |
84 # - the battery values are based on transmission voltages (different |
88 # - the battery values are based on transmission voltages (different |
85 # from battery voltages) and reported without units (raw 8-bit a2d |
89 # from battery voltages) and reported without units (raw 8-bit a2d |
86 # values) |
90 # values) |
102 |
106 |
103 $USAGE = "$0 @ARGV"; |
107 $USAGE = "$0 @ARGV"; |
104 die("Usage: $0 " . |
108 die("Usage: $0 " . |
105 "[-Q)uiet] [-F)ilter <script>] " . |
109 "[-Q)uiet] [-F)ilter <script>] " . |
106 "[-s)uppress checkensemble()] " . |
110 "[-s)uppress checkensemble()] " . |
107 "[require -4)-beam solutions] " . |
111 "[require -4)-beam solutions] [-d)iscard <beam#>] [apply beamvel-m)ask <file>] " . |
108 "[-r)ef-layer <bin|1,bin|6>] [-n) vels <min|2>] " . |
112 "[-r)ef-layer <bin|1,bin|6>] [-n) vels <min|2>] " . |
109 "[-e)rr-vel <max[0.1]] [-c)orrelation <min>] [-p)ct-good <min[100]>] " . |
113 "[-e)rr-vel <max[0.1]] [-c)orrelation <min>] [-p)ct-good <min[100]>] " . |
110 "[-m)ax <gap>] " . |
114 "[max -g)ap <len>] " . |
111 "[-d)rift <dx,dy>] [-g)ps <start lat,lon/end lat,lon>] " . |
|
112 "[output -f)ields <field[,...]> " . |
115 "[output -f)ields <field[,...]> " . |
113 "[-M)agnetic <declination>] [profile -B)ottom <depth>] " . |
116 "[-M)agnetic <declination>] [profile -B)ottom <depth>] " . |
114 "<RDI file>\n") |
117 "<RDI file>\n") |
115 unless (&Getopts("4AB:F:M:Qd:r:n:e:c:g:f:m:sp:") && @ARGV == 1); |
118 unless (&Getopts("4AB:F:M:Qd:g:r:n:e:c:f:m:sp:") && @ARGV == 1); |
116 |
119 |
117 $RDI_Coords::minValidVels = 4 if ($opt_4); # no 3-beam solutions |
120 $RDI_Coords::minValidVels = 4 if ($opt_4); # no 3-beam solutions |
118 |
121 |
119 require $opt_F if defined($opt_F); # load filter |
122 require $opt_F if defined($opt_F); # load filter |
120 |
123 |
121 $opt_r = "1,6" unless defined($opt_r); # defaults |
124 $opt_r = "1,6" unless defined($opt_r); # defaults |
122 $opt_n = 2 unless defined($opt_n); |
125 $opt_n = 2 unless defined($opt_n); |
123 $opt_e = 0.1 unless defined($opt_e); |
126 $opt_e = 0.1 unless defined($opt_e); |
124 $opt_c = 70 unless defined($opt_c); |
127 $opt_c = 70 unless defined($opt_c); |
125 $opt_m = 120 unless defined($opt_m); |
128 $opt_g = 120 unless defined($opt_g); |
126 $opt_p = 100 unless defined($opt_p); |
129 $opt_p = 100 unless defined($opt_p); |
127 |
130 |
128 ($minb,$maxb) = split(',',$opt_r); # reference layer |
131 ($minb,$maxb) = split(',',$opt_r); # reference layer |
129 die("$0: can't decode -r $opt_r\n") unless defined($maxb); |
132 die("$0: can't decode -r $opt_r\n") unless defined($maxb); |
130 |
133 |
131 if ($opt_g) { # GPS info |
|
132 ($s_lat,$s_lon,$e_lat,$e_lon) = gps_to_deg($opt_g); |
|
133 $lat = $s_lat/2 + $e_lat/2; |
|
134 $lon = $s_lon/2 + $e_lon/2; |
|
135 $ddx = dist($lat,$s_lon,$lat,$e_lon); |
|
136 $ddy = dist($s_lat,$lon,$e_lat,$lon); |
|
137 } |
|
138 |
|
139 if ($opt_d) { # ship drift |
|
140 ($ddx,$ddy) = split(',',$opt_d); |
|
141 die("$0: can't decode -d $opt_d\n") unless defined($ddy); |
|
142 } |
|
143 |
|
144 print(STDERR "Reading $ARGV[0]..."); # read data |
134 print(STDERR "Reading $ARGV[0]..."); # read data |
145 readData($ARGV[0],\%dta); |
135 readData($ARGV[0],\%dta); |
146 print(STDERR "done\n"); |
136 print(STDERR "done\n"); |
147 |
137 |
148 die("$ARGV[0]: not enough bins for choice of -r\n") # enough bins? |
138 die("$ARGV[0]: not enough bins for choice of -r\n") # enough bins? |
149 unless ($dta{N_BINS} >= $maxb); |
139 unless ($dta{N_BINS} >= $maxb); |
150 if ($dta{BEAM_COORDINATES}) { # coords used |
140 if ($dta{BEAM_COORDINATES}) { # coords used |
151 $beamCoords = 1; |
141 $beamCoords = 1; |
152 } elsif (!$dta{EARTH_COORDINATES}) { |
142 } elsif (!$dta{EARTH_COORDINATES}) { |
153 die("$ARGV[0]: only beam and earth coordinates implemented so far\n"); |
143 die("$ARGV[0]: only beam and earth coordinates implemented so far\n"); |
|
144 } |
|
145 |
|
146 if (defined($opt_m) && -r $opt_m) { |
|
147 die("$ARGV[0]: -m only implemented for data collected in beam coordinates\n") |
|
148 unless ($beamCoords); |
|
149 print(STDERR "Masking beam velocities as prescribed in $opt_m..."); |
|
150 |
|
151 open(BVM,$opt_m) || die("$opt_m: $!\n"); |
|
152 while (<BVM>) { |
|
153 s/#.*//; |
|
154 s/^\s*$//; |
|
155 next if ($_ eq ''); |
|
156 my($fe,$te,$db) = split; |
|
157 die("$opt_m: cannot decode $_\n") |
|
158 unless (numberp($fe) && numberp($te) && $te>=$fe && $db>=1 && $db<=4); |
|
159 die("$0: assertion failed") |
|
160 unless ($dta{ENSEMBLE}[$fe-1]->{NUMBER} == $fe && |
|
161 $dta{ENSEMBLE}[$te-1]->{NUMBER} == $te); |
|
162 for (my($ens)=$fe-1; $ens<=$te-1; $ens++) { |
|
163 $nens++; |
|
164 for (my($bin)=0; $bin<$dta{N_BINS}; $bin++) { |
|
165 undef($dta{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$db-1]); |
|
166 } |
|
167 } |
|
168 } |
|
169 close(BVM); |
|
170 print(STDERR " $nens ensembles edited\n"); |
|
171 } |
|
172 |
|
173 if (defined($opt_d)) { # discard entire beam |
|
174 die("$ARGV[0]: -d only implemented for data collected in beam coordinates\n") |
|
175 unless ($beamCoords); |
|
176 print(STDERR "Discarding beam-$opt_d velocities..."); |
|
177 for (my($ens)=0; $ens<=$#{$dta{ENSEMBLE}}; $ens++) { |
|
178 for (my($bin)=0; $bin<$dta{N_BINS}; $bin++) { |
|
179 undef($dta{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$opt_d-1]); |
|
180 } |
|
181 } |
|
182 print(STDERR "done\n"); |
154 } |
183 } |
155 |
184 |
156 if (defined($opt_M)) { # magnetic declination |
185 if (defined($opt_M)) { # magnetic declination |
157 $dta{HEADING_BIAS} = -1*$opt_M; |
186 $dta{HEADING_BIAS} = -1*$opt_M; |
158 } else { |
187 } else { |
176 # print(STDERR "addFields = $addFields\n"); |
205 # print(STDERR "addFields = $addFields\n"); |
177 # print(STDERR "\@f = @f\n"); |
206 # print(STDERR "\@f = @f\n"); |
178 } |
207 } |
179 |
208 |
180 #====================================================================== |
209 #====================================================================== |
181 # Misc funs used to decode options |
|
182 #====================================================================== |
|
183 |
|
184 sub dist($$$$) # distance |
|
185 { |
|
186 my($lat1,$lon1,$lat2,$lon2) = @_; |
|
187 my($a) = 6378139; # Earth's radius |
|
188 |
|
189 $lat1 = rad($lat1); $lon1 = rad($lon1); |
|
190 $lat2 = rad($lat2); $lon2 = rad($lon2); |
|
191 $ct1 = cos($lat1); $st1 = sin($lat1); $cp1 = cos($lon1); |
|
192 $sp1 = sin($lon1); $ct2 = cos($lat2); $st2 = sin($lat2); |
|
193 $cp2 = cos($lon2); $sp2 = sin($lon2); |
|
194 $cos = $ct1*$cp1*$ct2*$cp2 + $ct1*$sp1*$ct2*$sp2 + $st1*$st2; |
|
195 $cos = 1 if ($cos > 1); |
|
196 $cos = -1 if ($cos < -1); |
|
197 return $a * acos($cos); |
|
198 } |
|
199 |
|
200 sub deg_to_dec($) # parse degrees |
|
201 { |
|
202 my($deg,$min) = split(':',$_[0]); |
|
203 return $deg + $min/60; |
|
204 } |
|
205 |
|
206 sub gps_to_deg($) # decode lat/lon |
|
207 { |
|
208 my($start,$end) = split('/',$_[0]); |
|
209 my($sa,$so,$ea,$eo); |
|
210 |
|
211 my($lat,$lon) = split(',',$start); |
|
212 if ($lat =~ m{N$}) { $sa = deg_to_dec($`); } |
|
213 elsif ($lat =~ m{S$}) { $sa = -deg_to_dec($`); } |
|
214 else { $sa = $lat; } |
|
215 if ($lon =~ m{E$}) { $so = deg_to_dec($`); } |
|
216 elsif ($lon =~ m{W$}) { $so = -deg_to_dec($`); } |
|
217 else { $so = $lon; } |
|
218 |
|
219 my($lat,$lon) = split(',',$end); |
|
220 if ($lat =~ m{N$}) { $ea = deg_to_dec($`); } |
|
221 elsif ($lat =~ m{S$}) { $ea = -deg_to_dec($`); } |
|
222 else { $ea = $lat; } |
|
223 if ($lon =~ m{E$}) { $eo = deg_to_dec($`); } |
|
224 elsif ($lon =~ m{W$}) { $eo = -deg_to_dec($`); } |
|
225 else { $eo = $lon; } |
|
226 |
|
227 return ($sa,$so,$ea,$eo); |
|
228 } |
|
229 |
|
230 #====================================================================== |
|
231 # Step 0: Check data & Calculate Ping Rates |
210 # Step 0: Check data & Calculate Ping Rates |
232 #====================================================================== |
211 #====================================================================== |
233 |
212 |
234 unless ($dta{NARROW_BANDWIDTH}) { |
213 unless ($dta{NARROW_BANDWIDTH}) { |
235 print(STDERR "WARNING: $0 WIDE BANDWIDTH!\n"); |
214 print(STDERR "WARNING: $0 WIDE BANDWIDTH!\n"); |
264 #====================================================================== |
243 #====================================================================== |
265 # Step 1: Integrate w & determine water depth |
244 # Step 1: Integrate w & determine water depth |
266 #====================================================================== |
245 #====================================================================== |
267 |
246 |
268 ($firstgood,$lastgood,$atbottom,$w_gap_time,$zErr,$maxz,$rms_heave_accel) = |
247 ($firstgood,$lastgood,$atbottom,$w_gap_time,$zErr,$maxz,$rms_heave_accel) = |
269 mk_prof(\%dta,!$opt_s,$opt_F,$minb,$maxb,$opt_c,$opt_e,$opt_m,$opt_p); |
248 mk_prof(\%dta,!$opt_s,$opt_F,$minb,$maxb,$opt_c,$opt_e,$opt_g,$opt_p); |
270 |
249 |
271 unless (($atbottom > $firstgood) && ($lastgood > $atbottom)) { |
250 unless (($atbottom > $firstgood) && ($lastgood > $atbottom)) { |
272 if ($opt_Q) { |
251 if ($opt_Q) { |
273 print(STDERR "$ARGV[0]: no valid cast data found\n"); |
252 print(STDERR "$ARGV[0]: no valid cast data found\n"); |
274 exit(0); |
253 exit(0); |
573 } |
552 } |
574 } |
553 } |
575 $gb = ($gb[0]+$gb[1]+$gb[2]+$gb[3]) / 4; |
554 $gb = ($gb[0]+$gb[1]+$gb[2]+$gb[3]) / 4; |
576 |
555 |
577 #====================================================================== |
556 #====================================================================== |
578 # Step 5: Remove Ship Drift (probably not useful) |
557 # Step 5: Remove Ship Drift (probably not useful => removed) |
579 #====================================================================== |
558 #====================================================================== |
580 |
|
581 if (defined($opt_M) && defined($ddx)) { # remove barotropic |
|
582 $du = $ddx / $dta{ENSEMBLE}[$lastgood]->{ELAPSED_TIME};# mean drift vel |
|
583 $dv = $ddy / $dta{ENSEMBLE}[$lastgood]->{ELAPSED_TIME}; |
|
584 $iu = $dta{ENSEMBLE}[$lastgood]->{X} / # mean obs vel |
|
585 $dta{ENSEMBLE}[$lastgood]->{ELAPSED_TIME}; |
|
586 $iv = $dta{ENSEMBLE}[$lastgood]->{Y} / |
|
587 $dta{ENSEMBLE}[$lastgood]->{ELAPSED_TIME}; |
|
588 |
|
589 for ($e=$firstgood; $e<=$lastgood; $e++) { |
|
590 next unless (defined($dta{ENSEMBLE}[$e]->{X}) && |
|
591 defined($dta{ENSEMBLE}[$e]->{Y})); |
|
592 $dta{ENSEMBLE}[$e]->{U} -= $du; |
|
593 $dta{ENSEMBLE}[$e]->{V} -= $dv; |
|
594 $dta{ENSEMBLE}[$e]->{X} += $dta{ENSEMBLE}[$e]->{ELAPSED_TIME} * ($du-$iu); |
|
595 $dta{ENSEMBLE}[$e]->{Y} += $dta{ENSEMBLE}[$e]->{ELAPSED_TIME} * ($dv-$iv); |
|
596 } |
|
597 } |
|
598 |
559 |
599 #====================================================================== |
560 #====================================================================== |
600 # Step 6: Pitch, Roll, Rotation |
561 # Step 6: Pitch, Roll, Rotation |
601 #====================================================================== |
562 #====================================================================== |
602 |
563 |
782 $uErr, $dta{ENSEMBLE}[$lastgood]->{X}, $x_err, |
749 $uErr, $dta{ENSEMBLE}[$lastgood]->{X}, $x_err, |
783 $dta{ENSEMBLE}[$lastgood]->{Y} / |
750 $dta{ENSEMBLE}[$lastgood]->{Y} / |
784 $dta{ENSEMBLE}[$lastgood]->{ELAPSED_TIME}, |
751 $dta{ENSEMBLE}[$lastgood]->{ELAPSED_TIME}, |
785 $vErr, $dta{ENSEMBLE}[$lastgood]->{Y}, $y_err, |
752 $vErr, $dta{ENSEMBLE}[$lastgood]->{Y}, $y_err, |
786 ) if defined ($opt_M); |
753 ) if defined ($opt_M); |
787 print("#ANTS#PARAMS# start_lat{$s_lat} start_lon{$s_lon} " . |
|
788 "end_lat{$e_lat} end_lon{$e_lon} " . |
|
789 "lat{$lat} lon{$lon}\n") |
|
790 if defined($lat); |
|
791 if ($dta{TIME_BETWEEN_PINGS} == 0) { |
754 if ($dta{TIME_BETWEEN_PINGS} == 0) { |
792 print("#ANTS#PARAMS# pinging_rate{staggered}\n"); |
755 print("#ANTS#PARAMS# pinging_rate{staggered}\n"); |
793 } else { |
756 } else { |
794 printf("#ANTS#PARAMS# pinging_rate{%.2f}\n", |
757 printf("#ANTS#PARAMS# pinging_rate{%.2f}\n", |
795 1/$dta{TIME_BETWEEN_PINGS}); |
758 1/$dta{TIME_BETWEEN_PINGS}); |
796 } |
759 } |
797 printf("#ANTS#PARAMS# drift_x{%d} drift_y{%d} " . |
|
798 "drift_u{%.3f} drift_v{%.3f} " . |
|
799 "\n",$ddx,$ddy,$du,$dv) if defined($ddx); |
|
800 if (defined($water_depth)) { |
760 if (defined($water_depth)) { |
801 printf("#ANTS#PARAMS# water_depth{%d} sig-water_depth{%d}\n", |
761 printf("#ANTS#PARAMS# water_depth{%d} sig-water_depth{%d}\n", |
802 $water_depth,$sig_wd); |
762 $water_depth,$sig_wd); |
803 } else { |
763 } else { |
804 print("#ANTS#PARAMS# water_depth{nan} sig-water_depth{nan}\n"); |
764 print("#ANTS#PARAMS# water_depth{nan} sig-water_depth{nan}\n"); |
813 p($dta{ENSEMBLE}[$e]->{ELAPSED_TIME}); |
773 p($dta{ENSEMBLE}[$e]->{ELAPSED_TIME}); |
814 p($dta{ENSEMBLE}[$e]->{SECNO}); |
774 p($dta{ENSEMBLE}[$e]->{SECNO}); |
815 pb($dta{ENSEMBLE}[$e]->{UNIX_TIME} < $dta{ENSEMBLE}[$atbottom]->{UNIX_TIME}); |
775 pb($dta{ENSEMBLE}[$e]->{UNIX_TIME} < $dta{ENSEMBLE}[$atbottom]->{UNIX_TIME}); |
816 p($dta{ENSEMBLE}[$e]->{W}); |
776 p($dta{ENSEMBLE}[$e]->{W}); |
817 p($dta{ENSEMBLE}[$e]->{W_ERR}); |
777 p($dta{ENSEMBLE}[$e]->{W_ERR}); |
|
778 p($dta{ENSEMBLE}[$e]->{ERR_VEL}); |
818 p($dta{ENSEMBLE}[$e]->{DEPTH}); |
779 p($dta{ENSEMBLE}[$e]->{DEPTH}); |
819 p($dta{ENSEMBLE}[$e]->{DEPTH_ERR}); |
780 p($dta{ENSEMBLE}[$e]->{DEPTH_ERR}); |
820 p($dta{ENSEMBLE}[$e]->{DEPTH_BT}); |
781 p($dta{ENSEMBLE}[$e]->{DEPTH_BT}); |
821 p($dta{ENSEMBLE}[$e]->{PITCHROLL}); |
782 p($dta{ENSEMBLE}[$e]->{PITCHROLL}); |
|
783 p($dta{ENSEMBLE}[$e]->{HEADING}); |
822 p($dta{ENSEMBLE}[$e]->{ROTATION}); |
784 p($dta{ENSEMBLE}[$e]->{ROTATION}); |
823 if (defined($opt_M)) { |
785 if (defined($opt_M)) { |
824 p($dta{ENSEMBLE}[$e]->{U}); p($dta{ENSEMBLE}[$e]->{U_ERR}); |
786 p($dta{ENSEMBLE}[$e]->{U}); p($dta{ENSEMBLE}[$e]->{U_ERR}); |
825 p($dta{ENSEMBLE}[$e]->{V}); p($dta{ENSEMBLE}[$e]->{V_ERR}); |
787 p($dta{ENSEMBLE}[$e]->{V}); p($dta{ENSEMBLE}[$e]->{V_ERR}); |
826 p($dta{ENSEMBLE}[$e]->{X}); p($dta{ENSEMBLE}[$e]->{X_ERR}); |
788 p($dta{ENSEMBLE}[$e]->{X}); p($dta{ENSEMBLE}[$e]->{X_ERR}); |