NRGSymphonieRead

by

 

26 Aug 2010 (Updated )

NRGSymphonieRead imports NRG Systems Symphonie data logger text files.

Editor's Notes:

This file was selected as MATLAB Central Pick of the Week

NRGSymphonieRead.m
function [site,data] = NRGSymphonieRead(FileName)
%% NRGSYMPHONIEREAD imports NRG Systems Symphonie data files
% NRGSymphonieRead imports the text files produced from NRG Symphonie data
% logger. NRGSymphonieRead requires the Statistics Toolbox.
%
% usage: [site,data] = NRGSymphonieRead(FileName)
% 
% Inputs
% FileName = name of file to import data from 
% 
% Outputs
% site = structure containing the site and channel meta data
% data = dataset array containing the collected data
% 
%
% This function is designed to read the text file output of the NRG Systems
% Symphonie Data Retriever, which is a conversion utility that to generate 
% text files from the raw binary files from the data logger.  The MATLAB 
% function assumes that the text file is structured with many lines of 
% header information followed by a delimited table of data below.  The 
% header information is separated into sections based off of dividers in 
% the text file such as -----Logger Information-----.  The header 
% information is stored at a MATLAB structure.  The data table is assumed 
% to start with the string Date & Time Stamp.  The data table is stored in
% MATLAB as a dataset array.  Even thought certain assumptions were made 
% creating the NRGSymphonieReader, the function should also be useful as an
% example for creating similar functions for other text files with a header
% and data table.  An example data file, names exampledata.txt, is provided
% as reference for those unfamiliar with this file structure.  

% Copyright 2010 The MathWorks, Inc.
%   Author(s): T. Schultz

%% Check for inputs
if nargin > 1   % too many inputs provided
    error('NRGSymphonieread:argChk', ['This function only takes the ' ... 
                                      'file name as an input.'])
elseif nargin == 0   % no file name provided
    [FileName,PathName] = uigetfile('*.*');
    FileName = fullfile(PathName,FileName);
end

%% Check for outputs
if nargout ~= 2
    error('NRGSymphonieread:argChk', ['This function requires two' ...
           ' output arguments.']);
end

%% Open file
[fid,msg] = fopen(FileName);
if ~isempty(msg)
    error('NRGSymphonieread:fileChk','Cannot open selected file.')
end

%% File properties
delimiter = '\t';               % data delimiter
idStr = 'Date & Time Stamp';   % string that identifies start of data table

%% Read file into memory upto data table
lflag = true;
x = cell(200,1);                % initialize cell array for header text
iline = 0;                      % line number counter
idx = [];                       % line number for start of data table

while lflag
    tline = fgetl(fid);
    if ~ischar(tline)           % found end of file
        lflag = false;
    elseif ~isempty(regexp(tline,idStr,'once'))    % reached data table
        iline = iline + 1;
        idx = iline;
        tt = tline;
        lflag = false;
    else                        % found text header line
        iline = iline + 1;
        x{iline} = tline;
    end
end
x = x(~cellfun(@isempty,x));    % remove empty lines

%% Close file
fclose(fid);

%% Parse header info
% Parse and store header information into a MATLAB structure and determine
% the number of channels on the data logger and which channels were active.
site = struct;                  % structure for site info storage

% find sections in header
% the sections in this header file are of the form '-----Some Text-----'
sectionName = regexp(x,'^--+(.*?)--+','tokens','once');
iSection = cellfun(@(x) ~isempty(x),sectionName);
idxSection = find(iSection == true);

sectionName = [sectionName{iSection}]';

% remove any odd-ball characters and generate valid variable names
sectionName = regexprep(sectionName, '\W', ' ','ignorecase');
sectionName = genvarname(sectionName);

%% Handle case if line 1 isn't a section line
if idxSection ~= 1
    iline = 1;                  % start at the first line
    while iline < idxSection(1)
        % split header string into variable name and value
        [varName,varValue] = splitstring(x{iline},delimiter);
        
        % write to structure
        site.(varName) = varValue;
        iline = iline + 1;
    end
end

%% Handle remaining header sections
% This section will require modification for other text files.
for ii = 1:length(idxSection)
    % create structure field
    site.(sectionName{ii}) = [];
    
    % determine header lines in this section
    if ii == length(idxSection)
        iline = idxSection(ii) + 1:length(x);
    else
        iline = idxSection(ii) + 1: idxSection(ii+1) - 1;
    end
    
    switch lower(sectionName{ii})
        case 'sensorinformation'        % header section with subsections
            % reduce string to just the sensor info section
            sensor = x(iline);
            
            % determine location of channels
            startIndex = regexp(sensor,'^Channel','once');
            % determine number of channels
            nCH = cellfun(@(x) ~isempty(x),startIndex);
            idxCH = find(nCH == true);
            nCH = sum(nCH);
            
            % determine # of lines of text per sensor channel
            nline = mean(diff(idxCH)) - 1;
            activeCH = true(nCH,1);     % logical vector for active sensors
            for jj = 1:nCH
                site.(sectionName{ii}).(['CH' num2str(jj)]) = [];
                for kk = 1:nline
                    % split header string into variable name and value
                    [varName,varValue] = ... 
                               splitstring(sensor{idxCH(jj)+kk},delimiter);
            
                    % write to structure
                    site.(sectionName{ii}).(['CH' num2str(jj)]).(varName) ... 
                        = varValue;
                    
                    % check for active or inactive channel
                    if strcmp(varName,'Type')
                        activeCH(jj)= varValue ~= 0;
                    end
                end
            end
        case {'loggerinformation', 'siteinformation'}   % header sections
            for jj = 1:length(iline)
                % split header string into variable name and value
                [varName,varValue] = splitstring(x{iline(jj)},delimiter);
                
                % write to structure
                site.(sectionName{ii}).(varName) = varValue;
            end
    end
end

% save active channel list to site structure
site.activeCH = activeCH;

%% Read in data using dataset
% Use the dataset class to read in the tabular data.

% find the number of columns in the data table
startIndex = regexp(tt, delimiter);
nCol = length(startIndex) + 1;

% create format string, first column is date strings, the rest are numbers
fstr = ['%s ' repmat('%f ',1,nCol-1)];

% read in the data
data = dataset('File',FileName,'Delimiter',delimiter,'Format',fstr, ... 
               'HeaderLines',idx-1);

% change variable name for date and time stamp
data.Properties.VarNames{1} = 'DateTimeStamp';

end                         % [EOF]

function [varName,varValue] = splitstring(str,varargin)
%% SPLITSTRING splits a string into two parts
% Splits the intput string, str, into two parts based on the delimiter in
% the string. The default delimiter is '\t' but can be supplied as an
% optional second input.  

% Check input arguments
if nargin == 1
    delimiter = '\t';
elseif nargin == 2
    delimiter = varargin{1};
else
    error('NRGSymphonieread:splitstring:argChk', ... 
          'Too many inputs provided.')
end

% find delimiter and split string into parts
str = regexp(str,delimiter,'split');

% remove any odd-ball characters
str{1} = regexprep(str{1}, '\W', ' ','ignorecase');

% generate valid variable name and variable value
varName = genvarname(str{1});
varValue = str{2};

% test if varValue is valid numeric
tmp = str2double(varValue);
if ~isnan(tmp)
    varValue = tmp;
end

end                         % [EOF]

Contact us