Files
2026-07-03 21:54:47 +02:00

165 lines
5.6 KiB
Matlab

function ax = plotCryoData(tbl, tStart, tEnd)
% plotCryoData Plot cryo cell data in 3 stacked panels with shared datetime axis.
%
% [ax] = plotCryoData(tbl, tStart, tEnd)
% Returns struct with handles to the 3 axes for easy limit modification.
%
% The first input may be EITHER:
% * a table with the columns datetime, pressure_cell_hPa_,
% temperature__C_, x_mm_, y_mm_, z_mm_, flowCryo_l_min_, OR
% * a LabView structure produced by LabView_importData (optionally
% combined with LabView_combine). In that case it is converted to the
% required table on the fly (see the local function labviewToTable).
%--- Accept a LabView timeseries structure and convert it to a table ---
if isstruct(tbl)
tbl = labviewToTable(tbl);
end
%--- Extract datetime column ---
dt = tbl.datetime;
%--- If start/stop provided, subset the table ---
if nargin >= 3 && ~isempty(tStart) && ~isempty(tEnd)
mask = dt >= tStart & dt <= tEnd;
tbl = tbl(mask, :);
dt = dt(mask);
end
%--- Create tiled layout ---
figure;
tl = tiledlayout(4, 1);
tl.TileSpacing = 'compact';
tl.Padding = 'compact';
%--- Upper tile: pressure and temperature (spans 2 rows) ---
ax.pressure_temp = nexttile([2 1]);
yyaxis left;
plot(dt, tbl.pressure_cell_hPa_, 'o', 'MarkerSize', 2, 'MarkerFaceColor', 'auto');
ylabel('Pressure [hPa]');
ylim padded;
grid on;
yyaxis right;
plot(dt, tbl.temperature__C_, 'o', 'MarkerSize', 2, 'MarkerFaceColor', 'auto');
ylabel('Temperature [°C]');
ylim padded;
title('Pressure and Temperature');
set(gca, 'XTickLabel', []);
%--- Middle tile: x, y, z with dual y-axes ---
ax.xyz = nexttile;
yyaxis left;
plot(dt, tbl.y_mm_, 'o', 'MarkerSize', 2, 'MarkerFaceColor', 'auto', 'DisplayName', 'y'); hold on;
ylabel('Y [mm]');
ylim([10 15]);
grid on;
yyaxis right;
plot(dt, tbl.x_mm_, 's', 'MarkerSize', 2, 'MarkerFaceColor', 'auto', 'DisplayName', 'x'); hold on;
plot(dt, tbl.z_mm_, '^', 'MarkerSize', 2, 'MarkerFaceColor', 'auto', 'DisplayName', 'z');
ylabel('X, Z [mm]');
ylim([-2 2]);
legend({'y', 'x', 'z'}, 'Location', 'best');
set(gca, 'XTickLabel', []);
%--- Lower tile: flowCryo ---
ax.flow = nexttile;
plot(dt, tbl.flowCryo_l_min_, 'o', 'MarkerSize', 2, 'MarkerFaceColor', 'auto');
grid on;
ylabel('Flow [L/min]');
xlabel('Date & Time');
title('Cryo Flow');
%--- Link x-axes for all tiles ---
linkaxes([ax.pressure_temp, ax.xyz, ax.flow], 'x');
% Improve datetime formatting on x-axis
ax.flow.XAxis.TickLabelFormat = 'dd-MMM HH:mm';
end
% =========================================================================
% LOCAL FUNCTIONS
% =========================================================================
function tbl = labviewToTable(LabView, tsName)
%LABVIEWTOTABLE Convert a LabView cryo-log timeseries into a plotCryoData table.
%
% Uses LabView.merge if present (created by LabView_combine); otherwise the
% timeseries field named tsName, or the first timeseries in the structure.
% The mapping uses the FIXED ts.Data column order that LabView_importData
% produces for every file format:
% [IceTemp, ResP1, ResP2, cell/Baratron1, Cooler1, Cooler2, FlowHe, ...
% Baratron2, Baratron3, x, y, z, Tsealing]
% so it works for old and new files alike. Channels a given file does not
% contain (e.g. x/y/z in pre-2019 logs) are returned as NaN.
%--- Select which timeseries to convert ---
if nargin >= 2 && ~isempty(tsName)
if ~isfield(LabView, tsName)
error('plotCryoData:noSuchField', ...
'LabView has no timeseries field "%s".', tsName);
end
ts = LabView.(tsName);
elseif isfield(LabView, 'merge')
ts = LabView.merge; % combined log (preferred)
else
fn = fieldnames(LabView);
if isempty(fn)
error('plotCryoData:emptyStruct', ...
'LabView structure contains no timeseries.');
end
ts = LabView.(fn{1}); % single-file case
end
%--- Absolute time as a datetime column ---
try
dt = datetime(getabstime(ts));
catch
dt = datetime(ts.TimeInfo.StartDate) + ...
seconds(ts.Time * unitToSeconds(ts.TimeInfo.Units));
end
dt = dt(:);
%--- Pull channels by their fixed ts.Data column index ---
D = ts.Data;
tbl = table( ...
dt, ...
getCol(D, 4), ... % pressure_cell (hPa) <- cell / Baratron-1 slot
getCol(D, 1), ... % temperature (degC) <- ice sample
getCol(D, 10), ... % x (mm)
getCol(D, 11), ... % y (mm)
getCol(D, 12), ... % z (mm)
getCol(D, 7), ... % flow cryo (l/min) <- He cryoholder
'VariableNames', {'datetime', 'pressure_cell_hPa_', 'temperature__C_', ...
'x_mm_', 'y_mm_', 'z_mm_', 'flowCryo_l_min_'});
end
function c = getCol(D, k)
% Return column k of D, or a NaN column if that channel is absent
% (e.g. pre-2019 logs have only 9 columns, so no x/y/z).
if size(D, 2) >= k
c = D(:, k);
else
c = nan(size(D, 1), 1);
end
end
function s = unitToSeconds(u)
% Convert timeseries TimeInfo.Units to seconds (fallback path only).
switch lower(u)
case 'seconds', s = 1;
case 'minutes', s = 60;
case 'hours', s = 3600;
case 'days', s = 86400;
case 'milliseconds', s = 1e-3;
otherwise, s = 1; % assume seconds
end
end