Maxima in Plot bestimmen



  • hallo,
    ich habe eine Frage.
    Ich habe ein Bild davon erstelle ich einen Plot (leider weiß ich nicht wie und ob man hier Bilder hochladen kann, daher habe ich hier mal ein ähnliches Beispiel gesucht, damit man sich das vorstellne kann)
    matlab_umsetzung
    Hier sieht man Plots mit "Peaks". die Plots die ich habe sehen ähnlich aus. Ich habe schon den Code um solch einen Plot als Vektor zu erhalten. Nun habe ich einen Vektor mit Werten. Und will dort die Maxima bestimmen und das in C++.

    Wenn ich weiß welche Werte in meinem Vektor die lokalen MAxima sind, weiß ich wie ich die DIstanzen zwischen diesen Bestimmen kann (was ich ganz am Ende haben will). Nur fehlt mir eine Idee um die lokalen MAxima selbst zu bestimmen.

    Hat jemand eine Idee ?



  • Über vector iterieren und das delta zweier elemente nehmen und wenn sich das im Vorzeichen dreht (potentiell wenn diff = 0) bist du an einem lokalen minimum/maximum vorbeigekommen.
    Bitte nochmal hirnlich prüfen ob ichs mir grad zu einfach gemacht habe.



  • Mhh eine Idee wäre dann evtl einen zweiten Vektor anlegen mit den "diffs".
    Also z.B. in einem Loop
    vektor[i] - vektor[i - 1]. Wenn Das positiv ist, dann steigt es und wenn es negativ ist dann fällt es. Dann kann ich ja die Länge der Steigung und die Länge bestimmen wie lang es fällt. ( Da diese durch VOrzeichen gegeben sind). Dann muss ich nur angeben wie lang solch eine Steigung zwischen den Maxima sein muss, sodass nicht jeder ach so kleine mini peak gefunden wird oder ?
    Klingt logisch oder ? oder ist der weg nicht so gut ?
    Danke für die Idee 5cript.



  • @Sicci Achja und bei Vorzeichenwechsel sind dann die Maxima



  • @Sicci
    Um nochmal die Idee genauer zu formulieren.

    Man berechnet mit Hilfe der Differenzen die Steigungen an den einzelnen Punkten.

    Betrachtet man einen Wechsel der Steigungen von positiv nach negativ, so haben wir es mit einem Maximum zu tun.

    Betrachtet man einen Wechsel der Steigungen von negativ nach positivv, so haben wir es mit einem Minimum zu tun.

    Dann muss ich nur angeben wie lang solch eine Steigung zwischen den Maxima sein muss, sodass nicht jeder ach so kleine mini peak gefunden wird oder ?

    Evt. genügt auch ein Moving Average Filter.



  • @Sicci
    Also erst den Moving Average Filter anwenden und dann die Minima/Maxima suchen.



  • @Quiche-Lorraine tatsächlich ist mein Original vektor etwas verrauscht und ich teile in einer Schleife jeden Wert nochmal druch die Anzahl der Werte. Somit glätte ich die "Kurve". Wenn ich das richtig verstehe ist ja das schon genau das was so ein "moving average filter" (kannte ich vorher noch nicht) macht.



  • @Sicci
    Annahme du hast die Werte 1 2 3 4 5 6 7 8 9 10 und willst diesen mit einem Moving Average Filter der Größe 3 filtern.

    Der erste Wert ist dann (1 + 2 + 3) / 3 = 2, der zweite ist (2 + 3 + 4) / 3 = 3, der dritte Wert ist (3 + 4 + 5) / 3 = 4, usw.

    Entspricht das dem was du machst?



  • @Sicci
    Nein, nicht ganz. Du glättest deine Kurve, in dem du einfach durch eine Zahl teilst, dabei werden Eigenschaften von Abschnitten nicht berücksichtigt. Ein Moving Average Filter bildet den Durchschnitt von aufeinanderfolgenden Elementen über N Elemente (N ist hier die Fenstergröße).
    Bsp:
    Daten sind [4,2,3,7,5], N = 3

    Abschnitt 1 [4] -> 4
    Abschnitt 2 [4,2] -> 3
    Abschnitt 3 [4,2,3] -> 3
    Abschnitt 4 [2,3,7] -> 4
    Abschnitt 5 [3,7,5] -> 5

    Das geglättete Ergebnis ist dann [4,3,3,4,5]. Man kann sich auch überlegen, ob man Ergebnisse verwirft, bei denen noch keine N Daten zur Verfügung stehen (hier also Abschnitt 1 und 2).



  • EDIT: Ups, beziehe mich auf einen ziemlich alten post von dir direkt unter meine Antwort.

    @Sicci
    Wenn du eh nur die Abstände willst, dann ist das unnötiger speicheraufwand O(n) durch den extra vector.

    einfach wärst wenn du einfach zählst und dann bei (den korrekten) vorzeichenwechsel die akkumulation speicherst und auf 0 zurücksetzt.
    dann hast du ein vector aus Abständen.



  •  // moving average
        int l_size = 5;
        double sum = 0;
        double mAvg = 0;
        std::vector<int>avg;
    
        for (int i = 0; i <= (vPlot.size() - l_size); i++) {
           sum = 0;
    
           for (int j = i; j < i + l_size; j++) {
              sum += vPlot[j];
           }
           mAvg = sum / l_size;
           avg.push_back(mAvg);
        }
    
    // find maxima 
        std::vector<int> idxMax;
        int flag = 0;
    
        for(int i = 1; i < avg.size(); i++){
    
            double diff = avg[i] - avg[i-1];
    
            if(diff < 0){
                if(flag>0){
                    idxMax.push_back(i);
                    flag = -1;
    
                }
            }
            if(diff >= 0){
                if(flag<=0){
                    flag = 1;
    
                }
            }
        }
    

    ich hab hier nen Code geschrieben, der findet sogesehen die Maxima, jedoch auch abundzu mehr als gewollt. Also wenn mal in eienr Steigung ein ein Wert doch kleiner ist (lokales minimum).
    Also der Vektor idxMax beinhaltet am ende die Indizes (Position auf der x-Achse) der Maxima.
    DasProblem ist der vPlot Vektor kann unterschiedlich lang sein und unterschiedlich viele Peaks haben. Ein Vektor der länge hundert kann z.B. einmal 5 Peaks haben oder auch mal 40 usw.
    Wenn ich den moving average hoch stelle kanns ja sein, das bei ganz vielen peaks dann welche verloren gehen oder nicht?
    Also z.B, so ein Plot wie auf diesem Bild Plot. Nur das es gestauchter sein kann oder auch langezogener und mehr oder auch weniger sein können. jedoch sind die Peaks zumindest subjektiv betrachtet eindeutig.



  • @Sicci

    Wenn ich den moving average hoch stelle kanns ja sein, das bei ganz vielen peaks dann welche verloren gehen oder nicht?

    Ja stimmt.

    Deine gezackte Kurve entspricht Pi mal Daumen der blauen Kurve plus einem hochfrequenzen Störsignal (Periode 3-4 Samples). Ein Moving Average Filter ist ein Tiefpass-Filter, d.h. er lässt das niederfrequente Signal durch und blockiert das hochfrequente Störsignal. Die Fenstergröße bestimmt im Endeffekt die Grenzfrequenz, ab welchem der Filter das Signal blockiert.

    Tipp:
    Plotte doch mal deine gezackte Kurve und die mittels dem Moving Average Filter erzeugte Kurve in einen Plot und schaue dir mal an was passiert wenn du die Fenstergröße erhöhst. Du wirst sehen die Peaks verschwinden langsam und die Kurve wird glatter.



  • @Sicci sagte in Maxima in Plot bestimmen:

    Also z.B, so ein Plot wie auf diesem Bild Plot. Nur das es gestauchter sein kann oder auch langezogener und mehr oder auch weniger sein können. jedoch sind die Peaks zumindest subjektiv betrachtet eindeutig.

    Dass die Peaks subjektiv betrachtet eindeutig sind hilft dir leider nicht sie mit einem Algorithmus zu finden. Wenn die obere Grenzfrequenz des Nutzsignals nicht bekannt ist, dann hast du kaum eine Chance sie aus den Samples zu bestimmen.

    Ideal wäre es, wenn du mit einer fixen Fensterbreite für den moving-average arbeiten kannst. Bzw. einer fixen Grenzfrequenz für sonstige Tiefpassfilter.

    Und nochwas: selbst mit einem moving-average werden immer noch knapp benachbarte lokale Minima und Maxima übrig bleiben die nur durch das Rauschen erzeugt werden. Nämlich überall dort wo das niederfrequente Nutzsignal sich kaum bis gar nicht ändert. Weil so ein Tiefpassfilter (egal ob mit moving-average oder sonstwie) die hochfrequenten Anteile ja nicht entfernet - er dämpft bloss deren Amplitude.

    Diese rauszufiltern wird vermutlich tricky.



  • Die Matlab Implementierung für die Funktion ist einsehbar über

    edit findpeaks.m
    

    Die kannst du dann einfach genau so in C++ umsetzen.



  • Vielen Dank für die Antworten. Ja ich werde die nächste Zeit noch probieren. Falls ich eine gute Lösung finde, gibts hier ein Update von mir.


Log in to reply