Tuesday, June 8, 2010

Heart Beat and SpO2 detection

I made some real progress this weekend in integrating the software to compute the heart rate (in bpm) and the blood oxygen saturation. I also made some real progress in reading real PPG signals from the TIA and providing dynamic gain. The pieces are coming together and a final blog update post will chronicle the past successes.

Heartbeat detection, reference:
A reference ADC sample had to be taken to determine the frequency (bpm) of the PPG signal. To do this, I used the function generator to drive a simulated PPG signal with a frequency of 2 Hz with p2p of 100 mV.

From this reference I noted that I captured 5 full periods. I then measured the index between from a peak-to-peak. In the image below, I measured from index 38 (with value 1286) to index 134 (with value 1312). This distance of 134-38 = 96 represents an index count of one full period of the simulated PPG. I also know that the repetion rate is 2 Hz so each full period represents 500 millsecond.

Now when I have a real ADC sample I compare the distance between peaks in this. In the image below, I measured from index 125 (with value 952) to index 325 (with value 967). this distance of 325-125 = 200 represents the index count of my pulse.

I now can set a basic porportion by stating that 96 index = 0.5 sec and 200 index = X seconds. Solving for X the result is 1.041 second. Therefore I noted that my pulse is 1 beat per 1.041 second or 62.5 bpm. This is a little under the average human heart rate of 72 bpm because I eyeballed last measurement.

Simulated PPG waveform

Real PPG waveform

Heartbeat detection, simulation:
Before I started implementing any code on the micro controller to analyze the ADC information I wanted to run a simulation. I started by writing my own program and creating a mock-array to mimic a PPG pulse ox signal.

I then started researching how to do peak detection in LabVIEW environment. Peak detection is very common in Signal processing and there was an abundance of resources on the topic. I quickly discovered the Peak Detector .VI in LabVIEW. This is a really cool VI which interpolates your data as a polynomial then takes derivatives to find maxim and minim points. I found a good example provided in the SDK which I just modified around my simulated pulse ox signal. Here is an image from the result:


You just specify threshold for max and min and it calculates valley and peak and puts the index and amplitudes in corresponding arrays. Knowing this, I really wanted to use it to implement the solution on my micro controller.

Heartbeat detection, practice:
I quickly ran into some problems when I tried to use this .VI on the micro controller. It appeared that it wasn't processing the data. I examined and googled the error result "-20001" and discovered this is the code for OUT_OFMEMORY error. I knew I would likely hit this point at some point as my program had really grown in size. I tried to slim down my program by deleting unused memory allocation routines but to no avail.

This is the biggest drawback in my opinion of developing in the LabVIEW environment. In a C environment I would quickly be able to diagnose this error and make a creative solution. But since I have no idea how memory is allocated by the high level (it should be dynamic and typeless to prevent memory leak) I simply cannot use this VI.

I was really disappointed so I had to create a new way to detect peak and valley. The solution I came up with is kind of elegant and will work. Here is how it works.
1. Sort the ADC array in Ascending order (low # first, high # last).
2. Reverse the order of this array to descending (high # first, low # last).
3. Index into element [0] to find maximum value in ADC array.
4. Now must check over the entire ADC array, let iteration count be represented by element j.
a. If ( (ADC[j]>ADC[j-1]) & (ADC[j]>ADC[j+1])) then element represents peak.
b. If ( (ADC[j]

I then have this basic delta detection scheme to determine distance (in index) from peak-to-peak or through-to-through. Now that you have this number you compare it to the reference spectrum calculated earlier. Like I said earlier, from reference we know what a period in index corresponds to so it's really easy to calculate Bpm from this.

I haven't finished writing code for SpO2 calculation but it's very easy from this new module. The new module can easily calculate max and min and can take ratio of these elements.

I think my biggest concern right now is time. Can I put this all together and have it working by Thursday. The one thing if I had more time is I'd make it more robust and reliable. There are odd quirks that I wish I could diagnose better.

No comments:

Post a Comment