A simplified method for determining phenotypic traits in patients with

advertisement
A simplified method for determining phenotypic traits in patients with obstructive sleep
apnea
ONLINE SUPPLEMENT
Andrew Wellman, Bradley A. Edwards, Scott A. Sands, Robert L. Owens, Shamim Nemati,
James Butler, Chris L. Passaglia, Andrew C. Jackson, Atul Malhotra, and David P. White
Detailed instructions for analyzing the data
The data are analzyed in Matlab version R2011a (Mathworks, Natick, MA). There are 6 scripts
or programs (labeled I-VI below) that must be run to obtain all of the phenotype traits. They
should be run in consecutive order. You will need to copy and paste these scripts into Matlab.
Email Andrew Wellman at awellman@rics.bwh.harvard.edu for questions.
I. Determining Veupnea
Cut and paste the following program code into a blank Matlab .m file. Save it as
Veup_Sept_20_2011.m
______________________________________________________________________________
% Script for getting Eupneic Ventilation on optimum CPAP
%% Import signals into Matlab
clear; clc;
subjnum = '867';
ti = 1.52;
te = 2.06;
global fs
fs = 100;
%
%
%
%
% clear the workspace and Command Window
% Enter the subject number
approximate inspiratory time
approximate expiratory time
sample frequency
the sample frequency of the data is 100 samples/sec
% You will need to know the file path for where your data is located and
% put it here so that Matlab will know where to look for the data.
cd(strcat(['D:\Old files before automatic backups done\Phenotype NEW
METHOD\Need to Analyze\' subjnum '\veup']));
q = dir;
r=0;
for z = 1:length(q)
if ~q(z,1).isdir
r = r+1;
data = importdata(strcat(['D:\Old files before automatic backups
done\Phenotype NEW METHOD\Need to Analyze\' subjnum '\veup\' q(z,1).name]));
data = data.data;
% Create a Structure variable containing the signals of interest.
S(r).name = q(z,1).name;
S(r).time = data(:,1);
S(r).arousals = data(:,2);
S(r).co2 = data(:,4);
S(r).pmask = data(:,5);
S(r).vdot = data(:,7);
S(r).sao2 = data(:,8);
%}
end
end
clear q r z data n;
% In this example, the file path is "C:\Documents and Settings\user1\My
% Documents\MATLAB\Phenoloop New\941\veup". You will need to know the file
% path for where Matlab files are saved on your computer and put it here.
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\veup']))
save('S runs'); % Save the current data in the Workspace to a .mat file named
"S runs.mat"
a = 0; % a is a counting variable
Mvdote = [];
% allocate memory for mean ventilation
Mcpap = [];
% allocate memory for mean CPAP
%{
% On occasion, it may be necessary to "redo" a signal because one of the
% preprocessing steps below was not performed properly. Rather than
% re-importing the data, highlight lines 115-117 and press F9 and you can
% restart with the next signal in succession.
clear Lvdote1 Lvdotr Lvdotr1 vdotr leak1 leak2 leak3 ivmaxdown ivmaxup
ivmindown1 ivmindown2 ivminup1 ivmindown2 ivminup1 ivminup2 vmaxdown vmaxup
vmindown vminup uup slope scatter1 vdota vdota1 vdotd co2min mvdota plot7
plot8 postcmin postco2 postrr postte postti posttot postvt postv precmin
preco2 prerr prete preti pretot prev prevt scatter2 upp Lcmax Lvdota Lvdote
axes3 axes4 d delco2 delrr delv n Button abn arin bpm cdown cmax cmax1 cmin
cpap down i icmax icmin idown iup ivmax ivmin mco2 mttot mvdote p rate
slopeidown slopeiup stage tvmax tvmin Lmif Lmif1 aabn ans mif mifdown mmif
name scrsz w vmin up vdote vdote1 vdown vmax vmin vol
a = a-1;
clc;
%}
%% RESTART HERE WITH NEXT SIGNAL
% This cell will be run multiple times depending on the number of files in
% the veup folder. Thus, place the cursor in this cell and evaluate it.
% Then, evaluate it again for the next signal in the veup folder, and so on
% until all of the signals have been processed.
clear MVDOTE MCPAP mcpap mvdote vol ans cpap ivmax ivmin p time1 time2 tvmax
tvmin vdot vdote vmax vmin
a = a + 1;
% Depending on where you save your Matlab data, you'll need to put the file
% path here.
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\veup']))
load('S runs');
% A few functions will be called in this script. Those functions are
% located in the folder below. You'll need to put the file path for
% wherever you have placed those functions here
cd ('C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop New')
% Remove the NaNs
X = [S(1,a).time S(1,a).arousals S(1,a).co2 S(1,a).pmask S(1,a).vdot
S(1,a).sao2];
X(any(isnan(X),2),:) = [];
% Reconstruct signals without the NaNs
S(1,a).time = X(:,1);
S(1,a).arousals = X(:,2);
S(1,a).co2 = X(:,3);
S(1,a).pmask = X(:,4);
S(1,a).vdot = X(:,5);
S(1,a).sao2 = X(:,6);
clear X;
% Integrate the raw flow signal to get volume
vol = cumsum(S(1,a).vdot)/fs;
% Fit the volume signal with a straight line to get the leak
p = polyfit(S(1,a).time,vol,1);
S(1,a).vdot = S(1,a).vdot - p(1); % subtract the leak from the flow signal
vol = cumsum(S(1,a).vdot)/fs; %reintegrate to get the leak-corrected volume
% Call the function "get_vmin2" to find the troughs of the volume signal
[vmin,ivmin] = get_vmin2(vol,ti,te,1.4);
tvmin = ivmin/fs;
% Find the peaks of the volume signal
vmax = [];
ivmax = [];
for n = 2:length(ivmin)
[maxvol,indmax] = max(vol(ivmin(n-1):ivmin(n)));
indmax = ivmin(n-1)+indmax;
vmax = [vmax maxvol];
ivmax = [ivmax indmax];
end
vmax = vmax';
ivmax = ivmax';
tvmax = ivmax/fs;
clear indmax maxvol n;
% The code below allows you to interactively correct any misplaced
% troughs in the volume signal. If a trough is mismarked, then left click
% just to the left of it and then right click so that the vertical line for
% the cross hairs is located where the trough should be. See figure.
l = 8000;
n = 0;
xx = [];
yy = [];
Button = [];
while n < length(vol)
interactive_vmin2(vol, ivmin, vmin, n, l);
[x,y,button] = ginput;
Button = [Button button'];
xx = [xx x'];
yy = [yy y'];
n = n + l;
close
end
clear n x y yy button;
xdel = NaN(1,500) ; xadd = NaN(1,500);
for n = 1:length(Button)
if Button(n) == 1
xdel(n) = xx(n);
else
xadd(n) = xx(n);
end
end
xdel(isnan(xdel)) = [];
xadd(isnan(xadd)) = [];
clear xx l
for n = 1:length(xdel)
ind = find(ivmin>round(xdel(n)), 1, 'first'); %returns the larger index
ivmin(ind) = NaN;
vmin(ind) = NaN;
end
clear n ind xdel;
% Remove NaNs
ivmin(isnan(ivmin)) = [];
vmin(isnan(vmin)) = [];
for n = 1:length(xadd)
if xadd(n) < ivmin(end)
ind = find(ivmin>round(xadd(n)), 1, 'first'); %returns the larger
index
ivmin = [ivmin(1:ind-1)' round(xadd(n)) ivmin(ind:end)']'; %ivmin
must be a column vector
vmin = [vmin(1:ind-1)' vol(round(xadd(n))) vmin(ind:end)']';
else
ivmin = [ivmin' round(xadd(n))]';
vmin = [vmin' vol(round(xadd(n)))]';
end
end
clear n ind xadd Button;
tvmin = ivmin/fs;
clear ivmax tvmax vmax
% re-find the peaks of the volume signal after you have corrected the
% troughs
vmax = [];
ivmax = [];
for n = 2:length(ivmin)
[maxvol,indmax] = max(vol(ivmin(n-1):ivmin(n)));
indmax = ivmin(n-1)+indmax;
vmax = [vmax maxvol];
ivmax = [ivmax indmax];
end
% Make them column vectors
if size(vmax,2) > size(vmax,1)
vmax = vmax';
end
if size(ivmax,2) > size(ivmax,1)
ivmax = ivmax';
end
tvmax = ivmax/fs;
clear indmax maxvol n;
% Determine vdote
vdote = [];
for n = 1:length(vmax)
vdote(n) = (vmax(n)-vmin(n))/(tvmin(n+1)-tvmin(n));
end
vdote = vdote*60;
for n = 1:length(vdote)
if vdote(n) < 0
vdote(n) = 0;
end
end
vdote = vdote';
clear n;
% find the CPAP by looking at the Pmask at the start of inspiration.
cpap = S(1,a).pmask(ivmin);
%plotpress(pmask, ivmin, cpap);
cpap(end) = [];
mcpap = mean(cpap);
mvdote = mean(vdote)
Mvdote = [Mvdote mvdote];
MVDOTE = mean(Mvdote);
Mcpap = [Mcpap mcpap];
MCPAP = mean(Mcpap);
% Place file path for where your Matlab data will be stored here
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\veup']))
vdot = S(1,a).vdot;
time1 = num2str(round(S(1,a).time(1)));
time2 = num2str(round(S(1,a).time(end)));
clear S
save(horzcat([time1 '_' time2]));
save('veup sum.mat','MVDOTE','Mvdote','ti','te');
______________________________________________________________________________
In order for the program to work properly, you must also copy, paste, and save the following two
functions into a Matlab .m file. Save them as get_vmin2.m and interactive_vmin2.m,
respectively.
______________________________________________________________________________
% Save this function as "get_vmin2.m"
% This gets the volume minimum (end exp lung volume) from the tidal volume
function [vmin,ivmin] = get_vmin2(vol,ti,te,incr)
global fs
% allocate memory for collection vectors
ivmin = [];
vmin = [];
ivmax = [];
vmax = [];
% find the first minimum of the vol signal
[volmin,indmin] = min(vol(1:1+round(fs*(ti+te+ti)))); %search ti+te+ti
seconds ahead
%[volmin,indmin] = min(vol(1:1+round(fs*incr*te))); %search incr*te seconds
ahead
vmin = [vmin volmin]; % find the minimum volume
ivmin = [ivmin indmin]; % find the index of the minimum
while (indmin+(fs*ti*2)+(fs*2*te) < length(vol)) % stop looping when indmin
is within 2 breaths from the end
[volmax,indmax] = max(vol(indmin:indmin+round(fs*ti*incr))); % search
ahead by incr ti's
indmax = indmin + indmax-1;
vmax = [vmax volmax];
ivmax = [ivmax indmax];
[volmin,indmin] = min(vol(indmax:indmax+round(fs*incr*te))); % search
ahead by incr te's
indmin = indmax + indmin-1;
vmin = [vmin volmin];
ivmin = [ivmin indmin];
end
vmin = vmin';
ivmin = ivmin';
______________________________________________________________________________
% Save this function as "interactive_vmin2.m"
% This allows you to correct the volume minimums
function interactive_vmin2(vol, ivmin, vmin, n, l)
%CREATEFIGURE(vol,ivmin,vmin)
% vol: vector of y data
% ivmin: vector of x data
% vmin: vector of y data
%
Auto-generated by MATLAB on 21-Aug-2007 12:18:10
% Create figure
scrsz = get(0,'ScreenSize');
figure1 = figure('Position',[10 70 scrsz(3)-20 scrsz(4)-200]);
% Create axes
axes1 = axes('Parent',figure1);
axis([n n+l min(vol)-2 max(vol)+1]);
box('on');
hold('all');
% Create plot
plot1 = plot(vol);
% Create plot
plot2 = plot(...
ivmin,vmin,...
'LineStyle','none',...
'Marker','.',...
'MarkerSize',15,...
'MarkerEdgeColor',[0 0.498 0],...
'MarkerFaceColor',[0 0.498 0]);
______________________________________________________________________________
Next, identify the folder containing the raw data file (collected with your data acquisition
software on the study night) for the subject to be analyzed. Rename the folder containing this
raw data with a number that corresponds to the subject. In this example, subject “941” will be
analyzed. Nothing else should be in the title except the number. Then, make 5 empty subfolders
within that folder called: veup, lg, var, v0, uag.
You will need to know the exact location or file path of this raw data folder (and subfolders) so
you can tell Matlab where to find it. This can be obtained by right-clicking on the folder, click
properties, then write down the location. In this example, the location is:
D:\Phenotype NEW METHOD\Need to Analyze
Next, open the Veup_Sept_20_2011.m script and anywhere you see “D:\Phenotype NEW
METHOD\Need to Analyze”, replace it with the location of the raw data folder on your
computer. This will only need to be done once per computer. This file path will need to be
changed if you change the location of the raw data on your computer.
Open Matlab and create a folder called “941” (or whatever the subject’s number is). Within that
folder, create 5 blank subfolders: veup, lg, var, v0, uag. After the raw signals have been
analyzed in Matlab, they will be saved in these folders. Write down the location of this folder by
right-clicking on the “941” folder, click properties, and then note the location. In this example
the folder is located in:
C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop New.
Go through each line of the Veup_Sept_20_2011.m script and anywhere you see “C:\Documents
and Settings\user1\My Documents\MATLAB\Phenoloop New”, replace it with the location of
the Matlab folder on your computer. This will only need to be done once per computer.
If it’s not already opened, open the script named Veup_Sept_20_2011.m and enter the subject’s
number in single quotes at the line beginning with “subjnum”, e.g.
subjnum = '941';
% Enter the subject number
Open the file containing the subject’s raw data. The data should already have been staged and
scored. In this example, the data were collected using Spike 2 software (Cambridge, UK). Open
Spike 2 and make the following signals visible on the screen:
1. New Events (this is where the arousals are marked in Spike).
2. Epochs (contains the different sleep stages in 30 second epochs).
3. PCO2
4. Mask pressure
5. Flow
6. SaO2
Find a period of stable breathing asleep on optimum (or near-optimum) CPAP and measure the
approximate inspiratory and expiratory times. Put these times in the Matlab Veup script, e.g.
ti = 1.70;
te = 2.77;
% approximate inspiratory time
% approximate expiratory time
There should be two significant digits.
Pan the data and splice out sections where the subject is asleep (no arousals) and breathing on
optimum CPAP. Since the optimum pressure might not be known beforehand, evaluate several
levels of high of CPAP. The ventilations at the different pressures can be compared later to
determine the optimum pressure. Be sure that each spliced section has a constant CPAP – there
should be a separate section for each different level of CPAP.
In Spike, data are spliced by placing vertical cursors (labeled 1 and 2, see Figure 1) at the start
and finish of the region to be spliced. Then, click File > Export as > Save type as: spreadsheet
txt > File name: enter the approximate time at cursor 1 > click Save > Output sample rate in Hz:
100 > Start time: cursor 1 > End time: cursor 2 > Unclick "Time shift output so first line is at 0
sec".
The data b/w cursor 1 and 2
will be named “7750” and
saved in the veup folder.
Figure 1
Save the spliced signals in the raw data folder labeled "veup" (not the Matlab veup folder).
After all of the available breathing on optimum CPAP has been spliced and saved in the raw
veup folder, return to the Veup_Sept_20_2011.m script and evaluate the first "cell" called
"Import signals into Matlab". A cell is marked by “%%” and is evaluated by clicking within the
cell (so it is highlighted) and then clicking on the "Evaluate cell" icon in the upper left corner of
the Command Window.
The first cell is run only once. This first cell will import the data from your raw signals folder
into Matlab. If you are unfamiliar with Matlab, you may need some help in creating the structure
variable so that all of the signals are identified and named properly. See annotation in the script
file itself.
The second cell entitled “RESTART HERE WITH NEXT SIGNAL” will be run multiple times,
depending on the number of files in the raw veup folder. Highlight the second cell and run it. A
figure like the one below (Figure 2A)will appear. The blue signal is the tidal volume. The green
dots are the end expiratory volume. If you agree with where each of the green dots has been
placed, click ENTER. You can now analyze the next file in the veup folder by running this
second cell again.
If you disagree with where a green dot has been placed, you can manually correct it by LEFT
clicking to the left of it and then RIGHT clicking where you want it to be placed.
Figure 2A
Mismarked trough (i.e. the automated algorithm did not
find the correct end expiratory volume for this breath). It
needs to be corrected manually.
You do not need to add
dots for the last 1-2
breaths.
Move the cross hairs so that the vertical cursor is to the left
of the mismarked trough (but to the right of the previous
trough, i.e. within the bracketed region shown), and then
LEFT click. The location of the horizontal cursor does not
matter, just line up the vertical cursor.
Figure 2B
Now move the vertical cursor to where the trough
should be, and then RIGHT click. The location of
the horizontal cursor does not matter here, only
the vertical cursor needs to be lined up. Then click
ENTER.
Run the “RESTART HERE WITH NEXT SIGNAL” cell several times until the following
message appears in the Command Window:
??? Index exceeds matrix dimensions.
This means you are done analyzing all the raw veup signals and there are no more left to analyze.
Note that if you have 10 raw veup signals in your veup folder, then you will run the “RESTART
HERE WITH NEXT SIGNAL” cell 10 times.
You are now done with determining Veupnea. Next, determine loop gain.
II. Determining Loop Gain
Cut and paste the following program code into a blank Matlab .m file and save it as
lg_Sept_20_2011.m
______________________________________________________________________________
% Code for getting loop gain
% Must run the Veup script first
%% Import the loop gain data
clear; clc;
subjnum = '797';
global fs
fs = 100;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\veup']))
load('veup sum.mat','MVDOTE','te','ti');
veup = MVDOTE;
clear MVDOTE;
cd(strcat(['D:\Old files before automatic backups done\Phenotype NEW
METHOD\Need to Analyze\' subjnum '\lg']));
q = dir;
r=0;
for z = 1:length(q)
if ~q(z,1).isdir
r = r+1;
data = importdata(strcat(['D:\Old files before automatic backups
done\Phenotype NEW METHOD\Need to Analyze\' subjnum '\lg\' q(z,1).name]));
data = data.data;
S(r).name = q(z,1).name;
S(r).time = data(:,1);
S(r).arousals = data(:,2);
S(r).co2 = data(:,4);
S(r).pmask = data(:,5);
S(r).vdot = data(:,7);
S(r).sao2 = data(:,8);
end
end
clear q r z data n;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\lg']))
save('S runs');
a = 0;
Lg = [];
%{
%To redo a run, run the next few lines of code by highlighting and pressing
% F9.
clear num den ans aind bind idown iup ivmax ivmin leak1 leak2 leak3 lg time1
time2 tvmax tvmin up vdot vdote vdown veup vmax vmin vol vup
Lg(end) = [];
LG = nanmean(Lg);
a = a-1;
clc;
%}
%% RESTART HERE WITH NEXT SIGNAL
clc;
clear num den ans aind bind idown iup ivmax ivmin leak1 leak2 leak3 lg time1
time2 tvmax tvmin up vdot vdote vdown veup vmax vmin vol vup
a = a + 1;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\lg']))
load('S runs');
cd ('C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop New')
% Remove the NaNs
X = [S(1,a).time S(1,a).arousals S(1,a).co2 S(1,a).pmask S(1,a).vdot
S(1,a).sao2];
X(any(isnan(X),2),:) = [];
% Reconstruct signals without the NaNs
S(1,a).time = X(:,1);
S(1,a).arousals = X(:,2);
S(1,a).co2 = X(:,3);
S(1,a).pmask = X(:,4);
S(1,a).vdot = X(:,5);
S(1,a).sao2 = X(:,6);
clear X;
% determine iup and idown
% Create figure
scrsz = get(0,'ScreenSize');
figure1 = figure('Position',[10 270 scrsz(3)-20 scrsz(4)-400]);
% Create axes
axes1 = axes('Parent',figure1);
box('on');
hold('all');
% Create plot
plot1 = plot(S(1,a).pmask);
title('LEFT CLICK ON IUP AND IDOWN');
[x,y] = ginput;
clear y scrsz figure1 axes1 plot1;
x = round(x);
iup = x(1);
idown = x(2);
clear x n;
close;
% Determine Leak
vol = cumsum(S(1,a).vdot)/fs;
p1 = polyfit(S(1,a).time(1:iup),vol(1:iup),1);
leak1 = p1(1);
p2 = polyfit(S(1,a).time(iup:idown),vol(iup:idown),1);
leak2 = p2(1);
p3 = polyfit(S(1,a).time(idown:end),vol(idown:end),1);
leak3 = p3(1);
clear p1 p2 p3
%
% Subtract the first leak up to idown, then the second.
S(1,a).vdot(1:iup) = S(1,a).vdot(1:iup) - leak1;
S(1,a).vdot(iup+1:idown) = S(1,a).vdot(iup+1:idown) - leak2;
S(1,a).vdot(idown+1:end) = S(1,a).vdot(idown+1:end) - leak3;
%clear leak1 leak2 leak3;
% Recalculate volume
vol = cumsum(S(1,a).vdot)/fs;
% Find peak and trough
[vmin,ivmin] = get_vmin2(vol,ti,te,1.4);
tvmin = ivmin/fs;
% find the vmax
vmax = [];
ivmax = [];
for n = 2:length(ivmin)
[maxvol,indmax] = max(vol(ivmin(n-1):ivmin(n)));
indmax = ivmin(n-1)+indmax;
vmax = [vmax maxvol];
ivmax = [ivmax indmax];
end
vmax = vmax';
ivmax = ivmax';
tvmax = ivmax/fs;
clear indmax maxvol n;
clc;
% Left click to remove; Right click to add
% Remove min interactively
% Interactively chose data to delete
l = 8000;
n = 0;
xx = [];
yy = [];
Button = [];
while n < length(vol)
interactive_vmin2(vol, ivmin, vmin, n, l);
[x,y,button] = ginput;
Button = [Button button'];
xx = [xx x'];
yy = [yy y'];
n = n + l;
close
end
clear n x y yy button;
xdel = NaN(1,500) ; xadd = NaN(1,500);
for n = 1:length(Button)
if Button(n) == 1
xdel(n) = xx(n);
else
xadd(n) = xx(n);
end
end
xdel(isnan(xdel)) = [];
xadd(isnan(xadd)) = [];
clear xx l
% Assign NaNs to data you want to delete
% YOU MUST CLICK TO THE LEFT OF THE ONE YOU DON'T WANT
for n = 1:length(xdel)
ind = find(ivmin>round(xdel(n)), 1, 'first'); %returns the larger index
ivmin(ind) = NaN;
vmin(ind) = NaN;
end
clear n ind xdel;
% Remove NaNs
ivmin(isnan(ivmin)) = [];
vmin(isnan(vmin)) = [];
for n = 1:length(xadd)
if xadd(n) < ivmin(end)
ind = find(ivmin>round(xadd(n)), 1, 'first'); %returns the larger
index
ivmin = [ivmin(1:ind-1)' round(xadd(n)) ivmin(ind:end)']'; %ivmin
must be a column vector
vmin = [vmin(1:ind-1)' vol(round(xadd(n))) vmin(ind:end)']';
else
ivmin = [ivmin' round(xadd(n))]';
vmin = [vmin' vol(round(xadd(n)))]';
end
end
clear n ind xadd Button;
tvmin = ivmin/fs;
clear ivmax tvmax vmax
% find the vmax again
vmax = [];
ivmax = [];
for n = 2:length(ivmin)
[maxvol,indmax] = max(vol(ivmin(n-1):ivmin(n)));
indmax = ivmin(n-1)+indmax;
vmax = [vmax maxvol];
ivmax = [ivmax indmax];
end
% Make them column vectors
if size(vmax,2) > size(vmax,1)
vmax = vmax';
end
if size(ivmax,2) > size(ivmax,1)
ivmax = ivmax';
end
tvmax = ivmax/fs;
clear indmax maxvol n;
% Determine vdote
vdote = [];
for n = 1:length(vmax)
vdote(n) = (vmax(n)-vmin(n))/(tvmin(n+1)-tvmin(n));
end
vdote = vdote*60;
for n = 1:length(vdote)
if vdote(n) < 0
vdote(n) = 0;
end
end
vdote = vdote';
clear n;
aind = find(ivmin<iup,1,'last');
bind = ivmax(aind);
%aind = ivmin(aind);
if bind < iup
up = aind + 1;
else
if iup - ivmin(aind) > te*fs
up = aind + 1;
else
up = aind;
end
end
vup = mean(vdote(up:up+1));
%vup = vdote(up);
vdown = mean(vdote(up-5:up-1));
%
if veup-vdown < 0.5 || vup-veup < 0.5
lg = NaN;
else
lg = (vup-veup)/(veup-vdown);
end
Lg = [Lg lg];
LG = nanmean(Lg);
if isnan(LG)
LG = 30;
end
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\lg']))
vdot = S(1,a).vdot;
time1 = num2str(round(S(1,a).time(1)));
time2 = num2str(round(S(1,a).time(end)));
clear S
save(horzcat([time1 '_' time2]));
clc;
num = vup-veup
den = veup-vdown
lg
save('lg sum.mat', 'LG', 'Lg');
______________________________________________________________________________
Make the following changes to the lg_Sept_20_2011.m script:
1. Enter the correct subjnum
2. If you have not already done so, anywhere you see “D:\Phenotype NEW METHOD\Need
to Analyze”, replace it with the correct location for your data.
3. Likewise, anywhere you see “C:\Documents and Settings\user1\My
Documents\MATLAB\Phenoloop New”, replace it with the correct location for where
you want Matlab to save the signals after you have processed them.
Next, pan the subject’s raw data (in Spike or your data acquisition software) and look for “dial
ups” in CPAP that will be used for measuring loop gain. Splice each one out and save them in
the raw lg folder. The region to be spliced out should contain approximately 1 min prior to the
dial up and several breaths after the decrease (see cursors 1 and 2 in Figure 3). Name the file a
number, e.g., the approximate time that the dial up was made (which in Figure 3 is “13940”).
Figure 3
After you have spliced out all of the dial ups, return to the lg_Sept_20_2011.m script and run the
first cell named “Import the loop gain data”. You will only need to import the data one time (this
first cell only needs to be run once).
Next, run the cell named “RESTART HERE WITH THE NEXT SIGNAL”. This cell will be run
multiple times, depending on the number of loop gain runs that you have in your raw lg folder
(e.g., if you did 10 dial ups, you will run this cell 10 times). A figure of mask pressure will be
displayed. Place the vertical line of the cross-hairs at the point where optimum CPAP has been
achieved (vertical cursor in Figure 4A), then LEFT click. Next, place the vertical cursor at the
point where you started dialing down CPAP (see Figure 4B). This tells Matlab where the
subject is on a high level of CPAP so that the correct leak can be removed (the leak on high
CPAP will be greater than the leak on low CPAP).
Optimum CPAP
Figure 4A
suboptimum (or minimum
tolerable) CPAP
Figure 4B
Start of the
return back to a
suboptimum
pressure
Next, run the cell named “Find peak and trough”. The following figure of tidal volume will be
displayed. It is almost always necessary to manually correct the volume minimum for the breath
just before the dial up. LEFT click to the left of the mismarked trough (Figure 5A), then RIGHT
click at the inflection point for the next breath. This is the true start time for the first large breath
on high CPAP.
Figure 5A
Breath just before the dial up
Figure 5B
Sometimes the inflection point is not so obvious (see Figure 6), but it should be corrected as
accurately as possible.
Figure 6
Move this point to here
The following variables will be shown in the Command Window:
num =
3.9200
den =
0.9098
lg =
4.3089
Num is the numerator in the loop gain ratio. Den is the denominator. Lg is the ratio of num/den.
If the denominator is < 0.5 L/min (meaning ventilation was not lowered by more than 0.5 L/min
below Veup), then lg = NaN (not a number) will be shown.
Re-run the second (RESTART HERE WITH THE NEXT SIGNAL) and third (Find peak and
trough) cells for each of the signals in the lg folder until the following appears in the Command
Window indicating you’re done:
??? Index exceeds matrix dimensions.
If none of the loop gains could be determined (i.e. they all are lg = NaN’s), then a default loop
gain of 30 (a nonphysiologic value) will be automatically entered. This is only for convenience
so that the rest of the code can be run without interruption. It will need to be removed later.
You are now done analyzing loop gain. Next, determine Varousal.
III. Determining Varousal
As before, cut and paste the following program code into a blank Matlab .m file and save as
var_Sept_20_2011.m
______________________________________________________________________________
% code for getting ventilation causing arousal
%% Import arousal data
clear; clc;
subjnum = '867';
global fs
fs = 100;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\veup']))
load('veup sum.mat','MVDOTE','te','ti'); veup = MVDOTE; clear MVDOTE
cd(strcat(['D:\Old files before automatic backups done\Phenotype NEW
METHOD\Need to Analyze\' subjnum '\var']));
q = dir;
r=0;
for z = 1:length(q)
if ~q(z,1).isdir
r = r+1;
data = importdata(strcat(['D:\Old files before automatic backups
done\Phenotype NEW METHOD\Need to Analyze\' subjnum '\var\' q(z,1).name]));
data = data.data;
%{
S(r).name = q(z,1).name;
S(r).time = data(:,1);
S(r).arousals = data(:,2);
S(r).co2 = data(:,4);
S(r).pmask = data(:,5);
S(r).vdot = data(:,6);
S(r).sao2 = data(:,8);
%}
%
S(r).name = q(z,1).name;
S(r).time = data(:,1);
S(r).arousals = data(:,2);
S(r).co2 = data(:,4);
S(r).pmask = data(:,5);
S(r).vdot = data(:,7);
S(r).sao2 = data(:,8);
%}
end
end
clear q r z data n;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\var']))
save('S runs');
a = 0;
Ar = [];
%{
%To redo a run, enter this
clear ARbreaths aind ivmax ivmin p time1 time2 tind tvmax tvmin var vdot
vdote vmax vmin vol
Ar(end) = [];
if isempty(Ar)
AR = [];
else
AR = nanmean(Ar);
end
a = a-1;
clc;
%}
%% RESTART HERE WITH NEXT SIGNAL
clc;
clear ARbreaths aind ivmax ivmin p time1 time2 tind tvmax tvmin var vdot
vdote vmax vmin vol
a = a + 1;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\var']))
load('S runs');
cd ('C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop New')
% Remove the NaNs
X = [S(1,a).time S(1,a).arousals S(1,a).co2 S(1,a).pmask S(1,a).vdot
S(1,a).sao2];
X(any(isnan(X),2),:) = [];
% Reconstruct signals without the NaNs
S(1,a).time = X(:,1);
S(1,a).arousals = X(:,2);
S(1,a).co2 = X(:,3);
S(1,a).pmask = X(:,4);
S(1,a).vdot = X(:,5);
S(1,a).sao2 = X(:,6);
clear X;
vol = cumsum(S(1,a).vdot)/fs;
%
p = polyfit(S(1,a).time,vol,1);
S(1,a).vdot = S(1,a).vdot - p(1);
vol = cumsum(S(1,a).vdot)/fs;
% Find peak and trough
[vmin,ivmin] = get_vmin2(vol,ti,te,1.4);
tvmin = ivmin/fs;
% find the vmax
vmax = [];
ivmax = [];
for n = 2:length(ivmin)
[maxvol,indmax] = max(vol(ivmin(n-1):ivmin(n)));
indmax = ivmin(n-1)+indmax;
vmax = [vmax maxvol];
ivmax = [ivmax indmax];
end
vmax = vmax';
ivmax = ivmax';
tvmax = ivmax/fs;
clear indmax maxvol n;
%plotvol1(vol, ivmin, vmin, ivmin, vmin, ivmax, vmax);
% Left click to remove; Right click to add
% Remove min interactively
% Interactively chose data to delete
l = 8000;
n = 0;
xx = [];
yy = [];
Button = [];
while n < length(vol)
interactive_vmin2(vol, ivmin, vmin, n, l);
[x,y,button] = ginput;
Button = [Button button'];
xx = [xx x'];
yy = [yy y'];
n = n + l;
close
end
clear n x y yy button;
xdel = NaN(1,500) ; xadd = NaN(1,500);
for n = 1:length(Button)
if Button(n) == 1
xdel(n) = xx(n);
else
xadd(n) = xx(n);
end
end
xdel(isnan(xdel)) = [];
xadd(isnan(xadd)) = [];
clear xx l
% Assign NaNs to data you want to delete
% YOU MUST CLICK TO THE LEFT OF THE ONE YOU DON'T WANT
for n = 1:length(xdel)
ind = find(ivmin>round(xdel(n)), 1, 'first'); %returns the larger index
ivmin(ind) = NaN;
vmin(ind) = NaN;
end
clear n ind xdel;
% Remove NaNs
ivmin(isnan(ivmin)) = [];
vmin(isnan(vmin)) = [];
for n = 1:length(xadd)
if xadd(n) < ivmin(end)
ind = find(ivmin>round(xadd(n)), 1, 'first'); %returns the larger
index
ivmin = [ivmin(1:ind-1)' round(xadd(n)) ivmin(ind:end)']'; %ivmin
must be a column vector
vmin = [vmin(1:ind-1)' vol(round(xadd(n))) vmin(ind:end)']';
else
ivmin = [ivmin' round(xadd(n))]';
vmin = [vmin' vol(round(xadd(n)))]';
end
end
clear n ind xadd Button;
tvmin = ivmin/fs;
clear ivmax tvmax vmax
% find the vmax again
vmax = [];
ivmax = [];
for n = 2:length(ivmin)
[maxvol,indmax] = max(vol(ivmin(n-1):ivmin(n)));
indmax = ivmin(n-1)+indmax;
vmax = [vmax maxvol];
ivmax = [ivmax indmax];
end
% Make them column vectors
if size(vmax,2) > size(vmax,1)
vmax = vmax';
end
if size(ivmax,2) > size(ivmax,1)
ivmax = ivmax';
end
tvmax = ivmax/fs;
clear indmax maxvol n;
%plotvol1(vol, ivmin, vmin, ivmin, vmin, ivmax, vmax);
% Determine vdote
vdote = [];
for n = 1:length(vmax)
vdote(n) = (vmax(n)-vmin(n))/(tvmin(n+1)-tvmin(n));
end
vdote = vdote*60;
for n = 1:length(vdote)
if vdote(n) < 0
vdote(n) = 0;
end
end
vdote = vdote';
clear n;
% Create figure
scrsz = get(0,'ScreenSize');
figure1 = figure('Position',[10 270 scrsz(3)-20 scrsz(4)-400]);
% Create axes
axes1 = axes('Parent',figure1);
box('on');
hold('all');
% Create plot
plot1 = plot(vol);
title('LEFT CLICK ON the arousal breath');
[x,y] = ginput;
clear y scrsz figure1 axes1 plot1;
x = round(x);
tind = x(1);
clear x n;
close;
aind = find(ivmin<tind,1,'last');
var = mean(vdote(aind-5:aind-1));
ARbreaths = vdote(aind-5:aind-1);
if max(ARbreaths)-min(ARbreaths) > 0.5*max(ARbreaths)
var = NaN;
end
Ar = [Ar var];
AR = nanmean(Ar);
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\var']))
vdot = S(1,a).vdot;
time1 = num2str(round(S(1,a).time(1)));
time2 = num2str(round(S(1,a).time(end)));
clear S
save(horzcat([time1 '_' time2]));
clc;
veup
var
save('var sum.mat', 'AR', 'Ar');
________________________________________________________________
Be sure to enter the correct subjnum and, if it has not already been done, change the file paths as
previously.
Next, pan the subject’s raw data again and anywhere an arousal is seen, look to see if it is
preceded by flow limited breaths. Then make sure that there was no arousal in the preceding 60
seconds. If these criteria are met, then splice out a section starting ~60 sec before the arousal and
~30 sec after the arousal. Name the files with the time of the arousal and save them in the raw
var folder.
Run the first cell entitled “Import arousal data”. You will only need to import the data once.
Run the next cell entitled “RESTART HERE WITH NEXT SIGNAL”. This cell will be run
multiple times. As in Section II, correct any misplaced troughs in the tidal volume signal. Then,
when a figure like Figure 7A appears, Left click on the breath in which there is an arousal (Note:
if arousal occurs on expiration of a breath, then it may truncate the breath and make the
ventilation larger. In this case, select the truncated breath as the “arousal breath” (as shown in
Figure 7B), not the larger one. You may need to look back at the raw data to confirm which
breath the arousal occurs on.
Figure 7A
The vertical cursor
should be placed
somewhere on the
arousal breath, then
LEFT click and
press ENTER.
If arousal occurs on expiration, it may
truncate the breath, thereby making
the ventilation larger. Make sure to
place the cursor on the correct breath
as shown here.
Figure 7B
Rerun the same cell until all of the arousal files have been analyzed.
IV. Determining passive v0
Cut, paste, and save the program code below in a file called v0_Sept_20_2011.m. Correct the
subjnum and file paths as before.
______________________________________________________________________________
% code for getting Passive v0
% Must run Veup script first
%% Import v0 data
clear; clc;
subjnum = '797';
%{
% Run if v0 is clearly zero for all drops, then run this code
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\v0']))
VV0 = 0;
V0 = 0;
save('v0 sum.mat');
%}
global fs
fs = 100;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\veup']))
load('veup sum.mat','te','ti');
cd(strcat(['D:\Old files before automatic backups done\Phenotype NEW
METHOD\Need to Analyze\' subjnum '\v0']));
q = dir;
r=0;
for z = 1:length(q)
if ~q(z,1).isdir
r = r+1;
data = importdata(strcat(['D:\Old files before automatic backups
done\Phenotype NEW METHOD\Need to Analyze\' subjnum '\v0\' q(z,1).name]));
data = data.data;
%{
S(r).name = q(z,1).name;
S(r).time = data(:,1);
S(r).arousals = data(:,2);
S(r).co2 = data(:,4);
S(r).pmask = data(:,5);
S(r).vdot = data(:,6);
S(r).sao2 = data(:,8);
%}
%
S(r).name = q(z,1).name;
S(r).time = data(:,1);
S(r).arousals = data(:,2);
S(r).co2 = data(:,4);
S(r).pmask = data(:,5);
S(r).vdot = data(:,7);
S(r).sao2 = data(:,8);
%}
end
end
clear q r z data n;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\v0']))
save('S runs');
a = 0;
V0 = [];
%{
%To redo a run, enter this
clear aind bind down idown iup ivmax ivmin leak1 leak2 leak3 leak4 te ti
time1 time2 tvmax tvmin v0 vdot vdote vmax vmin vol
V0(end) = [];
VV0 = nanmean(V0);
a = a-1;
clc;
%}
%% RESTART HERE WITH NEXT SIGNAL
clc;
clear aind bind down idown iup ivmax ivmin leak1 leak2 leak3 leak4 te ti
time1 time2 tvmax tvmin v0 vdot vdote vmax vmin vol
a = a + 1;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\v0']))
load('S runs');
cd ('C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop New')
% Remove the NaNs
X = [S(1,a).time S(1,a).arousals S(1,a).co2 S(1,a).pmask S(1,a).vdot
S(1,a).sao2];
X(any(isnan(X),2),:) = [];
% Reconstruct signals without the NaNs
S(1,a).time = X(:,1);
S(1,a).arousals = X(:,2);
S(1,a).co2 = X(:,3);
S(1,a).pmask = X(:,4);
S(1,a).vdot = X(:,5);
S(1,a).sao2 = X(:,6);
clear X;
% determine iup and idown
% Create figure
scrsz = get(0,'ScreenSize');
figure1 = figure('Position',[10 270 scrsz(3)-20 scrsz(4)-400]);
% Create axes
axes1 = axes('Parent',figure1);
box('on');
hold('all');
% Create plot
plot1 = plot(S(1,a).pmask);
title('LEFT CLICK ON IDOWN AND IUP');
[x,y] = ginput;
clear y scrsz figure1 axes1 plot1;
x = round(x);
idown = x(1);
iup = x(2);
clear x n;
close;
% Determine Leak
vol = cumsum(S(1,a).vdot)/fs;
p1 = polyfit(S(1,a).time(1:idown),vol(1:idown),1);
leak1 = p1(1);
p2 = polyfit(S(1,a).time(idown:iup),vol(idown:iup),1);
leak2 = p2(1);
p3 = polyfit(S(1,a).time(iup:end),vol(iup:end),1);
leak3 = p3(1);
clear p1 p2 p3
%
% Subtract the first leak up to idown, then the second.
S(1,a).vdot(1:idown) = S(1,a).vdot(1:idown) - leak1;
S(1,a).vdot(idown+1:iup) = S(1,a).vdot(idown+1:iup) - leak2;
S(1,a).vdot(iup+1:end) = S(1,a).vdot(iup+1:end) - leak3;
%clear leak1 leak2 leak3;
% Recalculate volume
vol = cumsum(S(1,a).vdot)/fs;
% Create figure
scrsz = get(0,'ScreenSize');
figure1 = figure('Position',[10 270 scrsz(3)-20 scrsz(4)-400]);
% Create axes
axes1 = axes('Parent',figure1);
box('on');
hold('all');
% Create plot
plot1 = plot([0:length(S(1,a).vdot)-1],S(1,a).vdot,[0 length(S(1,a).vdot)],[0
0]);
title('Check to see if there is zero flow');
zf = input('Is there zero flow? (1=YES 2=NO): ');
% Find peak and trough
if zf == 1
v0 = 0;
else
[vmin,ivmin] = get_vmin2(vol,ti,te,1.4);
tvmin = ivmin/fs;
% find the vmax
vmax = [];
ivmax = [];
for n = 2:length(ivmin)
[maxvol,indmax] = max(vol(ivmin(n-1):ivmin(n)));
indmax = ivmin(n-1)+indmax;
vmax = [vmax maxvol];
ivmax = [ivmax indmax];
end
vmax = vmax';
ivmax = ivmax';
tvmax = ivmax/fs;
clear indmax maxvol n;
%plotvol1(vol, ivmin, vmin, ivmin, vmin, ivmax, vmax);
% ONLY RUN IF NEED TO ADD OR DELETE POINTS
clc;
% Left click to remove; Right click to add
% Remove min interactively
% Interactively chose data to delete
l = 8000;
n = 0;
xx = [];
yy = [];
Button = [];
while n < length(vol)
interactive_vmin2(vol, ivmin, vmin, n, l);
[x,y,button] = ginput;
Button = [Button button'];
xx = [xx x'];
yy = [yy y'];
n = n + l;
close
end
clear n x y yy button;
xdel = NaN(1,500) ; xadd = NaN(1,500);
for n = 1:length(Button)
if Button(n) == 1
xdel(n) = xx(n);
else
xadd(n) = xx(n);
end
end
xdel(isnan(xdel)) = [];
xadd(isnan(xadd)) = [];
clear xx l
% Assign NaNs to data you want to delete
% YOU MUST CLICK TO THE LEFT OF THE ONE YOU DON'T WANT
for n = 1:length(xdel)
ind = find(ivmin>round(xdel(n)), 1, 'first'); %returns the larger index
ivmin(ind) = NaN;
vmin(ind) = NaN;
end
clear n ind xdel;
% Remove NaNs
ivmin(isnan(ivmin)) = [];
vmin(isnan(vmin)) = [];
for n = 1:length(xadd)
if xadd(n) < ivmin(end)
ind = find(ivmin>round(xadd(n)), 1, 'first'); %returns the larger
index
ivmin = [ivmin(1:ind-1)' round(xadd(n)) ivmin(ind:end)']'; %ivmin
must be a column vector
vmin = [vmin(1:ind-1)' vol(round(xadd(n))) vmin(ind:end)']';
else
ivmin = [ivmin' round(xadd(n))]';
vmin = [vmin' vol(round(xadd(n)))]';
end
end
clear n ind xadd Button;
tvmin = ivmin/fs;
clear ivmax tvmax vmax
% find the vmax again
vmax = [];
ivmax = [];
for n = 2:length(ivmin)
[maxvol,indmax] = max(vol(ivmin(n-1):ivmin(n)));
indmax = ivmin(n-1)+indmax;
vmax = [vmax maxvol];
ivmax = [ivmax indmax];
end
% Make them column vectors
if size(vmax,2) > size(vmax,1)
vmax = vmax';
end
if size(ivmax,2) > size(ivmax,1)
ivmax = ivmax';
end
tvmax = ivmax/fs;
clear indmax maxvol n;
%plotvol1(vol, ivmin, vmin, ivmin, vmin, ivmax, vmax);
% Determine vdote
vdote = [];
for n = 1:length(vmax)
vdote(n) = (vmax(n)-vmin(n))/(tvmin(n+1)-tvmin(n));
end
vdote = vdote*60;
for n = 1:length(vdote)
if vdote(n) < 0
vdote(n) = 0;
end
end
vdote = vdote';
clear n;
%
aind = find(ivmin<idown,1,'last');
bind = ivmax(aind);
%aind = ivmin(aind);
if bind < idown
down = aind + 1;
else
down = aind;
end
v0 = mean(vdote(down+2:down+3));
%v0 = vdote(down);
end
V0 = [V0 v0];
VV0 = nanmean(V0);
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\v0']))
vdot = S(1,a).vdot;
time1 = num2str(round(S(1,a).time(1)));
time2 = num2str(round(S(1,a).time(end)));
clear S
save(horzcat([time1 '_' time2]));
clc;
v0
save('v0 sum.mat', 'VV0', 'V0');
________________________________________________________________
In the raw tracings, splice out data starting ~1 min before and 30 sec after each CPAP drop from
optimum pressure. Save them in the raw v0 folder.
Open the v0 script and enter the subject number and file paths as before.
Run the first cell to import the data.
Run the second cell multiple times to process each of the v0 signals. The second cell will
display a figure of mask pressure like Figure 8. Left click at the start (part A) and end (part B) of
the drop.
Figure 8A
Start of the drop
Figure 8B
End of the drop
Next, a plot of flow will be displayed (not shown here). Check to see if there is zero flow during
the drop. If so, then answer YES but typing “1” in the Command Window. If not, then answer
NO by typing “2” in the Command Window. Note that Figure 8 shows no fluctuations in the
mask pressure during the drop, indicating that there is probably zero flow in this example, so a
“1” would be entered.
If you type “2”, then the signal will need to be process using the same techniques as the previous
scripts. Continue running the second cell multiple times until all of the files have been analyzed.
The next script to run is for the active v0, or upper airway gain.
V. Determining active v0
Cut, paste, and save the following program code as uag_Sept_20_2011.m
______________________________________________________________________________
% code for getting active v0 and the Upper Airway Gain (uag)
%% Import the data
clear; clc;
subjnum = '867';
global fs
fs = 100;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\veup']))
load('veup sum.mat','MVDOTE','te','ti');
veup = MVDOTE; clear MVDOTE
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\lg']))
load('lg sum.mat','LG');
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\v0']))
load('v0 sum.mat','VV0');
cd(strcat(['D:\Old files before automatic backups done\Phenotype NEW
METHOD\Need to Analyze\' subjnum '\uag']));
q = dir;
r=0;
for z = 1:length(q)
if ~q(z,1).isdir
r = r+1;
data = importdata(strcat(['D:\Old files before automatic backups
done\Phenotype NEW METHOD\Need to Analyze\' subjnum '\uag\' q(z,1).name]));
data = data.data;
%{
S(r).name = q(z,1).name;
S(r).time = data(:,1);
S(r).arousals = data(:,2);
S(r).co2 = data(:,4);
S(r).pmask = data(:,5);
S(r).vdot = data(:,6);
S(r).sao2 = data(:,8);
%}
%
S(r).name = q(z,1).name;
S(r).time = data(:,1);
S(r).arousals = data(:,2);
S(r).co2 = data(:,4);
S(r).pmask = data(:,5);
S(r).vdot = data(:,7);
S(r).sao2 = data(:,8);
%}
end
end
clear q r z data n;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\uag']))
save('S runs');
a = 0;
Uag = [];
Vdown = [];
Cdown = [];
Vact = [];
%{
%To redo a run, enter this
clear aind bind cdown cpap down idown iup ivmax ivmin leak1 leak2 leak3 leak4
time1 time2 tvmax tvmin uag vact vdot vdote vdown vdrive veup vmax vmin vol
Uag(end) = [];
Vdown(end) = [];
Cdown(end) = [];
Vact(end) = [];
a = a-1;
clc;
%}
%% RESTART HERE WITH NEXT SIGNAL
clc;
clear aind bind cdown cpap down idown iup ivmax ivmin leak1 leak2 leak3 leak4
time1 time2 tvmax tvmin uag vact vdot vdote vdown vdrive veup vmax vmin vol
a = a + 1;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\uag']))
load('S runs');
cd ('C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop New')
% Remove the NaNs
X = [S(1,a).time S(1,a).arousals S(1,a).co2 S(1,a).pmask S(1,a).vdot
S(1,a).sao2];
X(any(isnan(X),2),:) = [];
% Reconstruct signals without the NaNs
S(1,a).time = X(:,1);
S(1,a).arousals = X(:,2);
S(1,a).co2 = X(:,3);
S(1,a).pmask = X(:,4);
S(1,a).vdot = X(:,5);
S(1,a).sao2 = X(:,6);
clear X;
% determine iup and idown
% Create figure
scrsz = get(0,'ScreenSize');
figure1 = figure('Position',[10 270 scrsz(3)-20 scrsz(4)-400]);
% Create axes
axes1 = axes('Parent',figure1);
box('on');
hold('all');
% Create plot
plot1 = plot(S(1,a).pmask);
title('LEFT CLICK ON IDOWN AND IUP');
[x,y] = ginput;
clear y scrsz figure1 axes1 plot1;
x = round(x);
idown = x(1);
iup = x(2);
clear x n;
close;
% Determine Leak
vol = cumsum(S(1,a).vdot)/fs;
p1 = polyfit(S(1,a).time(1:idown),vol(1:idown),1);
leak1 = p1(1);
p2 = polyfit(S(1,a).time(idown:iup),vol(idown:iup),1);
leak2 = p2(1);
p3 = polyfit(S(1,a).time(iup:end),vol(iup:end),1);
leak3 = p3(1);
clear p1 p2 p3
%
% Subtract the first leak up to idown, then the second.
S(1,a).vdot(1:idown) = S(1,a).vdot(1:idown) - leak1;
S(1,a).vdot(idown+1:iup) = S(1,a).vdot(idown+1:iup) - leak2;
S(1,a).vdot(iup+1:end) = S(1,a).vdot(iup+1:end) - leak3;
%clear leak1 leak2 leak3;
% Recalculate volume
vol = cumsum(S(1,a).vdot)/fs;
% Create figure
scrsz = get(0,'ScreenSize');
figure1 = figure('Position',[10 270 scrsz(3)-20 scrsz(4)-400]);
% Create axes
axes1 = axes('Parent',figure1);
box('on');
hold('all');
% Create plot
plot1 = plot([0:length(S(1,a).vdot)-1],S(1,a).vdot,[0 length(S(1,a).vdot)],[0
0]);
title('Check to see if there is zero flow');
zf = input('Is there zero flow? (1=YES 2=NO): ');
if zf == 1
vact = 0;
Uag = [Uag 0];
Vdown = [Vdown NaN];
cdown = mean(S(1,a).pmask);
Cdown = [Cdown cdown];
Vact = [Vact vact];
else
% Find peak and trough
[vmin,ivmin] = get_vmin2(vol,ti,te,1.4);
tvmin = ivmin/fs;
% find the vmax
vmax = [];
ivmax = [];
for n = 2:length(ivmin)
[maxvol,indmax] = max(vol(ivmin(n-1):ivmin(n)));
indmax = ivmin(n-1)+indmax;
vmax = [vmax maxvol];
ivmax = [ivmax indmax];
end
vmax = vmax';
ivmax = ivmax';
tvmax = ivmax/fs;
clear indmax maxvol n;
%plotvol1(vol, ivmin, vmin, ivmin, vmin, ivmax, vmax);
% ONLY RUN IF NEED TO ADD OR DELETE POINTS
clc;
% Left click to remove; Right click to add
% Remove min interactively
% Interactively chose data to delete
l = 8000;
n = 0;
xx = [];
yy = [];
Button = [];
while n < length(vol)
interactive_vmin2(vol, ivmin, vmin, n, l);
[x,y,button] = ginput;
Button = [Button button'];
xx = [xx x'];
yy = [yy y'];
n = n + l;
close
end
clear n x y yy button;
xdel = NaN(1,500) ; xadd = NaN(1,500);
for n = 1:length(Button)
if Button(n) == 1
xdel(n) = xx(n);
else
xadd(n) = xx(n);
end
end
xdel(isnan(xdel)) = [];
xadd(isnan(xadd)) = [];
clear xx l
% Assign NaNs to data you want to delete
% YOU MUST CLICK TO THE LEFT OF THE ONE YOU DON'T WANT
for n = 1:length(xdel)
ind = find(ivmin>round(xdel(n)), 1, 'first'); %returns the larger
index
ivmin(ind) = NaN;
vmin(ind) = NaN;
end
clear n ind xdel;
% Remove NaNs
ivmin(isnan(ivmin)) = [];
vmin(isnan(vmin)) = [];
for n = 1:length(xadd)
if xadd(n) < ivmin(end)
ind = find(ivmin>round(xadd(n)), 1, 'first'); %returns the larger
index
ivmin = [ivmin(1:ind-1)' round(xadd(n)) ivmin(ind:end)']'; %ivmin
must be a column vector
vmin = [vmin(1:ind-1)' vol(round(xadd(n))) vmin(ind:end)']';
else
ivmin = [ivmin' round(xadd(n))]';
vmin = [vmin' vol(round(xadd(n)))]';
end
end
clear n ind xadd Button;
tvmin = ivmin/fs;
clear ivmax tvmax vmax
% find the vmax again
vmax = [];
ivmax = [];
for n = 2:length(ivmin)
[maxvol,indmax] = max(vol(ivmin(n-1):ivmin(n)));
indmax = ivmin(n-1)+indmax;
vmax = [vmax maxvol];
ivmax = [ivmax indmax];
end
% Make them column vectors
if size(vmax,2) > size(vmax,1)
vmax = vmax';
end
if size(ivmax,2) > size(ivmax,1)
ivmax = ivmax';
end
tvmax = ivmax/fs;
clear indmax maxvol n;
%plotvol1(vol, ivmin, vmin, ivmin, vmin, ivmax, vmax);
% Determine vdote
vdote = [];
for n = 1:length(vmax)
vdote(n) = (vmax(n)-vmin(n))/(tvmin(n+1)-tvmin(n));
end
vdote = vdote*60;
for n = 1:length(vdote)
if vdote(n) < 0
vdote(n) = 0;
end
end
vdote = vdote';
clear n;
cpap = S(1,a).pmask(ivmin);
%plotpress(S(1,a).pmask, ivmin, cpap);
cpap(end) = [];
%
aind = find(ivmin<idown,1,'last');
bind = ivmax(aind);
%aind = ivmin(aind);
if bind < idown
down = aind + 1;
else
down = aind;
end
%
vact = mean(vdote(down+2:down+3));
%vact = vdote(down);
vdown = mean(vdote(down-5:down-1));
if ~isnan(LG)
vdrive = (veup-vdown)*LG;
else
vdrive = NaN;
end
uag = (vact-VV0)/vdrive;
Uag = [Uag uag];
Vdown = [Vdown vdown];
cdown = mean(cpap(1:down-1));
Cdown = [Cdown cdown];
Vact = [Vact vact];
end
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\uag']))
vdot = S(1,a).vdot;
time1 = num2str(round(S(1,a).time(1)));
time2 = num2str(round(S(1,a).time(end)));
clear S
save(horzcat([time1 '_' time2]));
clc;
save('uag sum.mat', 'Uag','Vdown','Cdown','Vact');
%save('uag sum.mat', 'Vact');
vact
________________________________________________________________
This script is almost exactly like the passive v0 script. Make the necessary changes to the
subjnum and file paths.
In the raw data, splice out signals starting ~1 min before and 30 sec after each drop from
suboptimum (or minimum tolerable) pressure. Save them in the raw uag folder (uag means
“upper airway gain”).
Open the uag script and enter the subject number and file paths as before.
Run the first cell to import the data.
Run the second cell multiple times to process each file. The second cell will display a figure like
the one in Figure 8 above. Again, left click at the start (part A) and end (part B) of the drop.
Next, a plot of flow will be displayed. Check to see if there is zero flow during the drop. If so,
then answer YES but typing “1” in the Command Window. If not, then answer NO by typing
“2” in the Command Window.
If you type “2”, then the signal will need to be process using the same techniques as the previous
scripts. Continue running the second cell until all of the files have been analyzed.
VI. Summarize the data
This last script summarizes all of the data and makes an OSA model diagram for the patient.
Cut, paste, and save it as sum_Sept_20_2011.m
______________________________________________________________________________
% code for summarizing the Phenotype data
% Run last
%% Evaluate Summary Data
clear; clc;
subjnum = '867';
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\veup']))
load('veup sum.mat','MVDOTE'); veup = MVDOTE; clear MVDOTE
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\lg']))
load('lg sum.mat','LG','Lg');
if isnan(LG)
LG = 30;
end
lg = -LG; Lg = -Lg; clear LG
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\v0']))
load('v0 sum.mat','VV0','V0'); v0 = VV0; clear VV0;
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\var']))
load('var sum.mat','AR','Ar'); var = AR; clear AR
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum '\uag']))
load('uag sum.mat');
cd (strcat(['C:\Documents and Settings\user1\My Documents\MATLAB\Phenoloop
New\' subjnum]))
X = [Cdown' Vact' Uag' Vdown'];
Y = sortrows(X,1);
Cdown = Y(:,1);
Vact = Y(:,2);
Uag = Y(:,3);
Vdown = Y(:,4);
roundCdown = round(Cdown);
%round the CPAP to nearest integer
lowCdown = []; %find the low values of suboptimum CPAP where drops were done
if length(roundCdown) <= 3
lowCdown = roundCdown;
else
lowCdown = roundCdown(1);
for n = 2:length(roundCdown)
d = roundCdown(n) - roundCdown(1);
if d < 1
lowCdown = [lowCdown roundCdown(n)];
end
end
end
if length(lowCdown) < 3
lowCdown = [];
lowCdown = roundCdown(1);
for n = 2:length(roundCdown)
d = roundCdown(n) - roundCdown(1);
if d <= 1
lowCdown = [lowCdown roundCdown(n)];
end
end
end
n = length(lowCdown);
lowestCdown = lowCdown;
Vact5 = Vact(1:n);
vact = mean(Vact5);
nremahi = input('Enter NREM AHI: ');
remahi = input('Enter REM AHI: ');
% loop gain line
xspan = 25;
x = veup:.01:50;
b = veup - (1/lg)*veup;
y = (1/lg)*x + b;
% Arousal threshold line
ta = lg*(var-b);
% upper airway gain line
uag = (vact-v0)/(ta-veup);
b1 = v0 - uag*veup;
y1 = uag*x + b1;
% Create figure
figure1 = figure;
% Create axes
axes1 = axes('Parent',figure1,'FontSize',12);
% Uncomment the following line to preserve the X-limits of the axes
xlim(axes1,[0 20]);
% Uncomment the following line to preserve the Y-limits of the axes
ylim(axes1,[0 10]);
hold(axes1,'all');
% Create multiple lines using matrix input to plot
plot1 = plot(veup,veup,veup,var,veup,vact,veup,v0,'MarkerFaceColor',[0 0
0],...
'MarkerEdgeColor',[0 0 0],...
'MarkerSize',15,...
'Marker','.',...
'LineStyle','none',...
'Color',[0 0 0],...
'Parent',axes1);
set(plot1(2),'DisplayName','var vs veup');
set(plot1(3),'DisplayName','vact vs veup');
set(plot1(4),'DisplayName','v0 vs veup');
% Create xlabel
xlabel('Ventilatory drive (L/min)','FontSize',14);
% Create ylabel
ylabel('Ventilation (L/min)','FontSize',14);
% Create title
title(horzcat(['10. AHI ' num2str(nremahi)]),'FontSize',14);
% Create multiple lines using matrix input to plot
plot2 = plot(x,y,x,y1,'MarkerFaceColor',[0 0 0],...
'MarkerEdgeColor',[0 0 0],...
'LineWidth',1,...
'Color',[0 0 0]);
set(plot2(1),'DisplayName','y vs x');
set(plot2(2),'DisplayName','y1 vs x');
% Create plot
plot([ta ta],[-10 50],'MarkerFaceColor',[0 0 0],'MarkerEdgeColor',[0 0 0],...
'LineWidth',1,...
'DisplayName','[-10 50] vs [ta ta]',...
'Color',[0 0 0]);
% Create multiple lines using matrix input to plot
plot(ta,var,ta,vact,'Visible','off','MarkerFaceColor',[0 0 0],...
'MarkerEdgeColor',[0 0 0],...
'MarkerSize',15,...
'Marker','.',...
'LineStyle','none',...
'DisplayName','vact vs ta',...
'Color',[0 0 0]);
% Create multiple lines using matrix input to plot
plot3 = plot([veup ta-.4],[var var],[veup ta-.4],[vact
vact],'MarkerFaceColor',[0 0 0],...
'MarkerEdgeColor',[0 0 0],...
'LineStyle',':',...
'Color',[0 0 0]);
set(plot3(1),'DisplayName','[var var] vs [veup ta-.1]');
set(plot3(2),'DisplayName','[vact vact] vs [veup ta-.1]');
% Create multiple lines using matrix input to plot
plot4 = plot(ta-.4,var,ta-.4,vact,'MarkerFaceColor',[0 0 0],...
'MarkerEdgeColor',[0 0 0],...
'MarkerSize',5,...
'Marker','>',...
'Color',[0 0 0]);
set(plot4(1),'DisplayName','var vs ta-.5');
set(plot4(2),'DisplayName','vact vs ta-.5');
% Create text
text('Parent',axes1,'String',['V_e_u_p_n_e_a = '
num2str(round(veup*10)/10)],...
'Position',[veup-4.1 veup 0],...
'Color',[0 0 0]);
% Create text
text('Parent',axes1,'String',['V_a_r_o_u_s_a_l = '
num2str(round(var*10)/10)],...
'Position',[veup-4.1 var 0],...
'Color',[0 0 0]);
% Create text
text('Parent',axes1,'String',['active V_0 = ' num2str(round(vact*10)/10)],...
'Position',[veup-4.4 vact 0],...
'Color',[0 0 0]);
if v0 < 1
text('Parent',axes1,'String',['passive V_0 = '
num2str(round(v0*10)/10)],...
'Position',[veup-4.9 v0+.4 0],...
'Color',[0 0 0]);
else
text('Parent',axes1,'String',['passive V_0 = '
num2str(round(v0*10)/10)],...
'Position',[veup-4.9 v0 0],...
'Color',[0 0 0]);
end
% Create text
text('Parent',axes1,'String',['Ar Thr = ' num2str(round(ta*10)/10)],...
'Position',[ta+.2 9 0],...
'Color',[0 0 0]);
% Create text
text('Parent',axes1,'String',['LG = ' num2str(round(lg*10)/10)],...
'Position',[ta+2 veup 0],...
'Color',[0 0 0]);
% Create text
if v0 < 1
text('Parent',axes1,'String',['UAG = ' num2str(round(uag*10)/10)],...
'Position',[ta+2 v0+0.3 0],...
'Color',[0 0 0]);
else
text('Parent',axes1,'String',['UAG = ' num2str(round(uag*10)/10)],...
'Position',[ta+2 v0 0],...
'Color',[0 0 0]);
end
saveas(gcf,'Model');
print -dmeta
save('sum data.mat');
________________________________________________________________
There is only 1 cell to run in this script and it is self-explanatory.
Download