I try to find that looks something like the red curve below and I am pretty clueless what is the best way. I tried first the Savitzky-Golay Filter, then I tried a simple fit with a second degree polynomial, then I tried a Hilbert transform to get the envelope, then I tried to sort out the peaks. Nothing really worked out, since the dips are just too dominant in the signal, but I am only interested in the path of the highs.



I implemented the idea from @Dan Boschen. The code in python looks like this:

def dc_nulling_filter(data):
    x_hold = [0]*len(data)
    alpha = 0.99
    output = [0]*len(data)

    for n in range(len(data)):
        if abs(data[n]) < abs(output[n]):
            x_hold[n] = abs(data[n])
            x_hold = x_hold[n-1]
        output[n] = x_hold[n] - x_hold[n-1] + alpha*output[n-1]


The results are as said by Dan Boschen look nearly the same as if I would implement a highpass-butterworth filter. In blue is the raw data in orange is the filter output. enter image description here

  • $\begingroup$ Can you tell us what "something like the red curve" would be, from properties? What's the thing that the red curve should do? To me, your red curve at best seems very vaguely related to the blue data, and so I don't think anyone could with certainty tell what you need; but if you tell us what the idea behind the red curve is, we might be able to help you! $\endgroup$ Nov 28, 2021 at 16:41

1 Answer 1


The OP would like a peak hold with some decay such that a moving window will follow the peaks. Certainly this could be done by that directly in that a moving window spanning a certain number of samples and the peak value over that window duration is displayed (and the choice of window length is the maximum dip that could be expected, at the expense of lower tracking bandwidth (slowly changing). The output of this can be smoothed to reduce the step changes that would occur.

An improved idea without significant complexity is to use a modified DC nulling filter on the peak values with a condition that only a peak higher than the current output will be allowed as an input, otherwise the last input is held as an input to differencer followed by a leaky accumulator. This is done using:

$$y[n] = x_h[n] - x_h[n-1] + \alpha y[n-1]$$

With $x_h[n]$ is the "held" input value given as the absolute value of the input $x_h[n] = |x[n]|$ when $|x[n]|>|y[n]|$ and $x_h[n-1]$ otherwise.

And $\alpha<1$ with the closer $\alpha$ is to 1, the longer the rate of decay will be.

In other words, condition each new input sample to check if its absolute magnitude is greater than the last output $y[n-1]$. If so update the held input to be that value and subtract it from the previous held input value. This is added to the leak term $\alpha$ multiplied by the last output value $y[n-1]$ to provide the current outptu $y[n]$.

As a guideline for setting $\alpha$, $\tau = 1/(1-\alpha)$ samples. The time constant is the time in samples to decay 63% with the time decay given as $1-e^{t/\tau}$.

The theory of this is the DC nulling filter is a "high-pass" so will immediately pass any leading edges, and then slowly decay based on its highpass bandwidth setting (very much similar to a series capacitor that blocks DC but passes all high frequencies). By gating the input to only create new leading edges when the current input is higher than our decaying output, we create a "leaky" hold which I believe is what the OP desires.

  • 1
    $\begingroup$ @Maxim if you do implement this, can you post the results with your original picture to show its effectiveness for your case (or what you ended up doing)? $\endgroup$ Nov 29, 2021 at 12:06

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.