Files
nappMATLAB-toolbox/import/importJeti.m
T

262 lines
6.7 KiB
Matlab

function dataTable = importJeti(filename)
%IMPORTJETI Import JETI SPECBOS irradiance data (CSV or TXT format)
% DATATABLE = IMPORTJETI(FILENAME) reads data from text file FILENAME.
%
% Supports:
% 1. CSV: Semicolon-separated with header metadata
% 2. isd: txt-style format with [sections] and tab-separated data
%
% Example:
% table = importJeti("20251212_1606_Jeti.csv");
% table = importJeti("spectrum_#2.isd");
%% Determine file type and route accordingly
[~, ~, ext] = fileparts(filename);
if strcmpi(ext, '.csv')
dataTable = importCSV(filename);
elseif strcmpi(ext, '.isd')
dataTable = importTXT(filename);
else
error('Unsupported file format: %s. Use .csv or .isd', ext);
end
end
%% ========== CSV IMPORT FUNCTION ==========
function dataTable = importCSV(filename)
fid = fopen(filename, 'r');
if fid == -1
error('Cannot open file: %s', filename);
end
metadata = struct();
metadata.numDatasets = NaN;
metadata.numPoints = NaN;
metadata.Date = {};
metadata.Time = {};
lineIdx = 0;
dataHeaderLineIdx = NaN;
while true
thisLine = fgetl(fid);
if ~ischar(thisLine)
break
end
lineIdx = lineIdx + 1;
% Detect start of data header line
if contains(thisLine, 'Wavelength [nm]')
dataHeaderLineIdx = lineIdx;
break
end
parts = strsplit(thisLine, ';');
if isempty(parts)
continue
end
key = strtrim(parts{1});
switch key
case 'Number of datasets'
if numel(parts) >= 2
metadata.numDatasets = str2double(strtrim(parts{2}));
end
case 'Number of points'
if numel(parts) >= 2
metadata.numPoints = str2double(strtrim(parts{2}));
end
case 'Date'
if numel(parts) >= 2
metadata.Date = parts(2:end);
end
case 'Time'
if numel(parts) >= 2
metadata.Time = parts(2:end);
end
end
end
if isnan(dataHeaderLineIdx)
fclose(fid);
error('Could not find data header line in CSV.');
end
firstDataLineInFile = dataHeaderLineIdx + 1;
fclose(fid);
% Derive number of columns:
% If 'Number of datasets' is present: use it.
% Otherwise infer from the header line (new Spec1/Spec2 format).[file:1]
fid = fopen(filename, 'r');
if fid == -1
error('Cannot reopen file: %s', filename);
end
headerLine = '';
for k = 1:dataHeaderLineIdx
headerLine = fgetl(fid);
end
fclose(fid);
headerParts = strsplit(headerLine, ';');
nHeaderCols = numel(headerParts);
if isnan(metadata.numDatasets)
% New format: first column is wavelength, remaining are datasets
metadata.numDatasets = nHeaderCols - 1;
end
numCols = 1 + metadata.numDatasets;
% Build dataLines
if isnan(metadata.numPoints)
dataLines = [firstDataLineInFile, Inf];
else
lastDataLineInFile = firstDataLineInFile + metadata.numPoints - 1;
dataLines = [firstDataLineInFile, lastDataLineInFile];
end
% Set up Import Options
opts = delimitedTextImportOptions("NumVariables", numCols);
opts.DataLines = dataLines;
opts.Delimiter = ";";
% Build variable names with units
varNames = cell(1, numCols);
varNames{1} = "Wavelength [nm]";
if ~isempty(metadata.Date) && ~isempty(metadata.Time)
nMeta = min([numel(metadata.Date), numel(metadata.Time), metadata.numDatasets]);
for k = 1:nMeta
dstr = strtrim(metadata.Date{k});
tstr = strtrim(metadata.Time{k});
try
% JETI CSV: e.g. 12/18/2025 and 10:40:14 for 12h clock.[file:1]
dt = datetime([dstr ' ' tstr], ...
'InputFormat', 'MM/dd/yyyy HH:mm:ss');
timestr = datestr(dt, 'yyyymmdd_HHMMss');
catch
timestr = sprintf('dataset%02d', k);
end
varNames{1 + k} = sprintf("SpectralIrradiance_%s [W/(sqm*nm)]", timestr);
end
for k = nMeta+1:metadata.numDatasets
varNames{1 + k} = sprintf("SpectralIrradiance_%02d [W/(sqm*nm)]", k);
end
else
for k = 1:metadata.numDatasets
varNames{1 + k} = sprintf("SpectralIrradiance_%02d [W/(sqm*nm)]", k);
end
end
opts.VariableNames = string(varNames);
opts.VariableTypes = repmat("double", 1, numCols);
opts.ExtraColumnsRule = "ignore";
opts.EmptyLineRule = "read";
opts.VariableNamingRule = "preserve";
dataTable = readtable(filename, opts);
end
%% ========== TXT IMPORT FUNCTION ==========
function dataTable = importTXT(filename)
fid = fopen(filename, 'r');
if fid == -1
error('Cannot open file: %s', filename);
end
metadata = struct();
metadata.Name = '';
metadata.NumberOfDataX = NaN;
metadata.NumberOfDataY = NaN;
metadata.XMin = NaN;
metadata.XMax = NaN;
metadata.XUnit = '';
metadata.YUnit = '';
dataStartLineIdx = NaN;
lineIdx = 0;
% Parse header sections
while true
thisLine = fgetl(fid);
if ~ischar(thisLine)
break
end
lineIdx = lineIdx + 1;
% Check for data section marker
if strcmp(strtrim(thisLine), 'Data')
dataStartLineIdx = lineIdx + 1;
break
end
% Parse key=value pairs
if contains(thisLine, '=')
parts = strsplit(thisLine, '=');
if numel(parts) == 2
key = strtrim(parts{1});
value = strtrim(parts{2});
switch key
case 'Name'
metadata.Name = value;
case 'NumberOfDataX'
metadata.NumberOfDataX = str2double(value);
case 'NumberOfDataY'
metadata.NumberOfDataY = str2double(value);
case 'X-MIN'
metadata.XMin = str2double(value);
case 'X-MAX'
metadata.XMax = str2double(value);
case 'X-Unit'
metadata.XUnit = value;
case 'Y-Unit'
metadata.YUnit = value;
end
end
end
end
if isnan(dataStartLineIdx)
fclose(fid);
error('Could not find data section in TXT file.');
end
fclose(fid);
% Set up import options for tab-separated data
opts = delimitedTextImportOptions("NumVariables", 2);
opts.DataLines = [dataStartLineIdx, Inf];
opts.Delimiter = '\t';
opts.VariableNamingRule = "preserve";
% Build column names as string array
if ~isempty(metadata.XUnit) && ~isempty(metadata.YUnit)
varNames = string({
sprintf("Wavelength [%s]", metadata.XUnit)
sprintf("SpectralIrradiance_%s [%s]", metadata.Name, metadata.YUnit)
});
else
varNames = string({
sprintf("Wavelength_%s", metadata.Name)
sprintf("SpectralIrradiance_%s", metadata.Name)
});
end
opts.VariableNames = varNames;
opts.VariableTypes = ["double", "double"];
dataTable = readtable(filename, opts);
end