function tbl = issFlowImportData(fullFileName) %FLOWIMPORTDATA Import the MFC flow-log channels from a new-format LabView file. % % tbl = flowImportData(fullFileName) reads the mid-2026 LabView chamber log % (tab-delimited, 2 header lines, ISO-8859-1) and returns a table of the % 7 MFC flow channels: % datetime - absolute time (date + time columns) % MFC4 .. MFC10 - one column per mass-flow controller, named by its % physical MFC number (as on the gas panel). % MFC4 [l/min] - cryo cooling flow (the old "flow cryo" channel) % MFC5..MFC10 [sccm] - dosing/carrier gas flows (the old flow1..flow6) % % MFC <-> COLUMN MAPPING % The file's header line 1 names 7 controllers in order (MFC4..MFC10, % with a gas type each), and the data columns log 7 flow channels in the % same order (flow-cryo, then flow1..flow6). This function maps them % 1:1 by that shared order: % MFC4 <- "flow cryo (l/min)" (col 9) % MFC5 <- "flow1 (sccm)" (col 11) % MFC6 <- "flow2 (sccm)" (col 12) % MFC7 <- "flow3 (sccm)" (col 13) % MFC8 <- "flow4 (sccm)" (col 14) % MFC9 <- "flow5 (sccm)" (col 15) % MFC10 <- "flow6 (sccm)" (col 16) % This is an ORDER-MATCH inference (the file does not literally print % "flow3 = MFC7"), so double-check it once against the gas panel / % LabView front panel if in doubt. The parsed gas type per MFC (from the % header) is stored in tbl.Properties.UserData.mfcMap for that check. % % OUTPUT % tbl.Properties.UserData.mfcMap - table with MFC, SourceColumn, Gas, % Unit, MfcVarName for all 7 channels % (for verification and lookup) % % EXAMPLE % tbl = flowImportData('01-07-2026_11-28datafile.txt'); % tbl.Properties.UserData.mfcMap % inspect / verify the mapping % ax = plotFlowData(tbl, [4 7 10]); % plot by MFC number % ax = plotFlowData(tbl, 'flow3'); % or by the raw logged tag % % See also PLOTFLOWDATA, LABVIEW_IMPORTDATA lines = readlines(fullFileName, 'Encoding', 'ISO-8859-1'); lines = lines(strlength(lines) > 0); % drop trailing blank from final CRLF if numel(lines) < 3 error('flowImportData:tooShort', 'File does not look like a valid log.'); end hdr1 = lines(1); % gas name line hdr2 = lines(2); % column names data = lines(3:end); if ~contains(hdr2, 'pressure_cell') && ~contains(hdr1, 'gas name') error('flowImportData:wrongFormat', ... 'This does not look like the new-format LabView file (no "gas name"/"pressure_cell" header found).'); end %--- Parse gas names/types from header line 1: "gas name MFCn:Gas" --- tok = regexp(hdr1, 'gas name (MFC\d+):(\S+)', 'tokens'); mfcNum = cellfun(@(t) str2double(erase(t{1},'MFC')), tok); gasType = cellfun(@(t) string(t{2}), tok); [mfcNum, order] = sort(mfcNum); gasType = gasType(order); if numel(mfcNum) ~= 7 warning('flowImportData:unexpectedMfcCount', ... 'Expected 7 named MFCs in the header, found %d. Mapping may be wrong.', numel(mfcNum)); end %--- Parse the data rows --- parts = split(data, sprintf('\t')); if size(parts, 2) < 16 error('flowImportData:tooFewColumns', 'Fewer columns than expected in data rows.'); end dateStr = parts(:,1); timeStr = parts(:,2); dt = datetime(strcat(dateStr, timeStr), 'InputFormat', 'dd.MM.yyyyHH:mm:ss'); flowCryo = str2double(parts(:,9)); % "flow cryo (l/min)" flowN = str2double(parts(:,11:16)); % flow1..flow6 (sccm) %--- Order-matched MFC <-> column mapping --- columnData = [{flowCryo}, num2cell(flowN,1)]; % 1x7 cell of column vectors columnNames = {'flowCryo','flow1','flow2','flow3','flow4','flow5','flow6'}; columnUnits = [{'l/min'}, repmat({'sccm'}, 1, 6)]; tbl = table(dt, 'VariableNames', {'datetime'}); nCh = min(7, numel(mfcNum)); mfcVarNames = strings(1, nCh); for k = 1:nCh varName = sprintf('MFC%d', mfcNum(k)); tbl.(varName) = columnData{k}; mfcVarNames(k) = varName; end mfcMap = table(mfcNum(1:nCh)', columnNames(1:nCh)', gasType(1:nCh)', columnUnits(1:nCh)', ... 'VariableNames', {'MFC','SourceColumn','Gas','Unit'}); mfcMap.MfcVarName = cellstr(mfcVarNames(:)); tbl.Properties.VariableUnits = [{''}, columnUnits(1:nCh)]; tbl.Properties.UserData = struct('mfcMap', mfcMap); end