IntroductionAt the highest level, the design of our project centers around an acquisition circuit, data processing in two MCUs, and the output on a TV screen. The first part of the stethoscope is the acquisition unit, which consists of an actual stethoscope mated with a microphone, and an amplifier circuit. The microphone captures the audible signal from the body that is acoustically amplified by the stethoscope. After that, we bias and set the gain of the signal using an operational amplifier so that the ADC on the MCU will be able to pick up the signal. The analog data will be independently sampled by the two MCUs at a rate appropriate for display on the TV (CPU1) and a rate sufficient to capture the appropriate characteristics of the signal for beat detection (CPU2). CPU2, uses a moving threshold scheme to detect the actual heartbeats, and from that derive the heart rate. Then the signal is blasted to the TV, which also displays pertinent data, such as beats per minute. Additional information is displayed on the HyperTerm. If applicable, a buzzer will sound if your heart rate falls out of a specified range.
In our final project we implemented a digital stethoscope. At the highest level, the design of our project centers around an acquisition circuit, data processing in two MCUs, and the output on a TV screen. The stethoscope detects and displays the heart beat and BPM. The first part of the stethoscope is the acquisition unit, which basically consists of an actual stethoscope mated with a microphone, and an amplifier circuit. The microphone captures the audible signal from the body that is acoustically amplified by the stethoscope. After that, we set the gain of the signal using an operational amplifier so that the ADC on the MCU will be able to pick up the signal. This is necessary because the amount of signal you get from the heartbeat in your neck is probably much more than the heartbeat in your wrist, for example.
The analog data will be independently sampled by the two MCUs at a rate appropriate for display on the TV (CPU1) and a rate sufficient to capture the appropriate characteristics of the signal for beat detection
(CPU2). With uniform data to work with in CPU2, we then wrote a scheme to detect the actual heartbeat, and from that derive the heart rate. There are many methods we could use to implement this including absolute minima/maxima, average min/max, and Fourier (frequency) representation of the signal. Our basic approach uses a moving threshold approach that is outlined in detail in the software section below. The heartbeat signal and rate (beats per minute) will then be output to the TV screen, similar to ECE476 lab 4. Figure 1 shows the basic setup of the entire project.
The first part of our circuit was the stethoscope itself. Aaron’s father is a cardiologist and we were able to obtain a used stethoscope from him free of charge. Originally the stethoscope had very flexible medical latex tubing which mated the end piece with the metal frame and the earpieces. The problem with the tubing is that we could not find a microphone small enough to fit inside it. Our solution was to make a trip to the hardware store and pick up some vinyl tubing. We used 3/16” inside diameter tubing for the main length and then 2 fitted larger sizes to telescope up to the size of our microphone. After we worked the microphone down into the largest piece, we secured it with a metal hose clamp, as shown in figure 2. We initially figured that the tube needed to be sealed so that acoustic loss would be minimized. We attempted to melt the pieces of tubing together, but that was quite disastrous and we ended up burning holes in the tubing. We eventually decided (after reassurance from
The WM-034DHB microphone we used is omnidirectional with -42dB sensitivity, >60dB SNR, and a 20-16kHz response range. This particular microphone requires a 1.5V bias to operate properly. We built a bias circuit using a 10kΩ trimpot, a 2N3904 NPN transistor, and a few resistors. The diagram for the microphone bias circuit is shown in figure 3. The gain portion of our circuit consists of an LMC7111 op-amp set up with a gain of 7, in a low-pass configuration, as shown in figure 4. For this circuit, the equations for the low-pass time constant and amplifier gain are as follows:
We used an actual time constant of 0.5 and a gain of 7, as shown in figure 4. The input of the amplifier was coupled to a DC voltage of around 2.5V. This was necessary to center the amplified signal in the A/D range for the MCU. We implemented this with a voltage divider with 2 x 1MΩ resistors, as shown in figure 4.
Figure 3 Figure 4
Since we use two MCUs (as detailed in the software details section), we had to build one MCU setup on a white board. Figure 5 is a photograph of CPU1 and the TV output circuit on the white board (The MCU and TV circuit are on the lower of the two whiteboards shown; the upper is the microphone bias and amplifier circuit, along with the buzzer). The TV uses pin D.5 as the sync signal, and D.6 as the video input. HyperTerm was set up by connections from the STK500 to the PC, D.0 was the receive bit and D.1 was the transmit bit. Please refer to the appendix for a picture of the actual Hyperterm output. The TV output DAC, shown in figure 1, was provided to us in ECE 476 lab 4. The appendix contains a detailed diagram of how the Mega32 is implemented on the whiteboard.
The final piece of hardware we used was a CT-1205C buzzer, which is shown on the upper board in figure 5. This is used to indicate a violation of the high or low BPM violations. We bought this particular buzzer because it was loud, annoying, inexpensive, and could be driven off of a single output pin in terms of current and voltage.
Initially we planned on using only one MCU, but we quickly realized that it just was not possible to do all the necessary calculations and blast output to the screen on one MCU. The 2-CPU solution we came up with uses CPU1 for the TV output, and CPU2 as a processing unit. Both CPUs sample the same heart beat signal independently of each other and at different rates.
Our CPU1 code was a modified version of our ECE476 lab 4 code, which in turn was a modified version of
CPU1 also takes several control lines that are generated by CPU2, including high and low violation lines, run/stop and one/two second screen widths from the buttons attached to CPU2. Finally, there are 8 parallel bits which transmit the beats per minute as they are calculated. Figure 1 shows how the two CPUs fit together and interface, along with outside connections. The following table (figure 6) outlines the various definitions for the interface and control lines.
CPU2 has three basic tasks. First, it is responsible for debouncing the 7 buttons attached on port B. We used a state machine structure that was similar to the one presented in ECE 476 lecture for debouncing buttons. The button functions are outlined in the following table, and a general diagram for a debouncing state machine can be found in the Appendix.
Second, CPU2 is responsible for calculating the BPM of the sampled signal. We chose to go with a windowed sampling scheme, instead of a real-time approach. This basically means we take a string of samples over a certain time period, process the data, determine the BPM, and start the next sample string. In order to cover the reasonable BPM ranges of the human cardiovascular system, we were aiming for reliable performance between 60 and 180BPM. The low end is where we really had to worry since at 60BPM, there is one beat each second.
Our detection scheme basically attempts to find pulse peaks in the data, determines the time between the peaks, and then converts that to BPM. The sample window had to be long enough to get at least two beats in one window for the lowest range. At 60BPM, a 2 second window gives this, and this is the window we chose. The downside to the long sample window is that we can only provide a new BPM update every 2 seconds. This decision between sample window length and the rate at with the BPM is output is a tradeoff that we made. Heart rates lower than 60BPM can be detected if two pulses happen to fall inside the 2 second window, but since the phase of the beats is relatively random, there is no guarantee this will happen. We modified our code such that if we only identified one peak, we would leave BPM unchanged. If we didn’t identify any peaks, then BPM was set to 0. In the lab, we were able to reliably detect heart rates of around 50BPM. The high end accuracy was limited by how much time we waited after identifying the first peak before looking for the second peak. Our code waits 150 samples at 2ms each, or a total of 300ms, which equates to a maximum of 200BPM.
The beat detection algorithm is actually quite simple. We took 1000 data points over 2 seconds, giving a sampling rate of 2ms. This corresponds to a sampling frequency of 500Hz. The Nyquist Sampling Theorem states then that the largest frequency component present in our sampled signal is 250Hz. This in effect is a low pass filter. This is not a problem, however, since we are only interested in the low frequencies anyway. A second digital low-pass filter was implemented as a weighted rolling average. The filter looks like this:
The alpha value in the equation dictates the amount of “smudging” that occurs. This in effect smoothes the data and lowers the noise floor. We experimentally determined the best alpha was 0.8. The resulting 1000 data points in CPU2 then would look something like figure 8, which graphs actual data we collected by printing it to the HyperTerm. Before sampling and the digital low-pass filter, the SNR of the heartbeat signal was about 5, but you can see from figure 8 that the post-filtered SNR is much higher. The detection uses a moving threshold algorithm. The first step is to determine the maximum value of data in the sequence. Then, we look for successive peaks with increasing slopes within 80% of the maximum value. This inherently assumes that the peaks in the input sequence are relatively stable, and within a reasonable range above the secondary peaks and noise.
The third function of CPU2 is to send data to CPU1 and to control the alarm buzzer. CPU2 sends BPM through PORTC and information about the modes of operation and violations through PORTA to CPU1. CPU2 sends one bit to the buzzer for violations through PORTA. Figure 1 shows the specific connections and figure 6 outlines the control lines. In addition to the data sent to CPU1, the second CPU also outputs other (excess) data to the HyperTerm. This includes the maximum value (out of 255) received over the last sample window, the indexes of the two beats used to determine the BPM, the actual BPM, and the high and low threshold values which are settable by the buttons attached to PORTB. The data is updated every 2 seconds, just like the BPM value. Typical HyperTerminal output is shown in the Appendix.
Our project was very successful as a whole, but there were a few things that did not work out as we had originally planned. First, we planned to display the high/low violation values on the TV. The problem with this is that the buttons to set the high/low values are attached to CPU2 on the STK500. We did not have enough output ports left to send two 8bit numbers to CPU1. Because there was no easy way to synchronize the CPUs we settled on using HyperTerm to display the high/low violation values. We did, however, print “HIGH” or “LOW” on the screen if the respective violations occurred.
Second, we wanted to blast the digitally filtered heartbeat signal to the television. The filtering would have to be done on CPU1 since there is too much data to transfer it from CPU2 to CPU1. Since the trace on the TV “rolls” across the screen, a significant amount of logic had to be inserted to keep track of the “edge” of the data trace. The filter would need to start on the edge, wrap around the screen and continue back to the edge so that the data is filtered in order. When we implemented this, the code was just too bulky, and interfered with the timing of the TV output. We decided to settle for displaying the heartbeat signal that was amplified and filtered in an analog fashion on the television.
Lastly, we wanted to implement automatic gain control (AGC), but realized that it was not very useful or necessary. In addition, it is nice to see the relative strength of different heartbeat signals. This was explained in the above section, Hardware/Software Tradeoffs.
[ Back to Top ]
In CPU1, our digital stethoscope draws the heartbeat trace to the television with a delay imperceptible to humans. Since CPU2 uses a sampling window to determine the BPM, there is an inherent 2 second delay between updates of the heart rate. The HyperTerm is updated every 2 seconds as well. All other components of our project execute with no perceptible delay and no concurrency issues ever arose.
Our design was able to achieve a good level of accuracy, considering the cheap parts used and simple structure of design. The signal to noise ratio for the amplified input (which was then sampled), was around 5:1, so the heartbeat displayed on the screen looks good. Figure 9 shows a typical trace on the TV screen. On occasion, some stray pixels were left on the screen, probably due to the timing of our CPU1 code. We were not able to entirely eliminate this, but it does not happen very often and we modified the code to solve this problem and make it happen as seldom as possible. When the digital stethoscope is put into stop mode and then started again these imperfections are cleared when the screen is initialized. On the whole, though, our trace is of very good quality, as is demonstrated below.
Accuracy for our BPM calculation was discussed in the software design section. In general, we found that our digital stethoscope was accurate in the range of around 50-180 BPM. We used a function generator to help determine these bounds. In addition, BPM is calculated every 2 second from the time between two successive peaks and then that time per beat is converted into BPM. Consequently, the actual BPM is only updated every 2 seconds.
Our digital stethoscope works most reliably with a strong heartbeat signal. If a signal is not very strong, it may be hard to detect peaks because of inherent noise. Thus, on a few occasions, we found it necessary to get out of our chairs in the lab and run up and down the stairs a few times to keep our blood moving. It’s quite amazing how much this makes a difference. Finding the right place for the end piece of stethoscope is also very important. The strongest and most reliable place on the body that we found was the neck. We had limited success on the heart when blood flow was good. The wrist rarely worked at all. Additionally, you must be very still and quiet to use our device. Talking or movement of the stethoscope produces output far above the voltage rail of the amplifier, and the resulting heartbeat trace and BPM will not be displayed accurately. This is however inherent to any stethoscope and not unique to our project; if an old-fashioned stethoscope moves around or the patient talks when it is on his/her neck there will be mostly noise.