Extremstellen bestimmen?

con-f-use

Erfahrenes Mitglied
Hallo zusammen,

Habe eine Tabelle von Messwerten (x und y). Hat jeand einen schönen Algorithmus (gerne auch eubeb Link) um die Extremstellen (Maxima und Minima) daraus zu bestimmen. Stehe da etwas auf dem Schlauch.

Gruß,
con-f-use
 
Möchtest du einfach die grössten und kleinsten Werte aus deiner Liste herauslesen oder möchtest du aus deinen Messpunkten eine Funktion generieren und dann die Maxima und Minima (mittels Ableitungen) finden.

Ersteres wäre um einiges einfacher:

Du suchst ja die min und max Werte entweder von allen x-Werten oder von allen y-Werten(meist von allen y-Werten, x-Werte sind oft kontinuierlich z.B. Zeit). Du musst also nur immer mit einer Zahl von deinem x-y-Paar verfahren:

- Variablen "min" und "max"
- nimm ersten und zweiten Messwert, vergleiche sie und weise den Kleineren "min" zu und den Grösseren "max"
- nimm den dritten Messwert vergleiche mit "min" ist er kleiner, weise ihn "min" zu, ist er grösser, vergleiche mit "max". Ist er grösser als "max" weise ihn "max" zu (ist er zwischen "min" und "max" interessiert er nicht)
- tu mit allen weiteren Messwerten das selbe wie mit dem Dritten


Willst du zuerst eine (mathematische) Funktion aus deinen Messwerten erstellen, so musst du zuerst die Funktion interpolieren (Interpolations-Polynom, Spline...), dann mit den Ableitugen dieser Funktion arbeiten.
In diesem Fall kann ich dir nur beschränkt helfen.

Ich hoffe das war verständlich (bin übermüdet). Sonst einfach nachfragen...

Gruss LukeS
 
Es geht um numerische Werte. Deine Methode findet nur das absolute Maximum. Bei meinen Messerwerten sind aber mehrere lokale Maxima dabei, die ich alle finden will. Es handelt sich also um eine "Kurve" mit mehreren Hoch- und Tiefpunkten. Ich suche eine nummerische Methode. Interpolations-Polynome wären hier einfach overkill.
 
Hallo,

was spricht denn dagegen einfach so zu verfahren:

Code:
if (f(x - 1) < f(x) && f(x + 1) < f(x))
  print("Lokales maximum an stelle f(x) gefunden");
else if (f(x - 1) > f(x) && f(x + 1) > f(x))
  print("Lokales minum an stelle f(x) gefunden");
else if (f(x - 1) < f(x) && f(x + 1) > f(x))
  print("Funktion f an stelle f(x) monton steigend");
else
  print("Funktion f an stelle f(x) monton fallend");

Sollte es doch denke ich tun, oder ist dir das zu "lokal"?

Gruß,
RedWing
 
Zwei Dinge:
1.) Recht viele Rechenoperationen. Will man das mit vielen Messwerten machen, gibt es Performance-Probleme. Hatte gehofft jemand hat einen eleganteren Algorithmus

2.) Der Messfehler. Ist der statistische Fehler recht hoch, bekommt man alle paar Stellen ein Extremum. Das Problem mit dem Messfehler ist aber schon behoben. Bin zeitgleich auf eine recht ähnliche Lösung gekommen, die aber über die nächsten Nachbarwerte mittelt um stistische Fluktuationen auzugleichen.
C:
// data ist die Liste mit den Ausgangs-Daten
const int RANGE = 5; // Soviele Elemente werden gemittelt
QList<int> poles; // Hier kommen die Ergebnisse rein (Indizes der Extrema)

float before, after; // Mittelwert der Werte vorher dem aktuellen und nach dem aktuellen
int lastPole=0; // Das Extremum einen Schleifendurchlauf vorher
for( int i=RANGE; i<data.size()-RANGE; ++i ) {
    for( int j=i-RANGE; i!=j; ++j )
        before += data[j];
    for( int j=i+RANGE; i!=j; --j )
        after += data[j];
    before = before/RANGE - data[i];
    after = after/RANGE - data[i];
    if( ((before>0 && after>0) || (before<0 && after<0)) && (i-lastPole)>RANGE ) {
        lastPole = i;
        poles << i;
    }
}
return poles;
Wie gesagt, hatte mir einen weniger rechenintensiven Algorithmus erhofft. Sowas bring ich auch gerade noch hin.
 
Zuletzt bearbeitet:
Hallo,

nein da kann ich dich leider auch nur in Richtung google verweisen, obwohl ich denke das es schneller nicht gehen wird ...

Apropos Performance:
Was bezweckst du eigtl. mit Folgendem?
C++:
before = before/QString::number(RANGE).toFloat() - data[i];

Du wandelst da eine Zahl in einen QString um um diesen am Ende wieder in eine Zahl zu konvertieren. Und das auch noch zur Laufzeit? Wozu?
1.) RANGE wird so oder so implizit in einen float gecastet da "before" ein float ist.
2.) wenn eine Umwandlung int->float schon von Nöten sein sollte, dann lass es doch den Compiler erledigen: Ein einfacher cast ala static_cast<const float>(RANGE) würde es auch tun.

Gruß,
RedWing
 
Sory, hatte deine Frage nicht genau verstanden.
So wie es du tust hast du aber nicht die genauen Extremwerte, da es ja Zufall wäre, wenn du immer genau an der Stelle einen Messwert hättest, an dem dein Signal eine Extremstelle hatte.
Wahrscheinlich genügt die Genauigkeit. Besonders, wenn du viel mehr Messpunkte als Extremstellen hast.

Ja der mit dem Interpolieren (und dann noch ableiten) wäre wirklich ein bisschen übertrieben...

Gruss LukeS
 
Das mit QString::number().toFloat() war ein Überbleibsel. Der echte Code ist ja etwas komplizierter weil sich das Messintervall verändet und u.a. per RegExp und Rechnung aus einem String ermittelt wird. So hat das natürlich keinen Sinn, klar. Einfach nicht beachten.
 
Zuletzt bearbeitet:
Zurück