Real-time heart rate calculation
15 views (last 30 days)
Show older comments
I have a real-time(phonocardiograph) plot which displays data from an electronic stethoscope via the COM port. I am trying to calculate the heart rate but having little success. I have created a uicontrol on the figure to display the BPM and have included the formulas to count the peak signals(beat_count). At the momement 'BPM:' displays on the plot figure but without a value so I am unable to get any BPM_avg reading.
a = arduino('COM4','Due');
y=0;
hPlot = plot(NaN);
intervalSize = 200;
currentInterval = 200;
t = 1; % number of samples
atInterval = 1;
beat_count = 0;
quitbutton = uicontrol('style','pushbutton',...
'string','Quit', ...
'fontsize',12, ...
'position',[10,2,50,20], ...
'callback','quitit=1;close');
quitit = 0;
bpmtext = uicontrol('style', 'text',...
'string', ['BPM: '],...
'fontsize', 12,...
'position', [80, 2, 100, 20]);
while(1)
k = 1;
while(t<currentInterval)
b=readVoltage(a, 'A0');
y=[y,b];
if ishandle(hPlot)
set(hPlot, 'YData', y);
else
break; % break out of the loop
end
xlabel('Samples')
ylabel('Voltage')
title('Phonocardiogram')
axis([currentInterval - intervalSize,currentInterval,0,3]);
%grid
t=t+k;
pause(0.002)
end
for m = 2 : length(b)-1
if(b(m) > b(m-1) & b(m) > b(m+1) & b(m) > 2.4)
%disp('Prominant peak found');
beat_count = beat_count + 1;
set(bpmtext, 'string', ['BPM: ',...
num2str(BPM_avg,4)]);
end
end
currentInterval = currentInterval + intervalSize;
atInterval = atInterval + 1;
if ~ishandle(hPlot)
break;
end
fs = 500;
N = length(b);
duration_in_seconds = N/fs;
duration_in_minutes = duration_in_seconds/60;
BPM_avg = beat_count/duration_in_minutes;
end
3 Comments
Iqra Chaudhary
on 14 Dec 2019
How to find heart beat rate of an audio wav file without using arduino?
Manju
on 25 May 2024
can u give me a code the shows the variation in the heart rate with respect to stress level
Accepted Answer
Geoff Hayes
on 22 Mar 2017
bilal - it doesn't look like BPM_avg is defined before you try and use it, so I'm surprised that you are not getting an error when you call
set(bpmtext, 'string', ['BPM: ', num2str(BPM_avg,4)]);
Also, why is the above in a for loop that does not do anything to BPM_avg
for m = 2 : length(b)-1
if(b(m) > b(m-1) & b(m) > b(m+1) & b(m) > 2.4)
%disp('Prominant peak found');
beat_count = beat_count + 1;
set(bpmtext, 'string', ['BPM: ',num2str(BPM_avg,4)]);
end
end
I think that that is part of the problem - BPM_avg is not being set or updated when it should be. Why not update it when you receive the data from the Arduino instead having this for loop outside of the while loop?
19 Comments
dpb
on 30 Mar 2017
...
while(t<currentInterval)
b=readVoltage(a, 'A0');
%length(b)
y=zeros(Nsamples,1); % preallocate array
for i=1:Nsamples
y(i)= b;
...
You've convoluted up the stuff I gave you in the sidebar email without again thinking much about what you're really doing it seems...
Above you start the collection, read a sample and only THEN preallocate an array. You then go thru a loop over a number of samples to collect and simply stuff the one reading into that array...hardly useful.
I gave you the outline as
initializeArduinohere
nSamples = HoweverManyYouWant;
y=zeros(nSamples,1); % preallocate
t=zeros(size(y)); % to collect the time of the conversion
tic % start the time
for i=1:nSamples % start the collection
y(i)=readVoltage(... % read the A/D
t(i)=toc; % save time
end
Now post-process the time history.
Your timing experiments have shown that as set up without other ways to figure out where all the CPU cycles are going that the
a = arduino('COM4','Due');
while(1)
tic
b=readVoltage(a, 'A0');
toc
end
gives:
Elapsed time is 0.146963 seconds.
Elapsed time is 0.083865 seconds.
Elapsed time is 0.046447 seconds.
Elapsed time is 0.045178 seconds.
Elapsed time is 0.050683 seconds.
Elapsed time is 0.019395 seconds.
Elapsed time is 0.019464 seconds.
Elapsed time is 0.019031 seconds.
Elapsed time is 0.017789 seconds.
that the best you're doing without any other processing is only about 50 Hz and some cycles are as much as 4-7X that.
As we've spoken off-forum, until you can figure out what's going on there, you're wasting time worrying about other stuffs.
As I've said elsewhere, I've never seen an Arduino so only know what I can find online, but the doc's at their site seem to indicate with the C interface readDigital can run at about 10 kHz; don't know how TMW can manage to have slowed it down to this extent, but there's where your biggest problem is. It would seem you should download the direct access IDE and try a "sketch" as they seem to call a program directly to see how that performs--you may be able to collect the data that way and then use Matlab to post-process it, but at this point it seems acquisition under Matlab is going to be problematical at best.
More Answers (1)
dpb
on 30 Mar 2017
Edited: dpb
on 30 Mar 2017
I'm going to put this as an Answer to emphasize the point again...your timing code of just a single read in a tight loop shows that whatever is going on in the Matlab interface to the Arduino readVoltage routine at least on your system it's just killing performance. I again STRONGLY suggest you read the blog of another experimenter with the Due for some very informative background on using the Due and on data collection in general.
It's clearly possible when running code directly on the board to run at much higher rates; as said above I don't understand how there can be as much latency using the Matlab interface, but until you can find some resolution there what you're trying to do just isn't going to work.
PS. I wonder if since there are 16 channels on the Due if they're all active the sample rate gets divided down by polling them all and just returning the one asked for, maybe? I didn't see where it says whether the A/D sampling is simultaneous or sequential, only that is 1MHz capable. As have emphasized off the board in our sidebar conversation, you need to dig into the guts of the board and the Matlab interface much more deeply to figure out what's going on here.
I don't suppose it could be some sort of communication issue slowing it down, is it? Can you test that somehow?
Mayhaps ask on one of the demo blogs from TMW what you should expect in a tight loop or, if you or your university has support, submit a support request and see if TMW will respond.
ADDENDUM
Btw, the last timing you sent is most curious...I pasted into a variable tacq and one gets the following interesting figure--
For some reason, the acquire time goes down with each loop; dramatically at the beginning and then looks like is approaching a steady-state rate, maybe. I don't know what would cause this behavior; seems very odd, indeed.
Why don't you try the above loop with nSamples at some sizable number and collect a waveform or two and see what you get? If you approach 60 hz as it appears this is, how long a time series do you want? Multiply N seconds by 60 and collect that many samples. Of course, do the preallocation and collect both the reading and the transpired time as shown and
plot(t,y)
to see what you get. Post those results back here. It would, of course also be informative to just collect the timing information for several trials of a large number to see if the above is consistent and what steady-state rate is. You might want to "pretrigger" by some number of samples before recording "real" data...
16 Comments
dpb
on 2 Apr 2017
I was asking about how it is physically connected to read the device? How the data transfer occurs is immaterial to trying to solve your instrumentation issues.
What was in the arduino.m file out of curiosity? Is it m-code too or did it drop down into a mex file or does it show an Arduino "sketch" or what?
Again, I'm still curious about whether there was anything attached to the Arduino on those timing runs that was powered up???
See Also
Categories
Find more on Real-Time Simulation and Testing in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!