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.