Files

286 lines
12 KiB
Matlab

function LabView = LabView_importData(fullFileName,varargin)
%
% LabView_importData reads data log ASCII files stored by LabView into
% a Matlab time series.
%
% LabView = LabView_importData(A) imports file A
% and stores its content as time series in a structure called "LabView".
%
% LabView = LabView_importData(A,LabView) imports file A
% and appends its content as time series to the LabView structure.
%
%
% Example
% LabView = LabView_importData('exmpl.dat',LabView)
%
% Input
% * Napp_chamber_file: Complete and absolute path to the Napp chamber log file.
% * LabView: name of output structure. Always call this'LabView'
%
% Output
% * LabView: time series, the name starting with "ts"
% followed by date and time the recording started.
%
% See also LABVIEW_COMBINE, LABVIEW_PLOT, LABVIEW_CUTDATA
%
%% Data Structure
%
% Data structure before 4.3.2019
% col 1: Date
% col 2: Time
% col 3: Reservoir "Pressure 1" - Unit "1 water" - mbar -> ts.Data:2
% col 4: Reservoir "Pressure 2" - Unit "2 other" - mbar -> ts.Data:3
% col 5: Baratron 1 - cell - 1mbar max - mbar -> ts.Data:4
% col 6: Baratron 2 - cell - 10mbar max - mbar -> ts.Data:8
% col 7: Baratron 3 - cell - 0.05mbar max - mbar -> ts.Data:9
% col 8: Baratron 4 - - mbar
% col 9: Temp.Ice Sample - °C -> ts.Data:1
% col 10: Temp.Heated Sample
% col 11: none
% col 12: Temp. Reservoir "Cooler 1" - °C -> ts.Data:5
% col 13: Temp. Reservoir "Cooler 2" - °C -> ts.Data:6
% col 14: Flow He(cryoholder) - l/min -> ts.Data:7
% col 15: none
% col 16: none
%
% Data structure after 4.3.2019
% col 1: Date
% col 2: Time
% col 3: Reservoir "Pressure 1" - Unit "1 water" - mbar -> ts.Data:2
% col 4: Reservoir "Pressure 2" - Unit "2 other" - mbar -> ts.Data:3
% col 5: Baratron 1 - cell - 1mbar max - mbar -> ts.Data:4
% col 6: Baratron 2 - cell - 10mbar max - mbar -> ts.Data:8
% col 7: Baratron 3 - cell - 0.05mbar max - mbar -> ts.Data:9
% col 8: Baratron 4 - - mbar
% col 9: Temp.Ice Sample - °C -> ts.Data:1
% col 10: Temp.Heated Sample
% col 11: Temp. Reservoir "Cooler 1" - °C -> ts.Data:5
% col 12: Temp. Reservoir "Cooler 2" - °C -> ts.Data:6
% col 13: Flow He(cryoholder) - l/min -> ts.Data:7
% col 14: Flow gas 1
% col 15: Pressure chamber - mbar
% col 16: x-position of cryoholder - mm -> ts.Data:10
% col 17: y-position of cryoholder - mm -> ts.Data:11
% col 18: z-position of cryoholder - mm -> ts.Data:12
% col 19: nothing
% col 20: Temp.Sealing - °C -> ts.Data:13
%%
% Create an InputParser object
p = inputParser;
% Add inputs to the scheme.
defaultAppendToStructure = 0;
addRequired(p,'fullFileName',@isfile);
addOptional(p,'appendToStructure',defaultAppendToStructure,@isstruct);
% Parse the inputs.
parse(p,fullFileName,varargin{:})
%% =====================================================================
% NEW FILE FORMAT (added 2026-07-02)
% ---------------------------------------------------------------------
% Detect the mid-2026 LabView format from its header and import it here,
% then return early so none of the older-format logic below is touched.
% New file: ISO-8859-1 encoded, 2 header lines, tab-delimited, 16 data
% columns + trailing tab, CRLF. The temperature column is written
% corrupted as "<int>NaN" (e.g. "-8NaN"); the leading integer is the real
% ice-sample temperature. Channels no longer logged are filled with NaN so
% the output keeps the same 13-column ts.Data layout, field naming and
% .Name as older files.
% col 3 pressure_cell (hPa) -> ts.Data:4 col 4 temperature -> ts.Data:1
% col 5-7 x/y/z (mm) -> ts.Data:10-12 col 8 Tsealing -> ts.Data:13
% col 9 flow cryo (l/min) -> ts.Data:7
% =====================================================================
keepTemperatureInteger = true; % true: recover a value from corrupted "-8NaN"-style
% entries (via the leading integer); false: NaN those out.
% Clean values (e.g. "32.072") are ALWAYS parsed in full,
% decimals included, regardless of this toggle -- it only
% affects what happens to the corrupted "<int>NaN" case.
if isstruct(p.Results.appendToStructure)
LabView = p.Results.appendToStructure;
end
fidChk = fopen(p.Results.fullFileName,'r','n','ISO-8859-1');
hdrLine1 = fgetl(fidChk);
hdrLine2 = fgetl(fidChk);
fclose(fidChk);
if (ischar(hdrLine2) && contains(hdrLine2,'pressure_cell')) || ...
(ischar(hdrLine1) && contains(hdrLine1,'gas name'))
fid = fopen(p.Results.fullFileName,'r','n','ISO-8859-1');
data = textscan(fid, ...
'%s %s %f %s %f %f %f %f %f %f %f %f %f %f %f %f %*s', ...
'HeaderLines', 2, 'Delimiter', '\t', 'EndOfLine', '\r\n');
fclose(fid);
if keepTemperatureInteger
temperature = cellfun(@(s) parseTemperature(s), data{4});
else
temperature = cellfun(@(s) parseTemperature(s, false), data{4});
end
nanCol = nan(numel(data{3}),1);
tsName = ['ts_' datestr(datenum([char(data{1}{1}), char(data{2}{1})], ...
'dd.mm.yyyyHH:MM:SS'),'YYYYmmdd_HHMM')];
LabView.(tsName) = timeseries( ...
[ temperature nanCol nanCol data{3} nanCol nanCol data{9} ...
nanCol nanCol data{5} data{6} data{7} data{8} ], ...
datestr(datenum([char(data{1}), char(data{2})],'dd.mm.yyyyHH:MM:SS'),0));
LabView.(tsName).Name = 'Readout Napp Chamber raw signal';
clearvars fid data temperature nanCol tsName hdrLine1 hdrLine2 fidChk ...
keepTemperatureInteger
return
end
%% =====================================================================
%%
% get filedate
[~,name,~] = fileparts(p.Results.fullFileName);
tmp = strsplit(name,'_PC');
filedate = datenum(tmp{1},'yyyy-mm-dd_HH.MM.SS');
clearvars name tmp
%%
% parse structure to append to
if isstruct(p.Results.appendToStructure)
LabView = p.Results.appendToStructure;
end
%%
if datenum(filedate) <= datenum('04-Mar-2019 13:30:00')
fid = fopen(p.Results.fullFileName);
data = textscan(fid, ...
'%s %s %f %f %f %f %f %f %f %f %f %f %f %f %f %f',...
'HeaderLines',1); % data file has 2 text columns, followed by 14 numeric columns
fclose(fid);
% define time series
LabView.(['ts_' datestr(datenum([char(data{1}{1}), char(data{2}{1})],'dd.mm.yyyyHH:MM:SS'),'YYYYmmdd_HHMM')]) ...
= timeseries([data{9} data{3} data{4} data{5} data{12} ...
data{13} data{14} data{6} data{7}] , ...
datestr(datenum([char(data{1}), char(data{2})],...
'dd.mm.yyyyHH:MM:SS'),0));
LabView.(['ts_' datestr(datenum([char(data{1}{1}), char(data{2}{1})],'dd.mm.yyyyHH:MM:SS'),'YYYYmmdd_HHMM')]).Name ...
= 'Readout Napp Chamber raw signal';
clear fid ans formatOut nans t x
elseif datenum(filedate) >= datenum('15-Sep-2021 01:00:00') && datenum(filedate) <= datenum('01-Apr-2023 01:00:00')
% during this time, date and time were in american format.
fid = fopen(p.Results.fullFileName);
data = textscan(fid, ...
'%s %s %s %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f',...
'HeaderLines',1); %
fclose(fid);
% the date formating in the dat file is really messed up. Try to make
% it consitent with MATLAB. The problem is that MATLAB does not
% understand 1 digit month and hours.
%
%
% Split the date in column 1 into year,month,day
newDateSplit = cellfun(@(x) split(char(x),'/'),data{1},'UniformOutput', false);
% Split the time in column 2 into hours, minutes, seconds
newTimeSplit = cellfun(@(x) split(char(x),':'),data{2},'UniformOutput', false);
% combine both with the am/pm string in column 3 to a new datestring
customDateStr = cellfun(@(x,y,z) [datestr(datenum([str2double(x{3}),str2double(x{1}),str2double(x{2}),str2double(y{1}),str2double(y{2}),str2double(y{3})])), ' ', char(z)], newDateSplit,newTimeSplit,data{3}, 'uniformOutput',false) ;
% define time series
LabView.(['ts_' datestr(customDateStr{1},'YYYYmmdd_HHMM')]) ...
= timeseries([data{10} data{4} data{5} data{6} data{12} ...
data{13} data{14} data{7} data{8} data{17} data{18} data{19} data{21}], ...
customDateStr);
LabView.(['ts_' datestr(customDateStr{1},'YYYYmmdd_HHMM')]).Name ...
= 'Readout Napp Chamber raw signal';
clearvars fid ans formatOut nans t x new* custom*
elseif datenum(filedate) >= datenum('01-Apr-2023 02:00:00')
fid = fopen(p.Results.fullFileName);
data = textscan(fid, ...
'%s %s %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f',...
'HeaderLines',1);
% data file has 2 text columns, followed by 18 numeric columns (THE AM
% PM IS MISSING and some changes to the LabView file. Confirm with Luca....)
fclose(fid);
% define time series
LabView.(['ts_' datestr(datenum([char(data{1}{1}), char(data{2}{1})],'dd.mm.yyyyHH:MM:SS'),'YYYYmmdd_HHMM')]) ...
= timeseries([data{9} data{3} data{4} data{5} data{11} ...
data{12} data{20} data{6} data{7} data{15} data{16} data{17} data{19}] , ...
datestr(datenum([char(data{1}), char(data{2})],...
'dd.mm.yyyyHH:MM:SS'),0));
LabView.(['ts_' datestr(datenum([char(data{1}{1}), char(data{2}{1})],'dd.mm.yyyyHH:MM:SS'),'YYYYmmdd_HHMM')]).Name ...
= 'Readout Napp Chamber raw signal';
clear fid ans formatOut nans t x
else
fid = fopen(p.Results.fullFileName);
data = textscan(fid, ...
'%s %s %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f %f',...
'HeaderLines',1); % data file has 2 text columns, followed by 14 numeric columns
fclose(fid);
% define time series
LabView.(['ts_' datestr(datenum([char(data{1}{1}), char(data{2}{1})],'dd.mm.yyyyHH:MM:SS'),'YYYYmmdd_HHMM')]) ...
= timeseries([data{9} data{3} data{4} data{5} data{11} ...
data{12} data{13} data{6} data{7} data{16} data{17} data{18} data{20}] , ...
datestr(datenum([char(data{1}), char(data{2})],...
'dd.mm.yyyyHH:MM:SS'),0));
LabView.(['ts_' datestr(datenum([char(data{1}{1}), char(data{2}{1})],'dd.mm.yyyyHH:MM:SS'),'YYYYmmdd_HHMM')]).Name ...
= 'Readout Napp Chamber raw signal';
clear fid ans formatOut nans t x
end
end
% =========================================================================
% LOCAL FUNCTION
% =========================================================================
function val = parseTemperature(s, recoverCorrupted)
%PARSETEMPERATURE Parse one temperature field from the new-format file.
%
% Handles two cases seen in the "temperature (degC)" column across
% different logging sessions:
% * CLEAN value, e.g. "32.072" -> parsed in full, decimals included.
% * CORRUPTED value, e.g. "-8NaN" (an integer immediately followed by
% the literal text "NaN", from an older logger bug) -> if
% recoverCorrupted is true (default), the leading integer is
% recovered (e.g. -8); if false, this returns NaN instead.
% * Legitimate "NaN" (a genuinely missing reading) -> always NaN.
%
% A field is only treated as "clean" if str2double can parse the WHOLE
% string as a number, so this never accidentally truncates a valid
% decimal reading -- it only engages the leading-integer fallback for
% strings that fail a full numeric parse (the corrupted pattern).
if nargin < 2
recoverCorrupted = true;
end
val = str2double(s); % succeeds for clean floats AND for 'NaN' itself
if ~isnan(val)
return % clean numeric value (decimals intact) -- done
end
if strcmpi(strtrim(s), 'NaN')
return % genuinely missing reading -- stays NaN
end
% Anything else that failed a full parse is treated as the corrupted
% "<int>NaN" pattern.
if recoverCorrupted
val = str2double(regexp(s, '^-?\d+', 'match', 'once'));
else
val = NaN;
end
end