function [ctd,varlabel,names,sensors]=ctd_rd(cnv_file,FMT) %#ok<*STOUT>
% CTD_RD Reads the SeaBird ASCII .CNV file format
%
% Usage: CTD=ctd_rd(cnv_file);
%
% Input: cnv_file = name of .CNV file (e.g. 'cast002.cnv')
%
% Output: CTD - a data structure containing the CTD data and header info.
%
% There are various formats possible for time/location information.
% Some of these can be handled with an optional second input parameter:
% CTD=ctd_rd(cnv_file,FORMAT)
%
% where FORMAT = 'NMEA' for SEASAVE output with GPS included through deckbox
%
% * System UpLoad Time = Oct 10 1999 18:20:32
% * NMEA Latitude = 48 36.69 N
% * NMEA Longitude = 123 13.07 W
% * NMEA UTC (Time) = Oct 10 1999 18:20:32
%
% 'IR' for an internally recording mode with a hand-typed
% header in this form:
%
% ** Latitude = 49 21.092 N
% ** Longitude = 121 49.028 W
% ** PST (Time) =Nov 23 2000 07:45
%
% will also work with SEASAVE output if no
% GPS NMEA string available.
% (default mode)
%
% If no '** Time' line gets it from System Upload Time
%
% 'RP' Ignore any header data but decode System Upload Time for
% the year, and the 'cast' line (DH command) for time -
% good for IR mode when to-yo-ing or otherwise too lazy
% to create proper headers.
%
% 'LAB' for a mode with no NMEA or header data (i.e. lab
% testing)
%
% Add more lat,lon and date string handling if your .CNV files are different.
%
% 4-8-98 Rich Signell (rsignell@usgs.gov)
% incorporates ideas from code by Derek Fong & Peter Brickley
% 19-9-99 R. pawlowicz (ric@ocgy.ubc.ca)
% - added a lot more decoding plus the idea of a data stucture for output
% 12-6-00 Changes variable names slightly.
% 19-2-02 dms as well as dmm.mm formats
% 20-5-11 modified by Rowan Fox (ro1@uvic.ca), adding in model #, temp
% sensor SN # & cond sensor SN
% 16-5-12 can now read new-format cnv files with xml info
if nargin==1
FMT='IR';
end
ctd.name='ctd';
ctd.station='';
% Open the .cnv file as read-only text
if contains(lower(cnv_file),'.cnv')
cnv_file=[cnv_file '.cnv'];
end
fid=fopen(cnv_file,'r');
% Read the header.
lat=[];
lon=[];
gtime=NaN(1,6);
tzone='unknown';
% Stop at line that starts with '*END*'
str='*START*';
while (~strncmp(str,'*END*',5))
str=fgetl(fid);
switch FMT
case 'NMEA'
if (strncmp(str,'* NMEA Lat',10))
lat=get_lat(str);
elseif (strncmp(str,'* NMEA Lon',10))
lon=get_lon(str);
elseif (strncmp(str,'* NMEA UTC',10))
gtime=get_timestamp(str);
tzone='UTC';
end
case 'IR'
if any(strfind(str,'Latitude')) || any(strfind(str,'Lat'))
lat=get_lat(str);
elseif any(strfind(str,'Longitude')) || any(strfind(str,'Long'))
lon=get_lon(str);
% Read the TIME string. This may vary with CTD setup. Will need
% ** xxxxxxxxxxTimexxxx = 21 Dec 2005 hh:mm:ss
% where timezone may also be in there somewhere.
elseif strncmp(str,'**',2) && any(strfind(str,'Time'))
gtime=get_timestamp(str);
tzone='unknown';
if any(strfind(str,'PST'))
tzone='PST';
elseif any(strfind(str,'PDT'))
tzone='PDT';
elseif any(strfind(str,'UTC'))
tzone='UTC';
elseif any(strfind(str,'EST'))
tzone='EST';
elseif any(strfind(str,'EDT'))
tzone='EDT';
end
% The default - get a time from the 'upload' string (usually the other time
% strings are later in the file so they will overwrite this, if they exist).
elseif (strncmp(str,'* System UpLoad',15))
tzone='unknown';
gtime=get_timestamp(str);
end
case 'LAB'
if (strncmp(str,'* System UpLoad',15))
tzone='unknown';
gtime=get_timestamp(str);
end
case 'RP'
if (strncmp(str,'* System UpLoad',15))
is=strfind(str,'=');
%EXTRACT THE UPLOAD YEAR FOR CAST START TIME Roger 2003sep04
upyearstr=str(is+9:is+12);
end
%-------------------------------------------------------------------
% READ CAST START TIME, SAMPLE RATE, COMPUTE mtime Roger 2003sep04
% * cast 0 06/23 17:38:06 samples 0 to 1334 sample rate = 1 scan every 0.5 seconds
if (strncmp(str,'* cast ',7))
%Find slash
indslash=find(str=='/');
indcolon=find(str==':');
if length(indslash)==1 && length(indcolon)>=2
datstr=[upyearstr ' '...
str(indslash-2:indslash-1) ' ' ...
str(indslash+1:indslash+2) ' ' ...
str(indcolon(1)-2:indcolon(1)-1) ' '...
str(indcolon(1)+1:indcolon(2)-1) ' '...
str(indcolon(2)+1:indcolon(2)+2)];
mtime=datenum(str2double(datstr));
gtime=datevec(mtime);
fprintf('Date from CAST START TIME in timezone of SBE clock\n');
else
error('ERROR: CAST START TIME: str does not have expected form')
end
end
%
otherwise
error('Unrecognized format specifier');
end
%-----------------------------
%
% Read the station name from a comment line
%
if (strncmpi((str),'** station',10))
ctd.station=strtrim(str(min(strfind(str,':'))+2:end));
%-----------------------------
%
% Read the ctd model from a comment line
%
elseif (strncmp(str,'* Sea-Bird',10))
ctd.model=str(strfind(str,'Sea-Bird SBE ')+13:strfind(str,' Data File')-1);
%-----------------------------
%
% Read the ctd temperature sensor SN from a comment line
%
elseif (strncmp(str,'* Temperature SN = ',19))
ctd.tempsn=str(strfind(str,'* Temperature SN = ')+19:end);
%-----------------------------
%
% Read the ctd conductivity sensor SN from a comment line
%
elseif (strncmp(str,'* Conductivity SN = ',20))
ctd.condsn=str(strfind(str,'* Conductivity SN = ')+20:end);
%-----------------------------
%
% Read the depth from a comment line
%
elseif (strncmpi((str),'** depth',8))
idelim=strfind(str,':');
ctd.depth=sscanf(str(idelim+1:end),'%f');
if isempty(ctd.depth), ctd.depth=NaN; end
% Units?
strrem=str(idelim+1:end);strrem(strrem>=48 & strrem<=57)=' '; %#ok<*NASGU>
if any(strfind(str(idelim+1:end),' m'))
% OK
elseif any(strfind(str(idelim+1:end),' ft'))
ctd.depth=ctd.depth*0.3048;
end
%------------------------------
%
% Get sampling interval
%
elseif (strncmp(str,'# interval',10))
ctd.samp_interval=sscanf(str(strfind(str,':')+1:end),'%f');
%------------------------------
%
% Get start time
%
elseif (strncmp(str,'# start_time',12))
ctd.start_time=str(15:end);
ctd.start_mtime=datenum(str(15:end),'mmm dd yyyy HH:MM:SS');
%------------------------------
%
% Read the variable names & units into a cell array
%
elseif (strncmp(str,'# name',6))
var=sscanf(str(7:10),'%d',1);
var=var+1;
ctd.varlabel{var}=str(strfind(str,'=')+2:min([strfind(str,':')-1 ...
strfind(str,'/')-1 strfind(str,'-')-1]));
%------------------------------
%
% Read the sensor names into a cell array
%
elseif (strncmp(str,'# sensor',8))
sens=sscanf(str(10:11),'%d',1);
sensors{sens+1}=str; %#ok<*AGROW>
%------------------------------
%
% Read the sensor ranges into a cell array
%
elseif (strncmp(str,'# span',6))
sens=sscanf(str(8:9),'%d',1);
ctd.spans{sens+1}=sscanf(str(strfind(str,'=')+1:end),'%f,%f');
%
% pick up bad flag value
elseif (strncmp(str,'# bad_flag',10))
isub=13:length(str);
bad_flag=sscanf(str(isub),'%g',1);
end
end
%==============================================
% Done reading header. Now read the data!
nvars=var; %number of variables
% Read the data into one big matrix
data=fscanf(fid,'%f',[nvars inf]).';
fclose(fid);
% Flag bad values with NaN
data(data==bad_flag)=NaN;
if exist('sensors'), ctd.sensors=char(sensors); end %#ok<*EXIST>
ctd.latitude=lat;
ctd.longitude=lon;
ctd.gtime=gtime;
ctd.mtime=datenum(gtime(1),gtime(2),gtime(3),gtime(4),gtime(5),gtime(6));
ctd.tzone=tzone;
if strcmp(FMT,'RP')
ctd.mtimescan=(0:size(data,1)-1)*ctd.samp_interval/86400+mtime;
end
labeldel=[];
for k=1:length(ctd.varlabel)
if diff(ctd.spans{k})~=0
eval(['ctd.' ctd.varlabel{k} '=data(:,k);']);
else
labeldel=[labeldel k];
end
end
ctd.varlabel(labeldel)=[];
ctd.spans(labeldel)=[];
return
%---------------------------------------------------
function lon=get_lon(str)
% decodes latitude from input string
% Get delimiter - '=' or ':'
is=strfind(str,'=');
if isempty(is), is=strfind(str,':'); end
isub=is+1:length(str);
dm=sscanf(str(isub),'%f');
% E or W
if(contains(str(isub),'E'))
sigl=1;
else
sigl=-1;
end
% dd.ddd or dd mm.mmm or dd mm ss formats
switch (length(dm))
case 1
lon=sigl*dm;
case 2
lon=sigl*(dm(1)+dm(2)/60);
case 3
lon=sigl*(dm(1)+dm(2)/60+dm(3)/3600);
otherwise
lon=NaN;
disp(['Can''t scan string ->' str '<- for longitude']);
end
return;
%---------------------------------------------------
function lat=get_lat(str)
% decodes latitude from input string
% Get delimiter - '=' or ':'
is=strfind(str,'=');
if isempty(is), is=strfind(str,':'); end
isub=is+1:length(str);
dm=sscanf(str(isub),'%f');
% N or S
if(contains(str(isub),'N'))
sigl=1;
else
sigl=-1;
end
% dd.ddd or dd mm.mmm or dd mm ss formats
switch (length(dm))
case 1
lat=sigl*dm;
case 2
lat=sigl*(dm(1)+dm(2)/60);
case 3
lat=sigl*(dm(1)+dm(2)/60+dm(3)/3600);
otherwise
lat=NaN;
disp(['Can''t scan string ->' str '<- for longitude']);
end
return;
%--------------------------------------------------
function gtime=get_timestamp(str)
% Decodes time string
% Time to right of '='
idelim=strfind(str,'=');
if any(idelim)
str=str(idelim+1:end);
else % try a colon delimiter
idelim=strfind(str,':');
if any(idelim)
str=str(idelim(1)+1:end);
end
end
% is there hh:mm:ss in there?
is=strfind(str,':');
if any(is)
isub=is(1)-2:length(str);
% Date in Dec 21 2005 HH:MM format
nbl=find(str(1:is(1)-3)~=' ');
datstr=str(min(nbl):max(nbl));
ibl=strfind(datstr,' ');
if length(ibl)==2
% Write into 21-Dec-2001 format which matlab can decode
datstr=[datstr(ibl(1)+1:ibl(2)-1) '-' datstr(1:ibl(1)-1) '-' datstr(ibl(2)+1:end)];
if ibl(2)-ibl(1)==2
datstr=['0' datstr];
end
gtime=datevec(datstr);
% Add hh:mm:ss
if length(is)==1
gtime(4:5)=sscanf(str(isub),'%d:%2d');
elseif length(is)==2
gtime(4:6)=sscanf(str(isub),'%d:%2d:%2d');
else
disp(['Can''t scan string ->' str '<- for time of day']);
gtime=[0 0 0 0 0 0];
end
else
disp(['Can''t scan string ->' str '<- for day of year']);
gtime=[0 0 0 0 0 0];
end
else
disp(['Can''t scan string ->' str '<- for time of day']);
gtime=[0 0 0 0 0 0];
end