RDI_PD0_IO.pl
changeset 37 40d85448debf
parent 36 515b06dae59c
child 39 3bddaa514ef5
equal deleted inserted replaced
36:515b06dae59c 37:40d85448debf
     1 #======================================================================
     1 #======================================================================
     2 #                    R D I _ B B _ R E A D . P L 
     2 #                    R D I _ P D 0 _ I O . P L 
     3 #                    doc: Sat Jan 18 14:54:43 2003
     3 #                    doc: Sat Jan 18 14:54:43 2003
     4 #                    dlm: Sat Jul 30 18:34:46 2016
     4 #                    dlm: Tue Mar  7 12:07:29 2017
     5 #                    (c) 2003 A.M. Thurnherr
     5 #                    (c) 2003 A.M. Thurnherr
     6 #                    uE-Info: 402 62 NIL 0 0 72 10 2 4 NIL ofnI
     6 #                    uE-Info: 1250 39 NIL 0 0 72 0 2 4 NIL ofnI
     7 #======================================================================
     7 #======================================================================
     8 
     8 
     9 # Read RDI BroadBand Binary Data Files (*.[0-9][0-9][0-9])
     9 # Read RDI PD0 binary data files (*.[0-9][0-9][0-9])
    10 
    10 
    11 # HISTORY:
    11 # HISTORY:
    12 #	Jan 18, 2003: - incepted aboard the Aurora Australis (KAOS)
    12 #	Jan 18, 2003: - incepted aboard the Aurora Australis (KAOS)
    13 #	Jan 19, 2003: - continued
    13 #	Jan 19, 2003: - continued
    14 #	Jan 20, 2003: - replaced INTENSITY by AMPLITUDE
    14 #	Jan 20, 2003: - replaced INTENSITY by AMPLITUDE
    76 #	Feb 23, 2016: - changed WBRhdr() to use 2nd ensemble (with correct data-source id)
    76 #	Feb 23, 2016: - changed WBRhdr() to use 2nd ensemble (with correct data-source id)
    77 #	Feb 26, 2016: - added basic BT data to WBPens(); not BT_RL_* and BT_SIGNAL_STRENGTH
    77 #	Feb 26, 2016: - added basic BT data to WBPens(); not BT_RL_* and BT_SIGNAL_STRENGTH
    78 #	Feb 29, 2016: - LEAP DAY: actually got BT data patching to work
    78 #	Feb 29, 2016: - LEAP DAY: actually got BT data patching to work
    79 #	Jul 30, 2016: - BUG: incomplete last ensemble with garbage content was returned on reading
    79 #	Jul 30, 2016: - BUG: incomplete last ensemble with garbage content was returned on reading
    80 #						 WH300 data
    80 #						 WH300 data
       
    81 #	Aug  5, 2016: - cosmetics
       
    82 #	Aug 23, 2016: - added &clearEns()
       
    83 #	Nov  9, 2016: - made WBRhdr() return undef on "empty" files
       
    84 #	Nov 18, 2016: - BUG: ensNo was not reported correctly in format errors
       
    85 #	Nov 23, 2016: - no longer set pitch/roll/heading to undef in clearEns()
       
    86 #	Mar  7, 2016: - renamed round() to stop clashing with ANTSLIB
    81 
    87 
    82 # FIRMWARE VERSIONS:
    88 # FIRMWARE VERSIONS:
    83 #	It appears that different firmware versions generate different file
    89 #	It appears that different firmware versions generate different file
    84 #	structures. Currently (Sep 2005) these routines have been tested
    90 #	structures. Currently (Sep 2005) these routines have been tested
    85 #	with the following firmware versions (as reported by [listHdr]):
    91 #	with the following firmware versions (as reported by [listHdr]):
   373 sub readHeader(@)
   379 sub readHeader(@)
   374 {
   380 {
   375 	my($fn,$dta) = @_;
   381 	my($fn,$dta) = @_;
   376 	$WBRcfn = $fn;
   382 	$WBRcfn = $fn;
   377     open(WBRF,$WBRcfn) || die("$WBRcfn: $!");
   383     open(WBRF,$WBRcfn) || die("$WBRcfn: $!");
   378     WBRhdr($dta);    
   384     WBRhdr($dta) || die("$WBRcfn: Insufficient data\n");
   379 }
   385 }
   380 
   386 
   381 sub WBRhdr($)
   387 sub WBRhdr($)
   382 {
   388 {
   383 	my($dta) = @_;
   389 	my($dta) = @_;
   387 	#--------------------
   393 	#--------------------
   388 	# HEADER
   394 	# HEADER
   389 	#--------------------
   395 	#--------------------
   390 
   396 
   391 	skip_initial_trash();
   397 	skip_initial_trash();
   392 	sysread(WBRF,$buf,6) == 6 || die("$WBRcfn: $!");
   398 	sysread(WBRF,$buf,6) == 6 || return undef;
   393 	($hid,$did,$dta->{ENSEMBLE_BYTES},$dummy,$dta->{NUMBER_OF_DATA_TYPES})
   399 	($hid,$did,$dta->{ENSEMBLE_BYTES},$dummy,$dta->{NUMBER_OF_DATA_TYPES})
   394 		= unpack('CCvCC',$buf);
   400 		= unpack('CCvCC',$buf);
   395 	$hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header (hid)",$hid,0));
   401 	$hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header (hid)",$hid,0));
   396 	$did == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header (did)",$did,0));
   402 	$did == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header (did)",$did,0));
   397 
   403 
   398 	$start_ens = sysseek(WBRF,$dta->{ENSEMBLE_BYTES}-6+2,1) || die("$WBRcfn: $!");
   404 	$start_ens = sysseek(WBRF,$dta->{ENSEMBLE_BYTES}-6+2,1) || return undef;
   399 	sysread(WBRF,$buf,6) == 6 || die("$WBRcfn: $!");
   405 	sysread(WBRF,$buf,6) == 6 || return undef;
   400 	($hid,$did,$dta->{ENSEMBLE_BYTES},$dummy,$dta->{NUMBER_OF_DATA_TYPES})
   406 	($hid,$did,$dta->{ENSEMBLE_BYTES},$dummy,$dta->{NUMBER_OF_DATA_TYPES})
   401 		= unpack('CCvCC',$buf);
   407 		= unpack('CCvCC',$buf);
   402 	$hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header (hid2)",$hid,0));
   408 	$hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header (hid2)",$hid,0));
   403 	$dta->{DATA_SOURCE_ID} = $did;
   409 	$dta->{DATA_SOURCE_ID} = $did;
   404 	if ($did == 0x7f) {
   410 	if ($did == 0x7f) {
   641 
   647 
   642 sub readData(@)
   648 sub readData(@)
   643 {
   649 {
   644 	my($fn,$dta) = @_;
   650 	my($fn,$dta) = @_;
   645 	$WBRcfn = $fn;
   651 	$WBRcfn = $fn;
   646     open(WBRF,$WBRcfn) || die("$WBRcfn: $!");
   652     open(WBRF,$WBRcfn) || die("$WBRcfn: $!\n");
   647     WBRhdr($dta);
   653     WBRhdr($dta) || die("$WBRcfn: Insufficient Data\n");
   648 	WBRens($dta->{N_BINS},$dta->{FIXED_LEADER_BYTES},
   654 	WBRens($dta->{N_BINS},$dta->{FIXED_LEADER_BYTES},
   649 		   \@{$dta->{ENSEMBLE}});
   655 		   \@{$dta->{ENSEMBLE}});
   650 	print(STDERR "$WBRcfn: $BIT_errors built-in-test errors\n")
   656 	print(STDERR "$WBRcfn: $BIT_errors built-in-test errors\n")
   651 		if ($BIT_errors);
   657 		if ($BIT_errors);
   652 }
   658 }
   668 		#----------------------------------------
   674 		#----------------------------------------
   669 
   675 
   670 		sysseek(WBRF,$start_ens,0) || die("$WBRcfn: $!");
   676 		sysseek(WBRF,$start_ens,0) || die("$WBRcfn: $!");
   671 		sysread(WBRF,$buf,6) == 6 || last;
   677 		sysread(WBRF,$buf,6) == 6 || last;
   672 		($hid,$did,$ens_length,$dummy,$ndt) = unpack('CCvCC',$buf);
   678 		($hid,$did,$ens_length,$dummy,$ndt) = unpack('CCvCC',$buf);
   673 		$hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header",$hid,0));
   679 		$hid == 0x7f || die(sprintf($FmtErr,$WBRcfn,"Header",$hid,defined($ensNo)?$ensNo+1:0));
   674 		${$E}[$ens]->{DATA_SOURCE_ID} = $did;
   680 		${$E}[$ens]->{DATA_SOURCE_ID} = $did;
   675 		if ($did == 0x7f) {
   681 		if ($did == 0x7f) {
   676 			${$E}[$ens]->{PRODUCER} = 'TRDI ADCP';
   682 			${$E}[$ens]->{PRODUCER} = 'TRDI ADCP';
   677 		} elsif ($did&0xF0 == 0xA0) {
   683 		} elsif ($did&0xF0 == 0xA0) {
   678 			${$E}[$ens]->{PRODUCER} = 'IMP+LADCP (Thurnherr software)';
   684 			${$E}[$ens]->{PRODUCER} = 'IMP+LADCP (Thurnherr software)';
   696 		# UH BB150 writes incomplete ensembles (i.e. short read
   702 		# UH BB150 writes incomplete ensembles (i.e. short read
   697 		# indicates EOF). FSU WH300 has bogus data in incomplete
   703 		# indicates EOF). FSU WH300 has bogus data in incomplete
   698 		# final ensemble.
   704 		# final ensemble.
   699 
   705 
   700 		sysseek(WBRF,$start_ens,0) || die("$WBRcfn: $!");
   706 		sysseek(WBRF,$start_ens,0) || die("$WBRcfn: $!");
   701 		unless ((sysread(WBRF,$buf,$ens_length) == $ens_length) &&
   707 		unless ((sysread(WBRF,$buf,$ens_length) == $ens_length) &&				# incomplete ensemble
   702 				(sysread(WBRF,$cs,2) == 2)) {
   708 				(sysread(WBRF,$cs,2) == 2)) {
   703 			pop(@{$E});
   709 			pop(@{$E});
   704 			last;
   710 			last;
   705 		}
   711 		}
   706 
   712 
   707 		pop(@{$E}),last unless (unpack('%16C*',$buf) == unpack('v',$cs));
   713 		unless (unpack('%16C*',$buf) == unpack('v',$cs)) {						# bad checksum
       
   714 			pop(@{$E});
       
   715 			last;
       
   716 #			next;																# using this might make the code work
       
   717 		}																		# for files with isolated bad ensembles
   708 
   718 
   709 		#------------------------------
   719 		#------------------------------
   710 		# Variable Leader
   720 		# Variable Leader
   711 		#------------------------------
   721 		#------------------------------
   712 	
   722 	
       
   723 		my($lastEns) = $ensNo;
   713 		sysseek(WBRF,$start_ens+$WBRofs[1],0) || die("$WBRcfn: $!");
   724 		sysseek(WBRF,$start_ens+$WBRofs[1],0) || die("$WBRcfn: $!");
   714 		sysread(WBRF,$buf,4) == 4 || die("$WBRcfn: $!");
   725 		sysread(WBRF,$buf,4) == 4 || die("$WBRcfn: $!");
   715 		($id,$ensNo) = unpack("vv",$buf);
   726 		($id,$ensNo) = unpack("vv",$buf);										# only lower two bytes!!!
   716 
   727 
   717 		$id == 0x0080 ||
   728 		$id == 0x0080 ||
   718 			die(sprintf($FmtErr,$WBRcfn,"Variable Leader",$id,$ensNo+1));
   729 			die(sprintf($FmtErr,$WBRcfn,"Variable Leader",$id,$ensNo + ($lastEns - ($lastEns & 0xFFFF))));
   719 
   730 
   720 		if ($fixed_leader_bytes==42 || $fixed_leader_bytes==58) {			# BB150 & Explorer DVL
   731 		if ($fixed_leader_bytes==42 || $fixed_leader_bytes==58) {				# BB150 & Explorer DVL
   721 			sysread(WBRF,$buf,7) == 7 || die("$WBRcfn: $!");
   732 			sysread(WBRF,$buf,7) == 7 || die("$WBRcfn: $!");
   722 			(${$E}[$ens]->{YEAR},${$E}[$ens]->{MONTH},
   733 			(${$E}[$ens]->{YEAR},${$E}[$ens]->{MONTH},
   723 			 ${$E}[$ens]->{DAY},${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE},
   734 			 ${$E}[$ens]->{DAY},${$E}[$ens]->{HOUR},${$E}[$ens]->{MINUTE},
   724 			 ${$E}[$ens]->{SECONDS},$B4) = unpack('CCCCCCC',$buf);
   735 			 ${$E}[$ens]->{SECONDS},$B4) = unpack('CCCCCCC',$buf);
   725 			${$E}[$ens]->{SECONDS} += $B4/100;
   736 			${$E}[$ens]->{SECONDS} += $B4/100;
   852 		sysseek(WBRF,$start_ens+$WBRofs[2],0) || die("$WBRcfn: $!");
   863 		sysseek(WBRF,$start_ens+$WBRofs[2],0) || die("$WBRcfn: $!");
   853 		sysread(WBRF,$buf,2+$ndata*2) == 2+$ndata*2 || die("$WBRcfn: $!");
   864 		sysread(WBRF,$buf,2+$ndata*2) == 2+$ndata*2 || die("$WBRcfn: $!");
   854 		($id,@dta) = unpack("vv$ndata",$buf);
   865 		($id,@dta) = unpack("vv$ndata",$buf);
   855 
   866 
   856 		$id == 0x0100 ||
   867 		$id == 0x0100 ||
   857 			die(sprintf($FmtErr,$WBRcfn,"Velocity Data",$id,$ens));
   868 			die(sprintf($FmtErr,$WBRcfn,"Velocity Data",$id,$ensNo));
   858 		
   869 		
   859 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
   870 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
   860 			for ($beam=0; $beam<4; $beam++,$i++) {
   871 			for ($beam=0; $beam<4; $beam++,$i++) {
   861 				${$E}[$ens]->{VELOCITY}[$bin][$beam] =
   872 				${$E}[$ens]->{VELOCITY}[$bin][$beam] =
   862 					unpack('s',pack('S',$dta[$i])) / 1000
   873 					unpack('s',pack('S',$dta[$i])) / 1000
   871 		sysseek(WBRF,$start_ens+$WBRofs[3],0) || die("$WBRcfn: $!");
   882 		sysseek(WBRF,$start_ens+$WBRofs[3],0) || die("$WBRcfn: $!");
   872 		sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!");
   883 		sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!");
   873 		($id,@dta) = unpack("vC$ndata",$buf);
   884 		($id,@dta) = unpack("vC$ndata",$buf);
   874 
   885 
   875 		$id == 0x0200 ||
   886 		$id == 0x0200 ||
   876 			die(sprintf($FmtErr,$WBRcfn,"Correlation Data",$id,$ens));
   887 			die(sprintf($FmtErr,$WBRcfn,"Correlation Data",$id,$ensNo));
   877 		
   888 		
   878 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
   889 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
   879 			for ($beam=0; $beam<4; $beam++,$i++) {
   890 			for ($beam=0; $beam<4; $beam++,$i++) {
   880 				${$E}[$ens]->{CORRELATION}[$bin][$beam] = $dta[$i]
   891 				${$E}[$ens]->{CORRELATION}[$bin][$beam] = $dta[$i]
   881 					if ($dta[$i]);
   892 					if ($dta[$i]);
   889 		sysseek(WBRF,$start_ens+$WBRofs[4],0) || die("$WBRcfn: $!");
   900 		sysseek(WBRF,$start_ens+$WBRofs[4],0) || die("$WBRcfn: $!");
   890 		sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!");
   901 		sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!");
   891 		($id,@dta) = unpack("vC$ndata",$buf);
   902 		($id,@dta) = unpack("vC$ndata",$buf);
   892 
   903 
   893 		$id == 0x0300 ||
   904 		$id == 0x0300 ||
   894 			die(sprintf($FmtErr,$WBRcfn,"Echo Intensity",$id,$ens));
   905 			die(sprintf($FmtErr,$WBRcfn,"Echo Intensity",$id,$ensNo));
   895 
   906 
   896 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
   907 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
   897 			for ($beam=0; $beam<4; $beam++,$i++) {
   908 			for ($beam=0; $beam<4; $beam++,$i++) {
   898 				${$E}[$ens]->{ECHO_AMPLITUDE}[$bin][$beam] = $dta[$i];
   909 				${$E}[$ens]->{ECHO_AMPLITUDE}[$bin][$beam] = $dta[$i];
   899 			}
   910 			}
   906 		sysseek(WBRF,$start_ens+$WBRofs[5],0) || die("$WBRcfn: $!");
   917 		sysseek(WBRF,$start_ens+$WBRofs[5],0) || die("$WBRcfn: $!");
   907 		sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!");
   918 		sysread(WBRF,$buf,2+$ndata) == 2+$ndata || die("$WBRcfn: $!");
   908 		($id,@dta) = unpack("vC$ndata",$buf);
   919 		($id,@dta) = unpack("vC$ndata",$buf);
   909 
   920 
   910 		$id == 0x0400 ||
   921 		$id == 0x0400 ||
   911 			die(sprintf($FmtErr,$WBRcfn,"Percent-Good Data",$id,$ens));
   922 			die(sprintf($FmtErr,$WBRcfn,"Percent-Good Data",$id,$ensNo));
   912 
   923 
   913 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
   924 		for ($i=0,$bin=0; $bin<$nbins; $bin++) {
   914 #			printf(STDERR "%-GOOD($bin): ");
   925 #			printf(STDERR "%-GOOD($bin): ");
   915 			for ($beam=0; $beam<4; $beam++,$i++) {
   926 			for ($beam=0; $beam<4; $beam++,$i++) {
   916 #				printf(STDERR "$dta[$i] ");
   927 #				printf(STDERR "$dta[$i] ");
  1026     sysseek(WBPF,0,0) || die("$WBPcfn: $!");						# rewind patch file
  1037     sysseek(WBPF,0,0) || die("$WBPcfn: $!");						# rewind patch file
  1027 
  1038 
  1028     WBPens($dta->{N_BINS},$dta->{FIXED_LEADER_BYTES},$dta);
  1039     WBPens($dta->{N_BINS},$dta->{FIXED_LEADER_BYTES},$dta);
  1029 }
  1040 }
  1030 
  1041 
  1031 sub round(@)
  1042 sub _round(@)
  1032 {
  1043 {
  1033 	return $_[0] >= 0 ? int($_[0] + 0.5)
  1044 	return $_[0] >= 0 ? int($_[0] + 0.5)
  1034 					  : int($_[0] - 0.5);
  1045 					  : int($_[0] - 0.5);
  1035 }
  1046 }
  1036 
  1047 
  1037 
  1048 
  1038 sub WBPens($$$)
  1049 sub WBPens($$$)
  1039 {
  1050 {
  1040 	my($nbins,$fixed_leader_bytes,$dta) = @_;
  1051 	my($nbins,$fixed_leader_bytes,$dta) = @_;
  1041 	my($start_ens,$B1,$B2,$B3,$B4,$I,$id,$bin,$beam,$buf,$dummy,@dta,$i,$cs,@WBPofs);
  1052 	my($start_ens,$B1,$B2,$B3,$B4,$I,$id,$bin,$beam,$buf,$dummy,@dta,$i,$cs,@WBPofs);
  1042 	my($ens,$ensNo,$dayStart,$ens_length,$hid,$ndt);
  1053 	my($ens,$dayStart,$ens_length,$hid,$ndt);
  1043 
  1054 
  1044 	for ($ens=$start_ens=0; $ens<=$#{$dta->{ENSEMBLE}}; $ens++,$start_ens+=$ens_length+2) {
  1055 	for ($ens=$start_ens=0; $ens<=$#{$dta->{ENSEMBLE}}; $ens++,$start_ens+=$ens_length+2) {
  1045 
  1056 
  1046 		#------------------------------
  1057 		#------------------------------
  1047 		# Patch Header (Data Source Id)
  1058 		# Patch Header (Data Source Id)
  1098 		# Variable Leader
  1109 		# Variable Leader
  1099 		#------------------------------
  1110 		#------------------------------
  1100 
  1111 
  1101 		sysseek(WBPF,$start_ens+$WBPofs[1]+14,0) || die("$WBPcfn: $!");		# jump to SPEED_OF_SOUND
  1112 		sysseek(WBPF,$start_ens+$WBPofs[1]+14,0) || die("$WBPcfn: $!");		# jump to SPEED_OF_SOUND
  1102 		
  1113 		
  1103 		$dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH} = round($dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH}*10);
  1114 		$dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH} = _round($dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH}*10);
  1104 
  1115 
  1105 		#---------------------------------
  1116 		#---------------------------------
  1106 		# NB: IMP allows for missing value
  1117 		# NB: IMP allows for missing value
  1107 		#---------------------------------
  1118 		#---------------------------------
  1108 
  1119 
  1109 		$dta->{ENSEMBLE}[$ens]->{HEADING} = defined($dta->{ENSEMBLE}[$ens]->{HEADING})
  1120 		$dta->{ENSEMBLE}[$ens]->{HEADING} = defined($dta->{ENSEMBLE}[$ens]->{HEADING})
  1110 							   ? round($dta->{ENSEMBLE}[$ens]->{HEADING}*100)
  1121 							   ? _round($dta->{ENSEMBLE}[$ens]->{HEADING}*100)
  1111 							   : 0xF000;
  1122 							   : 0xF000;
  1112 		$dta->{ENSEMBLE}[$ens]->{PITCH} = defined($dta->{ENSEMBLE}[$ens]->{PITCH})
  1123 		$dta->{ENSEMBLE}[$ens]->{PITCH} = defined($dta->{ENSEMBLE}[$ens]->{PITCH})
  1113 							 ? unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{PITCH}*100)))
  1124 							 ? unpack('S',pack('s',_round($dta->{ENSEMBLE}[$ens]->{PITCH}*100)))
  1114 							 : 0x8000;
  1125 							 : 0x8000;
  1115 		$dta->{ENSEMBLE}[$ens]->{ROLL} = defined($dta->{ENSEMBLE}[$ens]->{ROLL})
  1126 		$dta->{ENSEMBLE}[$ens]->{ROLL} = defined($dta->{ENSEMBLE}[$ens]->{ROLL})
  1116 						    ? unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{ROLL}*100)))
  1127 						    ? unpack('S',pack('s',_round($dta->{ENSEMBLE}[$ens]->{ROLL}*100)))
  1117 						    : 0x8000;
  1128 						    : 0x8000;
  1118 
  1129 
  1119 		$dta->{ENSEMBLE}[$ens]->{TEMPERATURE} =
  1130 		$dta->{ENSEMBLE}[$ens]->{TEMPERATURE} =
  1120 			unpack('S',pack('s',round($dta->{ENSEMBLE}[$ens]->{TEMPERATURE}*100)));
  1131 			unpack('S',pack('s',_round($dta->{ENSEMBLE}[$ens]->{TEMPERATURE}*100)));
  1121 
  1132 
  1122 		$buf = pack('vvvvvvv',
  1133 		$buf = pack('vvvvvvv',
  1123 			 $dta->{ENSEMBLE}[$ens]->{SPEED_OF_SOUND},
  1134 			 $dta->{ENSEMBLE}[$ens]->{SPEED_OF_SOUND},
  1124 			 $dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH},$dta->{ENSEMBLE}[$ens]->{HEADING},
  1135 			 $dta->{ENSEMBLE}[$ens]->{XDUCER_DEPTH},$dta->{ENSEMBLE}[$ens]->{HEADING},
  1125 			 $dta->{ENSEMBLE}[$ens]->{PITCH},$dta->{ENSEMBLE}[$ens]->{ROLL},
  1136 			 $dta->{ENSEMBLE}[$ens]->{PITCH},$dta->{ENSEMBLE}[$ens]->{ROLL},
  1135 
  1146 
  1136 		sysseek(WBPF,$start_ens+$WBPofs[2]+2,0) || die("$WBPcfn: $!");	# skip velocity data id (assume it is correct)
  1147 		sysseek(WBPF,$start_ens+$WBPofs[2]+2,0) || die("$WBPcfn: $!");	# skip velocity data id (assume it is correct)
  1137 		for ($bin=0; $bin<$nbins; $bin++) {
  1148 		for ($bin=0; $bin<$nbins; $bin++) {
  1138 			for ($beam=0; $beam<4; $beam++) {
  1149 			for ($beam=0; $beam<4; $beam++) {
  1139 				$dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam] = defined($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam])
  1150 				$dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam] = defined($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam])
  1140 							   						 ? round($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam]*1000)
  1151 							   						 ? _round($dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam]*1000)
  1141 							   						 : 0x8000;
  1152 							   						 : 0x8000;
  1142 				$buf = pack('v',unpack('S',pack('s',$dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam])));
  1153 				$buf = pack('v',unpack('S',pack('s',$dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin][$beam])));
  1143 				my($nw) = syswrite(WBPF,$buf,2);
  1154 				my($nw) = syswrite(WBPF,$buf,2);
  1144 				$nw == 2 || die("$WBPcfn: $nw bytes written ($!)");
  1155 				$nw == 2 || die("$WBPcfn: $nw bytes written ($!)");
  1145 			}
  1156 			}
  1200 		}
  1211 		}
  1201 
  1212 
  1202 		unless ($nxt == $ndt) {													# BT found
  1213 		unless ($nxt == $ndt) {													# BT found
  1203 			sysseek(WBPF,14,1) || die("$WBPcfn: $!");							# skip BT config
  1214 			sysseek(WBPF,14,1) || die("$WBPcfn: $!");							# skip BT config
  1204 			for ($beam=0; $beam<4; $beam++) {									# BT range low bytes (2 per beam)
  1215 			for ($beam=0; $beam<4; $beam++) {									# BT range low bytes (2 per beam)
  1205 				$buf = pack('v',round($dta->{ENSEMBLE}[$ens]->{BT_RANGE}[$beam] * 100) & 0xFFFF);
  1216 				$buf = pack('v',_round($dta->{ENSEMBLE}[$ens]->{BT_RANGE}[$beam] * 100) & 0xFFFF);
  1206 				my($nw) = syswrite(WBPF,$buf,2);
  1217 				my($nw) = syswrite(WBPF,$buf,2);
  1207 				$nw == 2 || die("$WBPcfn: $nw bytes written ($!)");
  1218 				$nw == 2 || die("$WBPcfn: $nw bytes written ($!)");
  1208 			}
  1219 			}
  1209 			
  1220 			
  1210 			for ($beam=0; $beam<4; $beam++) {									# BT velocities
  1221 			for ($beam=0; $beam<4; $beam++) {									# BT velocities
  1211 				$buf = pack('v',unpack('S',pack('s',
  1222 				$buf = pack('v',unpack('S',pack('s',
  1212 						defined($dta->{ENSEMBLE}[$ens]->{BT_VELOCITY}[$beam])
  1223 						defined($dta->{ENSEMBLE}[$ens]->{BT_VELOCITY}[$beam])
  1213 							? round($dta->{ENSEMBLE}[$ens]->{BT_VELOCITY}[$beam]*1000)
  1224 							? _round($dta->{ENSEMBLE}[$ens]->{BT_VELOCITY}[$beam]*1000)
  1214 							: 0x8000)));
  1225 							: 0x8000)));
  1215 				my($nw) = syswrite(WBPF,$buf,2);
  1226 				my($nw) = syswrite(WBPF,$buf,2);
  1216 				$nw == 2 || die("$WBPcfn: $nw bytes written ($!)");
  1227 				$nw == 2 || die("$WBPcfn: $nw bytes written ($!)");
  1217 			}
  1228 			}
  1218 			
  1229 			
  1234                 $nw == 1 || die("$WBPcfn: $nw bytes written ($!)");
  1245                 $nw == 1 || die("$WBPcfn: $nw bytes written ($!)");
  1235             }
  1246             }
  1236 
  1247 
  1237 			sysseek(WBPF,33,1) || die("$WBPcfn: $!");							# BT range high bytes (1 per beam)
  1248 			sysseek(WBPF,33,1) || die("$WBPcfn: $!");							# BT range high bytes (1 per beam)
  1238 			for ($beam=0; $beam<4; $beam++) {
  1249 			for ($beam=0; $beam<4; $beam++) {
  1239 				$buf = pack('C',(round($dta->{ENSEMBLE}[$ens]->{BT_RANGE}[$beam]*100) & 0xFF0000) >> 16);
  1250 				$buf = pack('C',(_round($dta->{ENSEMBLE}[$ens]->{BT_RANGE}[$beam]*100) & 0xFF0000) >> 16);
  1240 				my($nw) = syswrite(WBPF,$buf,1);
  1251 				my($nw) = syswrite(WBPF,$buf,1);
  1241 				$nw == 1 || die("$WBPcfn: $nw bytes written ($!)");
  1252 				$nw == 1 || die("$WBPcfn: $nw bytes written ($!)");
  1242 			}
  1253 			}
  1243 
  1254 
  1244         } # if BT found
  1255         } # if BT found
  1255 		$nw == 2 || die("$WBPcfn: $nw bytes written, ens=$ens ($!)");
  1266 		$nw == 2 || die("$WBPcfn: $nw bytes written, ens=$ens ($!)");
  1256 
  1267 
  1257 	} # ens loop
  1268 	} # ens loop
  1258 }
  1269 }
  1259 
  1270 
       
  1271 #----------------------------------------------------------------------
       
  1272 # &clearEns(^data,ens-index)
       
  1273 #	- undefine all velocities in ensemble, including BT
       
  1274 #		- this is required for the LDEO_IX software,
       
  1275 #		  which does not recognize missing attitude values
       
  1276 #	- set percent good to zero
       
  1277 #		- this is done for consistency
       
  1278 #	- DO NOT undef heading, pitch and roll
       
  1279 #		- the LDEO software does not recognize missing attitude vals
       
  1280 #		  and, therefore, misinterprets those
       
  1281 #		- while this should not matter because all the velocities are
       
  1282 #		  also deleted, it was found that setting only the heading to
       
  1283 #		  undef'd and leaving pitch and roll unchanged causes
       
  1284 #		  significant errors in GPS velocity referencing! This
       
  1285 #		  must be a bug
       
  1286 #		- also, if attitudes are undef'd the LDEO software
       
  1287 #		  cannto determine the instrument offset from pitch/roll
       
  1288 #		  and the pitch/roll DL vs UL plots are bogus
       
  1289 #----------------------------------------------------------------------
       
  1290 
       
  1291 sub clearEns($$)
       
  1292 {
       
  1293 	my($dta,$ens) = @_;
       
  1294 	croak("clearEns: ens-index $ens out of range\n")
       
  1295 		unless ($ens>=0 && $ens<=$#{$dta->{ENSEMBLE}});
       
  1296 	for (my($bin)=0; $bin<$dta->{N_BINS}; $bin++) {
       
  1297 		undef(@{$dta->{ENSEMBLE}[$ens]->{VELOCITY}[$bin]});
       
  1298 		@{$dta->{ENSEMBLE}[$ens]->{PERCENT_GOOD}[$bin]} = (0,0,0,0);
       
  1299 	}
       
  1300 	undef(@{$dta->{ENSEMBLE}[$ens]->{BT_VELOCITY}});
       
  1301 	@{$dta->{ENSEMBLE}[$ens]->{BT_PERCENT_GOOD}} = (0,0,0,0);
       
  1302 #	undef($dta->{ENSEMBLE}[$ens]->{HEADING});
       
  1303 #	undef($dta->{ENSEMBLE}[$ens]->{PITCH});
       
  1304 #	undef($dta->{ENSEMBLE}[$ens]->{ROLL});
       
  1305 }
       
  1306 
  1260 1;      # return true for all the world to see
  1307 1;      # return true for all the world to see