Calculate MAX value avoiding spikes / rolling max

Hello, I've searched a bit but didn't find anything similar to this so I made this thread. If I'm wrong please merge it to the corresponding thread.

I 'm using an Arduino DUE to display an ECG to a LCD screen. In order to have maximum use of the LCD height I calculate max, min and average so I can display it as big as I can in my screen.

My issue is some spikes I occasionally have which ruin my max value. I thought about comparing old max with the new one and if it is much bigger to ignore it or making a matrix which will be updated with the last X measurements and then calculate matrix's max value.

But because of the nature of my signal I think the above solutions aren't the optimal one.

Can anyone suggest me how I can calculate a rolling max so if I get a very high max it will be replaced after a while by another -lower- max when my signal is significantly smaller?

Spiros

If those spike are just noise (aka, not the thing you actually what to measure) then filtering the signal is the answer.

If that spike is correct but once it's off the screen you want to switch the resolution again that's a bit harder. Easiest I think is to trigger a calculation of a new max after the spike is off the screen (so you save the time of that spike) and let it run for at least the time on the screen before using that as a new windows height.

Unfortunatelly changing hardware is not an option plus the spikes are from body movement.

I have to solve this with code that is why I ask for suggestions. I don't want to make the window height standard so I hope I can work this out.

My problem is that the nature of my signal (ecg) is kinda "spiky" itself which makes things harder for me.

Thank you for your input thought.

spoums: Unfortunatelly changing hardware is not an option plus the spikes are from body movement.

He! I didn't say anything about hardware! You can filter in software as well ;)

septillion: He! I didn't say anything about hardware! You can filter in software as well ;)

Well I've thought about having a threshold on the measurements I take which will probably work but I was looking for a smoother solution.

If you want smoother, filter it ;) Threshold is not filtering (in the sens of filtering a signal).

And there are many many filter algorithms with all sorts of trade offs. Which is best depends on how long you can spare to calculate, what effect you need and how close the spikes look like your signal (filter steepness).

How about a threshold for the maximum allowable change in signal (let’s call it deviation). Just need to compare each reading with the previous reading. If the signal has risen beyond the deviation value, then this is a spike, so just ignore it and use the previous reading for your new reading. No need to detect the falling edge of the spike as it will not appear in the recorded data.

pseudo code …

byte ecgPin = A0;

// Get to know your ECG signal
// What is the maximum deviation of the spike?
// What is the maximum deviation in the clean portion of the signal?
// Make make maxDeviation value 1/2 way between the above values

const word maxDeviation = 250;

word signalValue, recordedValue, previousValue;

void setup() {
  signalValue = analogRead(ecgPin); // ignored
  signalValue = analogRead(ecgPin); // keep
  previousValue = signalValue;
}

void loop() {
  signalValue = analogRead(ecgPin);
  int deviation = signalValue - previousValue;

  if (abs(deviation) <= maxDeviation) {
    recordedValue = signalValue;
    previousValue = signalValue;
  }
  else {
    recordedValue = previousValue;
  }
}

Anticipated result …

Can anyone suggest me how I can calculate a rolling max

Take a look at the [u]Smoothing Example[/u]. (In programming terminology, this is called a circular buffer.)

So for example, you can save the last 10 or 20 peaks in an array, and take the average every time you update the array.

Then, you can decide what you want for a limit, or the limits of your display... You probably don't want to throw-away the outliers (because you might have some high values that are real and you could get into a "trap" of throwing-away good data) but you can limit the values for purposes of the display.

You don't want to filter because that would "smooth" all of the data. (Averaging is a kind of low-pass filtering, but you're just averaging the peaks for the purpose of scaling your display.)

That sounds interesting. Can you elaborate?

Another thing that concerns me is that the impedance of the electrodes wears off so the signal is getting smaller.

If I could check that my signal has gotten significantly smaller and could get a smaller new max value in order to have the same result in my display as before would be great.

Your idea with deviation could help with that if I have a matrix with my acceptable "spikes" and have an average on them could work.

Any more info on how to do your idea?

If I could check that my signal has gotten significantly smaller and could get a smaller new max value in order to have the same result in my display as before would be great.

Suggestion:

Fill a circular buffer (array) with readings representing a total interval greater than one "cycle" or period of the waveform.

Say you never get more than 5 readings that represent a spike or spikes within the buffer data. Now just look at how much the data changes from reading to reading (calculate this). The 7th highest [u]change[/u] in reading in the buffer could be the "maxSignalRise" value (maximum acceptable clean signal rise in value from reading to reading). The highest [u]change[/u] could be the "maxSpikeRise" value. Then;

maxAllowedRise = riseThreshold x (maxSpikeRise - maxSignalRise).

Where riseThreshold could be a constant and would need to be determined (probably 0.5 would work best) but could possibly be anything from 0.1 to 0.9.

Now the signal can get smaller (attenuated) or grow in amplitude and the variables will update as required. Using conditional logic, the spikes could be removed (or replaced), no matter how much they drift up or down on the signal or how much they fluctuate in amplitude.

Could you post or attach your buffer (array) of data representing something more than 1 period of the waveform?

Thank you for your input guys. I liked dlloyd's idea Imma try that.

I have smoothing for my average I don't think it can work for a maximum because of the nature of my readings.

In what format do you want my data? Copy paste from serial monitor?

I did some tests and my signal has usually 2k range but its offset varies every single time. In arduino's plotter works great and I see my results perfectly. I want to do something similar for my lcd too.

I had an idea too. I have a counter. I check every new value with my max. If the new value is greater then it it my new max and my counter is zero. If the new value is near max for instance newvalue>max-1000 then the counter is once again zero. If not then counter increases. If the counter reaches a number of my choice for example 1000 that means that it's been 1000 values where my max is bigger than I want so I reduce it. This way my max gets reduced gradually until it is ok.

So maybe I should ignore values if they are much greater than my previous max value.

My way worked but when I get a spike it takes too long to come back to where it should be.

Just an update although the above way worked I finally removed the whole max and min difference since I have the average like the example mentioned above.

Since my signal has max range 2K I just have 2k instead of max - min plus that for every point where its value exceeds my limits I ignore it.

I probably solved my issue much easier than I expected. I'll run some more tests to be sure.

If anyone still wants data or any part of my code feel free to ask.