Respiratory and heart rate monitoring dataset from aeration study 1.0.0

File: <base>/Code/DataProcessing.m (13,549 bytes)
%% Data Processing for 2023 ARM Trial 
% Ella Guy 
% Last Updated: 24FEB2024

clear all, close all, clc

%--------------------------------------------------------------------------
% Inputs ------------------------------------------------------------------

SubjectNumber = 20; % de-identifyed subject number
TestNumber = 2; % test reference (1: increasing PEEP,
                                % 2: Breath-holds with increasing PEEP, and 
                                % 3: Forced Expiratory Manuevers)

breathMin = 0.007; % minimum fluctuation in second derivative breath selection  

% Alignment Breath --------------------------------------------------------

% In BOB data 
T_min_BOB = 26; %[s]
T_max_BOB = 27; %[s] 

% In EIT data 
T_min_EIT = 26; %[s]
T_max_EIT = 27; %[s]
%--------------------------------------------------------------------------

%% Loads Data
%--------------------------------------------------------------------------
Trials = {'PEEP', 'PEEP_BH', 'FEM'};
Trial = Trials{TestNumber};

RecordingLengths = [350, 350, 60];
RecordingLength = RecordingLengths(TestNumber);

% sensor offsets
OffsetA = -0.150;
OffsetB = -0.064;

%--------------------------------------------------------------------------
% Load Respiratory Data ---------------------------------------------------

Infile_format = 'PQ_rawData/Subject%d_%s.csv';
Infile = sprintf(Infile_format, SubjectNumber, Trial);

Respiratory = readtable(Infile,'NumHeaderLines',1); 

time = table2array(Respiratory(:,1)); % time [s]
GaugeP = table2array(Respiratory(:,2)); % Gauge pressure reading [cmH2O]
InhaleDeltaP = table2array(Respiratory(:,3)); % Inspiratory differenrtial pressure [cmH2O]
ExhaleDeltaP = table2array(Respiratory(:,4)); % Expiratory differenrtial pressure [cmH2O]
Depth_chest = table2array(Respiratory(1,5)); % Chest crossectional depth (a) [cm]
Width_chest = table2array(Respiratory(1,6)); % Chest crossectional width (b) [cm]
StartTime = datestr(table2array(Respiratory(1,7)));

BOB_timestep = 0.01;

[h, m, s] = hms(datetime(StartTime, 'InputFormat', 'HH:mm:ss'));
PSD_StartTime = [h, m, s];

for ai = length(time):-1:1
    if time(ai) >= 0
        trim_PSG = ai;
break
    end
end

PSD_t = time(1:trim_PSG);
PSD_P = GaugeP(1:trim_PSG);

PSD_DPI = InhaleDeltaP(1:trim_PSG);
PSD_DPE = ExhaleDeltaP(1:trim_PSG);

% -------------------------------------------------------------------------
% Load EIT File -----------------------------------------------------------

EIT_infile_format = 'EIT_rawData/S%02d_%s.bin';
EIT_infile = sprintf(EIT_infile_format, SubjectNumber, Trial);

EIT_data = read_binData(EIT_infile);

Aeration = sum(sum(EIT_data));
Aeration = Aeration(:);

EIT_sample_frequency = 50; % [Hz]
EIT_timestep = 1/EIT_sample_frequency; % [s]
Time_Aeration = EIT_timestep.*([1:length(Aeration)]);

% -------------------------------------------------------------------------
% Load ECG File -----------------------------------------------------------

ECG_infile_format = 'HRM_rawData/ECG/S%02d_ECG.csv';
ECG_infile = sprintf(ECG_infile_format, SubjectNumber);

ECG_file = readtable(ECG_infile,'NumHeaderLines',1); 

ECG = table2array(ECG_file(:,2));
ECG_time = table2array(ECG_file(:,1));

[h1, m1, s1] = hms(datetime(ECG_time(1), 'InputFormat', 'HH:mm:ss.SSS'));
ECG_StartTime = [h1, m1, s1];

trim_ECG = 1;
for ei = 1:length(ECG_time)
    [hw, mw, sw] = hms(datetime(ECG_time(ei), 'InputFormat', 'HH:mm:ss.SSS'));
    if hw == PSD_StartTime(1)
        if mw == PSD_StartTime(2)
            if floor(sw) == PSD_StartTime(3)
                trim_ECG = ei;
    break
            end
        end
    end
end

ECG_time2 = ECG_time(trim_ECG:end);

for bii = 1:length(ECG_time2)
    [hw, mw, sw] = hms(datetime(ECG_time2(bii), 'InputFormat', 'HH:mm:ss.SSS'));
    ECG_t(bii) = (hw - PSD_StartTime(1))*3600 + ...
        (mw - PSD_StartTime(2))*60 + ...
        (sw - PSD_StartTime(3));
    if ECG_t(bii) >= RecordingLength
break
    end
end

ECG_trace = ECG(trim_ECG: trim_ECG+length(ECG_t)-1);

% -------------------------------------------------------------------------
% Load PPG File -----------------------------------------------------------

PPG_infile_format = 'HRM_rawData/PPG/S%02d_PPG.csv';
PPG_infile = sprintf(PPG_infile_format, SubjectNumber);

PPG_file = readtable(PPG_infile,'NumHeaderLines',1); 

PPG0 = table2array(PPG_file(:,2));
PPG1 = table2array(PPG_file(:,3));
PPG2 = table2array(PPG_file(:,4));
PPG_time = table2array(PPG_file(:,1));

[h2, m2, s2] = hms(datetime(PPG_time(1), 'InputFormat', 'HH:mm:ss.SSS'));
PPG_StartTime = [h2, m2, s2];

trim_PPG = 1;
for ci = 1:length(PPG_time)
    [hw, mw, sw] = hms(datetime(PPG_time(ci), 'InputFormat', 'HH:mm:ss.SSS'));
    if hw == PSD_StartTime(1)
        if mw == PSD_StartTime(2)
            if floor(sw) == PSD_StartTime(3)
                trim_PPG = ci;
    break
            end
        end
    end
end

PPG_time2 = PPG_time(trim_PPG:end);

for cii = 1:length(PPG_time2)
    [hw, mw, sw] = hms(datetime(PPG_time2(cii), 'InputFormat', 'HH:mm:ss.SSS'));
    PPG_t(cii) = (hw - PSD_StartTime(1))*3600 + ...
        (mw - PSD_StartTime(2))*60 + ...
        (sw - PSD_StartTime(3));
    if PPG_t(cii) >= RecordingLength
break
    end
end

PPG_trace0 = PPG0(trim_PPG: trim_PPG+length(PPG_t)-1);
PPG_trace1 = PPG1(trim_PPG: trim_PPG+length(PPG_t)-1);
PPG_trace2 = PPG2(trim_PPG: trim_PPG+length(PPG_t)-1);

% -------------------------------------------------------------------------
% Load HR Belt File -------------------------------------------------------

HRB_infile_format = 'HRM_rawData/HRB/%d.txt';
HRB_infile = sprintf(HRB_infile_format, SubjectNumber);

HRB_file = readtable(HRB_infile,'NumHeaderLines',1); 

HRB_time_str = table2array(HRB_file(:,1));
HRB_msgid = table2array(HRB_file(:,2));
HRB_rr_ms = table2array(HRB_file(:,3));
HRB_hr_bpm = table2array(HRB_file(:,4));

for i = 1:length(HRB_time_str)
    HRB_time(i) = datetime(HRB_time_str{i},'InputFormat', 'HH:mm:ss.SSSSSS''Z');
end

[h3, m3, s3] = hms(HRB_time(1));
HRB_StartTime = [h3, m3, s3];

if PSD_StartTime(1) >= 12
    PSD_StartTime(1) = PSD_StartTime(1) - 12;
end

trim_HRB = 1;
for di = 1:length(HRB_time)
    [hw, mw, sw] = hms(HRB_time(di));
    if hw >= 12
        hw = hw - 12;
    end
    
    if hw == PSD_StartTime(1)
        if mw == PSD_StartTime(2)
            if floor(sw) == PSD_StartTime(3)
                trim_HRB = di;
break
            end
        end
    end
end

HRB_time2 = HRB_time(trim_HRB:end);

for dii = 1:length(HRB_time2)
    [hw, mw, sw] = hms(HRB_time2(dii));
    if hw > 12
        hw = hw - 12;
    end

    HRB_t(dii) = (hw - PSD_StartTime(1))*3600 + ...
        (mw - PSD_StartTime(2))*60 + ...
        (sw - PSD_StartTime(3));
    if HRB_t(dii) >= RecordingLength
break
    end
end

HRB_HR = HRB_hr_bpm(trim_HRB: trim_HRB+length(HRB_t)-1);
HRB_RR = (trim_HRB: trim_HRB+length(HRB_t)-1);

% -------------------------------------------------------------------------

% Processing Respiratory Data --------------------------------------------
% Flow --------------------------------------------------------------------

d1 = 0.015;          % Venturi intake diameter [m]
d2 = 0.010;          % Venturi constriction diameter [m]
cd = 0.97;           % Discharge coefficient
rho = 1.225;         % Density of air [kg/m^3]

A1 = pi*(d1/2)^2;    % Venturi intake cross-sectional area [m^2]
A2 = pi*(d2/2)^2;    % Venturi constrictioncross-sectional area [m^2]

DeltaP = InhaleDeltaP(1:trim_PSG) - ExhaleDeltaP(1:trim_PSG);
PSD_Q = zeros(length(DeltaP), 1);

for ei = 1 : length(DeltaP)
    if PSD_P(ei) <= 0
        PSD_Q(ei) = 1000*cd*A2*sqrt((2*(abs(DeltaP(ei))*98.0665))/(rho*(1-(A2/A1)^2)));
    else
        PSD_Q(ei) = -1.*1000*cd*A2*sqrt((2*(abs(DeltaP(ei))*98.0665))/(rho*(1-(A2/A1)^2)));
    end
end

% -------------------------------------------------------------------------
% Indicies ----------------------------------------------------------------

Smoothed_Q = movmedian(PSD_Q, 20);

Smoothed_P = smooth(movmedian(PSD_P, 20), 250);
Inflect_P = smooth(movmedian(diff(Smoothed_P,2),20), 250);

InspInd_working1 = [];
for fi = 2:length(Inflect_P)
    if Inflect_P(fi-1) < 0 && Inflect_P(fi) >= 0 
        InspInd_working1 = [InspInd_working1, fi];
    end
end

InspInd_working2 = [InspInd_working1(1)];
for fii = 2:length(InspInd_working1)-1
    breath = max(cumtrapz(Inflect_P(InspInd_working1(fii):InspInd_working1(fii+1))));
    if breath >= breathMin 
        InspInd_working2 = [InspInd_working2, InspInd_working1(fii)];
    end
end

InspInd = [InspInd_working2(1)];
for fiii = 2:length(InspInd_working2)
    breath = min(cumtrapz(Inflect_P(InspInd_working2(fiii):-1:InspInd_working2(fiii-1))));
    if breath <= -1*breathMin 
        InspInd = [InspInd, InspInd_working2(fiii)];
    end
end

% -------------------------------------------------------------------------
% Volume ------------------------------------------------------------------

V_working = 0;
PSD_V = [V_working];

for hi = 2:length(PSD_Q)
    if  ismember(hi, InspInd) == 0
        V_working = V_working + trapz(BOB_timestep, PSD_Q(hi-1:hi));
    else 
        V_working = 0;
    end
    PSD_V  = [PSD_V ; V_working];
end

% -------------------------------------------------------------------------

figure(1)
subplot(2,1,1)
hold on 
plot(PSD_t, PSD_V)
xline(PSD_t(InspInd), '--')
xlim([0 RecordingLength])
grid on
grid minor
hold off

subplot(2,1,2)
hold on 
plot(Time_Aeration, Aeration)
xline(PSD_t(InspInd), '--')
xlim([0 RecordingLength])
grid on
grid minor
hold off

%% Aligning EIT Data ------------------------------------------------------

I_min_BOB = (BOB_timestep*floor(T_min_BOB/BOB_timestep))/BOB_timestep;
I_max_BOB = (BOB_timestep*floor(T_max_BOB/BOB_timestep))/BOB_timestep;

I_min_EIT = (EIT_timestep*floor(T_min_EIT/EIT_timestep))/EIT_timestep;
I_max_EIT = (EIT_timestep*floor(T_max_EIT/EIT_timestep))/EIT_timestep;

[LM_BOB, LMI_BOB] = max(PSD_V(I_min_BOB:I_max_BOB));
[LM_EIT, LMI_EIT] = max(Aeration(I_min_EIT:I_max_EIT));

LMT_BOB = PSD_t(I_min_BOB + LMI_BOB);
LMT_EIT = Time_Aeration(I_min_EIT + LMI_EIT);

% Aligning ----------------------------------------------------------------

T_align =  LMT_BOB - LMT_EIT;

EIT_time = Time_Aeration + T_align;

for ji = 1:length(EIT_time)
    if EIT_time(ji)>=0
        trim1_EIT = ji;
break
    end
end

trim2_EIT = length(EIT_time);
for jii = 1:length(EIT_time)
    if EIT_time(jii)>=RecordingLength
        trim2_EIT = jii;
break
    end
end

EIT_t = EIT_time(trim1_EIT:trim2_EIT);
EIT_A = Aeration(trim1_EIT:trim2_EIT);

% -------------------------------------------------------------------------
% Plots ------------------------------------------------------------------

figure(2)
subplot(7,1,1)
hold on 
plot(PSD_t, PSD_P)
plot(PSD_t(InspInd), PSD_P(InspInd), '.')
xline(PSD_t(InspInd), '--')
xlim([0 RecordingLength])
grid on
grid minor
hold off

subplot(7,1,2)
hold on 
plot(PSD_t, PSD_Q)
plot(PSD_t(InspInd), PSD_Q(InspInd), '.')
xline(PSD_t(InspInd), '--')
xlim([0 RecordingLength])
grid on
grid minor
hold off

subplot(7,1,3)
hold on 
plot(PSD_t, PSD_V)
xline(PSD_t(InspInd), '--')
xlim([0 RecordingLength])
grid on
grid minor
hold off

subplot(7,1,4)
hold on 
plot(EIT_t, EIT_A)
xline(PSD_t(InspInd), '--')
xlim([0 RecordingLength])
grid on
grid minor
hold off

subplot(7,1,5)
hold on 
plot(ECG_t, ECG_trace)
xline(PSD_t(InspInd), '--')
xlim([0 RecordingLength])
grid on
grid minor
hold off

subplot(7,1,6)
hold on 
plot(PPG_t, PPG_trace0)
plot(PPG_t, PPG_trace1)
plot(PPG_t, PPG_trace2)
xline(PSD_t(InspInd), '--')
xlim([0 RecordingLength])
grid on
grid minor
hold off

subplot(7,1,7)
hold on 
plot(HRB_t, HRB_HR)
xline(PSD_t(InspInd), '--')
xlim([0 RecordingLength])
grid on
grid minor
hold off

%% Saves Data 

csv_outfile_format = 'ProcessedDataset/ProcessedData_Subject%02d_%s.csv';
csv_outfile_name = sprintf(csv_outfile_format, SubjectNumber, Trial);

Output = zeros(length(PPG_t), 18);

Output(1:length(PSD_t),1) = PSD_t;
Output(1:length(PSD_t),2) = PSD_P;
Output(1:length(PSD_t),3) = PSD_DPI;
Output(1:length(PSD_t),4) = PSD_DPE;
Output(1:length(PSD_t),5) = PSD_Q;
Output(1:length(PSD_t),6) = PSD_V;
Output(1:length(InspInd), 7) = InspInd;

Output(1:length(EIT_t), 8) = EIT_t;
Output(1:length(EIT_t), 9) = EIT_A;

Output(1:length(ECG_t), 10) = ECG_t;
Output(1:length(ECG_t), 11) = ECG_trace;

Output(1:length(PPG_t), 12) = PPG_t;
Output(1:length(PPG_t), 13) = PPG_trace0;
Output(1:length(PPG_t), 14) = PPG_trace1;
Output(1:length(PPG_t), 15) = PPG_trace2;

Output(1:length(HRB_t), 16) = HRB_t;
Output(1:length(HRB_t), 17) = HRB_HR;
Output(1:length(HRB_t), 18) = HRB_RR;


OutputTable = array2table(Output);
OutputTable.Properties.VariableNames(1:18) = {'PSD Time [s]', ...
                'PSD Gauge Pressure [cmH2O]', ...
                'PSD Inspiratory Differential Pressure [cmH2O]', ...
                'PSD Expiratory Differential Pressure [cmH2O]', ...
                'PSD Flow [L/s]', ...
                'PSD Tidal Volume [L]', ...
                'PSD Inspiratory Indicies' ...
                ...
                'EIT Time [s]', ...
                'EIT Global Aeration', ...
                ...
                'ECG Time [s]', ...
                'ECG [mV]', ...
                ...
                'PPG Time [s]', ...
                'PPG0', ...
                'PPG1', ...
                'PPG2', ...
                ...
                'HRB Time [s]', ...
                'HRB Heartrate [bpm]', ...
                'HRB RR Interval [ms]'};

% writetable(OutputTable, csv_outfile_name)