% adr2cdf - Converts Sontek ADV files to netCDF format % function adr2cdf(adrFile, cdfFile, [writeburstfile],[writestatsfile],[diagnostics], metadata); % % where: % adrFile = input Sontek ADV file (ex: 'CA1001.adr') % cdfFile = netCDF file name (ex: 'C1001') to which b.cdf and s.cdf will be appended % writeburstfile = [startburst endburst]; if want to output a burst file (very large) % [1 Inf]; to select all []; omit all % writestatsfile = [startburst endburst]; if want to output a statistics file % [1 Inf]; to select all []; omit all if writeburstfile and % writestatsfile are omitted, then all data are written for both % diagnostics.pcountout = save the raw pressure count in the burst file, % use for druck sensors % diagnostics.fixpfreq = use fixparosoverflow to detect if wrong pressure offset % was used and apply a correction algorithm % metadata = metadata information, see structure definition below % % % here is the metadata structure for this deployment % % if you use an empty char string denoted by '' % % for an external sensor serial number, then that data will not be included % % calibration info will be assigned to variable attributes dynamically % % based on the field names of items under the struct field cals. % % Do not nest more structs under cals, or adr2cdf will not record the data % % no two data loggers can have the same four digit mooring number % metadata.mooring_number = '7281'; %four digit NNNL, NNN mooring + L logger % metadata.deployment_start = '08-nov-2002 12:33:00'; % the in water time % metadata.deployment_end = '16-feb-2003 13:05:00'; % the out of water time % metadata.lon = 13.29722; % decimal degrees, West = negative % metadata.lat = 43.75652; % decimal degrees, South = negative % metadata.declination = 2.0; % degrees west is negative % metadata.water_depth = 10.0; % m % metadata.system.serial = ''; % serial number of the Hydra electronics % metadata.system.synch_to = 'G144'; % G### | nothing % metadata.adv.serial = '217'; % metadata.adv.height = 0.70; % height of emitter above bottom, m % % used to reference anything coming from the ADV probe % % distance from emitter to sample volume: 18 cm for ADVO, 10 cm for ADVF 10 MHz, 5 cm for ADVF 16 MHz % metadata.adv.sample_volume_offset = 18; % % for attached sensors, use '' for the serial number if there is no sensor, % % and variable will not be written % metadata.extpress.serial = 'P82739'; % use the druck file name without the extension % metadata.extpress.height = 1.37; % m, same as adv if in probe % % pressure sensor calibration data will be read from the .drk file % metadata.ext1.serial = 'OBS1711'; % OBS### | TRANS### | XXX#### % metadata.ext1.height = 0.23; % m % % anything under the metadat.ext#.cals structure gets written as an attibute % % in the netCDF file % metadata.ext1.cals.gain = .33; % for OBS % % if coef is present, dohydraoptic will apply the coefficients to OBS data % % use [] or omit if there is no calibration for concentration % metadata.ext1.cals.coef = [0 1 0]; % coefficients to a calibration eqation % % more than three coefficients will be accommodated as higher powers. % % these are not used but are informative % metadata.ext1.cals.units = 'g/l'; % same as kg/m-3 % metadata.ext1.cals.equation = 'Conc [kg/m-3] = coef(1)+coef(2)*V+coef(3)*V^2'; % metadata.ext2.serial = 'TRANS99'; % OBS### | TRANS### | XXX#### % metadata.ext2.height = 0; % m % % anything under the metadat.ext#.cals structure gets written as an attibute % % in the netCDF file % metadata.ext2.cals.path_length = 25; % focal length of the trans, 5 | 25 | 100 cm, required! % metadata.ext2.cals.pre = [0 0]; % for trans: [air blocked] % metadata.ext2.cals.post = [0 0]; % for trans: [air blocked] % metadata.CTD.serial = 'SBE####'; % % metadata.CTD.height = 0.96; % m % % SBE37's record data in real units and do not need applied cals % metadata.metafile = [pwd '\meta####']; % metadata.metafile_data = datestr(now,1); % metadata.metafile_version = '1.0'; % metadata.metafile_author = 'RMH'; % % if the following fields are missing, UNKOWN will be used % metadata.origin = 'USGS/WHFC'; % with collaborator's data, could be USC, etc. % metadata.experiment = 'Boston Longterm'; % metadata.project = 'WHFC'; % might also use OFA funding agency, such as MWRA, EPA, WCMG % metadata.whichscheme = 1; % which sampling scheme to read out % % always 1 for single sampling scheme data, not more than 3 % % NOTE! If a frequency pressure sensor was used, then the .drk file must be in the % same directory as the .adr file % NOTE! if you want to add calibration info to every variable, you must % define them in the metadata struct, this program will prompt you only % for the most essential information. % % Revised by Marinna Martini Written by Andree L. Ramsey heavily based on % adr2mat.m written by Jingping Xu for the U.S. Geological Survey % Coastal and Marine Program Woods Hole Field Center, Woods Hole, MA % http://woodshole.er.usgs.gov/ Please report bugs to mmartini@usgs.gov % % prerequisites % downlooking ADV or PCADP data % netCDF toolbox http://mexcdf.sourceforge.net % hydratools processing software % % 13 Sep. 11 (MM) fix a bug where two schemes with the same number of % samples and sample interval confused the code. Those same schemes will % now go into the same netCDF file. % 29 May 09 (MM) globalatts.m likes to send strings, trap them for lon, lat, declination % and water_depth in metadata since strings cause trouble later on. % 18 Aug 08 remove ncchar designation from nc.MOORING assignment as one % does not necessarily know what will be fed into the program from users or % globalatts.m % 15 jul 2008 (MM) fix a bunch of mlint, check RS232 Paros handling % 9/14/07 etm %-- modified write_metadata2cdf to allow additional fields for global attributes %-- modified MetaADVExample.m to read attributes from a central file % %7 Jul 06 etm % -- added chk_ctdsal() to compute salinity if the sensor wasn't set up to do it % % 13 apr 06 % -- adapt for serial pressure now that I have a test file %12 apr 06 % -- removed function returning Qa - initialized to [] then never used % -- chaged case for .drk to .DRK (goes with changes to readdruck %% 18 oct 05 % -- program aborts if no metadata is provided. % 05 oct 05 % -- account for the ADVs in-situ calculated stats of heading, pitch and % roll: make sure the data are labelled correctly: if stats are not % provided then calculate median % 19 sep 05 % -- make some common subfunctions private and remove from this file % 14 Sep 2005 % -- write quality data only if stats file is selected % 10 Aug 2005 version 7.0 % -- add quality output file functionality % 8 Jul 2005 version 6.4 % -- fix a multiple scheme reading problem which was an index error in % calculating burst size. % 26 Apr 2005 % -- fix a problem with burst sample times % 29 Mar 2005 % -- updated metadata prompts for operation without a script file % -- fix the formatting of comments that got scrambled by another editor % -- what if someone deploys one with internal and external pressure?? Not % possible, there's only one place to save pressure % 9 Mar 2005 % -- Fixed the unit problem in brange & vrange % 1 Mar 2005 % -- Version 6.3 now ends gracefully at the end of a file. % 16 Feb 2005 % -- Version 6.2 CRS added ability to evaluate multiple sampling schemes. % Not sure if the recovery from trashy data is robust when multiple schemes % are present. % 11 Jan 2005 % -- fixed the crash at tend of file bug 10 Jan 2005 % -- fixed a bug which wasn't reacting properly to no CTD present 15 Oct 2004 % -- after a data meeting finalaize variable names (again) 10 Sept. 2003 % -- fix more bugs % -- output external sensors in volts % 11 Aug 2004 % -- add history % -- don't write ANY heading, pitch or roll data if CompassInstalled == No, % which means that ADVDeploymentSetupRecordedDataFlags{:}(2) should be 0 30 % June 2004 version 4.0 % -- match the inputs and behavior of adp2cdf, now writes both burst and stat % files at once if desired. % 21 June 2004 verision 3.4 % -- nail down attributes and variable names for good. % 14-Jun-2004 version 3.3 % -- found and fixed a major problem... extsensor data should have been % read as an unsigned int and was not. Now reading it as uint and get % positive numbers for a 0-5 volt A/D output % 8-Jun-2004 version 3.2 % -- decided NOT to compute and add mins and maxs to each variable in the % burst file, do add them for the stats file % -- fixed the tracking of record size so that this works on data sets that % omit CTD and pressure % 4-Jun-2004 version 3.1 % -- change nc.probe_offset to nc.ADVProbeHeight = metadata.adv.height % -- rewrite some underlying structure so that multiple burst types can be % dealt with and code can be read and debugged more easily % 2-Jun-2004 version 3.0 % -- This is version 3.0 restored from version 0.0 after restructuring % code caused too many problems. % -- Removed Samples dimension for Stats file as no Stats variables use it % -- Add synch metadata % -- Remove batch capability & replace with struct at command line % -- Add instrument heights & serial numbers to variables % -- Add cal coefficients based on how they are defined in m file % -- Smarten up how the file is defined so changes can be more easily accommodated % -- Omit writing of data for sensors that are either set to not record in % the Hydra, or are missing a serial number in the metadata structure % 15-Apr-2004 % comment out clear statements to add speed... so MATLAB doesn't spend % time reallocating memory move CTD data from burst to stats file removed % option for both stats and burst... it was too complicated % Version 2-Apr-2004 % Add batch capability % Version 15-Mar-2004 % will not work with multiple sampling schemes generated time stamps for % each sample when burst data is requested time for burst data is now % [burst, sample] removed pressure normalization, fixed conversion to % frequency % Version 04-Dec-2003 % TODO add handling for 3 OBS channels. 3rd OBS ends up being stored in the internal pressure space (2 bytes) % TODO limit output files to < 2 GB netCDF size limit % TODO the rewind statements are extremely inefficient... or are they? function adr2cdf(adrFile, cdfFile, writeburstfile,writestatsfile,diagnostics, metadata) prog_ver = 'SVN $Revision$'; disp(sprintf('%s %s running',mfilename,prog_ver)) %Qa = []; ATOD = 5/(2^16); % counts to volts conversion for 16 bit storage of A/D nSubbursts = 5; % number of subbursts for flagbadadv analysis tic % Get raw ADV filename. if (exist('adrFile','var') ~=1) || isempty(adrFile), [theFile, thePath] = uigetfile('*.adr', 'Select ADV Data File:'); if isequal(theFile,0) || isequal(thePath,0), disp('User pressed cancel') return; end disp(['User selected ', thePath, theFile]) adrFile = fullfile(thePath, theFile); disp(adrFile) end % get output file name if (exist('cdfFile','var') ~=1) || isempty(cdfFile), prompt = {'Enter an output file name to which b.cdf and s. cdf will be appended:'}; def = {'outputname'}; title = 'Output file name'; lineNo = 1; result = inputdlg(prompt,title,lineNo,def); if isempty(result), return; end cdfFile = result{1}; end % assume the user wants an avgerage file unless they explicitly say no if (exist('writestatsfile','var')~=1), writestatsfile = 1; stats = [1 Inf]; elseif isempty(writestatsfile), writestatsfile = 0; stats = []; elseif find(writestatsfile < 1), % no negative indeces disp('Cannot use negative indeces') return else stats = writestatsfile; writestatsfile = 1; end % assume the user wants a burst file unless they explicitly say no if exist('writeburstfile','var') ~= 1, writeburstfile = 1; bursts = [1 Inf]; elseif isempty(writeburstfile), writeburstfile = 0; bursts = []; elseif find(writeburstfile < 1), % no negative indeces disp('Cannot use negative indeces') return else bursts = writeburstfile; writeburstfile = 1; end if ~writeburstfile && ~writestatsfile, disp('No data will be output to a netCDF file.'); return end if (exist('diagnostics','var')~=1) || isempty(diagnostics), diagnostics.pcountout = 0; diagnostics.fixpfreq = 0; end % get the file size fid=fopen(adrFile); fseek(fid,0,1); filesize=ftell(fid); disp(sprintf('The file is %d bytes',filesize)) fseek(fid,0,-1); %rewind file % **************************** metadata handling % ************************************* % if globatt was used, all the numbers are strings... if isfield(metadata,'lon') && ischar(metadata.lon), metadata.lon = str2double(metadata.lon); end if isfield(metadata,'lat') && ischar(metadata.lat), metadata.lat = str2double(metadata.lat); end if isfield(metadata,'declination') && ischar(metadata.declination), metadata.declination = str2double(metadata.declination); end if isfield(metadata,'water_depth') && ischar(metadata.water_depth), metadata.water_depth = str2double(metadata.water_depth); end global BYTEMAP % map of the size of each data record, indexed by *.RecordedDataFlags flags % are [Amp/Corr Compass Sensor None Stat ExtSensor ExtPress CTD|LISST for % the CTD, four int32's are read, 32 bits = 4 bytes, and it can vary! % Bytemap will be adjusted by ADVSytemConfig if there's a LISST the CTD % size is infact, not documented properly in the Sontek manual, it is % listed as 4 bytes rather than 16 (or 4 x 32 bit integers) BYTEMAP = [6 6 4 0 36 4 3 16]; skip = 0; % we want to read these records and get the data ADVSystemConfig = ReadADVSystemConfig(fid, skip); % Probe Configuration (164 bytes) ADVProbeConfig = ReadADVProbeConfig(fid, skip); % Deployment Setup ADVDeploymentSetup = ReadADVDeploymentSetup(fid, skip); if (ADVDeploymentSetup.SamplesPerBurst(2) > 0) || (ADVDeploymentSetup.SamplesPerBurst(3) > 0), if isfield(metadata,'whichscheme'), whichscheme = metadata.whichscheme; else disp('This data file has more than one sampling scheme') %valid_schemes = find( ADVDeploymentSetup.SamplesPerBurst > 0 ); fprintf(1, 'Scheme: % 4d % 4d % 4d\n',1:3) fprintf(1, 'SampleRate: % 4d % 4d % 4d\n',ADVDeploymentSetup.SampleRate(:)) fprintf(1, 'BurstInterval: % 4d % 4d % 4d\n',ADVDeploymentSetup.BurstInterval(:)) fprintf(1, 'SamplesPerBurst: % 4d % 4d % 4d\n',ADVDeploymentSetup.SamplesPerBurst(:)) whichscheme = input('Select which scheme you want to process: '); fprintf(1, 'Processing scheme %d\n', whichscheme ) end else whichscheme = 1; end % Make sure that if the compass is missing, Recorded Data Flags reflect this % so that variables are read and written correctly throughout this program if strcmp(ADVSystemConfig.CompassInstalled, 'No'), ADVDeploymentSetup.RecordedDataFlags{whichscheme}(2) = 0; end if strcmp(ADVSystemConfig.CTDInstalled, 'None'), ADVDeploymentSetup.RecordedDataFlags{whichscheme}(8) = 0; end % **************************** metadata handling ************************************* if ~exist('metadata','var'), metadata = []; end if isempty(metadata), disp('Cannot process ADV data without cruise metadata') return end %Nbytes = ADVDeploymentSetup.Nbytes; metadata.SampleRate = ADVDeploymentSetup.SampleRate(whichscheme); %Hz nSamples = ADVDeploymentSetup.SamplesPerBurst(whichscheme); % make up our indeces for stepping through the subbursts. % account of uneven divisibility of number of subbursts into the actual % number of samples... get as many complete blocks as possible then do % the last one no matter how small it is nSubsamp = floor(nSamples/nSubbursts); indSubb(:,1) = (1:nSubsamp:nSamples)'; % starting indeces for each subburst if rem(nSamples, nSubbursts), indSubb(:,2) = (nSubsamp:nSubsamp:(nSubsamp*nSubbursts)+nSubsamp)'; % starting indeces for each subburst else indSubb(:,2) = (nSubsamp:nSubsamp:nSamples)'; % starting indeces for each subburst end indSubb = indSubb(1:nSubbursts,:); % Create netCDF files pathstr=fileparts(adrFile); if writestatsfile, ncsfile = fullfile(pathstr,[cdfFile 's.cdf']); % average file for burst statistic & one shot data cdfs=netcdf(ncsfile,'clobber'); disp(sprintf('User asked to write burst statistics to %s from burst %d to %d',ncsfile,stats)) % this does the globals- variable attributes added elsewhere write_metadata2cdf(cdfs, ADVSystemConfig, ADVProbeConfig, ADVDeploymentSetup, metadata, whichscheme); cdfs.CREATION_DATE = datestr(now); cdfs.DESCRIPT = ncchar('Sontek ADV raw data statistics file'); cdfs.COORD_SYSTEM = ncchar('GEOGRAPHICAL'); cdfs.DATA_TYPE = ncchar('TIME'); % quality file information is based on details of each burst, thus % is only written when burst files are written ncqfile = fullfile(pathstr,[cdfFile 'q.cdf']); % quality output file disp(sprintf('Quality information in %s',ncqfile)) cdfq=netcdf(ncqfile,'clobber'); cdfq.CREATION_DATE = datestr(now); cdfq.DESCRIPT = 'Sontek ADV raw data quality file'; cdfq.COORD_SYSTEM = ncchar('NONE'); cdfq.DATA_TYPE = ncchar('TIME'); end if writeburstfile, ncbfile = fullfile(pathstr,[cdfFile 'b.cdf']); % burst file for individual profile data disp(sprintf('User asked to write all burst samples to %s from burst %d to %d',ncbfile,bursts)) % this does the globals- variable attributes added elsewhere cdfb=netcdf(ncbfile,'clobber'); write_metadata2cdf(cdfb, ADVSystemConfig, ADVProbeConfig, ADVDeploymentSetup, metadata, whichscheme); cdfb.CREATION_DATE = datestr(now); cdfb.DESCRIPT = 'Sontek ADV raw data burst file'; cdfb.COORD_SYSTEM = ncchar('GEOGRAPHICAL+SAMPLE'); cdfb.DATA_TYPE = ncchar('TIME+SAMPLE'); end % get the pressure cals if there is pressure if ADVDeploymentSetup.RecordedDataFlags{whichscheme}(7) && ~isempty(metadata.extpress.serial), % was ext pressure recorded & do we have a serial number? % is it something that needs a Druck file? if strcmp(ADVSystemConfig.ExtPressInstalled,'Druck') || strcmp(ADVSystemConfig.ExtPressInstalled,'ParosFreq'), thePath = fileparts(adrFile); metadata.extpress.druckFile = fullfile(thePath,[metadata.extpress.serial '.DRK']); % readdruck will detect the type of sensor from the .drk cal file % that is in the same directory as the data file [metadata.extpress.druck, metadata.extpress.paros] = readdruck(metadata.extpress.druckFile); % now, make sure this makes sense if ~isempty(metadata.extpress.druck), disp(sprintf('Druck calibration constants found in %s',... metadata.extpress.druckFile)); if (metadata.extpress.serial(1) == 'p') || (metadata.extpress.serial(1) == 't'), disp('But a paros style file name was given... check your cal files') end elseif ~isempty(metadata.extpress.paros), disp(sprintf('Paros calibration constants found in %s',... metadata.extpress.druckFile)) else disp(sprintf('Unable to read pressure calibration from %s',... metadata.extpress.druckFile)) end else disp('Serial paros installed') % diagnostics for serial paros not needed, raw pressure is pressure in real units if diagnostics.pcountout, diagnostics.pcountout = 0; disp('Overriding pressure count output flag, pressure is in real units') end if diagnostics.fixpfreq, diagnostics.fixpfreq = 0; disp('Overriding pressure count fix') disp('This is a serial paros, pressure is in real units and does not need to be fixed') end end end % Figure out how many bursts there are if (ADVDeploymentSetup.SamplesPerBurst(2) > 0) || (ADVDeploymentSetup.SamplesPerBurst(3) > 0), disp('Cannot estimate the number of bursts when there is more than one sampling scheme.') nBursts = Inf; else nBursts = floor((filesize-441)/sum(ADVDeploymentSetup.BytesPerSample(:).*... ADVDeploymentSetup.SamplesPerBurst(:))); disp(['There are approximately ',num2str(nBursts),' bursts in the file']) end disp(['Each burst type ',num2str(whichscheme),' contains ',... num2str(nSamples),' samples']) % define the dimensions here if writeburstfile, if isinf(bursts(2)), bursts(2)=nBursts; end % It turns out to be very hard to estimate the exact number of bursts % in a file, and bursts can also be missing. Thus any attempts to save % time by defining the length of the record dimension explicitely has % not worked FYI, for a predefined number of bursts it took Burst #10 % of 4640 read, 2.878817 min elapsed Burst #20 of 4640 read, 3.029700 % min elapsed Burst #4600 of 4640 read, 78.503000 min elapsed where the % data disk was local to the computer doing the processing cdfb('burst') = 0; cdfb('sample') = nSamples; cdfb('axis') = 3; % stats = 1, Burst = 2 disp(sprintf('Writing bursts %d to %d to %s to the burst file', bursts(1),bursts(2), ncbfile)) define_variables(cdfb, 2, ADVDeploymentSetup.RecordedDataFlags, metadata, diagnostics, whichscheme); end if writestatsfile, if isinf(stats(2)), stats(2)=nBursts; end cdfs('burst') = 0; % this is faster if only a subset of the bursts are desired cdfs('axis') = 3; % stats DataType = 1, Burst = 2 disp(sprintf('Writing bursts %d to %d to %s to the stats file', stats(1),stats(2), ncsfile)) define_variables(cdfs, 1, ADVDeploymentSetup.RecordedDataFlags, metadata, diagnostics, whichscheme); % define dimensions of the quality file cdfq('burst') = 0; cdfq('axis') = 3; cdfq('subburst') = nSubbursts; define_qfile (cdfq, cdfb, ADVDeploymentSetup.RecordedDataFlags, metadata, diagnostics, whichscheme); end if ~ADVDeploymentSetup.RecordedDataFlags{whichscheme}(2), disp('Warning... no compass installed in this instrument, please provide compass information to adv2nc') end %Read and write data blocks (one data block for each sampling burst) % Burst Header Information (60 bytes) including date and time from the % real-time clock % a time-series of samples collected during the burst, and statistics % calculated at the end of each burst, optional (36 bytes) The size of % the data block will depend on the data recording parameters. % The end of the burst is a 2-byte checksum trashdata = 0; burstidx = 1; % index of bursts (groups) of profiles read schemeburstidx = [0 0 0]; cdfbwrite = 0; % flag that we are writing burst data cdfbwriteidx = 0; % index of bursts being written cdfswrite = 0; % flag that we are writing average (burst statistic) data cdfswriteidx = 0; % index of bursts being written if writeburstfile, finishedbursts = 0; else finishedbursts = 1; end if writestatsfile, finishedstats = 0; else finishedstats = 1; end while ~feof(fid), % if burstidx > 783, % disp(sprintf('Burst #%d of %d at position %x',burstidx,nBursts,ftell(fid))); % keyboard % end % Reading Burst Header (60 bytes) ADVBurstHeader = ReadADVBurstHeader(fid); if (~isstruct(ADVBurstHeader) && (ADVBurstHeader < 1)), %disp('End of file reached') break; end if ~isempty(ADVBurstHeader), % Detect which sampling scheme by the number of samples and sample rate schemes=find( (ADVBurstHeader.nsamplesthisburst==ADVDeploymentSetup.SamplesPerBurst) &... (ADVBurstHeader.SampRate==ADVDeploymentSetup.SampleRate) ); if length(schemes) > 1, scheme_no = schemes(1); else scheme_no = schemes; end else %scheme_no = []; %TODO need to assume the previous bursts' scheme scheme_no = 1; end if isempty(scheme_no), disp(sprintf('Could not detect scheme number of burst %d, aborting',burstidx)) break; end if( isempty(ADVBurstHeader) ), % we hit trashy data or the wrong scheme % we can survive this assuming the record size did not get % changed. So simply skip this record at this point, we have % already read 4 bytes of the BurstHeader, so the bytes to skip % are not the same as if we were seeking a specific burst flags % are [Amp/Corr Compass Sensor None Stat ExtSensor ExtPress % CTD|LISST ] burstsize = ADVDeploymentSetup.SamplesPerBurst(whichscheme)*ADVDeploymentSetup.BytesPerSample(whichscheme) + ... ADVDeploymentSetup.RecordedDataFlags{whichscheme}(5)*BYTEMAP(5) + ... % Stats at end of burst ADVDeploymentSetup.RecordedDataFlags{whichscheme}(8)*BYTEMAP(8) + ... % CTD at end of burst 2 - 4; % checksum - bytes alread read fseek(fid,burstsize,0); trashdata = 1; else trashdata = 0; end schemeburstidx(scheme_no) = schemeburstidx(scheme_no) + 1; if( (scheme_no == whichscheme) && ~trashdata ), if burstidx<50 && ~rem(burstidx,10), disp(sprintf('%d Burst #%d of %d read, %f min elapsed',ADVBurstHeader.BurstNumber,burstidx, nBursts, toc/60)), end if burstidx>50 && ~rem(burstidx,100), disp(sprintf('%d Burst #%d of %d read, %f min elapsed',ADVBurstHeader.BurstNumber,burstidx, nBursts, toc/60)), end % the index written to the file may not be the same as the index % read if writeburstfile && (burstidx >= bursts(1)) && (burstidx <= bursts(2)), cdfbwrite = 1; % we are in the region to write, turn write flag on if cdfbwriteidx == 0, cdfbwriteidx = 1; % the first burst index is a special case disp(sprintf('First burst #%d written to burst file',burstidx)) else cdfbwriteidx = cdfbwriteidx + 1; end else cdfbwrite = 0; end if writestatsfile && (burstidx >= stats(1)) && (burstidx <= stats(2)), cdfswrite = 1; % we are in the region to write, turn write flag on if cdfswriteidx == 0, cdfswriteidx = 1; % the first stats index is a special case disp(sprintf('First burst #%d written to statistics file',burstidx)) else cdfswriteidx = cdfswriteidx + 1; end else cdfswrite = 0; end % VELOCITY velx = fread(fid,nSamples,'int16',ADVDeploymentSetup.BytesPerSample(1)-2)*0.01; %cm/s if length(velx) ~= nSamples, disp(sprintf('%d velx samples read',length(velx))); break; end fseek(fid,-ADVDeploymentSetup.BytesPerSample(whichscheme)*nSamples+2,0); %rewind to get vel2 vely = fread(fid,nSamples,'int16',ADVDeploymentSetup.BytesPerSample(1)-2)*0.01; %cm/s if length(vely) ~= nSamples, disp(sprintf('%d vely samples read',length(vely))); break; end fseek(fid,-ADVDeploymentSetup.BytesPerSample(whichscheme)*nSamples+2,0); %rewind to get vel3 velz = fread(fid,nSamples,'int16',ADVDeploymentSetup.BytesPerSample(1)-2)*0.01; %cm/s if length(velz) ~= nSamples, disp(sprintf('%d velz samples read',length(velz))); break; end fseek(fid,-ADVDeploymentSetup.BytesPerSample(whichscheme)*nSamples+2,0); %rewind to get amp and corr if cdfbwrite, cdfb{'Velx'}(cdfbwriteidx,:) = velx; cdfb{'Vely'}(cdfbwriteidx,:) = vely; cdfb{'Velz'}(cdfbwriteidx,:) = velz; end %disp(sprintf('Now Reading Burst Number %%d...',ADVBurstHeader.BurstNumber)) tjstart = ADVBurstHeader.time1(1)+ADVBurstHeader.time2(1)./(3600*24*1000); tjend = ADVBurstHeader.time1(end)+ADVBurstHeader.time2(end)./(3600*24*1000); tjmid = tjstart+(tjend-tjstart)/2; if cdfswrite, % statistics only, we need time as the middle of the burst cdfs{'burst'}(cdfswriteidx) = ADVBurstHeader.BurstNumber; cdfs{'time'}(cdfswriteidx) = floor(tjmid); cdfs{'time2'}(cdfswriteidx) = (tjmid - floor(tjmid)).*(3600*24*1000); % quality file information is based on details of each burst, thus % is only written when burst files are written cdfq{'burst'}(cdfswriteidx) = ADVBurstHeader.BurstNumber; cdfq{'time'}(cdfswriteidx) = floor(tjmid); cdfq{'time2'}(cdfswriteidx) = (tjmid - floor(tjmid)).*(3600*24*1000); end if cdfbwrite, cdfb{'burst'}(cdfbwriteidx) = ADVBurstHeader.BurstNumber; cdfb{'time'}(cdfbwriteidx,:) = ADVBurstHeader.time1; cdfb{'time2'}(cdfbwriteidx,:) = ADVBurstHeader.time2; end if cdfswrite, cdfs{'MeanSoundspd'}(cdfswriteidx) = ADVBurstHeader.SoundSpeed; cdfs{'brange'}(cdfswriteidx) = ADVBurstHeader.BoundaryRange; cdfs{'vrange'}(cdfswriteidx) = ADVBurstHeader.VolumeBoundaryRange; end % AMPLITUDE AND CORRELATION if ADVDeploymentSetup.RecordedDataFlags{whichscheme}(1), % if amp & corr are included in the data for kk=1:6, ampcorr(:,kk) = fread(fid,nSamples,'uchar',ADVDeploymentSetup.BytesPerSample(whichscheme)-1); fseek(fid,-ADVDeploymentSetup.BytesPerSample(whichscheme)*nSamples+1,0); %rewind to get Heading end if cdfbwrite, % only write if this is a burst file cdfb{'amp'}(cdfbwriteidx,:,:) = ampcorr(:,1:3); %amplitude for beams 1-3, counts cdfb{'cor'}(cdfbwriteidx,:,:)= ampcorr(:,4:6); %Correlation for beams 1-3, counts end else % I don't think this bit will work for kk=1:2, ampcorr(:,kk) = fread(fid,nSamples,'uchar',ADVDeploymentSetup.BytesPerSample(whichscheme)-1); fseek(fid,-ADVDeploymentSetup.BytesPerSample(whichscheme)*nSamples+1,0); %rewind to get Heading end % these are the wrong shape if amp & corr are not recorded for % every sample if cdfbwrite, cdfb{'amp'}(cdfbwriteidx,:,:) = ampcorr(:,1); %Mean Amp cdfb{'cor'}(cdfbwriteidx,:,:) = ampcorr(:,2); %Mean Corr end % what about Std. Dev. amp and Std. Dev. corr end % HEADING, PITCH, ROLL if ADVDeploymentSetup.RecordedDataFlags{whichscheme}(2), heading = fread(fid,nSamples,'int16',ADVDeploymentSetup.BytesPerSample(whichscheme)-2)*0.1; %heading degrees fseek(fid,-nSamples*ADVDeploymentSetup.BytesPerSample(whichscheme)+2,0); %rewind to get Pitch pitch = fread(fid,nSamples,'int16',ADVDeploymentSetup.BytesPerSample(whichscheme)-2)*0.1; %pitch degrees fseek(fid,-nSamples*ADVDeploymentSetup.BytesPerSample(whichscheme)+2,0); %rewind to get Roll roll = fread(fid,nSamples,'int16',ADVDeploymentSetup.BytesPerSample(whichscheme)-2)*0.1; %roll degrees fseek(fid,-nSamples*ADVDeploymentSetup.BytesPerSample(whichscheme)+2,0); %rewind to get Temperature if cdfbwrite, % only write if this is a burst file cdfb{'heading'}(cdfbwriteidx,:) = heading; cdfb{'pitch'}(cdfbwriteidx,:) = pitch; cdfb{'roll'}(cdfbwriteidx,:) = roll; end end % TEMPERATURE AND PRESSURE if ADVDeploymentSetup.RecordedDataFlags{whichscheme}(3), temperature = fread(fid,nSamples,'int16',ADVDeploymentSetup.BytesPerSample(whichscheme)-2)*0.01; %temperature degrees C fseek(fid,-nSamples*ADVDeploymentSetup.BytesPerSample(whichscheme)+2,0); %rewind to get Pressure pressure = fread(fid,nSamples,'int16',ADVDeploymentSetup.BytesPerSample(whichscheme)-2); %pressure in counts fseek(fid,-nSamples*ADVDeploymentSetup.BytesPerSample(whichscheme)+2,0); %rewind to get External Sensor Channel 1 if cdfbwrite, % only write if this is a burst file cdfb{'temperature'}(cdfbwriteidx,:) = temperature; if strcmp(ADVSystemConfig.PressInstalled , 'Yes'), cdfb{'pressure'}(cdfbwriteidx,:) = pressure; end end stdp = gstd(pressure); end % EXTERNAL SENSORS if ADVDeploymentSetup.RecordedDataFlags{whichscheme}(6), % The variable ExtAdCh which holds the data in advdata.c is % delcared as an unsigned int extsensor1 = fread(fid,nSamples,'uint16',ADVDeploymentSetup.BytesPerSample(whichscheme)-2); %external sensor channel 1 in counts fseek(fid,-nSamples*ADVDeploymentSetup.BytesPerSample(whichscheme)+2,0); %rewind to get External Sensor Channel 2 extsensor2 = fread(fid,nSamples,'uint16',ADVDeploymentSetup.BytesPerSample(whichscheme)-2); %external sensor channel 2 in counts fseek(fid,-nSamples*ADVDeploymentSetup.BytesPerSample(whichscheme)+2,0); %rewind to get External Pressure % convert to volts for sanity extsensor1 = extsensor1.*ATOD; extsensor2 = extsensor2.*ATOD; if cdfbwrite, % only write if this is a burst file if ~isempty(metadata.ext1.serial), cdfb{'extsensor1'}(cdfbwriteidx,:) = extsensor1; end if ~isempty(metadata.ext2.serial), cdfb{'extsensor2'}(cdfbwriteidx,:) = extsensor2; end end if cdfswrite, if ~isempty(metadata.ext1.serial), cdfs{'MeanExtsensor1'}(cdfswriteidx) = mean(extsensor1); cdfs{'StdExtsensor1'}(cdfswriteidx) = std(extsensor1); end if ~isempty(metadata.ext2.serial), cdfs{'MeanExtsensor2'}(cdfswriteidx) = mean(extsensor2); cdfs{'StdExtsensor2'}(cdfswriteidx) = std(extsensor2); end end end % EXTERNAL PRESSURE if ADVDeploymentSetup.RecordedDataFlags{whichscheme}(7), pcount = fread(fid,nSamples,'ubit24',(ADVDeploymentSetup.BytesPerSample(whichscheme)-3)*8); % millidbars (paros)/milliHz (Druck/ParosFreq) % don't bother if the user didn't give a druck file if ~isempty(metadata.extpress.serial), % serial = serial number of sensor % if the user put in the wrong pressure offset, fix it if diagnostics.fixpfreq, [pcount, nfixed] = fixparosoverflow(pcount,ADVSystemConfig.PressFreqOffset); if nfixed > 0, disp(sprintf('fixed %d pressure samples for bit overflow',nfixed)); end end if cdfbwrite, % burst, save them all cdfb{'extpress'}(cdfbwriteidx,:) = pcount; end if cdfswrite, % TODO - what to do for RS232 Paros/Druck that has dropouts? That wrecks the statistics cdfs{'MeanExtpress'}(cdfswriteidx) = mean(pcount); cdfs{'StdExtpress'}(cdfswriteidx) = std(pcount); end if diagnostics.fixpfreq && cdfswrite, cdfq{'fixparosoverflow'}(cdfswriteidx) = nfixed; end % we want to compute the frequency if it's a frequency sensor if strcmp(ADVSystemConfig.ExtPressInstalled, 'ParosFreq') || strcmp(ADVSystemConfig.ExtPressInstalled, 'Druck'), PressFreq = (ADVSystemConfig.PressFreqOffset.*1000000 + pcount).*0.001; % shift left 16 bits if cdfbwrite, % burst, save them all cdfb{'extpressfreq'}(cdfbwriteidx,:) = PressFreq; % millidbars (paros)/milliHz (Druck/ParosFreq) end if cdfswrite, cdfs{'MeanExtpressfreq'}(cdfswriteidx) = mean(PressFreq); % millidbars (paros)/milliHz (Druck/ParosFreq) cdfs{'StdExtpressfreq'}(cdfswriteidx) = std(PressFreq); % millidbars (paros)/milliHz (Druck/ParosFreq) end stdp = std(PressFreq); end else stdp = std(pcount); end fseek(fid,-nSamples*ADVDeploymentSetup.BytesPerSample(whichscheme)+3,0); %rewind to get Statistics end % Skip to end of burst to check for statistics fseek(fid,ADVDeploymentSetup.BytesPerSample(whichscheme)*(nSamples-1),0); % STATISTICS (Means and Standard Deviations) computed by the ADV if ADVDeploymentSetup.RecordedDataFlags{whichscheme}(5), means = [fread(fid,[1,6],'uchar'),... fread(fid,[1,3],'int16'),... fread(fid,1,'int16'),... fread(fid,[1,1],'int32')]; stds = [fread(fid,[1,6],'uchar'),... fread(fid,[1,3],'int16'),... fread(fid,1,'int16'),... fread(fid,[1,1],'int16')]; SoundSpeedStat = fread(fid,1,'uint16')*0.1; % meters per second if cdfswrite, % want stats cdfs{'MeanAmp'}(cdfswriteidx,:) = means(1:3); %mean amplitude for beams 1-3, counts cdfs{'MeanCor'}(cdfswriteidx,:)= means(4:6); %mean correlation for beams 1-3, counts if ADVDeploymentSetup.RecordedDataFlags{whichscheme}(2), % only if compass is present... cdfs{'MeanHeading'}(cdfswriteidx) = means(7)*0.1; %degrees cdfs{'MeanPitch'}(cdfswriteidx) = means(8)*0.1; %degrees cdfs{'MeanRoll'}(cdfswriteidx) = means(9)*0.1; %degrees end cdfs{'MeanTemperature'}(cdfswriteidx) = means(10)*0.01; %degrees cdfs{'MeanPressure'}(cdfswriteidx) = means(11); %counts cdfs{'StdAmp'}(cdfswriteidx,:) = stds(1:3); %std deviation amplitude for beams 1-3, counts cdfs{'StdCorr'}(cdfswriteidx,:)= stds(4:6); %std deviation correlation for beams 1-3, counts if ADVDeploymentSetup.RecordedDataFlags{whichscheme}(2), % only if compass is present... cdfs{'StdHeading'}(cdfswriteidx) = stds(7)*0.1; %degrees cdfs{'StdPitch'}(cdfswriteidx) = stds(8)*0.1; %degrees cdfs{'StdRoll'}(cdfswriteidx) = stds(9)*0.1; %degrees end cdfs{'StdTemperature'}(cdfswriteidx) = stds(10)*0.01; %degrees cdfs{'StdPressure'}(cdfswriteidx) = stds(11); %counts cdfs{'StdSoundspd'}(cdfswriteidx) = SoundSpeedStat; end else % if no stats, but there is a compass, do std from burst data if ADVDeploymentSetup.RecordedDataFlags{whichscheme}(2), % only if compass is present... cdfs{'StdHeading'}(cdfswriteidx) = std(heading); %degrees cdfs{'StdPitch'}(cdfswriteidx) = std(pitch); %degrees cdfs{'StdRoll'}(cdfswriteidx) = std(roll); %degrees end end if ADVDeploymentSetup.RecordedDataFlags{whichscheme}(2), % only if compass is present... cdfs{'MedianHeading'}(cdfswriteidx) = median(heading); %degrees cdfs{'MedianPitch'}(cdfswriteidx) = median(pitch); %degrees cdfs{'MedianRoll'}(cdfswriteidx) = median(roll); %degrees end if cdfswrite, mnvelx = mean(velx); stdvelx = std(velx); mnvely = mean(vely); stdvely = std(vely); mnvelz = mean(velz); stdvelz = std(velz); cdfs{'MeanVelx'}(cdfswriteidx) = mnvelx; cdfs{'MeanVely'}(cdfswriteidx) = mnvely; cdfs{'MeanVelz'}(cdfswriteidx) = mnvelz; cdfs{'StdVelx'}(cdfswriteidx) = stdvelx; cdfs{'StdVely'}(cdfswriteidx) = stdvely; cdfs{'StdVelz'}(cdfswriteidx) = stdvelz; cdfs{'MeanSoundspd'}(cdfswriteidx) = ADVBurstHeader.SoundSpeed; % quality file stuff for flagbadadv cdfq{'flagbadadv_stdv'}(cdfswriteidx,1,:) = gstd(reshape(velx(indSubb(1,1):indSubb(end,2)),nSubsamp,nSubbursts)); cdfq{'flagbadadv_stdv'}(cdfswriteidx,2,:) = gstd(reshape(vely(indSubb(1,1):indSubb(end,2)),nSubsamp,nSubbursts)); cdfq{'flagbadadv_stdv'}(cdfswriteidx,3,:) = gstd(reshape(velz(indSubb(1,1):indSubb(end,2)),nSubsamp,nSubbursts)); cdfq{'flagbadadv_mcor'}(cdfswriteidx,1,:) = gmean(reshape(ampcorr(indSubb(1,1):indSubb(end,2),4),nSubsamp,nSubbursts)); cdfq{'flagbadadv_mcor'}(cdfswriteidx,2,:) = gmean(reshape(ampcorr(indSubb(1,1):indSubb(end,2),5),nSubsamp,nSubbursts)); cdfq{'flagbadadv_mcor'}(cdfswriteidx,3,:) = gmean(reshape(ampcorr(indSubb(1,1):indSubb(end,2),6),nSubsamp,nSubbursts)); cdfq{'flagbadadv_stdp'}(cdfswriteidx) = stdp; end % CTD or LISST if ADVDeploymentSetup.RecordedDataFlags{whichscheme}(8), CTD = fread(fid,[1,4],'int32'); if ~isempty(metadata.CTD.serial) && cdfswrite, % as these occur once per burst, save them in the stats file cdfs{'CTD_temp'}(cdfswriteidx) = CTD(1)*0.0001; %degrees C cdfs{'CTD_cond'}(cdfswriteidx) = CTD(2)*0.00001; %siemens cdfs{'CTD_press'}(cdfswriteidx) = CTD(3)*0.001; %dbar cdfs{'CTD_sal'}(cdfswriteidx) = CTD(4)*0.0001; %PSU end end % CHECKSUM - End of Sample fseek(fid,2,0); %checksum if writeburstfile && (burstidx >= bursts(2)), finishedbursts = 1; disp(sprintf('Last burst #%d written to burst file',burstidx)) end if writestatsfile && (burstidx >= stats(2)), finishedstats = 1; disp(sprintf('Last burst #%d written to average file',burstidx)) end if finishedbursts && finishedstats, break, end else % skip this burst, we're not recording it % flags are [Amp/Corr Compass Sensor None Stat ExtSensor ExtPress % CTD|LISST ] burstsize = ADVDeploymentSetup.SamplesPerBurst(scheme_no)*ADVDeploymentSetup.BytesPerSample(scheme_no) + ... ADVDeploymentSetup.RecordedDataFlags{scheme_no}(5)*BYTEMAP(5) + ... % Stats at end of burst ADVDeploymentSetup.RecordedDataFlags{scheme_no}(8)*BYTEMAP(8) + ... % CTD at end of burst 2; % checksum fseek(fid,burstsize,0); end %end if ADVBurstHeader.BurstNumber >= minBurst & ADVBurstHeader.BurstNumber <= maxBurst loop if(whichscheme==scheme_no), burstidx = burstidx + 1; %fprintf(1,'burstidx %d\n',burstidx); else %fprintf(1,'skipping burst index\n'); end end %end while ~feof(fid) loop fclose(fid); disp('Wrapping up, this may take some time...') if writestatsfile, chk_ctdsal(cdfs); % checks whether salinity was computed and does it, if not cdfs=add_minmaxvalues(cdfs); % min max only for stats for now % add_thresholds(qfile pointer, max #Std.Devs, min %corr) disp('adding quality thresholds') add_qthresholds(cdfq, 5, 70); % figure out starting quality thresholds end if writestatsfile, history = ['Converted to netCDF by ',mfilename,' ',prog_ver]; cdfs.history = ncchar(history); cdfs.DELTA_T = ncchar(sprintf('%d',cdfs.ADVDeploymentSetupBurstInterval(:))); close(cdfs); history = ['Written via MATLAB by ',mfilename,' ',prog_ver]; cdfq.history = ncchar(history); close (cdfq); end if writeburstfile, history = ['Converted to netCDF by ',mfilename,' ',prog_ver]; cdfb.history = ncchar(history); cdfb.DELTA_T = ncchar(sprintf('%d',cdfb.ADVDeploymentSetupBurstInterval(:))); % don't include add_minmaxvalues here because it is already in the % stats file close (cdfb); end disp(sprintf('Finished conversion in %f minutes', toc/60)) disp(sprintf('Detected %d %d %d bursts of schemes 1-3 respectively',schemeburstidx)); disp(sprintf('Wrote %d bursts of scheme %d',burstidx, whichscheme)) clear BYTEMAP return % ****************************** subfunctions ************************ function define_variables (nc, DataType, RecordedDataFlags, metadata, diagnostics, whichscheme) %% Define Variables and attributes nc{'burst'} = ncfloat('burst'); nc{'burst'}.units = ncchar('counts'); nc{'burst'}.long_name = ncchar('Burst Number'); nc{'burst'}.samplerate = nc.ADVDeploymentSetupSampleRate(:); nc{'burst'}.sampleperburst = nc.ADVDeploymentSetupSamplesPerBurst(:); switch DataType case 1 % stats only file nc{'time'} = ncdouble('burst'); ncobj = nc{'time'}; ncobj.units = ncchar('Julian Day'); ncobj.FORTRAN_format = ncchar('F10.2'); ncobj.long_name = ncchar('EPIC SYSTEM TIME'); ncobj.epic_code = nclong(624); ncobj.type = ncchar('EVEN'); ncobj.valid_min = nclong(0); ncobj.comment = ncchar('UT Julian days that begin at midnight; 1968-05-23 = 2440000'); ncobj.comment1 = ncchar('time, taken from the instrument, fixed at beginning of burst'); nc{'time2'} = ncdouble('burst'); ncobj = nc{'time2'}; ncobj.FORTRAN_format = ncchar('F10.2'); ncobj.units = ncchar('msec'); ncobj.type = ncchar('EVEN'); ncobj.long_name = ncchar('msec since 0:00 GMT'); ncobj.epic_code = nclong(624); ncobj.valid_min = nclong(0); if RecordedDataFlags{whichscheme}(1), nc{'MeanAmp'} = ncfloat('burst','axis'); ncobj = nc{'MeanAmp'}; ncobj.long_name = ncchar('Mean Amplitude for Burst'); ncobj.units = ncchar('counts'); ncobj.valid_range = ncfloat([-32768 32767]); nc{'MeanCor'} = ncfloat('burst','axis'); ncobj = nc{'MeanCor'}; ncobj.long_name = ncchar('Mean Correlation for Burst'); ncobj.units = ncchar('counts'); ncobj.valid_range = ncfloat([-32768 32768]); end % flags are [Amp/Corr Compass Sensor None Stat ExtSensor ExtPress CTD|LISST ] if RecordedDataFlags{whichscheme}(2), % only if compass is present if RecordedDataFlags{whichscheme}(5), % stats give in-situ calculated mean nc{'MeanPitch'} = ncfloat('burst'); ncobj = nc{'MeanPitch'}; ncobj.long_name = ncchar('Mean Pitch for Burst, magnetic'); ncobj.units = ncchar('degrees, magnetic'); ncobj.sensor_type = ncchar('Sontek ADV'); ncobj.valid_range = ncfloat([0 359.9999]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); ncobj.NOTE = ncchar('calculated by ADV in-situ'); nc{'MeanPitch'} = ncfloat('burst'); ncobj = nc{'MeanPitch'}; ncobj.long_name = ncchar('Mean Pitch for Burst, magnetic'); ncobj.units = ncchar('degrees'); ncobj.epic_code = nclong(1216); ncobj.sensor_type = ncchar('Sontek ADV'); ncobj.valid_range = ncfloat([-20 20]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); ncobj.NOTE = ncchar('calculated by ADV in-situ'); nc{'MeanRoll'} = ncfloat('burst'); ncobj = nc{'MeanRoll'}; ncobj.long_name = ncchar('Mean Roll for Burst, magnetic'); ncobj.units = ncchar('degrees'); ncobj.sensor_type = ncchar('Sontek ADV'); ncobj.valid_range = ncfloat([-20 20]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); ncobj.NOTE = ncchar('calculated by ADV in-situ'); end % calculate the median also, as subsequent software will look for it nc{'MedianHeading'} = ncfloat('burst'); ncobj = nc{'MedianHeading'}; ncobj.long_name = ncchar('Median Heading for Burst, magnetic'); ncobj.units = ncchar('degrees, magnetic'); ncobj.sensor_type = ncchar('Sontek ADV'); ncobj.valid_range = ncfloat([0 359.9999]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); nc{'MedianPitch'} = ncfloat('burst'); ncobj = nc{'MedianPitch'}; ncobj.long_name = ncchar('Median Pitch for Burst, magnetic'); ncobj.units = ncchar('degrees'); ncobj.epic_code = nclong(1216); ncobj.sensor_type = ncchar('Sontek ADV'); ncobj.valid_range = ncfloat([-20 20]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); nc{'MedianRoll'} = ncfloat('burst'); ncobj = nc{'MedianRoll'}; ncobj.long_name = ncchar('Median Roll for Burst, magnetic'); nc{'MeanRoll'} = ncfloat('burst'); ncobj = nc{'MeanRoll'}; ncobj.long_name = ncchar('Mean Roll for Burst'); ncobj.units = ncchar('degrees'); ncobj.sensor_type = ncchar('Sontek ADV'); ncobj.valid_range = ncfloat([-20 20]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); end if RecordedDataFlags{whichscheme}(5), nc{'MeanTemperature'} = ncfloat('burst'); ncobj = nc{'MeanTemperature'}; ncobj.units = ncchar('degrees'); ncobj.long_name = ncchar('Mean Transducer Temperature for Burst'); ncobj.valid_range = ncfloat([-5 40]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); if strcmp(nc.PressInstalled(:), 'Yes'), % internal sensor nc{'MeanPressure'} = ncfloat('burst'); ncobj = nc{'MeanPressure'}; ncobj.long_name = ncchar('Mean Pressure for Burst'); ncobj.units = ncchar('counts'); ncobj.valid_range = ncfloat([0 4095]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); end end % MeanVel names = {'x','y','z'}; for i = 1:length(names), eval(sprintf('nc{''MeanVel%s''} = ncfloat(''burst'');',names{i})) eval(sprintf('ncobj = nc{''MeanVel%s''};',names{i})) eval(sprintf('ncobj.long_name = ncchar(''Mean velocity %s component of instrument coordinates for Burst'');',names{i})) ncobj.units = ncchar('cm s-1'); ncobj.valid_range = ncfloat([-32768 32767]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); end % StdVel names = {'x','y','z'}; for i = 1:length(names), eval(sprintf('nc{''StdVel%s''} = ncfloat(''burst'');',names{i})) eval(sprintf('ncobj = nc{''StdVel%s''};',names{i})) eval(sprintf('ncobj.long_name = ncchar(''Std. Dev. of velocity of %s component of instrument coordinates for Burst'');',names{i})) ncobj.units = ncchar('cm s-1'); ncobj.valid_range = ncfloat([-32768 32767]); end if RecordedDataFlags{whichscheme}(2), % only if compass is present nc{'StdHeading'} = ncfloat('burst'); ncobj = nc{'StdHeading'}; ncobj.long_name = ncchar('Heading Standard Deviation for Burst'); ncobj.units = ncchar('degrees'); ncobj.valid_range = ncfloat([0 359.9999]); if RecordedDataFlags{whichscheme}(5), ncobj.NOTE = ncchar('calculated by ADV in-situ'); end nc{'StdPitch'} = ncfloat('burst'); ncobj = nc{'StdPitch'}; ncobj.long_name = ncchar('Pitch Standard Deviation for Burst'); ncobj.units = ncchar('degrees'); ncobj.valid_range = ncfloat([-20 20]); if RecordedDataFlags{whichscheme}(5), ncobj.NOTE = ncchar('calculated by ADV in-situ'); end nc{'StdRoll'} = ncfloat('burst'); ncobj = nc{'StdRoll'}; ncobj.long_name = ncchar('Roll Standard Deviation for Burst'); ncobj.units = ncchar('degrees'); ncobj.valid_range = ncfloat([-20 20]); if RecordedDataFlags{whichscheme}(5), ncobj.NOTE = ncchar('calculated by ADV in-situ'); end end if RecordedDataFlags{whichscheme}(5), nc{'StdAmp'} = ncfloat('burst','axis'); ncobj = nc{'StdAmp'}; ncobj.long_name = ncchar('Amplitude Standard Deviation for Burst'); ncobj.units = ncchar('counts'); ncobj.valid_range = ncfloat([-32768 32767]); nc{'StdCorr'} = ncfloat('burst','axis'); ncobj = nc{'StdCorr'}; ncobj.long_name = ncchar('Correlation Standard Deviation for Burst'); ncobj.units = ncchar('counts'); ncobj.valid_range = ncfloat([-32768 32768]); nc{'StdTemperature'} = ncfloat('burst'); ncobj = nc{'StdTemperature'}; ncobj.units = ncchar('degrees Celcius'); ncobj.long_name = ncchar('Transducer Temperature Standard Deviation for Burst'); ncobj.valid_range = ncfloat([-5 40]); if strcmp(nc.PressInstalled(:), 'Yes'), nc{'StdPressure'} = ncfloat('burst'); ncobj = nc{'StdPressure'}; ncobj.long_name = ncchar('Pressure Standard Deviation for Burst'); ncobj.units = ncchar('counts'); ncobj.valid_range = ncfloat([0 4095]); end nc{'StdSoundspd'} = ncfloat('burst'); ncobj = nc{'StdSoundspd'}; ncobj.long_name = ncchar('Standard deviation of sound velocity for burst'); ncobj.units = ncchar('m s-1'); ncobj.epic_code = nclong(80); ncobj.valid_range = nclong([0 10000]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); end nc{'MeanSoundspd'} = ncfloat('burst'); ncobj = nc{'MeanSoundspd'}; ncobj.long_name = ncchar('Mean sound velocity for burst'); ncobj.units = ncchar('m s-1'); ncobj.epic_code = nclong(80); ncobj.valid_range = nclong([1400 1600]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); nc{'brange'} = ncfloat('burst'); ncobj = nc{'brange'}; ncobj.long_name = ncchar('Boundary Range, mm'); ncobj.units = ncchar('mm'); ncobj.valid_range = nclong([0 1000000]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); nc{'vrange'} = ncfloat('burst'); ncobj = nc{'vrange'}; ncobj.long_name = ncchar('Volume Boundary Range, mm'); ncobj.units = ncchar('mm'); ncobj.valid_range = nclong([0 1000000]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); if ~strcmp(nc.ExtPressInstalled(:), 'No') && ... RecordedDataFlags{whichscheme}(7) && ~isempty(metadata.extpress.serial), if diagnostics.pcountout, nc{'MeanExtpress'} = ncfloat('burst'); ncobj = nc{'MeanExtpress'}; ncobj.long_name = ncchar('raw data from external pressure sensor for burst'); ncobj.units = ncchar('counts'); ncobj.valid_range = ncfloat([0 10000]); ncobj.height = ncfloat(metadata.extpress.height); ncobj.serial = ncchar(metadata.extpress.serial); if ~isempty(metadata.extpress.druck), addcalatts_fromstruct(ncobj,metadata.extpress.druck); elseif ~isempty(metadata.extpress.paros), addcalatts_fromstruct(ncobj,metadata.extpress.paros); end nc{'StdExtpress'} = ncfloat('burst'); ncobj = nc{'StdExtpress'}; ncobj.long_name = ncchar('Std. Dev. raw data from external pressure sensor for burst'); ncobj.units = ncchar('counts'); ncobj.valid_range = ncfloat([0 10000]); end if strcmp(nc.ExtPressInstalled(:), 'ParosFreq') || strcmp(nc.ExtPressInstalled(:), 'Druck'), % for Frequency Paros or Druck nc{'MeanExtpressfreq'} = ncfloat('burst'); ncobj = nc{'MeanExtpressfreq'}; ncobj.long_name = ncchar('external pressure frequency for burst'); ncobj.units = ncchar('Hz'); ncobj.epic_code = nclong(1); ncobj.valid_range = ncfloat([10000 40000]); ncobj.height = ncfloat(metadata.extpress.height); ncobj.serial = ncchar(metadata.extpress.serial); if ~isempty(metadata.extpress.druck), addcalatts_fromstruct(ncobj,metadata.extpress.druck); elseif ~isempty(metadata.extpress.paros), addcalatts_fromstruct(ncobj,metadata.extpress.paros); end nc{'StdExtpressfreq'} = ncfloat('burst'); ncobj = nc{'StdExtpressfreq'}; ncobj.long_name = ncchar('Std. Dev. external pressure frequency for burst'); ncobj.units = ncchar('Hz'); ncobj.epic_code = nclong(1); ncobj.valid_range = ncfloat([0 40000]); end if strcmp(nc.ExtPressInstalled(:), 'Paros'), % for Serial Paros nc{'MeanExtpress'} = ncfloat('burst'); ncobj = nc{'MeanExtpress'}; ncobj.long_name = ncchar('external pressure for burst'); ncobj.units = ncchar('milli db'); ncobj.epic_code = nclong(1); ncobj.valid_range = ncfloat([10000 40000]); ncobj.height = ncfloat(metadata.extpress.height); ncobj.serial = ncchar(metadata.extpress.serial); nc{'StdExtpress'} = ncfloat('burst'); ncobj = nc{'StdExtpress'}; ncobj.long_name = ncchar('Std. Dev. external pressure for burst'); ncobj.units = ncchar('milli db'); ncobj.epic_code = nclong(1); ncobj.valid_range = ncfloat([0 40000]); end end if RecordedDataFlags{whichscheme}(6), if ~isempty(metadata.ext1.serial), nc{'MeanExtsensor1'} = ncfloat('burst'); ncobj = nc{'MeanExtsensor1'}; ncobj.units = ncchar('volts'); % ncchar('counts'); ncobj.long_name = ncchar('raw data from external sensor channel 1 for burst'); ncobj.valid_range = ncfloat([0 5]); % ncfloat([0 2^16]) ncobj.height = ncfloat(metadata.ext1.height); ncobj.serial = ncchar(metadata.ext1.serial); if isfield(metadata.ext1,'cals'), addcalatts_fromstruct(ncobj,metadata.ext1.cals); end nc{'StdExtsensor1'} = ncfloat('burst'); ncobj = nc{'StdExtsensor1'}; ncobj.units = ncchar('volts'); % ncchar('counts'); ncobj.long_name = ncchar('raw data from external sensor channel 1 for burst'); ncobj.valid_range = ncfloat([0 5]); % ncfloat([0 2^16]); end if ~isempty(metadata.ext2.serial), nc{'MeanExtsensor2'} = ncfloat('burst'); ncobj = nc{'MeanExtsensor2'}; ncobj.units = ncchar('volts'); % ncchar('counts'); ncobj.long_name = ncchar('Std. Dev. raw data from external sensor channel 2 for burst'); ncobj.valid_range = ncfloat([0 5]); % ncfloat([0 2^16]); ncobj.height = ncfloat(metadata.ext2.height); ncobj.serial = ncchar(metadata.ext2.serial); if isfield(metadata.ext2,'cals'), addcalatts_fromstruct(ncobj,metadata.ext2.cals); end nc{'StdExtsensor2'} = ncfloat('burst'); ncobj = nc{'StdExtsensor2'}; ncobj.units = ncchar('volts'); % ncchar('counts'); ncobj.long_name = ncchar('Std. Dev. raw data from external sensor channel 2 for burst'); ncobj.valid_range = ncfloat([0 5]); % ncfloat([0 2^16]); end end if RecordedDataFlags{whichscheme}(8) && ~isempty(metadata.CTD.serial), nc{'CTD_temp'} = ncfloat('burst'); ncobj = nc{'CTD_temp'}; ncobj.long_name = ncchar('Temperature from CTD'); ncobj.units = ncchar('C'); ncobj.valid_range = ncfloat([-5 40]); ncobj.height = ncfloat(metadata.CTD.height); ncobj.serial = ncchar(metadata.CTD.serial); nc{'CTD_cond'} = ncfloat('burst'); ncobj = nc{'CTD_cond'}; ncobj.long_name = ncchar('Conductivity from CTD'); ncobj.units = ncchar('S/m'); ncobj.valid_range = ncfloat([0 7]); ncobj.height = ncfloat(metadata.CTD.height); ncobj.serial = ncchar(metadata.CTD.serial); nc{'CTD_press'} = ncfloat('burst'); ncobj = nc{'CTD_press'}; ncobj.long_name = ncchar('Pressure from CTD'); ncobj.units = ncchar('dbar'); %ncobj.valid_range = ncfloat([ ]); NEED... but no way to tell, %this will depend on what unit was installed ncobj.height = ncfloat(metadata.CTD.height); ncobj.serial = ncchar(metadata.CTD.serial); nc{'CTD_sal'} = ncfloat('burst'); ncobj = nc{'CTD_sal'}; ncobj.long_name = ncchar('Salinity from CTD'); ncobj.units = ncchar('PSU'); ncobj.valid_range = ncfloat([0 45]); ncobj.height = ncfloat(metadata.CTD.height); ncobj.serial = ncchar(metadata.CTD.serial); end case 2 % burst only file % 624:TIM:EPIC SYSTEM TIME :time: : :2 integers, jul day, % millisec since midnight nc{'time'} = ncdouble('burst','sample'); ncobj = nc{'time'}; ncobj.FORTRAN_format = ncchar('F10.2'); ncobj.units = ncchar('Julian Day'); ncobj.long_name = ncchar('EPIC SYSTEM TIME'); ncobj.epic_code = nclong(624); ncobj.type = ncchar('EVEN'); ncobj.valid_min = nclong(0); ncobj.comment = ncchar('UT Julian days that begin at midnight; 1968-05-23 = 2440000'); nc{'time2'} = ncdouble('burst','sample'); ncobj = nc{'time2'}; ncobj.FORTRAN_format = ncchar('F10.2'); ncobj.units = ncchar('msec'); ncobj.type = ncchar('EVEN'); ncobj.long_name = ncchar('msec since 0:00 GMT'); ncobj.epic_code = nclong(624); ncobj.valid_min = nclong(0); % Vel names = {'x','y','z'}; for i = 1:length(names), eval(sprintf('nc{''Vel%s''} = ncfloat(''burst'',''sample'');',names{i})) eval(sprintf('ncobj = nc{''Vel%s''};',names{i})) eval(sprintf('ncobj.long_name = ncchar(''velocity in the %s component of instrument coordinates'');',names{i})) ncobj.units = ncchar('cm s-1'); ncobj.valid_range = ncfloat([-32768 32767]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); end if RecordedDataFlags{whichscheme}(1), % if amp & corr were recorded for each sample nc{'amp'} = ncfloat('burst','sample','axis'); ncobj = nc{'amp'}; ncobj.units = ncchar('counts'); ncobj.long_name = ncchar('Beam amplitude'); ncobj.valid_range = ncfloat([-32768 32767]); nc{'cor'} = ncfloat('burst','sample','axis'); ncobj = nc{'cor'}; ncobj.units = ncchar('counts'); ncobj.long_name = ncchar('Beam correlation'); ncobj.valid_range = ncfloat([-32768 32767]); end if RecordedDataFlags{whichscheme}(2), nc{'heading'} = ncfloat('burst','sample'); ncobj = nc{'heading'}; ncobj.units = ncchar('degrees, magnetic'); ncobj.long_name = ncchar('INST Heading, magnetic'); ncobj.epic_code = nclong(1215); ncobj.valid_range = ncfloat([0 359.9999]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); nc{'pitch'} = ncfloat('burst','sample'); ncobj = nc{'pitch'}; ncobj.units = ncchar('degrees'); ncobj.long_name = ncchar('INST Pitch'); ncobj.epic_code = nclong(1216); ncobj.valid_range = ncfloat([-20 20]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); nc{'roll'} = ncfloat('burst','sample'); ncobj = nc{'roll'}; ncobj.units = ncchar('degrees'); ncobj.long_name = ncchar('INST roll'); ncobj.epic_code = nclong(1217); ncobj.valid_range = ncfloat([-20 20]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); end if RecordedDataFlags{whichscheme}(3), nc{'temperature'} = ncfloat('burst','sample'); ncobj = nc{'temperature'}; ncobj.units = ncchar('degrees Celcius'); ncobj.long_name = ncchar('ADV Transducer Temperature'); ncobj.epic_code = nclong(20); ncobj.valid_range = ncfloat([-5 40]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); if strcmp(nc.PressInstalled(:), 'Yes'), nc{'pressure'} = ncfloat('burst','sample'); ncobj = nc{'pressure'}; ncobj.long_name = ncchar('PRESSURE'); ncobj.units = ncchar('counts'); ncobj.epic_code = nclong(1); ncobj.valid_range = ncfloat([0 4095]); ncobj.height = ncfloat(metadata.adv.height); ncobj.serial = ncchar(metadata.adv.serial); end end if RecordedDataFlags{whichscheme}(1), if ~isempty(metadata.ext1.serial), nc{'extsensor1'} = ncfloat('burst','sample'); ncobj = nc{'extsensor1'}; ncobj.units = ncchar('volts'); % ncchar('counts'); ncobj.long_name = ncchar('raw data from external sensor channel 1'); ncobj.valid_range = ncfloat([0 5]); % ncfloat([0 2^16]); ncobj.height = ncfloat(metadata.ext1.height); ncobj.serial = ncchar(metadata.ext1.serial); if isfield(metadata.ext1,'cals'), addcalatts_fromstruct(ncobj,metadata.ext1.cals); end end if ~isempty(metadata.ext2.serial), nc{'extsensor2'} = ncfloat('burst','sample'); ncobj = nc{'extsensor2'}; ncobj.units = ncchar('volts'); % ncchar('counts'); ncobj.long_name = ncchar('raw data from external sensor channel 2'); ncobj.valid_range = ncfloat([0 5]); % ncfloat([0 2^16]); ncobj.height = ncfloat(metadata.ext2.height); ncobj.serial = ncchar(metadata.ext2.serial); if isfield(metadata.ext2,'cals'), addcalatts_fromstruct(ncobj,metadata.ext2.cals); end end end if ~strcmp(nc.ExtPressInstalled(:), 'No') && ... RecordedDataFlags{whichscheme}(7) && ~isempty(metadata.extpress.serial), if diagnostics.pcountout, nc{'extpress'} = ncfloat('burst','sample'); ncobj = nc{'extpress'}; ncobj.long_name = ncchar('raw data from external pressure sensor'); ncobj.units = ncchar('counts'); ncobj.valid_range = ncfloat([0 2^24]); ncobj.height = ncfloat(metadata.extpress.height); ncobj.serial = ncchar(metadata.extpress.serial); if ~isempty(metadata.extpress.druck), addcalatts_fromstruct(ncobj,metadata.extpress.druck); elseif ~isempty(metadata.extpress.paros), addcalatts_fromstruct(ncobj,metadata.extpress.paros); end end if strcmp(nc.ExtPressInstalled(:), 'ParosFreq') || strcmp(nc.ExtPressInstalled(:), 'Druck'), nc{'extpressfreq'} = ncfloat('burst','sample'); ncobj = nc{'extpressfreq'}; ncobj.long_name = ncchar('external pressure frequency'); ncobj.units = ncchar('Hz'); ncobj.epic_code = nclong(1); ncobj.valid_range = ncfloat([10000 40000]); ncobj.height = ncfloat(metadata.extpress.height); ncobj.serial = ncchar(metadata.extpress.serial); if ~isempty(metadata.extpress.druck), addcalatts_fromstruct(ncobj,metadata.extpress.druck); elseif ~isempty(metadata.extpress.paros), addcalatts_fromstruct(ncobj,metadata.extpress.paros); end end if strcmp(nc.ExtPressInstalled(:), 'Paros'), nc{'extpress'} = ncfloat('burst','sample'); ncobj = nc{'extpress'}; ncobj.long_name = ncchar('external pressure'); ncobj.units = ncchar('milli db'); ncobj.epic_code = nclong(1); ncobj.valid_range = ncfloat([10000 40000]); ncobj.height = ncfloat(metadata.extpress.height); ncobj.serial = ncchar(metadata.extpress.serial); end end end %end switch add_fillvalues(nc,1.0e+035); return % end of define_variables() function define_qfile (nc, cdfb, RecordedDataFlags, metadata, diagnostics, whichscheme) %% Define Variables and attributes nc{'burst'} = ncfloat('burst'); nc{'burst'}.units = ncchar('counts'); nc{'burst'}.long_name = ncchar('Burst Number'); nc{'time'} = ncdouble('burst'); ncobj = nc{'time'}; ncobj.units = ncchar('Julian Day'); ncobj.FORTRAN_format = ncchar('F10.2'); ncobj.long_name = ncchar('EPIC SYSTEM TIME'); ncobj.epic_code = nclong(624); ncobj.type = ncchar('EVEN'); ncobj.valid_min = nclong(0); ncobj.comment = ncchar('UT Julian days that begin at midnight; 1968-05-23 = 2440000'); ncobj.comment1 = ncchar('time, taken from the instrument, fixed at beginning of burst'); nc{'time2'} = ncdouble('burst'); ncobj = nc{'time2'}; ncobj.FORTRAN_format = ncchar('F10.2'); ncobj.units = ncchar('msec'); ncobj.type = ncchar('EVEN'); ncobj.long_name = ncchar('msec since 0:00 GMT'); ncobj.epic_code = nclong(624); ncobj.valid_min = nclong(0); % first item, if fixparosoverflow is used if ~strcmp(cdfb.ExtPressInstalled(:), 'No') && ... RecordedDataFlags{whichscheme}(7) && ... ~isempty(metadata.extpress.serial) && ... diagnostics.fixpfreq, nc{'fixparosoverflow_pfixed'} = ncfloat('burst'); ncobj = nc{'fixparosoverflow_pfixed'}; ncobj.long_name = ncchar('samples fixed by fixparosoverflow'); ncobj.units = ncchar('count'); end % standard items for flagbadadv nc{'flagbadadv_stdv'} = ncfloat('burst','axis','subburst'); ncobj = nc{'flagbadadv_stdv'}; ncobj.long_name = ncchar('Std. Dev. of velocity subbursts'); ncobj.units = ncchar('cm/s'); nc{'flagbadadv_scutoff'} = ncfloat('axis','subburst'); ncobj = nc{'flagbadadv_scutoff'}; ncobj.long_name = ncchar('Velocity standard deviation threshold'); ncobj.units = ncchar('cm/s'); data = ones(length(nc('axis')),length(nc('subburst'))).*5; ncobj(:,:) = data; nc{'flagbadadv_mcor'} = ncfloat('burst','axis','subburst'); ncobj = nc{'flagbadadv_mcor'}; ncobj.long_name = ncchar('Mean correlation of subbursts'); ncobj.units = ncchar('%'); nc{'flagbadadv_ccutoff'} = ncfloat('axis','subburst'); ncobj = nc{'flagbadadv_ccutoff'}; ncobj.long_name = ncchar('Correlation threshold'); data = ones(length(nc('axis')),length(nc('subburst'))).*70; ncobj(:,:) = data; ncobj.units = ncchar('%'); nc{'flagbadadv_stdp'} = ncfloat('burst'); ncobj = nc{'flagbadadv_stdp'}; ncobj.long_name = ncchar('Raw pressure Std. Dev.'); ncobj.units = ncchar('count or Hz'); nc{'flagbadadv_override_as_bad'} = ncfloat('burst','axis','subburst'); ncobj = nc{'flagbadadv_override_as_bad'}; ncobj.long_name = ncchar('Known bad flagged by user'); ncobj.units = ncchar('boolean, 1 = remove'); nc{'flagbadadv_override_as_good'} = ncfloat('burst','axis','subburst'); ncobj = nc{'flagbadadv_override_as_good'}; ncobj.long_name = ncchar('Known good flagged by user'); ncobj.units = ncchar('boolean, 1 = keep'); % this is the main data mask % 0 = OK, 1 = bad nc{'flagbadadv_mask'} = ncfloat('burst','axis','subburst'); ncobj = nc{'flagbadadv_mask'}; ncobj.long_name = ncchar('velocity data mask'); ncobj.units = ncchar('Boolean, 1 = bad'); return function add_qthresholds(cdfq, nstds, badcor) % add_thresholds(qfile pointer, max #Std.Devs, min %corr) % the Std. Dev. of the subbursts, is a measure of change in the noise % over the burst for each burst dims = size(cdfq{'flagbadadv_stdv'}); % [burst, axis, subburst] cdfq{'flagbadadv_ccutoff'}(:,:) = ones(dims(2),dims(3)).*badcor; for iBeam = 1:dims(2), %if isempty(cdfq{'flagbadadv_stdv'}(:,iBeam,:)), keyboard; end mstd = gmean(cdfq{'flagbadadv_stdv'}(:,iBeam,:)); sstd = gstd(cdfq{'flagbadadv_stdv'}(:,iBeam,:)); cdfq{'flagbadadv_scutoff'}(iBeam,:) = nstds.*sstd+mstd; end % prime the mask cdfq{'flagbadadv_mask'}(:,:,:) = zeros(dims); cdfq{'flagbadadv_override_as_bad'}(:,:,:) = zeros(dims); cdfq{'flagbadadv_override_as_good'}(:,:,:) = zeros(dims); % do some statistics for iBeam = 1:dims(2), for iSubburst = 1:dims(3), ivthsubbads = find(cdfq{'flagbadadv_stdv'}(:,iBeam,iSubburst) >= cdfq{'flagbadadv_scutoff'}(iBeam,iSubburst)); if ~isempty(ivthsubbads), cdfq{'flagbadadv_ivthsubbads'}(ivthsubbads,iBeam,iSubburst) = ones(size(ivthsubbads)); end icthsubbads = find(cdfq{'flagbadadv_mcor'}(:,iBeam,iSubburst) < cdfq{'flagbadadv_ccutoff'}(iBeam,iSubburst)); if ~isempty(icthsubbads), cdfq{'flagbadadv_icthsubbads'}(icthsubbads,iBeam,iSubburst) = ones(size(icthsubbads)); end % first shot at a mask is the union of subbursts failing the thresholds allbads = union(ivthsubbads, icthsubbads); if ~isempty(allbads), % this line spat out ## Indexing strides must be positive and constant. %cdfq{'flagbadadv_mask'}(allbads,iBeam,iSubburst) = ones(size(allbads)); % so mut lo0p instead... for ibad = 1:length(allbads), cdfq{'flagbadadv_mask'}(allbads(ibad),iBeam,iSubburst) = 1; end end end end return % Read Hardware Configuration (24 bytes) function ADVSystemConfig = ReadADVSystemConfig(fid, skip) global BYTEMAP if skip, % we don't need the details, just get to the next record fread(fid,24,'uchar'); ADVSystemConfig = []; return end ADVSystemConfig.cpuSoftWareVerNum = (fread(fid,1,'uchar')) * 0.1; ADVSystemConfig.dspSoftWareVerNum = (fread(fid,1,'uchar')) * 0.1; ADVSystemConfig.INST_TYPE = 'Sontek ADV'; a = fread(fid,6,'char'); ADVType = {'10MHz_5cm','10MHz_10cm','OCEAN'}; %Using Jingping's code, this seems to be reading incorrectly ADVSystemConfig.ADVType = ADVType{1+a(1)}; SensorOrientation = {'down','up','side'}; ADVSystemConfig.SensorOrientation = SensorOrientation{1+a(2)}; CompassInstalled = {'No','Yes'}; ADVSystemConfig.CompassInstalled = CompassInstalled{1+a(3)}; RecorderInstalled = {'No','Yes'}; ADVSystemConfig.RecorderInstalled = RecorderInstalled{1+a(4)}; TempInstalled = {'No','Yes'}; ADVSystemConfig.TempInstalled = TempInstalled{1+a(5)}; PressInstalled = {'No','Yes'}; ADVSystemConfig.PressInstalled = PressInstalled{1+a(6)}; ADVSystemConfig.PressScale = fread(fid,1,'int32'); ADVSystemConfig.PressOffset = fread(fid,1,'int32'); ADVSystemConfig.CompassOffset = fread(fid,1,'int16'); ADVSystemConfig.PressFreqOffset = fread(fid,1,'char'); a = fread(fid,2,'char'); %ExtSensorInstalled = {'None','Standard','OBS_Ch1','OBS_Ch2','OBS_Ch3','1_OBS'}; ExtSensorInstalled = {'None','Standard','3_OBS','1_OBS'}; ADVSystemConfig.ExtSensorInstalled = ExtSensorInstalled{1+a(1)}; ExtPressInstalled = {'No','Paros','Druck','ParosFreq'}; ADVSystemConfig.ExtPressInstalled = ExtPressInstalled{a(2)+1}; ADVSystemConfig.PressScale_2 = fread(fid,1,'int16'); a = fread(fid,1,'char'); CTDInstalled = {'None','MicroCat CTD','LISST'}; ADVSystemConfig.CTDInstalled = CTDInstalled{a+1}; % the CTD size is infact, not documented properly in the Sontek manual, it % is listed as 4 bytes rather than 16 (or 4 x 32 bit integers) CTDbytes = [0 16 80]; BYTEMAP(8) = CTDbytes(a+1); return % Probe Configuration (164 bytes) function ADVProbeConfig = ReadADVProbeConfig(fid, skip) if skip, % we don't need the details, just get to the next record fread(fid,164,'uchar'); ADVProbeConfig = []; return end fseek(fid,10,0); % skip the file information for now a=fread(fid,[1,6],'char'); a(a==0)=[]; ADVProbeConfig.SerialNum = char(a); % This is from adr2mat.m written by Jingping Xu ProbeConfiguration = {'Down XYZ 5cm','Down XYZ 5cm','Up XYZ 5cm','Side XYZ 5cm',... 'Down XZ 5cm','Up XZ 5cm','Side XY 5cm','Cable XYZ 5cm',... 'Down XYZ 10cm','Up XYZ 10cm','Side XYZ 10cm',... 'Down XZ 10cm','Up XZ 10cm','Side XY 10cm','Cable XYZ 10cm',... 'Ocean Probe','Micro Down XYZ 5cm','Micro Up XYZ 5cm',... 'Micro Side XYZ 5cm','Micro Down XZ 5cm','Micro Up XZ 5cm',... 'Micro Sdie XY 5cm','Micro Cable XYZ 5cm'}; ProbeIndex = [0 1 2 3 4 5 6 10 17 18 19 20 21 22 26 41 81 82 83 84 85 86 90]; a=fread(fid,2,'char'); index=find(ProbeIndex==a(1)); ADVProbeConfig.ProbeConfiguration=ProbeConfiguration{index}; SamplingVolumeOffset = [5 5 5 5 5 5 5 5 10 10 10 10 10 10 10 18 5 5 5 5 5 5 5]; ADVProbeConfig.SamplingVolumeOffset=SamplingVolumeOffset(index); %fseek(fid,102,0); ADVProbeConfig.NBeams = fread(fid,1,'int16'); ADVProbeConfig.NomPeakPos = fread(fid,1,'int16'); ADVProbeConfig.Nsamp = fread(fid,1,'int16'); ADVProbeConfig.SampInterval = fread(fid,1,'int16'); ADVProbeConfig.PulseLag = fread(fid,[5,3],'int16'); ADVProbeConfig.Nxmt = fread(fid,[5,3],'int16'); ADVProbeConfig.LagDelay = fread(fid,[5,3],'int16'); ADVProbeConfig.BeamDelay = fread(fid,1,'int16'); ADVProbeConfig.PingDelay = fread(fid,1,'int16'); ADVProbeConfig.XformMat=fread(fid,[3,3],'float32'); ADVProbeConfig.XmtRecDist=fread(fid,1,'float32'); ADVProbeConfig.CalCW=fread(fid,1,'float32'); return % Deployment Parameters (253 bytes) function ADVDeploymentSetup = ReadADVDeploymentSetup(fid, skip) % see advdata.h and advdata.c definition global BYTEMAP ADVDeploymentSetup.ConfigType = fread(fid,1,'uchar'); ADVDeploymentSetup.ConfigVer = fread(fid,1,'uchar'); ADVDeploymentSetup.Nbytes = fread(fid,1,'uint16'); % let's check and make sure it's really an ADV file if (ADVDeploymentSetup.ConfigType(:) ~= 18) || ... (ADVDeploymentSetup.ConfigVer(:) ~= 1) || ... (ADVDeploymentSetup.Nbytes(:) ~= 253), disp('Not sure this is an ADV file, ADVDeploymentSetupType read failed') ADVDeploymentSetup = []; return end if skip, % we don't need the details, just get to the next record fread(fid,ADVDeploymentSetup.Nbytes-4,'uchar'); ADVDeploymentSetup = []; return end % Skip Configuration time fseek(fid,8,0); ADVDeploymentSetup.Temp = fread(fid,1,'int16') * 0.1; %degrees Celcius ADVDeploymentSetup.Sal = fread(fid,1,'int16') * 0.1; %ppt ADVDeploymentSetup.CW = fread(fid,1,'int16') * 0.1; %m/s a = fread(fid,1,'uchar'); TempMode = {'User Value','Measured'}; ADVDeploymentSetup.TempMode = TempMode{a+1}; ADVDeploymentSetup.VelRangeIndex = fread(fid,1,'uchar'); a = fread(fid,1,'char'); SyncMode = {'Disable','Start','Sample'}; ADVDeploymentSetup.SyncMode = SyncMode{a+1}; a = fread(fid,1,'char'); CoordSystem = {'Beam','XYZ','ENU'}; ADVDeploymentSetup.CoordSystem = CoordSystem{a+1}; metadata.SampleRate = fread(fid,[1,3],'uint16') *0.01; %Hz ADVDeploymentSetup.SampleRate = metadata.SampleRate; %Hz ADVDeploymentSetup.BurstInterval = fread(fid,[1,3],'uint16'); %seconds nSamples = fread(fid,[1,3],'uint16'); ADVDeploymentSetup.SamplesPerBurst = nSamples; for i = 1:3, fillchar = '00000000'; recdata = fliplr(dec2bin(fread(fid,1,'uchar'))); if length(recdata) < 8, % need to pad out the missing zeros recdata(length(recdata)+1:8) = fillchar(1:8-length(recdata)); end for j=1:length(recdata), ADVDeploymentSetup.RecordedDataFlags{i}(j) = str2double(recdata(j)); end % flags are [Amp/Corr Compass Temp/Press undefined Stat ExtSensor ExtPress CTD|LISST ] % bytes are [6 6 4 0 36 4 3 4 ] if ~ADVDeploymentSetup.RecordedDataFlags{i}(1), % If Amp/Corr are not recorded minbytes = 8; % size of Vel + mean amp else minbytes = 6; % size of Vel end recdatainsample = ADVDeploymentSetup.RecordedDataFlags{i}; recdatainsample([5 8]) =[0 0]; % stats are not recorded at every sample ADVDeploymentSetup.BytesPerSample(i) = minbytes+sum(BYTEMAP(find(recdatainsample))); end a = fread(fid,1,'char'); OutMode = {'Auto','Polled'}; ADVDeploymentSetup.OutMode = OutMode {a+1}; a = fread(fid,1,'char'); OutFormat = {'Binary','Ascii'}; ADVDeploymentSetup.OutFormat = OutFormat {a+1}; a = fread(fid,1,'char'); RecorderEnabled = {'Disabled','Enabled'}; ADVDeploymentSetup.RecorderEnabled = RecorderEnabled {a+1}; a = fread(fid,1,'char'); RecorderMode = {'Normal Mode','Buffer Mode'}; ADVDeploymentSetup.RecorderMode = RecorderMode {a+1}; a = fread(fid,1,'char'); DeploymentMode = {'Disabled','Enabled'}; ADVDeploymentSetup.DeploymentMode = DeploymentMode {a+1}; %DeploymentName = char(fread(fid,[1,9],'char')); DeploymentName = fread(fid,[1,9],'*char'); ADVDeploymentSetup.DeploymentName = strcat(DeploymentName); year = fread(fid,1,'int16'); day = fread(fid,1,'char'); month = fread(fid,1,'char'); minute = fread(fid,1,'char'); hour = fread(fid,1,'char'); hs = fread(fid,1,'char'); sec = fread(fid,1,'char'); ADVDeploymentSetup.BeginDeployment = [day month year hour minute sec hs]; %Comment1 = char(fread(fid,[1,60],'char')); Comment1 = fread(fid,[1,60],'*char'); %Comment2 = char(fread(fid,[1,60],'char')); Comment2 = fread(fid,[1,60],'*char'); %Comment3 = char(fread(fid,[1,60],'char')); Comment3 = fread(fid,[1,60],'*char'); ADVDeploymentSetup.ADRComments = strcat(Comment1,' ',Comment2,' ',Comment3); ADVDeploymentSetup.AutoSleep = fread(fid,1,'char'); fseek(fid,7,0); %skip spare return % ADV Burst Header (60 bytes) function ADVBurstHeader = ReadADVBurstHeader(fid) % see advdata.h and advdata.c definition ADVBurstHeader.SyncChar = fread(fid,1,'uchar'); %0xA5 ADVBurstHeader.DataType = fread(fid,1,'uchar'); %0x11 in the advdata.h but 0x11 in reality ADVBurstHeader.Nbytes = fread(fid,1,'uint16'); %bytes in header if feof(fid), disp(sprintf('End of file at file position %x',ftell(fid))) ADVBurstHeader = -1; return end % let's check and make sure it's really an ADV file if (ADVBurstHeader.SyncChar ~= 165) || (ADVBurstHeader.DataType ~= 17), disp(sprintf('ADVBurstHeader read failed at file position %x',ftell(fid))) ADVBurstHeader = []; return end fread(fid,10,'uchar'); % skip the serial number ADVBurstHeader.BurstNumber = fread(fid,1,'uint32'); y = fread(fid,1,'int16'); d = fread(fid,1,'char'); m = fread(fid,1,'char'); min = fread(fid,1,'char'); hour = fread(fid,1,'char'); hs = fread(fid,1,'char'); sec = fread(fid,1,'char'); %if y*d*m*min*hr*sec*hs < 0, disp('Bad ADVBurstHeader.VelRangeInd = fread(fid,1,'uchar'); fseek(fid,1,0); %skip spare ADVBurstHeader.SampRate = fread(fid,1,'uint16')*0.01; % stored by Hydra in Hz*100 ADVBurstHeader.sampleinterval = 1./ADVBurstHeader.SampRate; % in sec ADVBurstHeader.nsamplesthisburst = fread(fid,1,'uint16'); ADVBurstHeader.CoordSystem = fread(fid,1,'char'); recdata = fliplr(dec2bin(fread(fid,1,'uchar'))); for i=1:length(recdata), ADVBurstHeader.RecordedDataFlags(i) = str2double(recdata(i)); end % flags are [Amp/Corr Compass Sensor Stat ExtSensor ExtPress CTD|LISST ] ADVBurstHeader.SoundSpeed = fread(fid,1,'uint16')*0.1; %in 0.1 m/s convert to m/s ADVBurstHeader.BoundaryRange = fread(fid,1,'int16')*0.1; %0.1 mm convert to mm ADVBurstHeader.VolumeBoundaryRange = fread(fid,1,'int16')*0.1; %0.1 mm convert to mm fread(fid,[1,20],'uchar')'; % skip spare % expand time so there is a time stamp for every sample assume that a burst % is never going to be longer than a day ADVBurstHeader.time1 = ones(1,ADVBurstHeader.nsamplesthisburst).*julian([y m d 0 0 0]); % julian day ADVBurstHeader.time2 = (0:ADVBurstHeader.sampleinterval:((ADVBurstHeader.nsamplesthisburst*ADVBurstHeader.sampleinterval)-... ADVBurstHeader.sampleinterval)).*1000; % in msec from start of burst % time2 is the start of burst in milliseconds from the start of the julian % day ADVBurstHeader.time2 = ADVBurstHeader.time2 + hour.*(3600*1000)+... % hours to milliseconds min.*(60*1000)+... % minutes to milliseconds sec.*(1000)+... % seconds to milliseconds hs.*10; % hundredths of seconds to milliseconds % but account for those bursts that extend over the day boundary rolloveridx = find(ADVBurstHeader.time2 >= 1000*60*60*24); % find amounts greater than the # of milliseconds in the day if ~isempty(rolloveridx), ADVBurstHeader.time2(rolloveridx) = ADVBurstHeader.time2(rolloveridx) - 1000*60*60*24; % we will add a day to time 1 for these ADVBurstHeader.time1(rolloveridx) = ADVBurstHeader.time1(rolloveridx) + 1; % these are technically in the next day end return function write_metadata2cdf(nc, ADVSystemConfig, ADVProbeConfig, ADVDeploymentSetup, ... metadata, whichscheme) % EPIC requirements USGS uses if isfield(metadata,'mooring_number'), nc.MOORING = metadata.mooring_number; else nc.MOORING = ncchar('XXXX'); end if isfield(metadata,'water_depth'), nc.WATER_DEPTH = metadata.water_depth; else nc.WATER_DEPTH = nclong(99); end if isfield(metadata,'lat'), nc.latitude = metadata.lat; else nc.latitude = ncfloat(999); end if isfield(metadata,'lon'), nc.longitude = metadata.lon; else nc.longitude = ncfloat(999); end if isfield(metadata,'declination'), nc.magnetic_variation = metadata.declination; else nc.magnetic_variation = ncfloat(0); end nc.INST_TYPE = ADVSystemConfig.INST_TYPE; if isfield(metadata,'origin'), nc.DATA_ORIGIN = ncchar(metadata.origin); else nc.DATA_ORIGIN = ncchar('UNKNOWN'); end if isfield(metadata,'experiment'), nc.EXPERIMENT = ncchar(metadata.experiment); else nc.EXPERIMENT = ncchar('UNKOWN'); end if isfield(metadata,'project'), nc.PROJECT = ncchar(metadata.project); else nc.PROJECT = ncchar('UNKOWN'); end if isfield(metadata,'description'), nc.DESCRIPT = ncchar(metadata.description); else nc.description = ncchar('UNKOWN'); end if isfield(metadata,'conventions'), nc.Conventions = ncchar(metadata.conventions); else nc.Conventions = ncchar('UNKOWN'); end % things simply to stay EPIC compliant, not that USGS needs them nc.DATA_SUBTYPE = ncchar(' '); nc.WATER_MASS = ncchar('?'); nc.COMPOSITE = nclong(0); % for flagging patched together data sets nc.POS_CONST = nclong(0); nc.FILL_FLAG = nclong(1); nc.DEPTH_CONST = nclong(0); % depth 0 indicates constant depth nc.DATA_CMNT = ncchar(' '); nc.VAR_FILL = ncfloat(1e35); nc.Deployment_date = metadata.deployment_start; nc.Recovery_date = metadata.deployment_end; nc.ADVProbeHeight = metadata.adv.height; nc.ADVSampleVolumeOffset = metadata.adv.sample_volume_offset; nc.cpuSoftWareVerNum = ADVSystemConfig.cpuSoftWareVerNum; nc.dspSoftWareVerNum = ADVSystemConfig.dspSoftWareVerNum; nc.ADVType = ADVSystemConfig.ADVType; nc.SensorOrientation = ADVSystemConfig.SensorOrientation; nc.CompassInstalled = ADVSystemConfig.CompassInstalled; nc.RecorderInstalled = ADVSystemConfig.RecorderInstalled; nc.TempInstalled = ADVSystemConfig.TempInstalled; nc.PressInstalled = ADVSystemConfig.PressInstalled; nc.PressScale = ADVSystemConfig.PressScale; nc.PressOffset = ADVSystemConfig.PressOffset; nc.CompassOffset = ADVSystemConfig.CompassOffset; nc.PressFreqOffset = ADVSystemConfig.PressFreqOffset; nc.ExtSensorInstalled = ADVSystemConfig.ExtSensorInstalled; nc.ExtPressInstalled = ADVSystemConfig.ExtPressInstalled; nc.PressScale_2 = ADVSystemConfig.PressScale_2; nc.CTDInstalled = ADVSystemConfig.CTDInstalled; nc.ADVProbeConfig = ADVProbeConfig.ProbeConfiguration; nc.ADVProbeSerial = ADVProbeConfig.SerialNum; nc.ADVProbeNbeams = ADVProbeConfig.NBeams; nc.ADVProbeNomPeakPos = ADVProbeConfig.NomPeakPos; nc.ADVProbeNsamp = ADVProbeConfig.Nsamp; nc.ADVProbeSampInterval = ADVProbeConfig.SampInterval; nc.ADVProbePulseLag = ADVProbeConfig.PulseLag; nc.ADVProbeNxmt = ADVProbeConfig.Nxmt; nc.ADVProbeLagDelay = ADVProbeConfig.LagDelay; nc.ADVProbeBeamDelay = ADVProbeConfig.BeamDelay; nc.ADVProbePingDelay = ADVProbeConfig.PingDelay; nc.ADVProbeXformMat = ADVProbeConfig.XformMat; nc.ADVProbeXmtRecDist = ADVProbeConfig.XmtRecDist; nc.ADVProbeCalCW = ADVProbeConfig.CalCW; nc.ADVProbeSamplingVolumeOffset = ADVProbeConfig.SamplingVolumeOffset; nc.ADVDeploymentSetupTemp = ADVDeploymentSetup.Temp; %degrees Celcius nc.ADVDeploymentSetupSal = ADVDeploymentSetup.Sal; %ppt nc.ADVDeploymentSetupCW = ADVDeploymentSetup.CW; %m/s nc.ADVDeploymentSetupTempMode = ADVDeploymentSetup.TempMode; nc.ADVDeploymentSetupVelRangeIndex = ADVDeploymentSetup.VelRangeIndex; nc.ADVDeploymentSetupSyncMode = ADVDeploymentSetup.SyncMode; nc.ADVDeploymentSetupCoordSystem = ADVDeploymentSetup.CoordSystem; nc.ADVDeploymentSetupSampleRate = ADVDeploymentSetup.SampleRate(whichscheme); nc.ADVDeploymentSetupBurstInterval = ADVDeploymentSetup.BurstInterval(whichscheme); %seconds nc.ADVDeploymentSetupSamplesPerBurst = ADVDeploymentSetup.SamplesPerBurst(whichscheme); nc.ADVDeploymentSetupOutMode = ADVDeploymentSetup.OutMode; nc.ADVDeploymentSetupOutFormat = ADVDeploymentSetup.OutFormat; nc.ADVDeploymentSetupRecorderEnabled = ADVDeploymentSetup.RecorderEnabled; nc.ADVDeploymentSetupRecorderMode = ADVDeploymentSetup.RecorderMode; nc.ADVDeploymentSetupDeploymentMode = ADVDeploymentSetup.DeploymentMode; nc.ADVDeploymentSetupDeploymentName = ADVDeploymentSetup.DeploymentName; nc.ADVDeploymentSetupBeginDeployment = ADVDeploymentSetup.BeginDeployment; nc.ADVDeploymentSetupADRComments = ADVDeploymentSetup.ADRComments; nc.ADVDeploymentSetupRecordedDataFlags = ADVDeploymentSetup.RecordedDataFlags{whichscheme}; return