Maxima in Plot bestimmen



  • @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