%Plotting code for pulse data and inline sensor data %Jordan Hil %11/06/2024 clc clear close all %% Load Data ------------------------------------------------------------ subject_num = 1; % subject number trial_number = 4; % trial number (1-7 with inline sensor) Fs = 250; % sampling frequency for pulse oximter %% Load pulse oximeter data for j = subject_num for i = trial_number subject{j}.test{i}.data_path = sprintf("Neck_Pulse_Oximeter_Data_timefixed/Subject_%d/*.csv", subject_num); %path for all data in subject folder subject{j}.test{i}.data_files = dir(subject{j}.test{i}.data_path); subject{j}.test{i}.num_files = length(subject{j}.test{i}.data_files); for filenum = 1:subject{j}.test{i}.num_files subject{j}.test{i}.filenames{filenum} = subject{j}.test{i}.data_files(filenum).name; end subject{j}.test{i}.sorted_datanames = natsort(string(subject{j}.test{i}.filenames)); % Sort the files chronologically for filenum = 1:subject{j}.test{i}.num_files temp_data_path = sprintf("Neck_Pulse_Oximeter_Data_timefixed/Subject_%d/%s", subject_num, subject{j}.test{i}.sorted_datanames(trial_number)); % Get the data path subject{j}.test{i}.loaded_data = readtable(temp_data_path, 'HeaderLines', 1); % load the data and skip first line end end end %% Load Inline Sensor data for j = subject_num for i = trial_number subject{j}.test{i}.data_path_breath = sprintf("Inline_PQ_Data/Subject%d/*.csv", subject_num); %path for all data in subject folder subject{j}.test{i}.data_files_breath = dir(subject{j}.test{i}.data_path_breath); subject{j}.test{i}.num_files_breath = length(subject{j}.test{i}.data_files_breath); for filenum = 1:subject{j}.test{i}.num_files_breath subject{j}.test{i}.filenames_breath{filenum} = subject{j}.test{i}.data_files_breath(filenum).name; end subject{j}.test{i}.sorted_datanames_breath = natsort(string(subject{j}.test{i}.filenames_breath)); % Sort the files chronologically for filenum = 1:subject{j}.test{i}.num_files_breath temp_data_path = sprintf("Inline_PQ_Data/Subject%d/%s", subject_num, subject{j}.test{i}.sorted_datanames_breath(trial_number)); % Get the data path subject{j}.test{i}.loaded_data_breath = readtable(temp_data_path, 'HeaderLines', 1); % load the data and skip first line % order - Time [s] ,Gauge Pressure [cmH2O], Inspiratory differenrtial pressure [cmH2O], Start Time end end end %% Filters Pulse Data -------------------------------------------------------------- % All frequency values are in Hz % Filter for pulse data N = 6; % Order Fc = 8; % Cutoff Frequency f_da = fdesign.lowpass('N,F3dB', N, Fc, Fs); Fda = design(f_da, 'butter'); %Filter the data for j = subject_num for i = trial_number for k = 2:9 %as k(1) is time temp_data = -subject{j}.test{i}.loaded_data{:,k}; %negative due to photodiode %filter the data with filtfilt for zerophase shift subject{j}.test{i}.unfiltered{k-1} = temp_data; subject{j}.test{i}.filtered{k-1} = filtfilt(Fda.sosMatrix,Fda.ScaleValues,temp_data); end end end %% Remove first and last 2 seconds of filtered data ----- % this accounts for the filter rise and end period when data has not been % filtered bang on for j = subject_num for i = trial_number for k = 2:9 % Define the number of samples to remove samples_to_remove = 500; % Process filtered signals fields = {'filtered'}; for field = fields temp_data = subject{j}.test{i}.(field{1}){k-1}; % Ensure the data length is sufficient if length(temp_data) > 2 * samples_to_remove % Remove first and last 500 samples processed_data = temp_data(samples_to_remove:end - samples_to_remove); subject{j}.test{i}.(field{1}){k-1} = processed_data; end end end end end %% Time -------------------------------------------------------------- time_test = cell(trial_number, 1); time_unchanged_test = cell(trial_number, 1); for i = trial_number % Test %Adjust from date timing from data to seconds time_unchanged = subject{j}.test{i}.loaded_data{:,1}; time = time_unchanged(1:length(time_unchanged)-999); %as remove first and last 500 samples above time_test{i} = time; time_unchanged_test{i} = time_unchanged; end %% Start time for the breathing data % Extract data using Var1–Var3 breath_data = subject{j}.test{i}.loaded_data_breath; time_breath = breath_data.Var1(1:19999); gauge_pressure = breath_data.Var2(1:19999); diff_pressure = breath_data.Var3(1:19999); % Extract start datenum from the first row of column 4 start_datenum = subject{j}.test{i}.loaded_data_breath{1,4}; % Convert datenum to datetime start_datetime = datetime(start_datenum, 'ConvertFrom', 'datenum', 'Format', 'dd-MMM-yyyy HH:mm:ss.SSSSSS'); %% Plotting ------------------------------------------------------------ for j = subject_num for i = trial_number % Unfiltered pulse data figure(10+i) sgtitle('Unfiltered Pulse Data') titles = {'PD1 660nm', 'PD2 660nm', 'PD1 940nm', 'PD2 940nm', 'PD3 660nm', 'PD4 660nm', 'PD3 940nm', 'PD4 940nm'}; index_adjustments = [0, 0, 2, 2, -2, -2, 0, 0]; for ii = 1:8 subplot(4,2,ii) plot(time_unchanged_test{i}, subject{j}.test{i}.unfiltered{ii + index_adjustments(ii)}, LineWidth=1.5) if ~isempty(titles{ii}) title(titles{ii}) end grid on ylabel('Voltage (V)') xlabel('Time (s)') end %plot filtered Pulse Data figure(20+i) sgtitle('Filtered Pulse Data') titles = {'PD1 660nm', 'PD2 660nm', 'PD1 940nm', 'PD2 940nm', 'PD3 660nm', 'PD4 660nm', 'PD3 940nm', 'PD4 940nm'}; index_adjustments = [0, 0, 2, 2, -2, -2, 0, 0]; for ii = 1:8 subplot(4,2,ii) plot(time_test{i}, subject{j}.test{i}.filtered{ii + index_adjustments(ii)}, LineWidth=1.5) if ~isempty(titles{ii}) title(titles{ii}) end grid on ylabel('Voltage (V)') xlabel('Time (s)') end % Gauge and differential pressure data figure(30+i) sgtitle('Inline Sensor Data') subplot(2,1,1) plot(time_breath, gauge_pressure, LineWidth=1.5) grid on ylabel('Gauge Pressure (cmH2O)') xlabel('Time (s)') subplot(2,1,2) plot(time_breath, diff_pressure, LineWidth=1.5) grid on ylabel('Differential Pressure (cmH2O)') xlabel('Time (s)') xlim([0, 50]) end end %% plot pressure & pulse on same plot -------------------------------------------------- figure(50) %sgtitle('Pulse and Pressure Data') titles = {'PD1 660nm', 'PD2 660nm', 'PD1 940nm', 'PD2 940nm', ... 'PD3 660nm', 'PD4 660nm', 'PD3 940nm', 'PD4 940nm', ... 'Gauge Pressure', 'Differential Pressure'}; index_adjustments = [0, 0, 2, 2, -2, -2, 0, 0]; % Plot the 8 filtered signals for ii = 1:8 subplot(5, 2, ii) plot(time_test{i}, subject{j}.test{i}.filtered{ii + index_adjustments(ii)}, 'LineWidth', 1.5) title(titles{ii}) grid on ylabel('Voltage (V)') xlabel('Time (s)') end % Plot gauge pressure subplot(5, 2, 9) plot(time_breath, gauge_pressure, 'b', 'LineWidth', 1.5) title(titles{9}) grid on ylabel('Pressure (cmH2O)') xlabel('Time (s)') xlim([0, 50]) % Plot differential pressure subplot(5, 2, 10) plot(time_breath, diff_pressure, 'r', 'LineWidth', 1.5) title(titles{10}) grid on ylabel('Pressure (cmH2O)') xlabel('Time (s)') xlim([0, 50]) % differential pressure and pules % Plot both on the same graph with different axes using yyaxis figure(60); t = tiledlayout(4, 1); % Create a 4x1 tiled layout titles = {'PD1', 'PD2', 'PD3', 'PD4'}; for ii = 1:4 nexttile; % Move to the next subplot % Plot using yyaxis for dual y-axis yyaxis left; plot(time_test{i}, subject{j}.test{i}.filtered{ii}, 'Color', [0 0.4470 0.7410], 'LineWidth', 2); % Blue ax = gca; ax.YColor = [0 0.4470 0.7410]; % Match y-axis color with the line yyaxis right; plot(time_breath, diff_pressure, 'Color', [0.6350 0.0780 0.1840], 'LineWidth', 2); % Red for diff pressure ax.YColor = [0.6350 0.0780 0.1840]; % Title and grid settings if ~isempty(titles{ii}) title(titles{ii}, 'FontName', 'Times New Roman', 'FontSize', 16); end grid on; grid minor; % Set font properties ax.FontName = 'Times New Roman'; ax.FontSize = 16; end % Shared x-axis label xlabel(t, 'Time (s)', 'FontName', 'Times New Roman', 'FontSize', 20, 'FontWeight', 'bold'); title(t, 'Filtered Pulse Signals and Differential Pressure', ... 'FontName', 'Times New Roman', 'FontSize', 22, 'FontWeight', 'bold'); % Gauge presure and Pulse % Plot both on the same graph with different axes using yyaxis figure(70); t = tiledlayout(4, 1); % Create a 4x1 tiled layout titles = {'PD1', 'PD2', 'PD3', 'PD4'}; for ii = 1:4 nexttile; % Move to the next subplot % Plot using yyaxis for dual y-axis yyaxis left; plot(time_test{i}, subject{j}.test{i}.filtered{ii}, 'Color', [0 0.4470 0.7410], 'LineWidth', 2); % Blue ax = gca; ax.YColor = [0 0.4470 0.7410]; % Match y-axis color with the line yyaxis right; plot(time_breath, gauge_pressure, 'Color', [0.6350 0.0780 0.1840], 'LineWidth', 2); % Red for diff pressure ax.YColor = [0.6350 0.0780 0.1840]; % Title and grid settings if ~isempty(titles{ii}) title(titles{ii}, 'FontName', 'Times New Roman', 'FontSize', 16); end grid on; grid minor; % Set font properties ax.FontName = 'Times New Roman'; ax.FontSize = 16; xlim([0, 50]) end % Shared x-axis label xlabel(t, 'Time (s)', 'FontName', 'Times New Roman', 'FontSize', 20, 'FontWeight', 'bold'); title(t, 'Filtered Pulse Signals and Gauge Pressure', ... 'FontName', 'Times New Roman', 'FontSize', 22, 'FontWeight', 'bold'); %% new plot figure(860 + i); clf t = tiledlayout(6,1); % 6 rows, 1 column t.TileSpacing = 'compact'; t.Padding = 'compact'; titles = {'PD1', 'PD2', 'PD3', 'PD4', 'Gauge Pressure', 'Differential Pressure'}; % --- First 4 tiles: PD pairs (660nm vs 940nm) --- for ii = 1:4 nexttile; yyaxis left; plot(time_test{i}, subject{j}.test{i}.filtered{ii}, ... 'Color', [0.6350 0.0780 0.1840], 'LineWidth', 2); % Dark red for 660nm ax = gca; ax.YColor = [0.6350 0.0780 0.1840]; if ii == 1 ylabel('660nm (V)', 'FontName','Times New Roman', 'FontSize',14) else ylabel('') end yyaxis right; plot(time_test{i}, subject{j}.test{i}.filtered{ii+4}, ... 'Color', [0 0.4470 0.7410], 'LineWidth', 2); % Blue for 940nm ax.YColor = [0 0.4470 0.7410]; if ii == 1 ylabel('940nm (V)', 'FontName','Times New Roman', 'FontSize',14) else ylabel('') end title(titles{ii}, 'FontName','Times New Roman', 'FontSize',16) grid on; grid minor; xlim([0 50]) if ii < 7 set(gca,'XTickLabel',[]) % hide x labels except bottom end end % --- 5th tile: Gauge pressure --- nexttile plot(time_breath, gauge_pressure, 'b', 'LineWidth', 2) title(titles{5}, 'FontName','Times New Roman', 'FontSize',16) ylabel('cmH_2O', 'FontName','Times New Roman', 'FontSize',14) grid on; grid minor; xlim([0 50]) set(gca,'XTickLabel',[]) % --- 6th tile: Differential pressure --- nexttile plot(time_breath, diff_pressure, 'r', 'LineWidth', 2) title(titles{6}, 'FontName','Times New Roman', 'FontSize',16) ylabel('cmH_2O', 'FontName','Times New Roman', 'FontSize',14) grid on; grid minor; xlim([0 50]) % Shared x-axis label at bottom xlabel(t, 'Time (s)', 'FontName','Times New Roman', ... 'FontSize',20, 'FontWeight','bold')