%contractometer.m
%
%Measures durations and intervals between uterine contractions during
%labor.
%
%When a contraction starts, click the mouse on the upper left green
%'Contraction Start' button. This will start the clock in the upper
%right, and a horizontal red line will rise over time indicating the
%duration of the current contraction on the left graph.
%
%When the contraction stops, click on the upper left red 'Contraction Stop'
%button (formerly the green 'Contraction Start' button). The duration of
%this contraction will be added to the plot on the left. If this is not the
%first contraction then the interval between the start of this and the previous
%contraction will be added to the plot on the right.
%
%Data are stored in a text file, 'contractionTimes.txt' in the current directory.
%The file is updated every time the user indicates a start or end of a
%contraction. This means that the user can quit the program (and quit MATLAB)
%and resume to it without loss of data.
%
%Data in 'contractionTimes.txt' are stored as date strings followed by a
%return character. Successive lines indicate contraction start and stop
%times. Contractions are separated by a blank line (return character).
%
%The only way the user can clear the data is to remove (or rename) the file
%'contractionTimes.txt'.
%
%The user can edit contractionTimes.txt with a text editor (if, for example
%a button is pressed inadvertently, or times need to be added manually after
%driving to the hospital). The program is not robust with respect to errors
%in the text file, so be sure that the data are entered in the proper format
%(e.g. no extra characters, or extra lines at the end of the file).
%
%Example:
%
%08-Jul-2007 10:58:37
%08-Jul-2007 10:58:47
%
%08-Jul-2007 11:09:06
%08-Jul-2007 11:09:16
%
%08-Jul-2007 11:38:24
%08-Jul-2007 11:38:34
%
%08-Jul-2007 11:50:43
%08-Jul-2007 11:50:53
%
%The 'Quit' button returns control flow back to the matlab prompt. Upon
%quitting, the button turns in to a 'Resume' button which starts the program
%again. Quitting and Resuming is a convenient way to incorporate manual
%changes in the data file 'contractionTimes.txt'.
%
%The standard literature says that it's time to go to the hospital when
%contraction are <= 5 minutes apart, and last longer than about 60 seconds,
%hence the pink zones on the graphs. But don't hold me responsible for this
%advice! Be sure to talk to your physician about what to do with the
%information gathered by this program.
%
%Written by G.M. Boynton, July 2007 in anticipation of a baby nerd due
%August 1st.
%Define some stuff for plotting and saving data.
fileName = 'contractionTimes.txt';
newline = sprintf('\n');
markerSize =5;
lineWidth = 1;
%Load in or initialize parameters
if exist(fileName,'file');
%Load in data from text file. This section is sort of lame -
%not much error handling to deal with problems with the text file.
fp = fopen(fileName,'r');
startStr = 'foo';
i=0;
startTimes = [];stopTimes = [];
clear state
while ischar(startStr)
i = i+1;
startStr = fgetl(fp);
if ischar(startStr)
startTimes(i) = datenum(startStr);
state =1;
end
stopStr = fgetl(fp);
if ischar(stopStr)
if ~isempty(stopStr)
stopTimes(i) = datenum(stopStr);
state = 0;
end
end
foo = fgetl(fp);
end
fclose(fp);
else %data file doesn't exist, so initialize parameters.
startTimes = []; %vector of starting clock times
stopTimes = []; %vector of stop clock times.
state = 0; %0: between contractions, 1: during contraction
end
%The vectors startTimes and stopTimes contain times in the form of serial
%date numbers (see datenum and datestr).
%Set up the graphs and UI buttons
figure(1)
clf
set(gcf,'NumberTitle','off','Name','Contractometer');
%Right graph: time between contractions
hsubplot1 = subplot('Position',[.55,.1,.4,.65]);
patch([0,1000,1000,0],[0,0,5,5],[1,.75,.75],'EdgeColor','none'); %pink zone
hold on
for y=0:5:450
plot([0,1000],[y,y],'-','Color',[.8,.8,.8]);
end
hplot1 = plot(0,0,'bo-','MarkerFaceColor','b','MarkerSize',markerSize,'LineWidth',lineWidth,'Visible','off');
hline1 = plot([0,1000],[0,0],'r-','LineWidth',lineWidth);
set(gca,'YLim',[0,45]);
set(gca,'XTick',[-inf,inf]);
ylabel('Minutes');
title('Time between contractions');
%Left graph: duration of contractions
hsubplot2 = subplot('Position',[.075,.1,.4,.65]);
patch([0,1000,1000,0],[60,60,1000,1000],[1,.75,.75],'EdgeColor','none'); %pink zone
hold on
for y=0:10:300
plot([0,1000],[y,y],'-','Color',[.8,.8,.8]);
end
hplot2 = plot(0,0,'bo-','MarkerFaceColor','b','MarkerSize',markerSize,'LineWidth',lineWidth,'Visible','off');
hline2 = plot([0,1000],[0,0],'r-','LineWidth',lineWidth);
%plot([0,1000],60*[1,1],'r:','LineWidth',lineWidth);
ylabel('Seconds');
title('Duration of contractions');
set(gca,'YLim',[0,70]);
set(gca,'XTick',[-inf,inf]);
%Contraction Start/Stop push button
hbutton = uicontrol('Units','normalized');
set(hbutton,'Position',[0,.85,.5,.15],'Style','togglebutton');
set(hbutton,'BusyAction','cancel');
set(hbutton,'ForegroundColor','w');
set(hbutton,'FontSize',12,'FontWeight','bold');
set(hbutton,'Value',state);
if state == 0
set(hbutton,'String','Contraction Start');
set(hbutton,'BackgroundColor','g');
else
set(hbutton,'String','Contraction Stop');
set(hbutton,'BackgroundColor','r');
end
%Quit/Resume button
hquit = uicontrol('units','normalized');
set(hquit,'Style','togglebutton');
set(hquit,'Position',[.9,.8,.1,.05]);
set(hquit,'String','Quit');
set(hquit,'BackgroundColor','w');
%Timing text handle
htext = uicontrol('Units','normalized');
set(htext,'Position',[0.5,.85,.5,.15]);
set(htext,'FontSize',12,'FontWeight','bold');
%loop until 'Quit' button is pressed.
while ~get(hquit,'Value')
t = datenum(clock); %get the clock time
if ~isempty(startTimes)
dt = t-startTimes(end); %time since start of previous contraction.
else
dt = NaN;
end
switch state %set up the text for the timing text window.
case 0 %We're in between contractions
str = 'Time since last contraction';
set(hline2,'Visible','off');
case 1 %We're in the middle of a contraction
str = 'Duration of current contraction';
set(hline2,'Visible','on');
set(hline2,'YData',24*60*60*dt*[1,1]); %creeping red line on left graph
end
%convert dt to minutes and seconds
min = floor(24*60*dt);
sec = floor(mod(24*60*60*dt,60));
if ~isnan(dt)
if sec<10
set(htext,'String',sprintf('%30s %d:0%d',str,min,sec));
else
set(htext,'String',sprintf('%30s %d:%d',str,min,sec));
end
end
set(hline1,'YData',24*60*dt*[1,1]); %creeping red line on right graph.
dateLabel = datestr(startTimes,'HH:MM');
if length(startTimes)>1 %plot the data on the right graph
contractionDiff = 24*60*diff(startTimes);
set(hplot1,'XData',1:length(contractionDiff));
set(hplot1,'YData',contractionDiff);
set(hplot1,'Visible','on');
set(hsubplot1,'XLim',[.5,length(contractionDiff)+.5]);
set(hsubplot1,'YLim',[0,max([max(contractionDiff)*1.05,30,1.05*24*60*dt])]);
set(hsubplot1,'XTick',1:length(contractionDiff));
end
if length(stopTimes)>0 %plot the data on the left graph
contractionDur = 24*60*60*(stopTimes-startTimes(1:length(stopTimes)));
set(hplot2,'XData',1:length(contractionDur));
set(hplot2,'YData',contractionDur);
set(hplot2,'Visible','on');
set(hsubplot2,'XLim',[.5,length(contractionDur)+.5]);
if state == 0
set(hsubplot2,'YLim',[0,max([max(contractionDur)*1.05,70])]);
else
set(hsubplot2,'YLim',[0,max([max(contractionDur)*1.05,70,1.05*24*60*60*dt])]);
end
set(hsubplot2,'XTick',1:length(contractionDur));
set(hsubplot2,'XTickLabel',dateLabel(1:length(contractionDur),:),'FontSize',8);
end
newState = get(hbutton,'Value');
if newState~=state %user has pushed the 'Contraction Start/Stop' button
t = round(t*24*60*60)/(24*60*60); %round time to nearest second.
state = newState;
switch state
case 0 %Contraction is starting!
stopTimes = [stopTimes, t];
set(hbutton,'String','Contraction Start');
set(hbutton,'BackgroundColor','g');
case 1 %Contraction has ended.
startTimes = [startTimes,t];
set(hbutton,'String','Contraction Stop');
set(hbutton,'BackgroundColor','r');
end
%Save the data in 'contractionTimes.txt'
fp = fopen(fileName,'w');
for i=1:length(startTimes)
fwrite(fp,[datestr(startTimes(i)),newline]);
if length(stopTimes)>=i;
fwrite(fp,[datestr(stopTimes(i)),newline]);
end
fwrite(fp,newline);
end
fclose(fp);
end
drawnow
end
%We're here, so the user must have selected the 'Quit' button.
%Prepare for 'Resume' mode and exit the program
set(hquit,'String','Resume');
set(htext,'ForegroundColor',[.5,.5,.5]);
set(hbutton,'Visible','off');
set(hquit,'CallBack','contractometer'); %Hitting 'Resume' button calls this program again.