Need help/advice with heart BPM (higher frequencies not accurate)

Hello all, I am currently working on a project where I am using a pulse sensor.

I wanted to have a real time heart rate value inside the serial monitor. I achieved this by averaging the time between 4 pulses and it seems to be working for normal heart rates. However, if I increase the frequency of beats it seems to drastically decrease my BPM value instead of increasing it.

I would like to hear your suggestions on how to improve and/or fix my code, also feel free to suggest a better method for calculating heart rate in “real time”.

bool InPulse = false;

void loop() {

  Signal = analogRead(PulseSensorPin);  // Reading the Pulse sensor value
  
  
//Detecting when a heart beat happens

  if(Signal > Threshold && !InPulse){ 
    InPulse = true;                              // Sets "InPulse" to true to avoid multiple readings inside 1 pulse
    
    Pulse[3] = Pulse[2];
    Pulse[2] = Pulse[1];
    Pulse[1] = Pulse[0];
    Pulse[0] = millis();

    BPM = round(((Pulse[0] - Pulse[4])/5)*60.0/1000.0);
  }
  if(Signal < Threshold){
    InPulse = false;
  }
  Serial.println(BPM);

  delay(10);
}

For "real time" you need to measure the time between two adjacent pulses, not the time between 4 pulses. Are you watching the input on an oscilloscope so you know the type of signal you are receiving? The heart beat signal is coming from what device? Are you allowing for the signal from each of the two heart chambers?

Paul

Paul_KD7HB: For "real time" you need to measure the time between two adjacent pulses, not the time between 4 pulses. Are you watching the input on an oscilloscope so you know the type of signal you are receiving? The heart beat signal is coming from what device? Are you allowing for the signal from each of the two heart chambers?

Paul

I'm watching the signal in the Serial plotter first so I know what my threshold is. The signal is coming from a Pulse sensor from World Famous Electronics. I'm only looking at the main pulse signal i.e. the one with the highest amplitude.

I tried to change the code now to measure just 2 adjacent beats but the problem still exists. However, it's not important if the BPM value is not actually real time (a 2-3 second delay is OK).

I should also note that I am currently just simulating the heartbeat by tapping my finger on the sensor to create spikes in the signal, because I first want to test my code (which is obviously not working yet).

EDIT: I also noticed the longer the time between each pulse, the higher my bpm gets. :/

If you are not watching the signal on a scope, then you are doing blind engineering. You may have all kinds of noise on the input signal which a serial plotter is incapable of showing. Are your connecting wires picking up 50/60 AC signals? Is there a common mode AC signal coming from your pulse sensor that you need to filter? Only a scope will help you define the source or the error.

Perhaps the sensor is sending a double pulse signal because it needs the damping from being attached to flesh. Is it picking up an echo of your "tap"?

Paul

It ought to be okej to average like You do but I react on the calculation of BMP, BPM = round(((Pulse[0] - Pulse[4])/5)*60.0/1000.0); I would like to use : BPM = round(((Pulse[0] - Pulse[4])/4)*60.0/1000.0); The lapsed time from the fresh Pulse[0] to Pulse[4] is 4 in my opinion. How much did You raise the frequency? I hope You didn't try kHz......

Railroader: BPM = round(((Pulse[0] - Pulse[4])/4)*60.0/1000.0); The lapsed time from the fresh Pulse[0] to Pulse[4] is 4 in my opinion.

Why 4? The number of pulses recorded is 5 (0,1,2,3,4), so I should divide by 5 if I'm not mistaken?

Paul_KD7HB: Perhaps the sensor is sending a double pulse signal because it needs the damping from being attached to flesh. Is it picking up an echo of your "tap"?

Paul

I think there is no echo caused by tapping, none shows in the plotter, but then again as you said the plotter is incapable of detecting such noise maybe. I mean the sensor works by transmitting and receiving light, right? So lifting my finger quickly from the sensor should enable the sensor to pick up a huge amount of light until I put my finger down, causing it to spike up over the set threshold and quickly down, well below the predefined threshold. Even if there was some echo, while quickly tapping on the sensor, my BPM should increase rather than decrease, no?

The pulse[0] is just recorded and no time has elapsed when You do the calculation! The elapsed time is the time between 0 and 1, 1 and 2, 2 and 3, 3 and 4. Check Your pulse some way and compare! 100 beats per minute will show up as 80 instead of 100.

I thought all along you were monitoring a "heart beat". You are monitoring a "pulse" of fluid in a very flexible tube. All the "heart beat" information has been removed by the flexible artery walls.

Paul

Note: You are using Pulse[4] in your calculation but you never set it.

BPM = round(((Pulse[0] - Pulse[4])/5)*60.0/1000.0);

should beBPM = round(((Pulse[0] - Pulse[3])/3)*60.0/1000.0);

Pulse[0]-Pulse[1] is the time of the latest pulse. Pulse[1]-Pulse[2] is the time of the pulse before that. Pulse[2]-Pulse[3] is the time of the pulse before that.

That is three pulses so we divide by 3 to get the average.

Haha,You realy have sharp eyes Johnwasser!

johnwasser: Note: You are using Pulse[4] in your calculation but you never set it.

BPM = round(((Pulse[0] - Pulse[4])/5)*60.0/1000.0);

should beBPM = round(((Pulse[0] - Pulse[3])/3)*60.0/1000.0);

Pulse[0]-Pulse[1] is the time of the latest pulse. Pulse[1]-Pulse[2] is the time of the pulse before that. Pulse[2]-Pulse[3] is the time of the pulse before that.

That is three pulses so we divide by 3 to get the average.

Yes, my mistake while pasting the code. Fixed it afterwards, but still the bpm drops slowly from around 68-72 to 12-8 when I start increasing the speed of the beats/finger taps.

BPM = round(((Pulse[0] - Pulse[3])/3)*60.0/1000.0);

The formula is still wrong. beats per minute means that the beats are in the numerator and time is the denominator - the formula has them inverted which is why the output drops from 68-72 to 12-8 as the rate increases. The formula should be:

BPM = round(3*60000.0/(Pulse[0] - Pulse[3]));

Pete

el_supremo: BPM = round(((Pulse[0] - Pulse[3])/3)*60.0/1000.0);

The formula is still wrong. beats per minute means that the beats are in the numerator and time is the denominator - the formula has them inverted which is why the output drops from 68-72 to 12-8 as the rate increases. The formula should be:

BPM = round(3*60000.0/(Pulse[0] - Pulse[3]));

Pete

That seems to fix the problem, can't believe I did that wrong. Thank you so much Pete and to all that helped.