function nc = definerawsonarncfile(outFileRoot, settings, ncdims, whichFlag) % definerawsonarncfile - Set up netcdf file for raw sonar data % nc = defineSonarNcFile(outFileRoot, settings, ncdims, whichFlag); % % outFileRoot - name of output .cdf file % settings - parameters gleaned from the metadata.txt file, % ncdims - dimensions of the variables in the .nc files % whichFlag - no longer used (can omit the variable), used to have to be 'r' % 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/WHCMSC'); 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.DESCRIPTION = 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.CREATION_DATE = ncchar(' '); nc.INST_TYPE = ncchar(' '); nc.Conventions = ncchar('EPIC'); nc.platform_type=ncchar('tripod'); % set dimensions nc('time') = 0; %unlimited dimension nc('scan') = ncdims.nscans; nc('points') = ncdims.npoints; if strmatch(settings.SonartoAnimate,'azm') nc('rots')= ncdims.rots; end % write metadata into global attributes 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 % since we only have one instrument of each type we can do this- if we get % more variety, this code will have to change if strmatch(settings.SonartoAnimate,'azm') sn='3937'; type='rotating Imagenex Model 881A Digital profiling sonar'; elseif strmatch(settings.SonartoAnimate,'pen') sn='3937'; type='Imagenex Model 881A Digital profiling sonar'; else sn='1751'; type='Imagenex Model 881 Digital tilt adjusting imaging sonar'; end nc.INST_TYPE(:)=type; nc.serial_number=ncchar(sn); % write additional metadata nc.CREATION_DATE = ncchar(datestr(now)); % add coordinate variables in all data nc{'time'} = nclong('time'); nc{'time'}.units = ncchar('EPIC Julian Day'); nc{'time'}.type = ncchar('EVEN'); nc{'time'}.epic_code = ncshort(624); nc{'time2'} = nclong('time') ; nc{'time2'}.units = ncchar('msec since 0:00 GMT'); nc{'time2'}.type = ncchar('EVEN'); nc{'time2'}.epic_code = ncshort(624); % 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'} = ncshort('scan') ; nc{'scan'}.units = ncchar('scan number'); nc{'scan'}.type = ncchar('EVEN'); nc{'points'} = ncshort('points') ; nc{'points'}.units = ncchar('number of points in each scan'); nc{'points'}.type = ncchar('EVEN'); nc{'rots'} = ncshort('rots') ; nc{'rots'}.units = ncchar('number of angles swept '); nc{'rots'}.type = ncchar('EVEN'); % we want head angle for sure nc{'headangle'} = ncfloat('time','rots','scan'); nc{'headangle'}.long_name = ncchar('angle of transducer head during scan'); nc{'headangle'}.units = ncchar('degrees relative to head orientation'); nc{'headangle'}.valid_range = ncfloat([-180 180]); nc{'headangle'}.initial_sensor_height = ncfloat(nc.Height(:)); nc{'headangle'}.sensor_depth = ncfloat(nc.WATER_DEPTH(:)-nc.Height(:)); nc{'headangle'}.serial_number = ncchar(sn); nc{'headangle'}.sensor_type = ncchar(type); nc{'headangle'}.height_depth_units = ncchar('m'); nc{'headangle'}.FillValue_ = ncfloat(1e35); nc{'headangle'}.NOTE1 = ncchar('headangle is computed from head_pos'); % we want az angle for sure nc{'azangle'} = ncshort('time','rots'); nc{'azangle'}.long_name = ncchar('rotation angle of transducer during scan'); nc{'azangle'}.units = ncchar('degrees relative to transducer 0'); nc{'azangle'}.valid_range = ncshort([0 180]); nc{'azangle'}.initial_sensor_height = ncfloat(nc.Height(:)); nc{'azangle'}.sensor_depth = ncfloat(nc.WATER_DEPTH(:)-nc.Height(:)); nc{'azangle'}.height_depth_units = ncchar('m'); nc{'azangle'}.serial_number = nc.serial_number(:); nc{'azangle'}.sensor_type = nc.INST_TYPE(:)' nc{'azangle'}.FillValue_ = ncshort(-32767); nc{'azangle'}.NOTE1 = ncchar('azangle is only possible for .R## files'); % now profile_range (only for azimuth) nc{'profile_range'} = ncshort('time','rots','scan'); nc{'profile_range'}.long_name = ncchar('first value above threshold'); nc{'profile_range'}.units = ncchar('cm'); nc{'profile_range'}.valid_range = ncfloat([0 1500]); nc{'profile_rangee'}.initial_sensor_height = ncfloat(nc.Height(:)); nc{'profile_range'}.sensor_depth = ncfloat(nc.WATER_DEPTH(:)-nc.Height(:)); nc{'profile_range'}.serial_number = nc.serial_number(:); nc{'profile_range'}.sensor_type = nc.INST_TYPE(:) 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'} = ncshort('time','rots','points','scan'); nc{'raw_image'}.long_name = ncchar('sonar return echo intensity'); nc{'raw_image'}.units = ncchar('counts'); nc{'raw_image'}.valid_range = ncshort([0 127]); nc{'raw_image'}.initial_sensor_height = ncfloat(nc.Height(:)); nc{'raw_image'}.sensor_depth = ncfloat(nc.WATER_DEPTH(:)-nc.Height(:)); nc{'raw_image'}.serial_number = nc.serial_number(:); nc{'raw_image'}.sensor_type = nc.INST_TYPE(:); nc{'raw_image'}.height_depth_units = ncchar('m'); nc{'raw_image'}.FillValue_ = ncshort(-32767); 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 % for fan and pencil nc{'scan'} = ncshort('scan') ; nc{'scan'}.units = ncchar('scan number'); nc{'scan'}.type = ncchar('EVEN'); % nc{'points'} = ncshort('points') ; nc{'points'}.units = ncchar('number of points'); nc{'points'}.type = ncchar('EVEN'); % we want head angle for sure nc{'headangle'} = ncfloat('scan'); nc{'headangle'}.long_name = ncchar('angle of transducer head during scan'); nc{'headangle'}.units = ncchar('degrees relative to head orientation'); nc{'headangle'}.valid_range = ncfloat([-180 180]); nc{'headangle'}.initial_sensor_height = ncfloat(nc.Height(:)); nc{'headangle'}.sensor_depth = ncfloat(nc.WATER_DEPTH(:)-nc.Height(:)); nc{'headangle'}.height_depth_units = ncchar('m'); nc{'headangle'}.serial_number = nc.serial_number(:); nc{'headangle'}.sensor_type = nc.INST_TYPE(:); nc{'headangle'}.FillValue_ = ncfloat(1e35); nc{'headangle'}.NOTE1 = ncchar('headangle is computed from head_pos'); % now profile_range nc{'profile_range'} = ncshort('time','scan'); nc{'profile_range'}.long_name = ncchar('first value above threshold'); nc{'profile_range'}.units = ncchar('cm'); nc{'profile_range'}.valid_range = ncshort([0 2048]); nc{'profile_range'}.initial_sensor_height = ncfloat(nc.Height(:)); nc{'profile_range'}.sensor_depth = ncfloat(nc.WATER_DEPTH(:)-nc.Height(:)); nc{'profile_range'}.height_depth_units = ncchar('m'); nc{'profile_range'}.serial_number = nc.serial_number(:); nc{'profile_range'}.sensor_type = nc.INST_TYPE(:); nc{'profile_range'}.FillValue_ = ncshort(-32767); 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'} = ncshort('time','scan'); nc{'head_pos'}.long_name = ncchar('Head position during scan'); nc{'head_pos'}.units = ncchar('numeric location'); nc{'head_pos'}.valid_range = ncshort([0 5000]); nc{'head_pos'}.initial_sensor_height = ncfloat(nc.Height(:)); nc{'head_pos'}.sensor_depth = ncfloat(nc.WATER_DEPTH(:)-nc.Height(:)); nc{'head_pos'}.height_depth_units = ncchar('m'); nc{'head_pos'}.serial_number = nc.serial_number(:); nc{'head_pos'}.sensor_type = nc.INST_TYPE(:); nc{'head_pos'}.FillValue_ = ncshort(-32767); 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 a matrix of the image data nc{'raw_image'} = ncshort('time','points','scan'); nc{'raw_image'}.long_name = ncchar('sonar return echo intensity'); nc{'raw_image'}.units = ncchar('?'); nc{'raw_image'}.valid_range = ncshort([0 252]); nc{'raw_image'}.initial_sensor_height = ncfloat(nc.Height(:)); nc{'raw_image'}.sensor_depth = ncfloat(nc.WATER_DEPTH(:)-nc.Height(:)); nc{'raw_image'}.sensor_type = nc.INST_TYPE(:); nc{'raw_image'}.height_depth_units = ncchar('m'); nc{'raw_image'}.serial_number = nc.serial_number(:); nc{'raw_image'}.sensor_type = nc.INST_TYPE(:); nc{'raw_image'}.FillValue_ = ncshort(-32767); nc{'raw_image'}.scale_factor = ncshort(1); nc{'raw_image'}.NOTE1 = ncchar('raw image is matrix of return amplitudes as returned by logger'); % now NDataBytes nc{'nDataBytes'} = ncshort('scan'); nc{'nDataBytes'}.long_name = ncchar('number of data bytes/scan'); nc{'nDataBytes'}.units = ncchar('count'); nc{'nDataBytes'}.valid_range = ncshort([0 550]); nc{'nDataBytes'}.initial_sensor_height = ncfloat(nc.Height(:)); nc{'nDataBytes'}.sensor_depth = ncfloat(nc.WATER_DEPTH(:)-nc.Height(:)); nc{'nDataBytes'}.height_depth_units = ncchar('m'); nc{'nDataBytes'}.serial_number = nc.serial_number(:); nc{'nDataBytes'}.sensor_type = nc.INST_TYPE(:); nc{'nDataBytes'}.FillValue_ = ncshort(-32767); nc{'nDataBytes'}.NOTE1 = ncchar('nDataBytes is returned in each scan header: combined into a vector'); nc{'nDataBytes'}.NOTE2 = ncchar('var_name matches Imagenex doc'); % nc.VAR_DESC = ncchar('points:scans:head_pos:Headangle:nDataBytes:profile_range:raw_image'); end