85 # - BUG: initial in-air scans were not handled correctly (nscans not updated) |
85 # - BUG: initial in-air scans were not handled correctly (nscans not updated) |
86 # Mar 25, 2019: - changed error message to allow creating 1Hz from 4Hz file (SBE19) |
86 # Mar 25, 2019: - changed error message to allow creating 1Hz from 4Hz file (SBE19) |
87 # - BUG: ITS was not set. How is this possible????? |
87 # - BUG: ITS was not set. How is this possible????? |
88 # Apr 21, 2019: - modified code to allow production of 24Hz files (previous code required |
88 # Apr 21, 2019: - modified code to allow production of 24Hz files (previous code required |
89 # min 2 samples per bin, allowing for max 12Hz sampling rate) |
89 # min 2 samples per bin, allowing for max 12Hz sampling rate) |
|
90 # Aug 27, 2019: - began adding correction for dropped CTD scans |
|
91 # Aug 28, 2019: - made it work |
90 |
92 |
91 # NOTES: |
93 # NOTES: |
92 # w_CTD is positive during the downcast to make the sign of the apparent |
94 # w_CTD is positive during the downcast to make the sign of the apparent |
93 # water velocity consistent with w_ocean |
95 # water velocity consistent with w_ocean |
94 |
96 |
148 if ($rec =~ /^\*/) { # SBE CNV file |
150 if ($rec =~ /^\*/) { # SBE CNV file |
149 $libSBE_quiet = 1; # suppress diagnostic messages |
151 $libSBE_quiet = 1; # suppress diagnostic messages |
150 ($nfields,$nscans,$sampint,$badval,$ftype,$lat,$lon) = # decode SBE header |
152 ($nfields,$nscans,$sampint,$badval,$ftype,$lat,$lon) = # decode SBE header |
151 SBE_parseHeader(F,0,0); # SBE field names, no time check |
153 SBE_parseHeader(F,0,0); # SBE field names, no time check |
152 |
154 |
153 # _croak("$CNVfile: unexpected sampling interval $sampint s\n") |
|
154 # unless (abs($sampint-1/24) < 1e-5); |
|
155 _croak("$CNVfile: insufficient time resolution ($sampint s) for ${opt_s}Hz time series\n") |
155 _croak("$CNVfile: insufficient time resolution ($sampint s) for ${opt_s}Hz time series\n") |
156 if (round(1/$sampint/$opt_s) < 1); |
156 if (round(1/$sampint/$opt_s) < 1); |
157 |
157 |
158 if (defined($opt_l)) { # set/override station location with -l |
158 if (defined($opt_l)) { # set/override station location with -l |
159 my($slat,$slon) = split('[,/]',$opt_l); |
159 my($slat,$slon) = split('[,/]',$opt_l); |
228 $ants_[$nscans][$tempF] = nan unless defined($ants_[$nscans][$tempF]); |
237 $ants_[$nscans][$tempF] = nan unless defined($ants_[$nscans][$tempF]); |
229 $ants_[$nscans][$condF] = nan unless defined($ants_[$nscans][$condF]); |
238 $ants_[$nscans][$condF] = nan unless defined($ants_[$nscans][$condF]); |
230 } |
239 } |
231 } |
240 } |
232 |
241 |
233 printf(STDERR "\n\t%d scans (%d seconds)",$nscans,int($nscans*$sampint)) |
242 printf(STDERR "\n\t%d scans (%d minutes)",$nscans,round($nscans*$sampint/60)) |
234 if ($opt_v > 1); |
243 if ($opt_v > 1); |
235 printf(STDERR "\n") if ($opt_v); |
244 printf(STDERR "\n") if ($opt_v); |
|
245 |
|
246 #---------------------------------------------------------------------- |
|
247 # Fill gaps in CTD time series due to dropped scans (modulo errors) |
|
248 #---------------------------------------------------------------------- |
|
249 |
|
250 if ($fill_gaps) { |
|
251 print(STDERR "Filling CTD time-series gaps...") if ($opt_v); |
|
252 |
|
253 my($scans_filled) = 0; |
|
254 my($scans_replaced) = 0; |
|
255 my($scans_deleted) = 0; |
|
256 |
|
257 for (my($scan)=30; $scan<@ants_; $scan++) { # start a bit more than 1 second into the cast |
|
258 next if ($ants_[$scan][$systimeF] == $ants_[$scan-1][$systimeF]); # skip forward to next systime second |
|
259 |
|
260 # while ($ants_[$scan][$systimeF] > $ants_[$scan-1][$systimeF]+1) { # gap spans full second |
|
261 # my(@splicescan); # scan to splice in |
|
262 # $splicescan[$systimeF] = $ants_[$scan-1][$systimeF] + 1; |
|
263 # $splicescan[$xmerrF] = $ants_[$scan-1][$xmerrF]; |
|
264 # for (my($i)=0; $i<24; $i++) { |
|
265 # splice(@ants_,$scan,0,\@splicescan); |
|
266 # $scans_filled++; |
|
267 # } |
|
268 # } |
|
269 |
|
270 my($second_start) = $scan - 1; # backtrack to beginning of second |
|
271 my($scans_this_sec) = 1; |
|
272 while ($ants_[$second_start-1][$systimeF] == $ants_[$second_start][$systimeF]) { |
|
273 $second_start--; $scans_this_sec++; |
|
274 } |
|
275 die("\nscan = $scan, second_start = $second_start, st = $ants_[$second_start][$systimeF]") |
|
276 unless ($second_start > 0); |
|
277 |
|
278 while ($scans_this_sec > 24) { # CTD clock running fast => remove scans |
|
279 splice(@ants_,$scan-1,1); |
|
280 $scans_deleted++; $scans_this_sec--; $scan--; |
|
281 } |
|
282 |
|
283 my($gap_len) = 24 - $scans_this_sec; # gap length in this second only |
|
284 die("gap_len = $gap_len at scan#$scan") unless ($gap_len >= 0); |
|
285 |
|
286 my($ngaps) = 0; # gaps between end of previous and beginning of next section |
|
287 for (my($s)=$second_start; $s<=$scan; $s++) { |
|
288 $ngaps++ if ($ants_[$s][$xmerrF] > $ants_[$s-1][$xmerrF]); |
|
289 } |
|
290 |
|
291 my(@splicescan); # scan to splice in |
|
292 $splicescan[$systimeF] = $ants_[$second_start][$systimeF]; |
|
293 $splicescan[$xmerrF] = $ants_[$second_start][$xmerrF]; |
|
294 |
|
295 if ($ngaps==0 && $gap_len>0) { # clock drift => add scan |
|
296 # print(STDERR "adding $gap_len scans to make up for clock drift starting at scan $scan-1 (ss = $second_start) (st = $splicescan[$systimeF])\n"); |
|
297 for (my($i)=0; $i<$gap_len; $i++) { # fill gap |
|
298 splice(@ants_,$scan-1,0,\@splicescan); |
|
299 $scans_filled++; $scan++; |
|
300 } |
|
301 } elsif ($ngaps == 1) { # single gap => fill it |
|
302 my($gap_location) = $second_start; # find it |
|
303 while ($ants_[$gap_location][$xmerrF] == $ants_[$second_start-1][$xmerrF]) { |
|
304 $gap_location++; |
|
305 } |
|
306 die('INTERNAL ERROR') unless ($gap_location <= $scan); |
|
307 # print(STDERR "filling $gap_len gap starting at scan $gap_location (ss = $second_start) (st = $splicescan[$systimeF])\n"); |
|
308 for (my($i)=0; $i<$gap_len; $i++) { # fill gap |
|
309 splice(@ants_,$gap_location,0,\@splicescan); |
|
310 $scans_filled++; $scan++; |
|
311 } |
|
312 } else { # multiple gaps => delete data |
|
313 my($last_gap); |
|
314 for (my($s)=$second_start; $s<$scan; $s++) { # replace ambiguous data scans |
|
315 next if ($ants_[$s][$xmerrF] == $ants_[$second_start-1][$xmerrF]); |
|
316 last if ($ants_[$s][$xmerrF] == $ants_[$scan][$xmerrF]); |
|
317 splice(@ants_,$s,1,\@splicescan); # replace |
|
318 $scans_replaced++; |
|
319 $last_gap = $s; |
|
320 } |
|
321 for (my($i)=0; $i<$gap_len; $i++) { # fill gaps |
|
322 splice(@ants_,$last_gap+1,0,\@splicescan); |
|
323 $scans_filled++; $scan++; |
|
324 } |
|
325 } |
|
326 |
|
327 my($scans_this_sec) = 0; |
|
328 die("$ants_[$second_start][$systimeF]==$ants_[$second_start-1][$systimeF]+1") |
|
329 unless ($ants_[$second_start][$systimeF]==$ants_[$second_start-1][$systimeF]+1); |
|
330 for (my($i)=0; $ants_[$second_start+$i][$systimeF]==$ants_[$second_start-1][$systimeF]+1; $i++) { |
|
331 $scans_this_sec++; |
|
332 } |
|
333 die("\n$scans_this_sec scans in second $ants_[$second_start][$systimeF] at scans $second_start .. $scan-1 (gap_len $gap_len, $ngaps gaps)\n") |
|
334 unless ($scans_this_sec == 24); |
|
335 } # for ($scan |
|
336 |
|
337 # my($sts) = 1; |
|
338 # for (my($scan)=1; $scan<@ants_; $scan++) { |
|
339 # $sts++,next if ($ants_[$scan][$systimeF] == $ants_[$scan-1][$systimeF]); |
|
340 # printf(STDERR "sts = $sts beginning at scan %d (st = $ants_[$scan-1][$systimeF])\n",$scan-$sts) |
|
341 # unless ($sts == 24); |
|
342 # $sts = 1; |
|
343 # } |
|
344 |
|
345 |
|
346 &antsAddParams('gaps_scans_filled',$scans_filled, |
|
347 'scans_removed',$scans_deleted, |
|
348 'gap_scans_cleared',$scans_replaced); |
|
349 |
|
350 if ($opt_v>1 && $scans_filled) { |
|
351 printf(STDERR "\n\t%d scans removed (clock drift)",$scans_deleted); |
|
352 printf(STDERR "\n\t%d scans added (gaps & clock drift)",$scans_filled); |
|
353 printf(STDERR "\n\t%d scans cleared (gap clusters)",$scans_replaced); |
|
354 } |
|
355 printf(STDERR "\n") if ($opt_v); |
|
356 } # if ($fill_gaps |
236 |
357 |
237 #---------------------------------------------------------------------- |
358 #---------------------------------------------------------------------- |
238 # Redirect STDOUT to %.6Hz & create %_w_CTD.ps,%_sspd.ps if STDOUT is a tty |
359 # Redirect STDOUT to %.6Hz & create %_w_CTD.ps,%_sspd.ps if STDOUT is a tty |
239 #---------------------------------------------------------------------- |
360 #---------------------------------------------------------------------- |
240 |
361 |
318 printf(STDERR "\n\tvalid pressure guess: %d dbar (%d samples)",$press_rez*$modeBin-100,$modeSamp) |
440 printf(STDERR "\n\tvalid pressure guess: %d dbar (%d samples)",$press_rez*$modeBin-100,$modeSamp) |
319 if ($opt_v > 1); |
441 if ($opt_v > 1); |
320 ($min,$max) = validRange($modeBin); |
442 ($min,$max) = validRange($modeBin); |
321 $min = $press_rez*$min-100; $max = $press_rez*$max-100; |
443 $min = $press_rez*$min-100; $max = $press_rez*$max-100; |
322 for (my($s)=0; $s<$nscans; $s++) { |
444 for (my($s)=0; $s<$nscans; $s++) { |
|
445 next unless numberp($ants_[$s][$pressF]); |
323 if ($ants_[$s][$pressF] > $max) { $outliers++; $ants_[$s][$pressF] = nan; } |
446 if ($ants_[$s][$pressF] > $max) { $outliers++; $ants_[$s][$pressF] = nan; } |
324 if ($ants_[$s][$pressF] < $min) { $outliers++; $ants_[$s][$pressF] = nan; } |
447 if ($ants_[$s][$pressF] < $min) { $outliers++; $ants_[$s][$pressF] = nan; } |
325 } |
448 } |
326 &antsAddParams("pressure_outliers",sprintf("%d",$outliers)); |
449 &antsAddParams("pressure_outliers",sprintf("%d",$outliers)); |
327 printf(STDERR "\n\tcontinuous pressure range: %d..%d dbar (%d outliers removed)",$min,$max,$outliers) if ($opt_v > 1); |
450 printf(STDERR "\n\tcontinuous pressure range: %d..%d dbar (%d outliers removed)",$min,$max,$outliers) if ($opt_v > 1); |
332 # edit conductivity outliers outside contiguous range |
455 # edit conductivity outliers outside contiguous range |
333 #---------------------------------------------------- |
456 #---------------------------------------------------- |
334 $outliers = $modeSamp = 0; |
457 $outliers = $modeSamp = 0; |
335 undef(@hist); |
458 undef(@hist); |
336 for (my($s)=0; $s<$nscans; $s++) { |
459 for (my($s)=0; $s<$nscans; $s++) { |
|
460 $ants_[$s][$condF] = nan unless defined($ants_[$s][$condF]); |
337 next unless ($ants_[$s][$condF] > 0); |
461 next unless ($ants_[$s][$condF] > 0); |
338 my($b) = $ants_[$s][$condF]*$condHistRes; # 1/10 S/m histogram resolution (1 mS/cm) |
462 my($b) = $ants_[$s][$condF]*$condHistRes; # 1/10 S/m histogram resolution (1 mS/cm) |
339 $hist[$b]++; |
463 $hist[$b]++; |
340 next unless ($hist[$b] > $modeSamp); |
464 next unless ($hist[$b] > $modeSamp); |
341 $modeSamp = $hist[$b]; $modeBin = $b; |
465 $modeSamp = $hist[$b]; $modeBin = $b; |
342 } |
466 } |
343 ($min,$max) = validRange($modeBin); |
467 ($min,$max) = validRange($modeBin); |
344 $min /= $condHistRes; $max /= $condHistRes; |
468 $min /= $condHistRes; $max /= $condHistRes; |
345 for (my($s)=0; $s<$nscans; $s++) { |
469 for (my($s)=0; $s<$nscans; $s++) { |
|
470 next unless numberp($ants_[$s][$condF]); |
346 if ($ants_[$s][$condF] > $max) { $outliers++; $ants_[$s][$condF] = nan; } |
471 if ($ants_[$s][$condF] > $max) { $outliers++; $ants_[$s][$condF] = nan; } |
347 if ($ants_[$s][$condF] < $min) { $outliers++; $ants_[$s][$condF] = nan; } |
472 if ($ants_[$s][$condF] < $min) { $outliers++; $ants_[$s][$condF] = nan; } |
348 } |
473 } |
349 &antsAddParams("conductivity_outliers",sprintf("%d",$outliers)); |
474 &antsAddParams("conductivity_outliers",sprintf("%d",$outliers)); |
350 printf(STDERR "\n\tcontinuous conductivity range: %.1f..%.1f S/m (%d outliers removed)",$min,$max,$outliers) if ($opt_v > 1); |
475 printf(STDERR "\n\tcontinuous conductivity range: %.1f..%.1f S/m (%d outliers removed)",$min,$max,$outliers) if ($opt_v > 1); |
372 # if ($opt_v > 1); |
498 # if ($opt_v > 1); |
373 ($min,$max) = validRange($modeBin); |
499 ($min,$max) = validRange($modeBin); |
374 $min = ($min / 0.5) - 10; |
500 $min = ($min / 0.5) - 10; |
375 $max = ($max / 0.5) - 10; |
501 $max = ($max / 0.5) - 10; |
376 for (my($s)=0; $s<$nscans; $s++) { |
502 for (my($s)=0; $s<$nscans; $s++) { |
|
503 next unless numberp($ants_[$s][$tempF]); |
377 if ($ants_[$s][$tempF] > $max) { $outliers++; $ants_[$s][$tempF] = nan; } |
504 if ($ants_[$s][$tempF] > $max) { $outliers++; $ants_[$s][$tempF] = nan; } |
378 if ($ants_[$s][$tempF] < $min) { $outliers++; $ants_[$s][$tempF] = nan; } |
505 if ($ants_[$s][$tempF] < $min) { $outliers++; $ants_[$s][$tempF] = nan; } |
379 } |
506 } |
380 &antsAddParams("temperature_outliers",sprintf("%d",$outliers)); |
507 &antsAddParams("temperature_outliers",sprintf("%d",$outliers)); |
381 printf(STDERR "\n\tcontinuous temperature range: %.1f..%.1f degC (%d outliers removed)",$min,$max,$outliers) |
508 printf(STDERR "\n\tcontinuous temperature range: %.1f..%.1f degC (%d outliers removed)",$min,$max,$outliers) |