function nc = defineSonarNcFile(outFileRoot, settings, ncdims, whichFlag); % called by procsonar_MM.m to create the netcdf files % % usage: nc = defineSonarNcFile(outFileRoot, settings, ncdims, whichFlag); % outFileRoot is the second argument to procsonarMM, ie. 'MVCOfantst' % settings containg parameters gleaned from th metadata.txt file, again an % argument to procsonarMM % ncdims defines the dimensions of the variables in the .nc files % whichFlag sayw whether to create the raw ('r') or processed format % % emontgomery from mmartini nc = netcdf([outFileRoot,'.cdf'],'clobber'); %% Global attributes: nc.CREATION_DATE = ncchar(' '); nc.DATA_TYPE = ncchar('IMAGE'); nc.DATA_SUBTYPE = ncchar(' '); nc.DATA_ORIGIN = ncchar('USGS/WHSC'); nc.EXPERIMENT = ncchar(' '); nc.PROJECT = ncchar(' '); nc.MOORING = ncchar(' '); nc.DELTA_T = ncchar(' '); nc.COMPOSITE = nclong(0); nc.DATA_CMNT = ncchar(' '); nc.POS_CONST = nclong(0); nc.DEPTH_CONST = nclong(0); nc.WATER_MASS = ncchar('?'); nc.DESCRIPT = ncchar(' '); nc.DRIFTER = nclong(0); nc.history = ncchar(' '); nc.start_time = ncchar(' '); nc.stop_time = ncchar(' '); nc.latitude = ncfloat(999); nc.longitude = ncfloat(999); nc.magnetic_variation = ncfloat(0); nc.water_depth = ncfloat(0); nc.CREATION_DATE = ncchar(' '); nc.INST_TYPE = ncchar(' '); % do different things with creating the file depending on whether you're % making a raw or processed file % set dimensions if (strncmp(upper(whichFlag),'R',1)) %R here is raw or processed- NOT rotate nc('time') = 0; %unlimited dimension nc('scan') = ncdims.nscans; nc('points') = ncdims.npoints; if strmatch(settings.SonartoAnimate,'azm') nc('rots')= ncdims.rots; end else % now do the processed if strmatch('fan',lower(settings.SonartoAnimate)) nc('time') = 0; %unlimited dimension nc('sweep')= ncdims.sweep; nc('x') = ncdims.x; nc('y') = ncdims.y; elseif strmatch('pen',lower(settings.SonartoAnimate)) nc('time') = 0; %unlimited dimension nc('sweep')= ncdims.sweep; nc('x') = ncdims.npoints; nc('z') = ncdims.nscans; elseif strmatch('azm', lower(settings.SonartoAnimate)) nc('time') = 0; %unlimited dimension nc('rots')= ncdims.rots; nc('x') = ncdims.npoints; nc('z') = ncdims.nscans; else nc('time') = 0; %unlimited dimension nc('sweep')= ncdims.sweep; nc('x') = ncdims.npoints; nc('z') = ncdims.nscans; end end % global attributes % write metadata metaFields = fieldnames(settings); for i = 1:length(metaFields) theField = metaFields{i}; theFieldDef = getfield(settings,theField); nRows = size(theFieldDef,1); nCols = size(theFieldDef,2); temp = []; if ischar(theFieldDef) if nRows>1 for ii = 1:nRows temp = [temp,' ',theFieldDef(ii,1:nCols)]; end theFieldDef = temp; end eval(['nc.',theField,' = ncchar(theFieldDef);']) else eval(['nc.',theField,'= ncfloat(theFieldDef);']) end end % write additional metadata nc.CREATION_DATE = ncchar(datestr(now)); % add coordinate variables in all data nc{'time'} = nclong('time'); nc{'time'}.FORTRAN_format = ncchar('F10.2'); nc{'time'}.units = ncchar('True Julian Day'); nc{'time'}.type = ncchar('EVEN'); nc{'time'}.epic_code = ncint(624); nc{'time2'} = nclong('time') ; nc{'time2'}.FORTRAN_format = ncchar('F10.2'); nc{'time2'}.units = ncchar('msec since 0:00 GMT'); nc{'time2'}.type = ncchar('EVEN'); nc{'time2'}.epic_code = ncint(624); % now do the raw vs processed fork, within which are fan and pencil % splits if (strncmp(upper(whichFlag),'R',1)) %fan and pencil can be treated the same here, but not azimuth. % add the rest of the coordinate vars as appropriate if strmatch('azm',lower(settings.SonartoAnimate)) nc{'scan'} = ncint('scan') ; nc{'scan'}.FORTRAN_format = ncchar('F10.2'); nc{'scan'}.units = ncchar('scan number in the radial sweep'); nc{'scan'}.type = ncchar('EVEN'); nc{'points'} = ncint('points') ; nc{'points'}.FORTRAN_format = ncchar('F10.2'); nc{'points'}.units = ncchar('number of points in each scan'); nc{'points'}.type = ncchar('EVEN'); nc{'rots'} = ncint('rots') ; nc{'rots'}.FORTRAN_format = ncchar('F10.2'); nc{'rots'}.units = ncchar('number of angles swept '); nc{'rots'}.type = ncchar('EVEN'); % we want head angle for sure nc{'headangle'} = ncfloat('time','rots','points'); nc{'headangle'}.long_name = ncchar('angle of xducer head during scan'); nc{'headangle'}.units = ncchar('degrees relative to head orientation'); nc{'headangle'}.valid_range = ncfloat([-180 180]); nc{'headangle'}.FORTRAN_format = ncchar('F10.2'); nc{'headangle'}.FillValue_ = ncfloat(settings.FillVal); nc{'headangle'}.note1 = ncchar('headangle is computed from head_pos'); % we want head angle for sure nc{'azangle'} = ncint('time','rots'); nc{'azangle'}.long_name = ncchar('rotatio nangle of xducer head during scan'); nc{'azangle'}.units = ncchar('degrees relative to xducer 0'); nc{'azangle'}.valid_range = ncfloat([0 180]); nc{'azangle'}.FORTRAN_format = ncchar('F10.2'); nc{'azangle'}.FillValue_ = ncfloat(settings.FillVal); nc{'azangle'}.note1 = ncchar('azangle is only possible for .R## files'); % now profile_range nc{'profile_range'} = ncint('time','rots','points'); nc{'profile_range'}.long_name = ncchar('first value above threshold'); nc{'profile_range'}.units = ncchar('cm'); nc{'profile_range'}.valid_range = ncfloat([0 5000]); nc{'profile_range'}.FORTRAN_format = ncchar('F10.2'); nc{'profile_range'}.FillValue_ = ncfloat(settings.FillVal); nc{'profile_range'}.note1 = ncchar('profile_range is returned in each scan header: combined into a vector'); nc{'profile_range'}.note2 = ncchar('var_name matches Imagenex doc'); % now a matrix of the image data nc{'raw_image'} = ncint('time','rots','points','scan'); nc{'raw_image'}.long_name = ncchar('sonar return echo intensity'); nc{'raw_image'}.units = ncchar('?'); nc{'raw_image'}.valid_range = ncfloat([0 252]); nc{'raw_image'}.sensor_type = nc.INST_TYPE(:); nc{'raw_image'}.FORTRAN_format = ncchar('F10.2'); nc{'raw_image'}.FillValue_ = ncfloat(settings.FillVal); nc{'raw_image'}.scale_factor = ncint(1); nc{'raw_image'}.note1 = ncchar('raw image is matrix of amplitudes as returned by logger'); nc.VAR_DESC = ncchar('points:scans:rots:Headangle:azangle:profile_range:raw_image'); else nc{'scan'} = ncint('scan') ; nc{'scan'}.FORTRAN_format = ncchar('F10.2'); nc{'scan'}.units = ncchar('scan number in the radial sweep'); nc{'scan'}.type = ncchar('EVEN'); nc{'points'} = ncint('points') ; nc{'points'}.FORTRAN_format = ncchar('F10.2'); nc{'points'}.units = ncchar('number of points in each scan'); nc{'points'}.type = ncchar('EVEN'); % we want head angle for sure nc{'headangle'} = ncfloat('time','scan'); nc{'headangle'}.long_name = ncchar('angle of xducer head during scan'); nc{'headangle'}.units = ncchar('degrees relative to head orientation'); nc{'headangle'}.valid_range = ncfloat([-180 180]); nc{'headangle'}.FORTRAN_format = ncchar('F10.2'); nc{'headangle'}.FillValue_ = ncfloat(settings.FillVal); nc{'headangle'}.note1 = ncchar('headangle is computed from head_pos'); % now profile_range nc{'profile_range'} = ncfloat('time','scan'); nc{'profile_range'}.long_name = ncchar('first value above threshold'); nc{'profile_range'}.units = ncchar('cm'); nc{'profile_range'}.valid_range = ncfloat([0 5000]); nc{'profile_range'}.FORTRAN_format = ncchar('F10.2'); nc{'profile_range'}.FillValue_ = ncfloat(settings.FillVal); nc{'profile_range'}.note1 = ncchar('profile_range is returned in each scan header: combined into a vector'); nc{'profile_range'}.note2 = ncchar('var_name matches Imagenex doc'); % now head position nc{'head_pos'} = ncfloat('time','scan'); nc{'head_pos'}.long_name = ncchar('Head position during scan'); nc{'head_pos'}.units = ncchar('numeric location'); nc{'head_pos'}.valid_range = ncfloat([0 5000]); nc{'head_pos'}.FORTRAN_format = ncchar('F10.2'); nc{'head_pos'}.FillValue_ = ncfloat(settings.FillVal); nc{'head_pos'}.note1 = ncchar('head_pos is returned in each scan header: combined into a vector'); nc{'head_pos'}.note2 = ncchar('var_name matches Imagenex doc'); nc{'head_pos'}.note2 = ncchar('angle=deg/step*(head_pos-1400)'); % now NDataBytes nc{'nDataBytes'} = ncfloat('time','scan'); nc{'nDataBytes'}.long_name = ncchar('number of data bytes/scan'); nc{'nDataBytes'}.units = ncchar('number'); nc{'nDataBytes'}.valid_range = ncfloat([0 5000]); nc{'nDataBytes'}.FORTRAN_format = ncchar('F10.2'); nc{'nDataBytes'}.FillValue_ = ncfloat(settings.FillVal); nc{'nDataBytes'}.note1 = ncchar('nDataBytes is returned in each scan header: combined into a vector'); nc{'nDataBytes'}.note2 = ncchar('var_name matches Imagenex doc'); % now a matrix of the image data nc{'raw_image'} = ncfloat('time','points','scan'); nc{'raw_image'}.long_name = ncchar('sonar return echo intensity'); nc{'raw_image'}.units = ncchar('?'); nc{'raw_image'}.valid_range = ncfloat([0 252]); nc{'raw_image'}.sensor_type = nc.INST_TYPE(:); nc{'raw_image'}.FORTRAN_format = ncchar('F10.2'); nc{'raw_image'}.FillValue_ = ncfloat(settings.FillVal); nc{'raw_image'}.scale_factor = ncint(1); nc{'raw_image'}.note1 = ncchar('raw image is matrix of return amplitudes as returned by logger'); nc.VAR_DESC = ncchar('points:scans:head_pos:Headangle:nDataBytes:profile_range:raw_image'); end else % now do processed data files %fan and pencil have different contents and variable names if strmatch('fan',lower(settings.SonartoAnimate)) nc{'x'} = ncfloat('x') ; nc{'x'}.FORTRAN_format = ncchar('F10.2'); nc{'x'}.long_name = ncchar('interpolated horizontal distance from sonar'); nc{'x'}.valid_range = ncfloat([-5 5]); nc{'x'}.units = ncchar('m'); nc{'x'}.type = ncchar('EVEN'); nc{'y'} = ncfloat('y') ; nc{'y'}.FORTRAN_format = ncchar('F10.2'); nc{'y'}.long_name = ncchar('interpolated horizontal distance from sonar'); nc{'y'}.valid_range = ncfloat([-5 5]); nc{'y'}.units = ncchar('m'); nc{'y'}.type = ncchar('EVEN'); nc{'sweep'} = ncint('sweep') ; nc{'sweep'}.FORTRAN_format = ncchar('I4'); nc{'sweep'}.long_name = ncchar('integer sweep number'); nc{'sweep'}.valid_range = ncfloat([1 12]); nc{'sweep'}.units = ncchar('none '); nc{'sweep'}.type = ncchar('EVEN'); % a scale factor is applied to the variable 'sonar_image' in order to store % the image data as an integer rather than a float. nc{'sonar_image'} = ncfloat('time','sweep','x','y'); nc{'sonar_image'}.long_name = ncchar('Imagenex Sonar Image'); nc{'sonar_image'}.units = ncchar('?'); nc{'sonar_image'}.valid_range = ncfloat([0 log10(256)*1000]); nc{'sonar_image'}.sensor_type = nc.INST_TYPE(:); nc{'sonar_image'}.FORTRAN_format = ncchar('F10.2'); nc{'sonar_image'}.FillValue_ = settings.FillVal; nc{'sonar_image'}.scale_factor = ncfloat(1000); % adding the notes below makes a ncdim error occur, so % commenting out for now % nc('sonar_image').note1 = ncchar('made polar and rotated so +y is North'); % nc('sonar_image').note2 = ncchar('the interpolated onto an x-y grid'); nc.VAR_DESC=ncchar('x:y:sweep:sonar_image'); elseif strmatch('pen',lower(settings.SonartoAnimate)) % pencil %horizontal scale for sonar_image nc{'x'} = ncfloat('x') ; nc{'x'}.FORTRAN_format = ncchar('F10.2'); nc{'x'}.long_name = ncchar('interpolated horizontal distance from sonar'); nc{'x'}.valid_range = ncfloat([-5 5]); nc{'x'}.units = ncchar('m'); nc{'x'}.type = ncchar('EVEN'); %vertical scale for sonar_image nc{'z'} = ncfloat('z') ; nc{'z'}.FORTRAN_format = ncchar('F10.2'); nc{'z'}.long_name = ncchar('interpolated vertical distance from sonar'); nc{'z'}.valid_range = ncfloat([-5 0]); nc{'z'}.units = ncchar('m'); nc{'z'}.type = ncchar('EVEN'); % now allow the sweeps nc{'sweep'} = ncint('sweep') ; nc{'sweep'}.FORTRAN_format = ncchar('I4'); nc{'sweep'}.long_name = ncchar('integer sweep number'); nc{'sweep'}.valid_range = ncfloat([1 12]); nc{'sweep'}.units = ncchar('none '); nc{'sweep'}.type = ncchar('EVEN'); % horizontal distance- use with elev and max_ret % may only need one of these but keeping all for now nc{'hdst'} = ncfloat('time','sweep','x') ; nc{'hdst'}.FORTRAN_format = ncchar('F10.2'); nc{'hdst'}.long_name = ncchar('horizontal distance from below sonar head-interpolated '); nc{'hdst'}.valid_range = ncfloat([-5 5]); nc{'hdst'}.units = ncchar('m'); nc{'hdst'}.type = ncchar('EVEN'); nc{'hdst'}.FillValue_ = ncfloat(settings.FillVal); % height (or elevation) of max return nc{'elev'} = ncfloat('time','sweep','x'); nc{'elev'}.long_name = ncchar('Distance to strongest pencil return (seafloor) -interpolated'); nc{'elev'}.units = ncchar('m'); nc{'elev'}.valid_range = ncfloat([-5 0]); nc{'elev'}.FORTRAN_format = ncchar('F10.2'); nc{'elev'}.FillValue_ = ncfloat(settings.FillVal); %value of the max return the height in elev % anything with the potential to have fillvalue has to be ncfloat nc{'max_ret'} = ncfloat('time','sweep','x'); nc{'max_ret'}.long_name = ncchar('value of highest return of Pencil Beam scans- interpolated'); nc{'max_ret'}.units = ncchar(''); nc{'max_ret'}.valid_range = ncfloat([0 255]); nc{'max_ret'}.sensor_type = nc.INST_TYPE(:); nc{'max_ret'}.FORTRAN_format = ncchar('F10.2'); nc{'max_ret'}.FillValue_ = settings.FillVal; nc{'max_ret'}.scale_factor = ncint(1); % for the shaped image showing max_ret and elev nc{'sonar_image'} = ncfloat('time','sweep','x','z'); nc{'sonar_image'}.long_name = ncchar('Imagenex Sonar Image'); nc{'sonar_image'}.units = ncchar('?'); nc{'sonar_image'}.valid_range = ncfloat([0 256]); nc{'sonar_image'}.sensor_type = nc.INST_TYPE(:); nc{'sonar_image'}.FORTRAN_format = ncchar('F10.2'); nc{'sonar_image'}.FillValue_ = settings.FillVal; nc{'sonar_image'}.scale_factor = ncint(1000); % found in slant range coords, then trig done to compensate nc{'rdst'} = ncfloat('time','x') ; nc{'rdst'}.FORTRAN_format = ncchar('F10.2'); nc{'rdst'}.long_name = ncchar('horizontal distance from below middle of sonar head -raw'); nc{'rdst'}.valid_range = ncfloat([-5 5]); nc{'rdst'}.units = ncchar('m'); nc{'rdst'}.type = ncchar('EVEN'); nc{'rdst'}.FillValue_ = ncfloat(settings.FillVal); % height of max return nc{'relev'} = ncfloat('time','x'); nc{'relev'}.long_name = ncchar('vertical Distance to seafloor -raw'); nc{'relev'}.units = ncchar('m'); nc{'relev'}.valid_range = ncfloat([0 settings.max_range]); nc{'relev'}.FORTRAN_format = ncchar('F10.2'); nc{'relev'}.FillValue_ = settings.FillVal; nc.VAR_DESC=ncchar('x:z:hdst:elev:max_ret:sonar_image'); elseif strmatch('azm',lower(settings.SonartoAnimate)) nc{'x'} = ncfloat('x') ; nc{'x'}.FORTRAN_format = ncchar('F10.2'); nc{'x'}.long_name = ncchar('interpolated horizontal distance from sonar'); nc{'x'}.valid_range = ncfloat([-5 5]); nc{'x'}.units = ncchar('m'); nc{'x'}.type = ncchar('EVEN'); nc{'y'} = ncfloat('y') ; nc{'y'}.FORTRAN_format = ncchar('F10.2'); nc{'y'}.long_name = ncchar('interpolated horizontal distance from sonar'); nc{'y'}.valid_range = ncfloat([-5 5]); nc{'y'}.units = ncchar('m'); nc{'y'}.type = ncchar('EVEN'); nc{'rot_ang'} = ncint('rot_angle') ; nc{'rot_ang'}.FORTRAN_format = ncchar('I4'); nc{'rot_ang'}.long_name = ncchar('integer sweep number'); nc{'rot_ang'}.valid_range = ncfloat([1 180]); nc{'rot_ang'}.units = ncchar('none '); nc{'rot_ang'}.type = ncchar('EVEN'); % a scale factor is applied to the variable 'sonar_image' in order to store % the image data as an integer rather than a float. nc{'sonar_image'} = ncfloat('time','rot_angle','x','y'); nc{'sonar_image'}.long_name = ncchar('Imagenex Sonar Image'); nc{'sonar_image'}.units = ncchar('?'); nc{'sonar_image'}.valid_range = ncfloat([0 log10(256)*1000]); nc{'sonar_image'}.sensor_type = nc.INST_TYPE(:); nc{'sonar_image'}.FORTRAN_format = ncchar('F10.2'); nc{'sonar_image'}.FillValue_ = settings.FillVal; nc{'sonar_image'}.scale_factor = ncint(1000); % adding the notes below makes a ncdim error occur, so % commenting out for now % nc('sonar_image').note1 = ncchar('made polar and rotated so +y is North'); % nc('sonar_image').note2 = ncchar('the interpolated onto an x-y grid'); nc.VAR_DESC=ncchar('x:y:rot_ang:sonar_image'); else disp('does not match existing categories - not processing') exit end end