arduinoaveragesensorsheartbeatpulse

How to convert the ANALOG value of a pulse sensor to BPM?


first of all I would like to apologise for not speaking English very well.

My problem is the following: I have an arduino sensor (the iDuino SE049). I need to transform the analog value into BPM value. So first I have to eliminate the drift (slide, (I don't know the precise word)) that the sensor can encounter. To do this I am advised to :

❶Work on an array of X values ❷Calculate the average ❸Subtract the average from each of the values

After I need to find the optimal value for X with the curve on Arduino IDE (I work on 1.8.19 version). (Start with X = 50 for the size of the array, my teacher told me that)

Once I have this average, I need to make the system robust to light changes. Problem: The amplitude varies so we can't work with a fixed threshold. The heart rate is hidden in temporal information. You just need to be able to measure the characteristic time. Solution : I can work with a curve that always has maximum amplitude of 1, then find an ideal threshold.

❶Work on the table of X values after eliminating the drift. ❷Look for the maximum ❸Divide all values by this maximum ❹Split by a threshold value

And then I have to do the study to find the threshold value

I tried to do a code that didn't worked well for the drift/slide, and average of the signal. But it didn't worked well because I can't get the value of the average outside of my loop to substract it to the analog value readed by the sensor.

I want to get all the value readed by the sensor during a time of 20 milliseconds, thats why I use the function millis(). And all this values needs to be stored in my array.

#include <Arduino.h>


int Sensor = 0;
//#define start_read 0
float tab[20]={0};
float sum = 0;
int i;


void setup() {
   Serial.begin(9600);
}


void loop ()
{
unsigned long currentTime=0;
while (millis() - currentTime > 20)
{
      tab[i] = analogRead(Sensor);
      i++;

      sum += tab[i];
      float average = sum/20;
      Serial.println(average);
}
currentTime = millis();
i = 0;

}

I have another code to test, I should work but it's not I don't know why : The variable names are in French but you can copy it and change the name to work on it if it's clearer, I'll understand the changes.

#include <Arduino.h>

int sensor=A0, comp=1, var=0;
float bpm=0;
double temps;
const int nbr=50;
float tab[nbr]={0}, moyenne=0, maximum=0;

void setup() {
  Serial.begin(9600);
  pinMode(sensor, INPUT);
}

void loop() {
  maximum=0;
  moyenne=0;

  for (int i = 0; i < nbr; i++)
  {
    tab[i]=analogRead(sensor);
    moyenne=moyenne+tab[i];
    delay(40);

  }
 

  moyenne=moyenne/nbr;


  for (int i = 0; i < nbr; i++)
  {
    tab[i]=tab[i]-moyenne;
  }

  maximum=tab[0];
  for (int i = 0; i < nbr; i++)
  {
    if (tab[i]>maximum)
    {
      maximum=tab[i];
    }
   
  }
 
  for (int i = 0; i < nbr; i++)
  {
    tab[i]=tab[i]/maximum;
  }
 
  for (int i = 0; i < nbr; i++)
  {
    if (tab[i]>(0.950))
    {
      bpm++;
    }
   
  }
 
  temps=(millis()/1000);
  var=15*comp;
  if (temps/(var)>=1)
  {
    bpm=bpm*4;
    //Serial.setCursor(0,10);
    Serial.print("BPM : ");
    Serial.print(bpm);
    Serial.println("♥️");
    //Serial.display();
    //Serial.clearDisplay();
    comp=comp+1;
    bpm=0;
  }
 
}

Solution

  • I can't get the value of the average outside of my loop

    average is declared inside the loop so when an iteration ends it goes out of scope. You should declare it outside the while loop.

    I want to get all the value readed by the sensor during a time of 20 milliseconds

    You probably want to get something like 1 value per millisecond because all the values readed in 20 milliseconds are not 20 also you may not be able to know the exact number of values as it depends on the sensor's sample rate among other things.

    If you need to reed those values to get a fixed threshold (i.e. use the code to study some behavior and get a const that will be used in the second code), put the code in void setup() instead of void loop() otherwise it will loop forever.

    void loop ()
    {
    unsigned long currentTime=0;
    while (millis() - currentTime > 20)
    {
          tab[i] = analogRead(Sensor);
          i++;
    
          sum += tab[i];
          float average = sum/20;
          Serial.println(average);
    }
    currentTime = millis();
    i = 0;
    
    }
    

    Here there are some problems. Every time void loop() ends and executes again currentTime its going to be deleted and declared again holding the value 0. This makes the while loop execute for an infinite amount of time causing i to increment over tab's length leading to memory errors.

    Also analogRead() does not return a float (returns an integer between 0 and 1023).

    That's what I found about the first code, but about the second one I don't understand what is the problem. It is a compiling error? You don't get the expected output in the serial monitor? If it's the last thing, what is the output?