function aqa2cdf(metaFile, outFileRoot)
% aqa2cdf.m  A function to convert Aquascat ABS data (*.aqa and *.aqf) to
%            netCDF.
%
% usage:    aqa2cdf(metaFile, outFileRoot);
%
%       where:  metaFile is the name of your text file containing metadata,
%                        surrounded by single quotes WITHOUT the file
%                        extension .txt. An example metadata file,
%                        absmetaexample.txt, is provided in this package of
%                        mfiles.
%               outFileRoot is the name given to the output netCDF files,
%                           surrounded by single quotes WITHOUT the file
%                           extension .cdf.  Output files will be named:
%                             'outFileRoot'abs(1...n)b.cdf for burst netcdf
%                                               files where (1...n) denotes
%                                               data subsets
%                             'outFileRoot'abss.cdf for stats netcdf file 
%
% Written by Charlene Sullivan
% USGS Woods Hole Field Center
% csullivan@usgs.gov
%
%
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
% Use of this program is self described.
% Program written in Matlab v7.1.0 SP3
% Program ran on PC with Windows XP Professional OS.
%
% "Although this program has been used by the USGS, no warranty, 
% expressed or implied, is made by the USGS or the United States 
% Government as to the accuracy and functioning of the program 
% and related program material nor shall the fact of distribution 
% constitute any such warranty, and no responsibility is assumed 
% by the USGS in connection therewith."
%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%%
%
% Dependencies:
%   readaqa_oleg.m (O. Mouraenko)
%   matpctile.m (C. Sherwood)
%   julian.m
%   gregorian.m

% TODO:  Read frequencies from 'ABS_info' variable if they're not specified
% in the user's metadata file 
% TODO:  Correct the valid range attribute
% TODO:  Is the use of floats necessary for the ABS burst files? These
% contain integer values.
% C. Sullivan   03/21/06,   version 1.6
% Add latitude and longitude variables to burst and statistic netcdf files.
% Run code with Matlab R2006a to check for compatibility issues, and use
% M-lint code analyzer for suggestions on how to improve code speed.
% C. Sullivan   08/22/05,   version 1.5
% Add capeability to process USC ABS data.  Read this data with
% read_aquatec_v4.m.  This code is a modified form of the code
% read_aquatec_V3_2.m provided by G. Voulgaris (USC).  Include metadata
% output to 'ABS_info' by readaqa_oleg.m and read_aquatec_v4.m in metadata.
% Change netcdf variables 'Mdata*' to 'abs_trans*'.
% C. Sullivan   07/11/05,   version 1.4
% Add the attributes 'input_directory', 'output_directory', and 'Conventions'
% to the metadata file. Users should place their metadata file in the 
% directory specified by the attribute 'output_directory', and run this
% mfile from that directory. Remove the attributes 'SampleRate', 'SerialNumber',
% 'BuildDate', 'DSPVersion', and 'FPGAVersion' from the metadata file because
% these attributes will be read from the .aq(a)(f) files. Removing median
% variable form statistics netCDF file b/c these values are given by the 50th
% percentile.
% C. Sullivan   07/07/05,   version 1.3
% Some netCDF files are not being closed appropriately. Getting rid of
% 'isunix' loop for finding files as we can use the 'dir' command on both
% unix and windows with the same result.
% C. Sullivan   07/05/05,   version 1.2
% This version assumes the user has deleted extra .aqa or .aqf files that
% were collected prior to (after) instrument deployment (recovery). We cannot
% get burst number from 'ABS_info.burstnum', output by readaqa_oleg.m, because
% these are not sequentially numbered from 1:nBursts.  For example, the 300th
% .aqa file has an ABS_info.burstnum=44 and ABS_info.burstnum appears to 
% repeats after every 255th burst.
% C. Sullivan   07/01/05,   version 1.1
% Calculate percentiles for the statistics netCDF file. Calculate statistics
% using both the raw amplitudes and the raw amplitudes squared. This version
% will also load ABS data downloaded from the instrument as a series of 
% *.aqa and/or *.aqf files.
% C. Sullivan   06/28/05,   version 1.0
% This function converts ABS data, downloaded from the instrument as a series
% of *.aqa files, to raw data burst and statistic netCDF (*.cdf) files. It
% assumes all metadata is defined in a simple text file (see absmetaexample.txt),
% and the user is reading a USGS ABS with the mfile readaqa_oleg.m. A maximum 
% size limit of 500 MB is imposed on the burst netCDF files, therefore there
% may be multiple burst netCDF files created. It has been possible to write
% all the statistics to a single statistics netCDF file.


more off

version = '1.6';

% Check for metadata file
metaPath = pwd;
meta = dir([metaFile,'.txt']);
if isempty(meta)
    fprintf('\n')
    fprintf('The metadata file %s.txt does not exist in this directory\n',metaFile)
    metaPath = input('Please enter the full path to the directory with your metadata file:  ','s');
    meta = dir(fullfile(metaPath,[metaFile,'.txt']));
    if isempty(meta)
        error(['Still cannot find the metadata file ',fullfile(metaPath,[metaFile,'.txt'])])
    end
end
metaFile = fullfile(metaPath,meta.name);

% Get user's metadata structure
userMeta = readAbsMeta(metaFile);

% Check for Aquascat files
inputDir = userMeta.input_directory;
aqa = dir(fullfile(inputDir,'*.aqa'));
aqf = dir(fullfile(inputDir,'*.aqf'));
if isempty(aqa) && isempty(aqf)
    fprintf('\n')
    error(['Aquascat ABS data files do not exist in ',pwd]);
else
    if ~isempty(aqa)
        nFiles = length(aqa);
        aqaFiles = struct([]);
        for n = 1:nFiles
            aqaFiles{n} = aqa(n).name;
        end
    end
    if ~isempty(aqf)
        nFiles = length(aqf);
        aqfFiles = struct([]);
        for n = 1:nFiles
            aqfFiles{n} = aqf(n).name;
        end
    end
    if ~isempty(aqa) && ~isempty(aqf)
        aqFiles = char(union(aqaFiles,aqfFiles));
    elseif ~isempty(aqf)
        aqFiles = char(aqfFiles);
    elseif ~isempty(aqa)
        aqFiles = char(aqaFiles);
    end
    nAqFiles = size(aqFiles,1);
end

% Determine which mfile will read the Aquascat files
testFile = fullfile(inputDir,aqFiles(1,:));
try
    %WH ABS
    disp(' ')
    disp('Determining how to read Aquascat data files')
    disp('Trying to read data with readaqa_oleg.m')
    disp(' ')
    [absMeta, absData] = readaqa_oleg(testFile);
    disp(' ')
    disp('readaqa_oleg.m sucessful')
    disp('Data will be read with readaqa_oleg.m')
    readAbsMfile = 'readaqa_oleg';
catch
    try
        %USC ABS
        disp(' ')
        disp('readaqa_oleg.m failed. Trying to read data with read_aquatec_v4.m')
        [absMeta, absData]=read_aquatec_v4(testFile);
        disp(' ')
        disp('read_aquatec_v4.m successful')
        disp('Data will be read with read_aquatec_v4.m')
        readAbsMfile = 'read_aquatec_v4';
    catch
        error('Could not read data with readaqa_oleg.m or read_aquatec_v4.m')
    end
end

% The 1st, 15th, 50th, 84th, and 99th percentiles will be calculated for
% the statistics file. Include this information in the user's metadata.
pctiles = [1; 16; 50; 84; 99];
userMeta.pctiles = pctiles';
userMeta.nPctiles = length(userMeta.pctiles);

% There is a 500 MB size limit imposed on the raw data burst netCDF (.cdf)
% files. Additional raw data burst netCDF files are created as needed.
maxBytes = 500000000;
burstFileNum = 1; %initialize burst netcdf file #
lastBrec = 0; %initialize burst record #

tic

% The following loop reads the data in each Aquascat data file, writes the
% burst data to the burst netCDF file, performs basic statistics on the
% burst, and writes the statistics to the statistics netCDF file.
for n = 1:nAqFiles
   
    aqFile = fullfile(inputDir,aqFiles(n,:)); %burst file name
    brec = n - lastBrec; %burst record number
    srec = n; %statistic record number
    
    %Read the data
    switch readAbsMfile
        case 'readaqa_oleg'
            [absMeta, absData] = readaqa_oleg(aqFile); %WH ABS
        case 'read_aquatec_v4'
            [absMeta, absData]=read_aquatec_v4(aqFile); %USC ABS
    end
    
    %Clean up fields in 'userMeta'
    if ~isfield(userMeta,'serial_number') && ...
        isfield(absMeta,'sysinfo')
             userMeta.serial_number = absMeta.sysinfo(23:29);
    end
        
    %Clean up the fields in 'absMeta'
    if isfield(absMeta,'ProfileRate')
        absMeta.samp_rate = absMeta.ProfileRate;
        absMeta = rmfield(absMeta,'ProfileRate');
    end
    if isfield(absMeta,'Averaging1')
        absMeta.avg_over = absMeta.Averaging1;
        absMeta = rmfield(absMeta,'Averaging1');
    end
    absMeta = rmfield(absMeta,{'year','month','day',...
                                 'hour','minute','second'});

    %Add fields to 'absMeta' to specify dimensions
    absMeta.nBins = size(absData.mdata,1); %number of bins
    absMeta.nProfiles = size(absData.mdata,2); %number of profiles
    absMeta.nXducers = size(absData.r,2); %number of xducers
    
    %Write fields in 'userMeta' and 'absMeta' to a new structure,
    %'allMeta'. All fields in 'allMeta' are written to the netcdf
    %files as global attributes.
    usrFields = fieldnames(userMeta);
    for f = 1:size(usrFields,1)
        eval(['allMeta.',usrFields{f},' = userMeta.',usrFields{f},';'])
    end
    absFields = fieldnames(absMeta);
    for f = 1:size(absFields,1)
        eval(['allMeta.',absFields{f},' = absMeta.',absFields{f},';'])
    end

    if n == 1
        %Create burst and statistic netCDF files
        [cdfb, burstFile] = defineAbsBurstCdf(allMeta, outFileRoot, burstFileNum);
        [cdfs, statFile] = defineAbsStatCdf(allMeta, outFileRoot);
        fprintf('\n')
        fprintf('There are %d bursts to write to netCDF\n',nAqFiles)
        fprintf('Writing burst data to the file %s\n',burstFile)
        fprintf('Writing statistics data to the file %s\n',statFile)
        
        %Extract dimensions.  These are constant for each
        %Aquascat file, so extract them once at the start.
        binDim = cdfb('bin');
        nBins = size(binDim,1);
        profDim = cdfb('profile');
        nProfiles = size(profDim,1);
        xducerDim = cdfb('xducer');
        nXducers = size(xducerDim,1);
        pctlDim = cdfs('pctile');
        nPctiles = size(pctlDim,1);
        
        %Some index variables are constant for each Aquascat
        %file, so write these only once at the beginning.
        cdfb{'r'}(1:nBins,1:nXducers) = absData.r / 1000;  %Distance from the ABS, m
        cdfs{'r'}(1:nBins,1:nXducers) = absData.r / 1000; 
        cdfs{'pctile'}(1:nPctiles) = pctiles; %Percentiles

    end
    
    %Write Aquascat data to the burst netCDF file
    profStartTime = julian(datevec(absData.sdatenum)); % profile start time, julian days
    sampleRate = absMeta.samp_rate;        %sample rate
    samples_per_avg = absMeta.avg_over;    %samples per average
    profDt = (1/(sampleRate/samples_per_avg))/3600/24; 
    profTime = profStartTime : profDt : profStartTime+(profDt*(nProfiles-1));
    cdfb{'time'}(brec, 1:nProfiles) = floor(profTime);
    cdfb{'time2'}(brec, 1:nProfiles) = (profTime-floor(profTime)).*(24*3600*1000);
    if ~isequal(absMeta.burstnum,n) %if burst #'s begin to repeat,
        cdfb{'burst'}(brec) = n;     %override them
    else
        cdfb{'burst'}(brec) = absMeta.burstnum;
    end
    cdfb{'abs_trans1'}(brec, 1:nProfiles, 1:nBins) = absData.mdata(:,:,1)'; %Amplitude at frequency 1
    cdfb{'abs_trans2'}(brec, 1:nProfiles, 1:nBins) = absData.mdata(:,:,2)'; %Ampliude at frequency 2
    cdfb{'abs_trans3'}(brec, 1:nProfiles, 1:nBins) = absData.mdata(:,:,3)'; %Ampliude at frequency 3
     
    %Get the size of the burst netCDF file after the
    %1st Aquascat file is written. Use this size to determine
    %the number of Aquascat files you can write to each
    %burst netCDF file
    if n == 1
        filechk = dir(burstFile);
        bytesPerAqFile = filechk.bytes; 
        nAqFilesPerBurstCdf = floor(maxBytes/bytesPerAqFile);
    end

    %write statistics to the statistic netCDF file
    cdfs{'time'}(srec) = floor(profTime(1));%use first time stamp in each burst
    cdfs{'time2'}(srec) = (profTime(1)-floor(profTime(1))).*(24*3600*1000); 
    if ~isequal(absMeta.burstnum,n) %if burst #'s begin to repeat,
        cdfs{'burst'}(srec) = n;     %override them
    else
        cdfs{'burst'}(srec) = absMeta.burstnum;
    end
    cdfs{'abs_trans1_mean'}(srec, 1:nBins) = mean(absData.mdata(:,:,1),2)';
    cdfs{'abs_trans2_mean'}(srec, 1:nBins) = mean(absData.mdata(:,:,2),2)';
    cdfs{'abs_trans3_mean'}(srec, 1:nBins) = mean(absData.mdata(:,:,3),2)';
    cdfs{'abs_trans1_mean_sq'}(srec, 1:nBins) = mean(absData.mdata(:,:,1)'.^2);
    cdfs{'abs_trans2_mean_sq'}(srec, 1:nBins) = mean(absData.mdata(:,:,2)'.^2);
    cdfs{'abs_trans3_mean_sq'}(srec, 1:nBins) = mean(absData.mdata(:,:,3)'.^2);
    cdfs{'abs_trans1_std'}(srec, 1:nBins) = std(absData.mdata(:,:,1),0,2)';
    cdfs{'abs_trans2_std'}(srec, 1:nBins) = std(absData.mdata(:,:,2),0,2)';
    cdfs{'abs_trans3_std'}(srec, 1:nBins) = std(absData.mdata(:,:,3),0,2)';
    cdfs{'abs_trans1_std_sq'}(srec, 1:nBins) = std(absData.mdata(:,:,1)'.^2);
    cdfs{'abs_trans2_std_sq'}(srec, 1:nBins) = std(absData.mdata(:,:,2)'.^2);
    cdfs{'abs_trans3_std_sq'}(srec, 1:nBins) = std(absData.mdata(:,:,3)'.^2);
    cdfs{'abs_trans1_pctl'}(srec, 1:nBins, 1:nPctiles) = matpctile(absData.mdata(:,:,1)', pctiles)';
    cdfs{'abs_trans2_pctl'}(srec, 1:nBins, 1:nPctiles) = matpctile(absData.mdata(:,:,2)', pctiles)';
    cdfs{'abs_trans3_pctl'}(srec, 1:nBins, 1:nPctiles) = matpctile(absData.mdata(:,:,3)', pctiles)';
    cdfs{'abs_trans1_pctl_sq'}(srec, 1:nBins, 1:nPctiles) = matpctile(absData.mdata(:,:,1)'.^2, pctiles)';
    cdfs{'abs_trans2_pctl_sq'}(srec, 1:nBins, 1:nPctiles) = matpctile(absData.mdata(:,:,2)'.^2, pctiles)';
    cdfs{'abs_trans3_pctl_sq'}(srec, 1:nBins, 1:nPctiles) = matpctile(absData.mdata(:,:,3)'.^2, pctiles)';
    
    %Update the user with the code's progress
    if mod(n,50)==0
        fprintf('Finished writing burst %d; %6.2f minutes elapsed\n',...
                 n,toc/60)
    end
    
    %If n equals the number of bursts you can write to the burst netCDF 
    %file, close this burst netCDF file and create another one to which
    %you will write subsequent bursts
    if mod(n,nAqFilesPerBurstCdf)==0 
        lastBrec = cdfb{'burst'}(end);
        %Write latitude and longtitude variables once at the end
        cdfb{'lat'}(:) = cdfb.latitude(:);
        cdfb{'lon'}(:) = cdfb.longtiude(:);
        %Update the attributes of the current burst netCDF file
        fprintf('The burst file %s is full\n',burstFile)
        cdfb.burstnum = [];
        start_time = cdfb{'time'}(1,1) + cdfb{'time2'}(1,1)/3600/1000/24;
        cdfb.start_time = ncchar(datestr(gregorian(start_time)));
        stop_time = cdfb{'time'}(end,end) + cdfb{'time2'}(end,end)/3600/1000/24;
        cdfb.stop_time = ncchar(datestr(gregorian(stop_time)));
        hist = cdfb.history(:);
        hist_new = ['Converted to netCDF via Matlab by aqa2cdf.m V ',version,'; ',hist];
        cdfb.history = ncchar(hist_new);
        cdfb=close(cdfb);
        %Create a new burst netCDF file for subsequent bursts
        burstFileNum = burstFileNum + 1;
        [cdfb, burstFile] = defineAbsBurstCdf(allMeta, outFileRoot, burstFileNum);
        fprintf('Now writing burst data to the file %s\n',burstFile)
        cdfb{'r'}(1:nBins,1:nXducers) = absData.r / 1000;  %Distance from the ABS, m
    end

    if mod(n,nAqFiles)==0
            cdfb.burstnum = [];
            %Write latitude and longtitude variables once at the end
            cdfb{'lat'}(:) = cdfb.latitude(:);
            cdfb{'lon'}(:) = cdfb.longtiude(:);
            %Update the attributes of the last burst netCDF file
            start_time = cdfb{'time'}(1,1) + cdfb{'time2'}(1,1)/3600/1000/24;
            cdfb.start_time = ncchar(datestr(gregorian(start_time)));
            stop_time = cdfb{'time'}(end,end) + cdfb{'time2'}(end,end)/3600/1000/24;
            cdfb.stop_time = ncchar(datestr(gregorian(stop_time)));
            hist = cdfb.history(:);
            hist_new = ['Converted to netCDF via Matlab by aqa2cdf.m V ',version,'; ',hist];
            cdfb.history = ncchar(hist_new);
            cdfb=close(cdfb);
            
            %update the attributes of the statistics netCDF file and
            %calculate min/max values
            cdfs.burstnum = [];
            %Write latitude and longtitude variables once at the end
            cdfs{'lat'}(:) = cdfs.latitude(:);
            cdfs{'lon'}(:) = cdfs.longtiude(:);
            start = cdfs{'time'}(1) + cdfs{'time2'}(1)/3600/1000/24;
            cdfs.start_time = ncchar(datestr(gregorian(start)));
            stop = cdfs{'time'}(end) + cdfs{'time2'}(end)/3600/1000/24;
            cdfs.stop_time = ncchar(datestr(gregorian(stop)));
            delta_t = mean(diff(cdfs{'time'}(:) + cdfs{'time2'}(:)/3600/1000/24));
            cdfs.DELTA_T = ncchar([num2str(delta_t*24*3600),' s']);
            hist = cdfs.history(:);
            hist_new = ['Converted to netCDF via Matlab by aqa2cdf.m V ',version,'; ',hist];
            cdfs.history = ncchar(hist_new);
            calc_minmax_vals(cdfs);
            cdfs=close(cdfs);
            fprintf('Finished writing all bursts. %6.2f minutes elapsed\n',toc/60)
    end

end

% ---------------------- Subfunction ------------------------------------ %
function userMeta = readAbsMeta(metaFile)
[atts, defs] = textread(metaFile,'%s %63c','commentstyle','shell');
defs = cellstr(defs);
for i = 1:length(atts)
    theAtt = atts{i}(:)';
    theDef = defs{i}(:)';
    % deblank removes trailing whitespace
    theAtt = deblank(theAtt);
    theDef = deblank(theDef);
    % check for and replace spaces in
    % the attributes with underscores
    f1 = find(isspace(theAtt));
    f2 = strfind(theAtt,'-');
    f = union(f1,f2);
    if ~isempty(f)
        theAtt(f) = '_';
    end
    % attribute definitions read in as characters; convert to
    % numbers where appropriate
    theDefNum = str2double(theDef);
    if ~isnan(theDefNum) 
        theDef = theDefNum;
    end
    userMeta.(theAtt) = theDef;
end

% ---------------------- Subfunction ------------------------------------ %
function [cdfb, burstFile] = defineAbsBurstCdf(userMeta, outFileRoot, burstFileNum)

outputDir = userMeta.output_directory;
burstFileNum = num2str(burstFileNum);
burstFile = fullfile(outputDir,[outFileRoot,burstFileNum,'b.cdf']);

cdfb = netcdf(burstFile,'clobber');

% write metadata
metaFields = fieldnames(userMeta);
for i = 1:length(metaFields)
    theField = metaFields{i};
    theFieldDef = userMeta.(theField);
    nRows = size(theFieldDef,1);
    nCols = size(theFieldDef,2);
    temp = [];
    if nRows>1
        for ii = 1:nRows
            temp = [temp,' ',theFieldDef(ii,1:nCols)];
        end
        theFieldDef = temp;
    end
    if ~strcmp(theField,'bins') && ... %don't write these attributes b/c
            ~strcmp(theField,'freqs') && ... %they are not read from the .aqa files correctly
            ~strcmp(theField,'gains') %and their information is provided in other attributes
        cdfb.(theField) = theFieldDef;
    end
end

% write additional metadata
cdfb.CREATION_DATE = ncchar(datestr(now));
cdfb.DESCRIPT = ncchar('Aquascat ABS raw data burst file');
cdfb.DATA_TYPE = ncchar('ABS');

% define dimensions
cdfb('burst') = 0; %unlimited
cdfb('profile') = userMeta.nProfiles;
cdfb('bin') = userMeta.nBins;
cdfb('xducer') = userMeta.nXducers;

% define burst variables
cdfb{'time'} = nclong('burst','profile');
cdfb{'time'}.FORTRAN_format = ncchar('F10.2');
cdfb{'time'}.units = ncchar('True Julian Day');
cdfb{'time'}.type = ncchar('EVEN');
cdfb{'time'}.epic_code = nclong(624);
cdfb{'time'}.FillValue_ = nclong(0);

cdfb{'time2'} = nclong('burst','profile') ;
cdfb{'time2'}.FORTRAN_format = ncchar('F10.2');
cdfb{'time2'}.units = ncchar('msec since 0:00 GMT');
cdfb{'time2'}.type = ncchar('EVEN');
cdfb{'time2'}.epic_code = nclong(624);
cdfb{'time2'}.FillValue_ = nclong(0);

cdfb{'burst'} = nclong('burst');
cdfb{'burst'}.FORTRAN_format = ncchar('F10.2');
cdfb{'burst'}.units = ncchar('counts');
cdfb{'burst'}.type = ncchar('EVEN');
cdfb{'burst'}.FillValue_ = nclong(0);

cdfb{'lat'} = ncfloat('lat');
cdfb{'lat'}.FORTRAN_format = ncchar('F10.4');
cdfb{'lat'}.units = ncchar('degree_north');
cdfb{'lat'}.type = ncchar('EVEN');
cdfb{'lat'}.epic_code = nclong(500);

cdfb{'lon'} = ncfloat('lon');
cdfb{'lon'}.FORTRAN_format = ncchar('F10.4');
cdfb{'lon'}.units = ncchar('degree_east');
cdfb{'lon'}.type = ncchar('EVEN');
cdfb{'lon'}.epic_code = nclong(502);

cdfb{'r'} = ncfloat('bin','xducer');
cdfb{'r'}.long_name = ncchar('Distance from ABS sensor head (m)');
cdfb{'r'}.units = ncchar('m');
cdfb{'r'}.valid_range = ncfloat([0 5000]);
cdfb{'r'}.sensor_type = cdfb.INST_TYPE(:);
cdfb{'r'}.height = ncchar([num2str(cdfb.sensor_height(:)),' m']);
cdfb{'r'}.serial = ncchar(cdfb.SerialNumber(:));
cdfb{'r'}.FORTRAN_format = ncchar('F10.2');
cdfb{'r'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfb{'abs_trans1'} = ncfloat('burst','profile','bin');
cdfb{'abs_trans1'}.long_name = ncchar(['Amplitude at ',num2str(cdfb.frequency1(:)),' Mhz']);
cdfb{'abs_trans1'}.units = ncchar('ABS units');
cdfb{'abs_trans1'}.valid_range = ncfloat([0 1e16]);
cdfb{'abs_trans1'}.sensor_type = cdfb.INST_TYPE(:);
cdfb{'abs_trans1'}.height = ncchar([num2str(cdfb.sensor_height(:)),' m']);
cdfb{'abs_trans1'}.serial = ncchar(cdfb.serial_number(:));
cdfb{'abs_trans1'}.frequency = ncchar([num2str(cdfb.frequency1(:)),' Mhz']);
cdfb{'abs_trans1'}.FORTRAN_format = ncchar('F10.2');
cdfb{'abs_trans1'}.epic_code = 1900;
cdfb{'abs_trans1'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfb{'abs_trans2'} = ncfloat('burst','profile','bin');
cdfb{'abs_trans2'}.long_name = ncchar(['Amplitude at ',num2str(cdfb.frequency2(:)),' Mhz']);
cdfb{'abs_trans2'}.units = ncchar('ABS units');
cdfb{'abs_trans2'}.valid_range = ncfloat([0 1e16]);
cdfb{'abs_trans2'}.sensor_type = cdfb.INST_TYPE(:);
cdfb{'abs_trans2'}.height = ncchar([num2str(cdfb.sensor_height(:)),' m']);
cdfb{'abs_trans2'}.serial = ncchar(cdfb.serial_number(:));
cdfb{'abs_trans2'}.frequency = ncchar([num2str(cdfb.frequency2(:)),' Mhz']);
cdfb{'abs_trans2'}.FORTRAN_format = ncchar('F10.2');
cdfb{'abs_trans2'}.epic_code = 1900;
cdfb{'abs_trans2'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfb{'abs_trans3'} = ncfloat('burst','profile','bin');
cdfb{'abs_trans3'}.long_name = ncchar(['Amplitude at ',num2str(cdfb.frequency3(:)),' Mhz']);
cdfb{'abs_trans3'}.units = ncchar('ABS units');
cdfb{'abs_trans3'}.valid_range = ncfloat([0 1e16]);
cdfb{'abs_trans3'}.sensor_type = cdfb.INST_TYPE(:);
cdfb{'abs_trans3'}.height = ncchar([num2str(cdfb.sensor_height(:)),' m']);
cdfb{'abs_trans3'}.serial = ncchar(cdfb.serial_number(:));
cdfb{'abs_trans3'}.frequency = ncchar([num2str(cdfb.frequency3(:)),' Mhz']);
cdfb{'abs_trans3'}.FORTRAN_format = ncchar('F10.2');
cdfb{'abs_trans3'}.epic_code = 1900;
cdfb{'abs_trans3'}.FillValue_ = ncfloat(1.00000004091848e+035);
endef(cdfb)

return

% ---------------------- Subfunction ------------------------------------ %
function [cdfs, statFile] = defineAbsStatCdf(userMeta, outFileRoot)

outputDir = userMeta.output_directory;
statFile = fullfile(outputDir,[outFileRoot,'s.cdf']);

cdfs = netcdf(statFile,'clobber');

% write metadata
metaFields = fieldnames(userMeta);
for i = 1:length(metaFields)
    theField = metaFields{i};
    theFieldDef = userMeta.(theField);
    nRows = size(theFieldDef,1);
    nCols = size(theFieldDef,2);
    temp = [];
    if nRows>1
        for ii = 1:nRows
            temp = [temp,' ',theFieldDef(ii,1:nCols)];
        end
        theFieldDef = temp;
    end
    if ~strcmp(theField,'bins') && ... %don't write these attributes b/c
            ~strcmp(theField,'freqs') && ... %they are not read from the .aqa files correctly
            ~strcmp(theField,'gains') %and their information is provided in other attributes
        cdfs.(theField) = theFieldDef;
    end
end

% write additional metadata
cdfs.CREATION_DATE = ncchar(datestr(now));
cdfs.DESCRIPT = ncchar('Aquascat ABS raw data statistics file');
cdfs.DATA_TYPE = ncchar('ABS');

% define dimensions
cdfs('burst') = 0; %unlimited
cdfs('bin') = userMeta.nBins;
cdfs('pctile') = userMeta.nPctiles;
cdfs('xducer') = userMeta.nXducers;

% define stats variables
cdfs{'time'} = nclong('burst');
cdfs{'time'}.FORTRAN_format = ncchar('F10.2');
cdfs{'time'}.units = ncchar('True Julian Day');
cdfs{'time'}.type = ncchar('UNEVEN');
cdfs{'time'}.epic_code = nclong(624);
cdfs{'time'}.FillValue_ = nclong(0);

cdfs{'time2'} = nclong('burst') ;
cdfs{'time2'}.FORTRAN_format = ncchar('F10.2');
cdfs{'time2'}.units = ncchar('msec since 0:00 GMT');
cdfs{'time2'}.type = ncchar('UNEVEN');
cdfs{'time2'}.epic_code = nclong(624);
cdfs{'time2'}.FillValue_ = nclong(0);

cdfs{'burst'} = nclong('burst');
cdfs{'burst'}.FORTRAN_format = ncchar('F10.2');
cdfs{'burst'}.units = ncchar('counts');
cdfs{'burst'}.type = ncchar('EVEN');
cdfs{'burst'}.FillValue_ = nclong(0);

cdfs{'pctile'} = nclong('pctile');
cdfs{'pctile'}.FORTRAN_format = ncchar('F10.2');
cdfs{'pctile'}.units = ncchar('%');
cdfs{'pctile'}.type = ncchar('EVEN');
cdfs{'pctile'}.FillValue_ = nclong(0);

cdfs{'lat'} = ncfloat('lat');
cdfs{'lat'}.FORTRAN_format = ncchar('F10.4');
cdfs{'lat'}.units = ncchar('degree_north');
cdfs{'lat'}.type = ncchar('EVEN');
cdfs{'lat'}.epic_code = nclong(500);

cdfs{'lon'} = ncfloat('lon');
cdfs{'lon'}.FORTRAN_format = ncchar('F10.4');
cdfs{'lon'}.units = ncchar('degree_east');
cdfs{'lon'}.type = ncchar('EVEN');
cdfs{'lon'}.epic_code = nclong(502);

cdfs{'r'} = ncfloat('bin','xducer');
cdfs{'r'}.long_name = ncchar('Distance from ABS sensor head (m)');
cdfs{'r'}.units = ncchar('m');
cdfs{'r'}.valid_range = ncfloat([0 5000]);
cdfs{'r'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'r'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'r'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'r'}.FORTRAN_format = ncchar('F10.2');
cdfs{'r'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans1_mean'} = ncfloat('burst','bin');
cdfs{'abs_trans1_mean'}.long_name = ncchar(['Mean Amplitude at ',num2str(cdfs.frequency1(:)),' Mhz']);
cdfs{'abs_trans1_mean'}.units = ncchar('ABS units');
cdfs{'abs_trans1_mean'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans1_mean'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans1_mean'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans1_mean'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans1_mean'}.frequency = ncchar([num2str(cdfs.frequency1(:)),' Mhz']);
cdfs{'abs_trans1_mean'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans1_mean'}.epic_code = 1900;
cdfs{'abs_trans1_mean'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans2_mean'} = ncfloat('burst','bin');
cdfs{'abs_trans2_mean'}.long_name = ncchar(['Mean Amplitude at ',num2str(cdfs.frequency2(:)),' Mhz']);
cdfs{'abs_trans2_mean'}.units = ncchar('ABS units');
cdfs{'abs_trans2_mean'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans2_mean'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans2_mean'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans2_mean'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans2_mean'}.frequency = ncchar([num2str(cdfs.frequency2(:)),' Mhz']);
cdfs{'abs_trans2_mean'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans2_mean'}.epic_code = 1900;
cdfs{'abs_trans2_mean'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans3_mean'} = ncfloat('burst','bin');
cdfs{'abs_trans3_mean'}.long_name = ncchar(['Mean Amplitude at ',num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans3_mean'}.units = ncchar('ABS units');
cdfs{'abs_trans3_mean'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans3_mean'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans3_mean'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans3_mean'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans3_mean'}.frequency = ncchar([num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans3_mean'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans3_mean'}.epic_code = 1900;
cdfs{'abs_trans3_mean'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans1_mean_sq'} = ncfloat('burst','bin');
cdfs{'abs_trans1_mean_sq'}.long_name = ncchar(['Squared Mean Amplitude at ',num2str(cdfs.frequency1(:)),' Mhz']);
cdfs{'abs_trans1_mean_sq'}.units = ncchar('ABS units^2');
cdfs{'abs_trans1_mean_sq'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans1_mean_sq'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans1_mean_sq'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans1_mean_sq'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans1_mean_sq'}.frequency = ncchar([num2str(cdfs.frequency1(:)),' Mhz']);
cdfs{'abs_trans1_mean_sq'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans1_mean_sq'}.epic_code = 1901;
cdfs{'abs_trans1_mean_sq'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans2_mean_sq'} = ncfloat('burst','bin');
cdfs{'abs_trans2_mean_sq'}.long_name = ncchar(['Squared Mean Amplitude at ',num2str(cdfs.frequency2(:)),' Mhz']);
cdfs{'abs_trans2_mean_sq'}.units = ncchar('ABS units^2');
cdfs{'abs_trans2_mean_sq'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans2_mean_sq'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans2_mean_sq'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans2_mean_sq'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans2_mean_sq'}.frequency = ncchar([num2str(cdfs.frequency2(:)),' Mhz']);
cdfs{'abs_trans2_mean_sq'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans2_mean_sq'}.epic_code = 1901;
cdfs{'abs_trans2_mean_sq'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans3_mean_sq'} = ncfloat('burst','bin');
cdfs{'abs_trans3_mean_sq'}.long_name = ncchar(['Squared Mean Amplitude at ',num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans3_mean_sq'}.units = ncchar('ABS units^2');
cdfs{'abs_trans3_mean_sq'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans3_mean_sq'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans3_mean_sq'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans3_mean_sq'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans3_mean_sq'}.frequency = ncchar([num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans3_mean_sq'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans3_mean_sq'}.epic_code = 1901;
cdfs{'abs_trans3_mean_sq'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans1_std'} = ncfloat('burst','bin');
cdfs{'abs_trans1_std'}.long_name = ncchar(['Amplitude Standard Deviation at ',num2str(cdfs.frequency1(:)),' Mhz']);
cdfs{'abs_trans1_std'}.units = ncchar('ABS units');
cdfs{'abs_trans1_std'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans1_std'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans1_std'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans1_std'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans1_std'}.frequency = ncchar([num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans1_std'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans1_std'}.epic_code = 1902;
cdfs{'abs_trans1_std'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans2_std'} = ncfloat('burst','bin');
cdfs{'abs_trans2_std'}.long_name = ncchar(['Amplitude Standard Deviation at ',num2str(cdfs.frequency2(:)),' Mhz']);
cdfs{'abs_trans2_std'}.units = ncchar('ABS units');
cdfs{'abs_trans2_std'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans2_std'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans2_std'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans2_std'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans2_std'}.frequency = ncchar([num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans2_std'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans2_std'}.epic_code = 1902;
cdfs{'abs_trans2_std'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans3_std'} = ncfloat('burst','bin');
cdfs{'abs_trans3_std'}.long_name = ncchar(['Amplitude Standard Deviation at ',num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans3_std'}.units = ncchar('ABS units');
cdfs{'abs_trans3_std'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans3_std'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans3_std'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans3_std'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans3_std'}.frequency = ncchar([num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans3_std'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans3_std'}.epic_code = 1902;
cdfs{'abs_trans3_std'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans1_std_sq'} = ncfloat('burst','bin');
cdfs{'abs_trans1_std_sq'}.long_name = ncchar(['Squared Amplitude Standard Deviation at ',num2str(cdfs.frequency1(:)),' Mhz']);
cdfs{'abs_trans1_std_sq'}.units = ncchar('ABS units^2');
cdfs{'abs_trans1_std_sq'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans1_std_sq'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans1_std_sq'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans1_std_sq'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans1_std_sq'}.frequency = ncchar([num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans1_std_sq'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans1_std_sq'}.epic_code = 1903;
cdfs{'abs_trans1_std_sq'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans2_std_sq'} = ncfloat('burst','bin');
cdfs{'abs_trans2_std_sq'}.long_name = ncchar(['Squared Amplitude Standard Deviation at ',num2str(cdfs.frequency2(:)),' Mhz']);
cdfs{'abs_trans2_std_sq'}.units = ncchar('ABS units^2');
cdfs{'abs_trans2_std_sq'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans2_std_sq'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans2_std_sq'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans2_std_sq'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans2_std_sq'}.frequency = ncchar([num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans2_std_sq'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans2_std_sq'}.epic_code = 1903;
cdfs{'abs_trans2_std_sq'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans3_std_sq'} = ncfloat('burst','bin');
cdfs{'abs_trans3_std_sq'}.long_name = ncchar(['Squared Amplitude Standard Deviation at ',num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans3_std_sq'}.units = ncchar('ABS units^2');
cdfs{'abs_trans3_std_sq'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans3_std_sq'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans3_std_sq'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans3_std_sq'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans3_std_sq'}.frequency = ncchar([num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans3_std_sq'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans3_std_sq'}.epic_code = 1903;
cdfs{'abs_trans3_std_sq'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans1_pctl'} = ncfloat('burst','bin','pctile');
cdfs{'abs_trans1_pctl'}.long_name = ncchar(['Amplitude Percentiles at ',num2str(cdfs.frequency1(:)),' Mhz']);
cdfs{'abs_trans1_pctl'}.units = ncchar('ABS units');
cdfs{'abs_trans1_pctl'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans1_pctl'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans1_pctl'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans1_pctl'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans1_pctl'}.frequency = ncchar([num2str(cdfs.frequency1(:)),' Mhz']);
cdfs{'abs_trans1_pctl'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans1_pctl'}.epic_code = 1904;
cdfs{'abs_trans1_pctl'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans1_pctl_sq'} = ncfloat('burst','bin','pctile');
cdfs{'abs_trans1_pctl_sq'}.long_name = ncchar(['Squared Amplitude Percentiles at ',num2str(cdfs.frequency1(:)),' Mhz']);
cdfs{'abs_trans1_pctl_sq'}.units = ncchar('ABS units^2');
cdfs{'abs_trans1_pctl_sq'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans1_pctl_sq'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans1_pctl_sq'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans1_pctl_sq'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans1_pctl_sq'}.frequency = ncchar([num2str(cdfs.frequency1(:)),' Mhz']);
cdfs{'abs_trans1_pctl_sq'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans1_pctl_sq'}.epic_code = 1905;
cdfs{'abs_trans1_pctl_sq'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans2_pctl'} = ncfloat('burst','bin','pctile');
cdfs{'abs_trans2_pctl'}.long_name = ncchar(['Amplitude Percentiles at ',num2str(cdfs.frequency2(:)),' Mhz']);
cdfs{'abs_trans2_pctl'}.units = ncchar('ABS units');
cdfs{'abs_trans2_pctl'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans2_pctl'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans2_pctl'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans2_pctl'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans2_pctl'}.frequency = ncchar([num2str(cdfs.frequency2(:)),' Mhz']);
cdfs{'abs_trans2_pctl'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans2_pctl'}.epic_code = 1904;
cdfs{'abs_trans2_pctl'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans2_pctl_sq'} = ncfloat('burst','bin','pctile');
cdfs{'abs_trans2_pctl_sq'}.long_name = ncchar(['Squared Amplitude Percentiles at ',num2str(cdfs.frequency2(:)),' Mhz']);
cdfs{'abs_trans2_pctl_sq'}.units = ncchar('ABS units^2');
cdfs{'abs_trans2_pctl_sq'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans2_pctl_sq'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans2_pctl_sq'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans2_pctl_sq'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans2_pctl_sq'}.frequency = ncchar([num2str(cdfs.frequency2(:)),' Mhz']);
cdfs{'abs_trans2_pctl_sq'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans2_pctl_sq'}.epic_code = 1905;
cdfs{'abs_trans2_pctl_sq'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans3_pctl'} = ncfloat('burst','bin','pctile');
cdfs{'abs_trans3_pctl'}.long_name = ncchar(['Amplitude Percentiles at ',num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans3_pctl'}.units = ncchar('ABS units');
cdfs{'abs_trans3_pctl'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans3_pctl'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans3_pctl'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans3_pctl'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans3_pctl'}.frequency = ncchar([num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans3_pctl'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans3_pctl'}.epic_code = 1904;
cdfs{'abs_trans3_pctl'}.FillValue_ = ncfloat(1.00000004091848e+035);

cdfs{'abs_trans3_pctl_sq'} = ncfloat('burst','bin','pctile');
cdfs{'abs_trans3_pctl_sq'}.long_name = ncchar(['Squared Amplitude Percentiles at ',num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans3_pctl_sq'}.units = ncchar('ABS units^2');
cdfs{'abs_trans3_pctl_sq'}.valid_range = ncfloat([0 1e16]);
cdfs{'abs_trans3_pctl_sq'}.sensor_type = cdfs.INST_TYPE(:);
cdfs{'abs_trans3_pctl_sq'}.height = ncchar([num2str(cdfs.sensor_height(:)),' m']);
cdfs{'abs_trans3_pctl_sq'}.serial = ncchar(cdfs.serial_number(:));
cdfs{'abs_trans3_pctl_sq'}.frequency = ncchar([num2str(cdfs.frequency3(:)),' Mhz']);
cdfs{'abs_trans3_pctl_sq'}.FORTRAN_format = ncchar('F10.2');
cdfs{'abs_trans3_pctl_sq'}.epic_code = 1905;
cdfs{'abs_trans3_pctl_sq'}.FillValue_ = ncfloat(1.00000004091848e+035);
endef(cdfs)

return

% ---------------------- Subfunction ------------------------------------ %
function calc_minmax_vals(cdf)

theVars = var(cdf);
for i = 1:length(theVars),
    if ~strcmp(ncnames(theVars{i}),'time') && ...
       ~strcmp(ncnames(theVars{i}),'time2')
        data = theVars{i}(:);
        N = ndims(data);
        if N==1   %1D data
            theVars{i}.minimum = ncfloat(min(data));
            theVars{i}.maximum = ncfloat(max(data));
        elseif N==2 %2D data
            [row, col] = size(data);
            mins = ones(1,col);
            maxs = ones(1,col);
            for icol = 1:col
                mins(icol) = min(data(:,icol));
                maxs(icol) = max(data(:,icol));
            end
            theVars{i}.minimum = ncfloat(mins);
            theVars{i}.maximum = ncfloat(maxs);
            clear mins maxs
        elseif N==3 %3D data
            [row, col, lvl] = size(data);
            for jlvl = 1:lvl
                    mins(:,jlvl) = min(data(:,:,jlvl))';
                    maxs(:,jlvl) = max(data(:,:,jlvl))';
            end
            theVars{i}.minimum = ncfloat(mins);
            theVars{i}.maximum = ncfloat(maxs);
            clear mins maxs
        end
        clear data
    end
end
return


