I am working on a PPG sensor for measuring heart rate, and I am having issues with the digital aspect of the system. I have my coefficients for the difference equation (from Matlab) and an algorithm to implement the difference equation in near-real time, but the Serial Plotter shows that my y_current values are decreasing for all time. If anyone can help me in spotting where I may be going wrong, that would be greatly appreciated!
/* Filter variables */
float x_current ; // current input
float y_current ; // variable used to hold current output
const int num_B = 3 ; // number of B coefficients
const int num_A = 3 ; // number of A coefficients
float x[num_B] = {0.0} ; // current and previous inputs
float y[num_A] = {0.0} ; // current and previous outputs
float A[num_A] = {
+1.0000,
-1.9989 ,
+0.9989 } ; // denominator polynomial coefficients
float B[num_B] = {
+0.9994 ,
-1.9989 ,
+0.9994} ; // numerator polynomial coefficients
unsigned long t0 , t1 ; // variables to keep track of time
unsigned int samplingIntervalMillis = 50 ;
float y_peak ; // peak value of output
int peaking = false ; // flag for peak detector, true if signal is "high"
unsigned long t_peak ; // time at which peak occurred
int thresh_high = 500 ; // high-level threshold for peak detector
int thresh_low = 450 ; // low-level threshold for peak detector
/* SETUP Block */
void setup()
{
pinMode(7,OUTPUT);
digitalWrite(7,HIGH);
pinMode(8,OUTPUT);
digitalWrite(8,LOW);
Serial.begin(250000); // setup serial baud rate
}
/* LOOP Block */
void loop()
{
t0 = millis() ;
x_current = analogRead(A0);
x[0] = x_current ;
// implement difference equation
y_current = 0.0 ;
for ( int i=0 ; i<num_B ; ++i ) {
y_current += ( B[i] * x[i] ) ;
}
for ( int k=1 ; k<num_A ; ++k ) {
y_current -= ( A[k] * y[k] ) ;
}
y_current /= A[0] ;
y[0] = y_current ;
// peak detection
if ( !peaking ) {
y_peak = 0.0 ;
peaking = ( y_current >= thresh_high ) ;
}
if ( peaking ) {
if ( y_current > y_peak ) {
y_peak = y_current ; // maximum peak value in the spike
t_peak = t0 ; // time at which the peak value occurred
}
peaking = ( y_current > thresh_low ) ;
}
// output to serial
Serial.print("x:");
Serial.print(x_current);
Serial.print(",y:");
Serial.print(y_current);
Serial.print(",peak:");
Serial.println(y_peak);
// shift our tracking windows for x[n] and y[n] by one sample
// gets rid of oldest sample no longer used
for ( int i=(num_B-1) ; i>0 ; --i ) {
x[i] = x[i-1];
}
for ( int k=(num_A-1) ; k>0 ; --k ) {
y[k] = y[k-1];
}
t1 = millis();
delay(samplingIntervalMillis - (t1 - t0));
}
I wonder about the purpose of the filter. For diagnostic purposes you risk to suppress flicker or produce misleading artifacts, for bpm the determination of peaks is sufficient.
I guess he is getting the peak value as all above the average, in this case the average is LPF biquad.
But the gain seems too high, it is not clear what is the level of the input signal. A photodiode without amplifier and self biasing will give hardly any signal ...
It is.
The filter is basically an integrator. The impulses will be above the averaged signal. The averaged signal will vary depending on the ambient light. This is a good attempt to avoid the HW I posted. The code can repeat the HW strategy. However, a photodiode must have at least a current-to-voltage converter to work.