# Can I combine an IIR (an EWMA) with a maximum?

I'd like to have a exponentially weighted moving average (EWMA) which is raised to the value of the input signal whenever this is higher than the filter output. This taking of the maximum shall take place during the iteration, not afterwards (which would be simple).

So, the algorithm should look like this:

o = 0  # or some arbitrary initial value
for i in input:
o = (o * 99 + i) / 100
if i > o:
o = i
print o


So effectively, my output shall fall slowly after a quickly falling edge in the input without rising quickly before a rising edge.

In fact, any other algorithm which just copies the input except for the places where it has a rapidly falling edge (there it should play parachute and let the output fall slower) would do fine.

The only restriction I have is that this needs to be implemented in the usual Python libraries (numpy, scipy, pandas); iterating myself will not be fast enough.

I tried applying a rolling maximum, followed by a rolling mean with a Gaussian window of the same width (using pandas.Series(arr).rolling()); this gives me nice smoothing of the fall after a falling edge; unfortunately it also gives me an equal smoothing before the rising edges (which I don't want).

If there was a way to apply an asymmetric Gaussian window (e. g. rising slowly and falling quickly) that would be a solution I guess. But I haven't found a way to achieve this yet.

What you are describing is an envelope detector which can be formed by a Peak Detector followed by an ADSR.

The peak detection is performed by the non linear 'max' filter as per your description. This, on its own, would track the maximum of the signal and stay at that max value.

To now modify that signal's dynamics so that it 'launches' and 'parachutes' at specific rates, you add the Attack-Decay-Sustain-Release component. You don't need all four stages. This could simply be an Attack-Decay (as per your needs).

In fact, in your application, the Attack is zero. As soon as a new max is detected the output of the system is reset immediately. But, while the new values are lower than the maximum, this 'output' now decreases at a desired rate (The Decay stage). In your case this could be as simple as o-=aRate if o>0 else 0 in the else branch of the if.

Hope this helps.

• Maybe, yes, though I have my doubts that an ADSR would not oversimplify my signal for my needs (that's why I ask for a way to apply an exponential decay combined with a maximum). If the input is just slightly below the output, the output should fall much slower than if the input is far below the output. With an ADSR that wouldn't be the case. Anyway, any hint on how to "peak detect" my signal? – Alfe Jan 31 '18 at 13:00
• @Alfe I do not understand what "oversimplification" means here. Apart from the "classic" peak detector, there are also techniques like this one. Is it possible to share some more information about the application? – A_A Jan 31 '18 at 13:04
• I described one aspect of oversimplification when I said that an ADSR would not react on the form of the input below it; no matter if that is way, way far below it or so shallow that it is nearly touching the ADSR, the ADSR will have a fixed decay rate. That's not what I want. I want the output react on the form of the input, even if it is below the output (and if the input is above the output, the output shall be raised at once to this value). – Alfe Jan 31 '18 at 13:24
• My usecase is to get a smoothed envelope (for a special kind of audio volume compression algorithm), where the rising and the falling rate of the smoothing can be different, i. e. a long time before a loud part the output is slowly diminished (to keep the psychological effect of a sudden bang), whereas a silent part after a loud one can be loud at once. By parameters the opposite should also be possible (the bang should appear equally loud to the quiet part before it, but the quiet part after it should be silent and raise in volume only slowly), and mixes of both of course. – Alfe Jan 31 '18 at 13:32
• @Alfe Closely related to the ADSR part but this use-case sounds very close to audio compression / expanding and associated techniques. (Did not notice the amendment in the post before, what you depict is plain simple ADSR with a typical RC time constant.) – A_A Jan 31 '18 at 13:55

I am a long time programmer. I've recently learned Python, and I like it very much. However, if I were writing time critical applications I would not choose it. Even if it is being used as "just glue" to hold together a bunch of library calls. Likewise, I would not choose Java or Ruby either.

The algorithm you describe seems to do exactly what you want. If it existed in the libraries you mentioned you would have found it in the documentation. I think you should consider learning how to write your own C/C++ libraries for Python and include it that way. There are several ways to do this, and I haven't tried any so I can't give you any recommendations.

Ced

• I could program anything I want in C/C++ and attach it to Python but I want to provide a library to the general public and in this context it is not suitable to add such complexity. And no, finding stuff in libraries like numpy, scipy, and pandas isn't always easy. I am almost sure that combining stuff from there can do what I want, I'm just not experienced enough to see it. My signal processing classes were 25 years ago and I simply forgot much of it :-} At least I could not remember anymore how to design a and b of an IIR to create a simple EWMA … – Alfe Jan 31 '18 at 16:48
• Well, maybe "not suitable" was not the best way to put it. Let's call it a design decision in my project to rely on numpy etc. alone to achieve my goals. – Alfe Jan 31 '18 at 16:51