I'm filtering a raw PPG signal sampled at 100sps

After applying a bandpass filter my signal looks like this PPG with trend

As you can see, It has a trend (a low pass component which is not in the desired signal). I tried applying a high pass filter, it removes the trend but also changes wave shape significantly. Is there a way to detrend this signal without losing the shape?

I'm using python to implement filters. This is only a part of the signal and, actual signal is a few mins long. I'm not worried about the speed as this doesn't have to be real-time.

  • $\begingroup$ Have you tried a high-pass filter? $\endgroup$ Jun 30, 2021 at 4:34
  • $\begingroup$ @den yes, it also get rid of signal components $\endgroup$ Jun 30, 2021 at 7:44

3 Answers 3


I assume you want to remove the trend which behaves like that:

enter image description here

Probably some kind of a parametric model will do the work.
Something as simple as a 2nd degree polynomial with regularization will estimate this pretty well.

  • 1
    $\begingroup$ It might require some HPF filter before that to minimize the effect of the periodic signal. $\endgroup$
    – Royi
    Jul 31, 2021 at 9:23

OP mentioned using high pass filter but this still removed components. This simply means the high pass cutoff was too high.

I think the simplest solution is to use and exponential averager to extract the moving average, and then subtract this from the result.

Below is the simple structure to create an exponential averager. Parameter $\alpha$ will modify the averaging time and is typically a value close to 0 (but must be greater than 0 and less than 1!). For instance .1, .01, .001 where .001 would have the longest averaging time of those three choices. It will be easy to see from observation of the moving average which value would be most appropriate in trading moving average elimination and maintaining signal features.

exponential averager


You have a very large bias, that means that every filtering that you do will either create a strong transient response unless the filter state is properly initiated.

A few options:

  1. If the bias is stable, you can simply calculate it as the mean and subtract it
  2. Apply a "DC blocking" filter. Details depends on the lengths of you signal and the frequency range of interest and what time domain properties you need to preserve
  3. Properly initialize the filter state. Something like https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.lfilter_zi.html#scipy.signal.lfilter_zi or https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.sosfilt_zi.html#scipy.signal.sosfilt_zi

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.