Implementierung eines Low pass Filters

Wenn du dir nicht sicher bist, in welchem der anderen Foren du die Frage stellen sollst, dann bist du hier im Forum für allgemeine Fragen sicher richtig.
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das kann ich nicht beurteilen. Ich kenne deine Daten, nicht die dazugehörige Bewegung. Und deine roten Punkte sind ja auch nicht an jedem Peak. Warum sollte das mit dem Verfahren bei den negativen anders sein?
Risingsun
User
Beiträge: 43
Registriert: Dienstag 8. November 2022, 14:56

Um meine Frage zu konkretisieren, zeige ich mal meine Minimafunktion auf.

Code: Alles auswählen

import numpy as np
import matplotlib
import matplotlib.pyplot as plt
matplotlib.use('Agg')
from scipy.signal import argrelextrema


def butter_lowpass(cutoff, fs, order=5):
    nyq = fs/2
    normal_cutoff = cutoff / nyq
    b, a = butter(order, normal_cutoff, btype='low', analog=False)
    return b, a


def butter_lowpass_filter(data, cutoff, fs, order=5):
    b, a = butter_lowpass(cutoff, fs, order=order)
    y = lfilter(b, a, data)
    return y


data=pd.read_csv('hussein2_acc.csv',sep=";", decimal=",",encoding='latin-1')
sensor_data=data[['Euklidische Norm']]
sensor_data = np.array(sensor_data).ravel()
sensor_data = sensor_data - np.average(sensor_data) # eliminate DC

# Filter requirements.
order = 2
fs = 100  # sample rate, Hz
cutoff = 1

y = butter_lowpass_filter(sensor_data, cutoff, fs, order)

array_data = np.arange(start = 0, stop = 4098, step = 1, dtype='int')
minima_ind = argrelextrema(y, np.less)
minima_ind = minima_ind[0]

x_minima = minima_ind
y_minima = y[minima_ind]
print(y_minima,x_minima)

# plot the peaks
(fig, ax) = plt.subplots()
ax.plot(array_data, y)
ax.scatter(x_minima, y_minima,color = 'r', s = 25, label = 'Minima')
ax.legend
Das ist der Code um die Minimas zu berechnen. Es findet zwar viele lokale Minimas, komischerweise ist sind 2 positive Peaks ebenfalls ein Minima, aber es sind viel zu viele.
Meine Bewegung sind die Bizepcurls, eine Wiederholung hat die Form von einem "M". Es erkennt pro Wiederholung mindestens 3 negative Peaks, was einer mindestens zu viel ist.

Wie man hier an dem Bild erkennt
https://ibb.co/7Krw6Vg

Es hängt denke ich mit der erwarteten Distanz der Peaks zusammen bzw, das die Distanz vergrößert werden muss genau die Funktion wie bei der Peak detection mit dem Parameter Distance.

Code: Alles auswählen

array_data = np.arange(start = 0, stop = 4098, step = 1, dtype='int')
Mit diesem Abschnitt wollte ich etwas ähnliches bewirken, jedoch wenn ich den Parameter

Code: Alles auswählen

Steps
erhöhe kommt einer Fehlermeldung.

https://ibb.co/51yzMMz

Das Problem war bei der Peak Detection nicht, wieso kommt es jetzt zu diesem Konflikt?
Ich habe dann versucht die gefilterten Daten auf die selbe Anzahl von shapes zu bringen wie die Daten mit den

Code: Alles auswählen

steps 
was aber kläglich gescheitert ist.

Gibt es eine andere Lösung als die Shapes auf die selbe Anzahl zu bringen oder gibt es eine besser Alternative, als die Minima Funktion in meinem Code?
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wieso benutzt du nicht die peak detection? Die hat doch halbwegs gute Ergebnisse geliefert, und sollte auch bei negativen peaks funktionieren. Sollte sie das aus irgendwelchen Gründen nicht tun, ist es ja trivial, das zu reparieren - einfach * -1 nehmen.
Risingsun
User
Beiträge: 43
Registriert: Dienstag 8. November 2022, 14:56

Die Daten müssen ja *-1 genommen werden oder?
Also Sprich

Code: Alles auswählen

peaks = find_peaks(y*-1, height = 0.00, threshold = None, distance=170)  # *-1

eight = peaks[1]['peak_heights'] #list of heights of peaks
peak_pos = peaks[0]
print(peaks)

# plot the peaks
fig = plt.figure()
ax = fig.subplots()
ax.plot(y*-1) # *-1
ax.scatter(peak_pos, height,color = 'r', s = 25, label = 'Maxima')
ax.legend
plt.show()

Dann sieht es so aus
https://ibb.co/9Y43hQ7

Ich denke das sieht sehr gut spiegelverkehrt wie die Peakdetection aus. Vielen Dank für den Hinweis, ich habe viel zu kompliziert gedacht.

Jetzt brauche ich die Werte zwischen den Peaks jeweils für die Segmentierung oder?
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Du willst eine Segmentierung, und du musst auch wissen, was wo wie zu einem Segment gehoert. Wenn die Peaks da eine gute Grenze darstellen, dann nimm die doch.
Risingsun
User
Beiträge: 43
Registriert: Dienstag 8. November 2022, 14:56

Ich habe soweit die negativen Peaks. Ich muss jetzt die Daten vom Low pass Filter in den jeweiligen Punkte schneiden wo die lokalen Peaks angesetzt sind, also heißt die Daten des Lowpassfilters in subarrays schneiden. Es soll dann geschnitten werden wenn es einen Peak findet richtig?

Code: Alles auswählen

[0.06110087, 0.10401105, 0.07522478, 0.09554681, 0.08982648,
       0.09118464, 0.09309628, 0.10440643, 0.08335122, 0.14826715,
       0.09760258, 0.13332452, 0.11009777, 0.1806636 ]
Also das sind meine lokalen Peaks. Die Arrays müssen so geschnitten werden das sie von dem Peak 0.061100887 bis 0.10401105 alle Daten in einem Array sind und von dem Peak 0.10401105 bis 0.07522478 alle Daten in ein Array etc.

Code: Alles auswählen

y = butter_lowpass_filter(sensor_data, cutoff, fs, order)


peaks = find_peaks(y*-1, height = 0.00, threshold = None, distance=170)
height = peaks[1]['peak_heights'] #list of heights of peaks
peak_pos = peaks[0] 



def subdivise(arr,peak_heights):
    intervals = [(min(peak_heights[i],peak_heights[i + 1]),max(peak_heights[i],peak_heights[i + 1]))
            for i in range(len(peak_heights) - 1)]
    
    subarrays = [[] for _ in range(len(intervals))]

    for value in arr:
        for subarray_index,interval in enumerate(intervals):
            if value > interval[0] and value <= interval[1]:
                subarrays[subarray_index].append(value)
    
    return subarrays


print(subdivise(y,height))
Ich habe mich da ran probiert, aber irgendwie nicht erfolgreich, das Problem hierbei ist, das die Zahlen nach ihrem Wert in die Subarrays einteilt, glaube ich. Nicht, wenn es ein Peak findet.
Hängt es vielleicht auch mit der Struktur von meiner Variable y ab, ist das ein Integer Array?
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Alter Beitrag geloescht, war quatsch. Wobei so ganz auch nicht. Du hast die peak_pos. Die musst du aber schon auch benutzen.
Risingsun
User
Beiträge: 43
Registriert: Dienstag 8. November 2022, 14:56

Also ich habe etwas gefunden was etwas klappt, jedoch nicht so das rauskommt was ich brauche.

Code: Alles auswählen

[


y = butter_lowpass_filter(sensor_data, cutoff, fs, order)


peaks = find_peaks(y*-1, height = 0.00, threshold = None, distance=170)
height = peaks[1]['peak_heights'] #list of heights of peaks
peak_pos = peaks[0] 


print([y[pre: next] for pre, next in zip_longest(peak_pos,peak_pos[1:])])

Es geht um diesen Codeabschnitt.
Es teilt die Daten in subarrays nach peaks, jedoch etwas komisch
Das sind meine Peaks.

Code: Alles auswählen

[0.06110087, 0.10401105, 0.07522478, 0.09554681, 0.08982648,
       0.09118464, 0.09309628, 0.10440643, 0.08335122, 0.14826715,
       0.09760258, 0.13332452, 0.11009777, 0.1806636 ]
Jedoch teilt es erst ab den 3.Peak richtig. Sprich ich bekomme die Daten zwischen 0.07522478 und 0.09554681. Davor aber teilt es komisch Zahlen, wie hier zu sehen sind.
https://ibb.co/kgD9vT0

Dabei enthält mein Graph nocht nicht mal so hohe Zahlen.
Wie hier zu sehen ist.
https://ibb.co/9Y43hQ7

Ich habe mir dann die Variable y ausprinten lassen und da sind tatsächlich solche Zahlen drin. Wie hier zusehen ist.
https://ibb.co/Cv74qK7

Meine Fragen:

Welche Strukur hat die Variable y und wie kann ich es machen das es nicht nur ab dem 3.Peak richtig schneidet und warum sind zuerst so komische Zahlen in der Variable y, so dass es erst ab dem 3. Peak richtig schneiden kann?
Wie hier auf dem Bild zusehen ist, den Wechsel von "komische" Zahlen zu "normalen" Zahl ( in dem Fall 3. Peak) habe ich markiert.
https://ibb.co/J78GGdQ


Und anstatt das es nach dem Peak aufhört zu schneiden, schneidet es vom letzten Peak bis zur letzten Zahl, jedoch soll nach dem letzten Peak alle anderen Zahlen ignoriert werden und auch alle Zahlen vor dem ersten Peak soll ignoriert werden.
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Das sind keine komischen Zahlen. Das ist einfach nur die Exponenten-Darstellung, auf die Python zurückgreift, wenn Zahlen kleiner oder größer sind, und dann eine ausgeschriebene Darstellung zu viel Platz beanspruchen würde.

0.000000000000000000001

vs

1E-20

(Ich mag mich verzählt haben, aber so in etwa).

Ich halte deinen ganzen Ansatz für problematisch. Du arbeitest dich gerade daran ab Code zu schrieben, der deine Curls sauber erkennt. Wenn du den erstellt hast, ist deine Aufgabe gelöst. Das ist aber nicht der Plan. Der Plan ist, Daten für ein ML Verfahren zu erzeugen, welches dann diese Erkennung durchführt. Das bereitstellen und Labeln dieser Daten ist eine manuelle Aufgabe (bei überwachten Verfahren zumindest). Keine automatische. Es spricht natürlich nichts dagegen, sich beim erstellen dieser Testdaten vom Rechner helfen zu lassen, wenn es wie hier zb gute Features wie die peaks gibt. Aber es ist dann trotzdem nötig, sowas wie Start und Ende hier händisch zu definieren. Für diese konkreten Daten! Andere sehen anders aus, und müssen anders bearbeitet werden.
Risingsun
User
Beiträge: 43
Registriert: Dienstag 8. November 2022, 14:56

Zu meiner Vorgehensweise:

Mein Ziel ist es alle Rohdaten (x,y,z) zwischen den Peaks zu bekommen und auf diesen Daten sollen die Features berechnet werden, die ich auswählen muss. Diese Daten sollen gelabelt werden und dann in die ML-Pipeline in Matlab eingespeist werden. Zumindest wird es uns so mehr oder weniger vorgegeben.
Ich merke gerade das ich das schneiden in die subarrays nicht mit den Daten des Low pass filter machen muss, sondern mit sensor_data. Also sprich nach peak positionen die Achsen (x,y,z) jeweils schneiden und mit diesen Daten sollen die Features berechnet werden.

Achja, zu den Zahlen: Aber wieso fangen die Zahlen mit -6.6 oder -7.7 an, ich habe doch nur Zahlen die eine 0 vor dem Komma haben?

Ich dachte das ich mit (peak_pos,peak_pos[1:]) den Start und Endpunkt definiere, also es soll ja vom ersten bis zum letzten Peak gehen.
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Wieso sollen denn die Rohdaten statt der gefilterten genommen werden? Das ergibt doch gar keinen Sinn, wenn man als Grund für die Filterung das Sensorrauschen annimmt. Die Peaks findest du auch ohne Filter.

Und 7 durch 1**5 ist immer noch 0.00007. So ist diese Notation definiert, das solltest du mal nachlesen.

Mit zip_longest füllst du das Ende mit None, und damit bekommst du auch alles nach dem letzten Peak.
Risingsun
User
Beiträge: 43
Registriert: Dienstag 8. November 2022, 14:56

Ich frage mal meinen Professor, ob er das wirklich so meint, ob die Features mit den Rohdaten berechnet werden sollen.

Oh okay, ich werde mich mal schlau machen über die Notation, danke!

Ich möchte nicht die Daten nach dem letzten Peak haben. Es soll ja nach dem letzten Peak stoppen, weil da die Übung aufhört. Aber ich bekomme die Daten nach dem letzten Peak mit und ohne None.
Ich dachte das wenn man nichts hinsetzt, das es nur bis zum letzten Peak geht. Wie bekomme ich das hin das es nach dem letzten Peak stoppt?
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Der Code den du gezeigt hast lässt alle peaks als anfangswert eines Intervalls zu. Das darfst du dann eben nicht machen.
Risingsun
User
Beiträge: 43
Registriert: Dienstag 8. November 2022, 14:56

Ich habe nach geschaut, es fängt beim ersten Peak an zu schneiden, was gut ist. Daher ist es eigentlich gut wenn es die Peaks, als Anfangswert nimmt.

Nur nicht den letzten Peak.
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

In deinem Code steht quasi das hier:

Code: Alles auswählen

for anfangs_index, end_index in zip(alle_peaks_inklusive_des_letzten_peaks, ..)):
Warum ist das dann ueberraschend fuer dich, wenn anfangs_index auch den Wert des letzten Peaks annimmt? Und damit ein Intervall nach dem letzten Peak erzeugt? Das hast du doch so festgelegt. Wenn du paarweise nur die Indizes bis zum *vorletzten* Startindex erzeugen willst, dann musst du das doch auch so angeben. Ganz aehnlich zu der Art, wie du das fuer den End-Index ja auch gemacht hast.
Risingsun
User
Beiträge: 43
Registriert: Dienstag 8. November 2022, 14:56

Ich habe angegeben das es nur bis zum vorletzten Peak das Intervall starten soll mit dem Code:

Code: Alles auswählen

print([sensor_x[pre: next] for pre, next in zip_longest(peak_pos,peak_pos[1:len(peak_pos)-2])])
Aber es ändert sich nichts, es nimmt immer noch die Werte nach dem letzen Peak. Dazu habe ich noch ein Phänomen festgestellt.
https://ibb.co/N1xnWQN

Auf de Bild sind die letzten beiden Subarrays angezeigt. Das vorletzte Array startet am vorletzten Peak soweit so gut, es endet aber nicht am letzten Peak, sondern erst zum letzten Punkt nach dem letzten Peak. Das seltsamste jedoch ist, das es noch ein Subarray erstellt mit nochmal allen Werten was nach dem letzten Peak kommt ?!

Ich habe im vorletzten Array die Zahl markiert wo die Zahlen nach dem letzten Peak anfangen und aufhören. Und genau die selben Zahlen kommen nochmal alleine vor im letzten subarray. Wieso werden diese Werte nochmal kopiert und es erzeugt sogar ein Subarray dafür?

Wie ist das zu erklären und was mache ich da falsch?
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Hast du nicht. peak_pos läuft über alle Werte. Darum benutzt du ja auch zip_longest. Lass das. Nimm zip. Dann fällt dir dein Fehler auf.
Risingsun
User
Beiträge: 43
Registriert: Dienstag 8. November 2022, 14:56

Achsoo, jetzt funktioniert es, vielen Dank! Ich habe alle Werte zwischen den Peaks und beim letzten Subarray fängt es am vorletztem Peak an und hört beim letzten Peak auf ! Also egal was man macht zip_longest geht immer über alle Werte?
__deets__
User
Beiträge: 14522
Registriert: Mittwoch 14. Oktober 2015, 14:29

Darum heißt es doch longest. Wenn’s in kürzeren Iterables keine Werte gibt, wird mit None aufgefüllt.
Risingsun
User
Beiträge: 43
Registriert: Dienstag 8. November 2022, 14:56

Ich bin gerade dabei Features zu berechnen auf meine Segmente. Ein Feature ist die cross-correlation die uns nahe gelegt wurde.

Der Code um meine Segmente zu teilen ist das

Code: Alles auswählen

y=[y[pre: next] for pre, next in zip(peak_pos,peak_pos[1:len(peak_pos)])]
Da es ein Array ist mit mehreren subarrays habe ich folgenden Code geschrieben.

Code: Alles auswählen

k = []
for elem in z:
    k.append(np.correlate(elem,elem+1))
    
print (k)
Hier ist das Ergebnis was mir geliefert wird.

https://ibb.co/cksVbFS

Ich bin mir nicht sicher ob es mir das richtige Ergebnis liefert. Dabei muss ich es auf jedem Segment berechnen muss, muss das jeweilige Segment mit allen weiteren Segmente die Cross-Correlation berechnet werden oder?

Ich bin mir bei dem Code nicht sicher, ob es das tut was es soll. Ich denke aber das es nur die Cross-Correlation mit dem nächsten Segment berechnet oder?
Antworten