Forum: PC-Programmierung Bursts in einem Signal zählen


von Uhu U. (uhu)


Angehängte Dateien:

Lesenswert?

Ich möchte per Programm die Bursts im oberen Signal zählen.

Zunächst habe ich die Signalwerte gleichgerichtet und dann einen 
gleitenden Mittelwert über 128 Werte gebildet, nach dem Prinzip
1
accu += wert
2
accu -= accu / 128
3
wert2 = accu / 128

Das Ergebnis (wert2) ist das mittlere Signal.

Das untere Signal ist aus dem mittleren entstanden, indem der 
Algorithmus mit 1/256 wiederholt wurde.

Das neue Signal ist zwar weniger zittrig, als das mittlere, aber der 
erste, schwach ausgebildete Puls im Originalsignal hat gelitten.

Nun suche ich nach einer halbwegs robusten Methode, um aus einem der 
abgeleiteten Signale die Anzahl Pulse im Original auszuzählen.

Gibt es was besseres, als durch zwei Y-Werte mit delta-Y > 1 eine Gerade 
zu legen und Vorzeichenwechsel der Steigung von + nach - zu suchen?

von Udo S. (urschmitt)


Lesenswert?

Bin schon zu lange raus aus dem Geschäft aber ich versuchs mal.
Dein Signel verschleift, weil du kein echtes gleitendes Fenster hast 
sondern die Historie immer mitschleppst.
Du brauchst einen Ringpuffer und musst die Summe der neuesten X Werte 
nehmen.
Dazu musst du nicht bei jedem Step den gesamten Ringpuffer addieren, es 
reicht wenn du den ältesten Wert von der gespeicherten Summe abziehst, 
ihn dann mit dem neuen Wert überschreibst und den neuesten zur Summe 
dazuaddierst. Dann die Summe wie gehabt durch die Anzahl der Elemente im 
Ringpuffer.

: Bearbeitet durch User
von Uhu U. (uhu)


Lesenswert?

Udo Schmitt schrieb:
> Du brauchst einen Ringpuffer und musst die Summe der neuesten X Werte
> nehmen.

Für die Geradenberechnug, wie oben kurz angerissen, ist das klar. Für 
die Signalaufbereitung ist der Tiefpass schon der richtige Ansatz.

von Udo S. (urschmitt)


Lesenswert?

Uhu Uhuhu schrieb:
> Für
> die Signalaufbereitung ist der Tiefpass schon der richtige Ansatz.

Als reiner Tiefpass ja. Aber willst du das?
Beispiel du hast Werte (Fenster n = 4):

4 4 4 4 4 4 4 0 0 0 0 0 4 4 4 4 4

Ein gleitendes Fenster ist nach dem 4. '0' Wert auch bei 0 angelangt, 
dein Tiefpass krebst noch irgendwo um die 1 rum, das gleiche bei den auf 
0 folgenden Vierern, da ist das gleitende Fenster nach 4 Werten wieder 
auf '4', dein Tiefpass irgendwo um die 3.
Du hast also im Endeffekt statt Werten zwischen 0 und 4 welche zwischen 
1 und 3. Das ist ein großer Unterschied.

Probiers doch mal aus.

: Bearbeitet durch User
von Uhu U. (uhu)


Lesenswert?

Udo Schmitt schrieb:
> Als reiner Tiefpass ja. Aber willst du das?

Es scheint vorteilhaft zu sein, denn es macht aus dem Gezitter im oberen 
Oszillogramm schon mal was deutlich ruhigeres, ohne die Bursts 
wegzuglätten.

Die Frage ist, wie man es am besten anstellt, in einem der gefilterten 
Signale die Bursts zu finden - das Original dürfte sehr viel 
ungeeigneter dafür zu sein.

von Uhu U. (uhu)


Angehängte Dateien:

Lesenswert?

Jetzt habe ich eine Lösung, die zumindest für mein Testsignal ganz gut 
funktioniert:

Im zweimal gefilterte Signal aus dem Eingangsposting wird durch zwei 
Messwerte - hier mit 80 Samples Abstand - eine Gerade gelegt und die 
Steigung berechnet.

Wenn das Signal > 800 ist und die Steigung von + nach - wechselt, wird 
der Puls erkannt.

von Udo S. (urschmitt)


Lesenswert?

Uhu Uhuhu schrieb:
> Es scheint vorteilhaft zu sein, denn es macht aus dem Gezitter im oberen
> Oszillogramm schon mal was deutlich ruhigeres, ohne die Bursts
> wegzuglätten.

Das macht das gleitende Mittelwertfilter auch. Aber gerade bei so 
starken Änderungen von Signalen zu Pausen reagiert es schneller, das 
heisst dein mittleres Signal wird ausgeprägter.
Aber wenn es so jetzt klappt ists ja auch gut.
Viel Erfolg noch
Udo

von Vlad T. (vlad_tepesch)


Lesenswert?

Uhu Uhuhu schrieb:
> Im zweimal gefilterte Signal aus dem Eingangsposting wird durch zwei
> Messwerte - hier mit 80 Samples Abstand - eine Gerade gelegt und die
> Steigung berechnet.

wenn du Pech hast liegt dein Maximum aber genau zwischen zwei 
"Sample-Punkten"

Beispiel:


Alle 3 ein Sample

         p1            p2
2 2 3 4 5 6 4 3 4 5 6 6 7 6 5 3 2
|     |     |     |     |     |
2     4     4     5     7     3

p1 wird hier übersehen.

ein Einfacher Kantenfilter würde es doch auch tun, oder nicht?
[-1 0 1] oder vielleicht [-1 -2 0  2  1]
Und deine ersten beiden Faltungen kannst du auch zu einer 
zusammenfassen.

: Bearbeitet durch User
von Possetitjel (Gast)


Lesenswert?

Uhu Uhuhu schrieb:

> Udo Schmitt schrieb:
>> Du brauchst einen Ringpuffer und musst die Summe der
>> neuesten X Werte nehmen.
>
> Für die Geradenberechnug, wie oben kurz angerissen, ist
> das klar. Für die Signalaufbereitung ist der Tiefpass
> schon der richtige Ansatz.

Udos Vorschlag ist ein Tiefpass - allerdings ein FIR-Tiefpass
("nicht-rekursives Filter"), das einen besseren Phasengang hat
als Dein IIR-Filter ("rekursives Digitalfilter"), das i.d.R.
weniger Rechnerei erfordert.

Davon abgesehen: Der erste Puls ist bei Dir so klein, weil
beim Start der "Kondensator" in Deinem Tiefpass völlig
"entladen" ist. Das ist, wie Du durch genaues Hinsehen
prüfen kannst, zwischen den anderen Pulsen nicht der Fall.

Das kannst Du leicht korrigieren, indem Du nicht mit einem
"accu = 0" startest, sondern statt dessen mit einemm
"typischen Tal-Wert". Den kannst Du vor Beginn der Rechnung
schätzen; eleganter ist es natürlich, erstmal loszurechnen,
dabei einen Tal-Wert zu bestimmen, und anschließend den
Kopfblock mit ... was weiß ich ... 1000 Werten nochmal mit
dem korrigierten Startwert neu zu rechnen.

von Possetitjel (Gast)


Lesenswert?

Vlad Tepesch schrieb:

> wenn du Pech hast liegt dein Maximum aber genau
> zwischen zwei "Sample-Punkten"
>
> Beispiel:
>
> Alle 3 ein Sample

Nein... ich habe das so verstanden, dass er die Anstiegs-
berechnung gleitend macht, also
Wert[1] zu Wert[81]
Wert[2] zu Wert[82]
Wert[3] zu Wert[83]
... usw.

von Uhu U. (uhu)


Lesenswert?

Vlad Tepesch schrieb:
> wenn du Pech hast liegt dein Maximum aber genau zwischen zwei
> "Sample-Punkten"

Die Daten stammen aus .wav-Files - was zwischen den dort aufgezeichneten 
Samples los war, kann man sich zwar denken, wissen tut man es aber 
nicht...

Der Ruf des Vogels, um den es geht, ist zwar den in Feinheiten sehr 
variabel, aber im Großen und Ganzen doch nach einem ziemlich festen 
Schema aufgebaut. Die Intervalle variieren von Ruf zu Ruf, aber in 
gewissen, bekannten Grenzen. An diese Grenzen muss die Parametrisierung 
des Algorithmus angepasst sein.

Es geht darum, die Anzahl von Pulsen im Ruf zu zählen - ob man da genau 
das Maximum erwischt, oder nicht, ist so lange egal, wie man das alles 
nicht so verschmiert, dass zwei Pulse nicht mehr auseinanderzuhalten 
sind.

Zudem wird die ganze Chose für alle Werte sukzessive durchgerechnet.

Insofern verstehe ich deinen Einwand nicht.


> Und deine ersten beiden Faltungen kannst du auch zu einer
> zusammenfassen.

Wie müsste das aussehen?

von Vlad T. (vlad_tepesch)


Lesenswert?

Uhu Uhuhu schrieb:
> Insofern verstehe ich deinen Einwand nicht.

der Einwand bezog sich nicht auf das original Signal, sondern auf dein 
künstlich (1/80) unterabgetastetes:

Uhu Uhuhu schrieb:
> Im zweimal gefilterte Signal aus dem Eingangsposting wird durch zwei
> Messwerte - hier mit 80 Samples Abstand - eine Gerade gelegt und die
> Steigung berechnet.


Uhu Uhuhu schrieb:
>> Und deine ersten beiden Faltungen kannst du auch zu einer
>> zusammenfassen.
>
> Wie müsste das aussehen?

Deine Gleitender Mittelwert ist ja nix als eine Faltung des Signals mit 
einem Rechteck (ein Kernel mit allen Elementen 1/n).

du machst also (Stern ist der Faltunsoperator)

das ist das selbe wie:
oder

Da R1 und R2 konstant sind, kann man das vorher ausrechnen.
deine 2 Rechteckfaltungen ergeben also eine Trapezförmige
Den Kantenflter kann man dann auch noch da rein falten.
prinzipiell ist dein im Abstand von 80 den Anstieg berechnen ja das 
gleiche.
Nur würde ich das für jedes Fenster machen (also überlappend - falten 
ebend - und nicht nur alle 80 Schritte) und die Zwischenwerte mit 
Berücksichtigen.

Statt deinem [-1 (78 x 0)  1] Kernel, würde ich eher sowas wie [(35 x 
-1) 0 0 0 0 0 (35 x 1)] nehmen.


Die Länge des Gesamtkernels addiert sich allerdings aus den Kernels der 
Einzelkernels. Bei Rechteckkernels ist es möglicherweise effizienter die 
separat zu rechnen.

Wendet man diesen Kernal an, fällt dann eine Kurve raus, die die Extrema 
als 0-Durchgänge beinhaltet (wie bei dir).

in Matlab/octave könnte das ganze so aussehen:
1
R = rand(1,2000 * 10).*abs(sin([1:20000]*2*pi/2000); # signal simulieren
2
3
K1 = ones(1,128)/128; # 128 Mittelwertfilter
4
K2 = ones(1,256)/256; # 256 Mittelwertfilter
5
Ks = conv(K1, K2);    # resultierender Glättungskernel
6
Kz = [(ones(1,35)*-1) 0 0 0 0 0 ones(1,35)];  # Gradientenfilter
7
8
KRes = conv(Ks, Kz); # resultierender Kernel
9
10
# ein paar plots der einzelnen Kernel
11
plot(Ks);
12
figure;
13
plot(Kz);
14
figure;
15
plot(KRes);
16
17
figure;
18
smoothedR = conv(R, Ks, "same"); # nur zur Anschauung berechnet
19
result = conv(R, KRes, "same");
20
plot( [R' smoothedR' result']);

: Bearbeitet durch User
von Possetitjel (Gast)


Lesenswert?

Vlad Tepesch schrieb:

> Deine Gleitender Mittelwert [...]

Der Uhu hat KEINEN gleitenden Mittelwert. Das war Udos
Vorschlag, den er abgelehnt hat.

Der Uhu hat ein IIR-Filter .

Für ein FIR-Filter ist Dein Vorschlag meiner Meinung nach
wesentlich rechenaufwändiger als zwei gleitende Mittelwerte,
ohne einen Zusatznutzen zu bringen.

von Uhu U. (uhu)


Lesenswert?

Vlad Tepesch schrieb:
> Nur würde ich das für jedes Fenster machen (also überlappend - falten
> ebend - und nicht nur alle 80 Schritte) und die Zwischenwerte mit
> Berücksichtigen.

Das mach ich doch. Mein Programm bekommt die einzelnen Rufe nicht auf 
dem Silbertablett serviert, sondern soll sie aus dem Datenstrom im .wav 
rausfischen und rechnet das für jedes einzelne Sample.

Ich habe zwar im Moment nur eine Testdatei mit ca 20 Rufen, aber die 
wird gut genug ausgewertet. Wie es dann mit "echten" Daten aussieht, 
wird sich zeigen.


Possetitjel schrieb:
> Der Uhu hat KEINEN gleitenden Mittelwert. Das war Udos
> Vorschlag, den er abgelehnt hat.

Was heißt da abgelehnt?

Offensichtlich ist doch der "schlechtere" Phasengang meines rekursiven 
Tiefpasses schlicht wurscht - wenn ich das Dingens zweimal 
hintereinander anwende, kommt ein Signal heraus, das "glatt" genug ist, 
damit der 80-er-Kantenfilter - der natürlich auf einem Zirkularpuffer 
läuft - ein brauchbares Ergebnis liefert.

Wenn ein Filter, der die Funktionen in einem Schritt realisiert, weniger 
Rechenaufwand erfordert, als die 3 Einzelschritte, dann ist er für die 
Produktionsversion natürlich interessant.

Allerdings ist der Aufwand für beiden IIR-Filter winzig:
1
lpAccu += sample
2
lpAccu -= lpAccu / l1
3
4
lpAccu2 += lpAccu
5
lpAccu2 -= lpAccu2 / l2

Im Moment bastel ich mit ruby - Octave ist sicherlich besser geeignet 
und schneller.

von Vlad T. (vlad_tepesch)


Lesenswert?

Possetitjel schrieb:
> Für ein FIR-Filter ist Dein Vorschlag meiner Meinung nach
> wesentlich rechenaufwändiger als zwei gleitende Mittelwerte,
> ohne einen Zusatznutzen zu bringen.

Da gebe ich dir recht. mit den aktuell gewählten Parameter ja, wie ich 
ja auch geschrieben habe.
Die Unterabtastung halte ich für fragwürdig.
Ich weiß natürlich nicht, wie viele Samples ein Burst in etwa hat. Wenn 
der mindestens 300-400 Samples breit ist und nicht stört, dass die 
Maxima nicht direkt getroffen werden, mag das kein Problem sein.

von Uhu U. (uhu)


Lesenswert?

Vlad Tepesch schrieb:
> Ich weiß natürlich nicht, wie viele Samples ein Burst in etwa hat.

Die gesamte Kette aus Bursts ist ca 150 ms. Das Signal ist mit 44,1 kHz 
abgetastet.

> Die Unterabtastung halte ich für fragwürdig.

Eher nicht. Das ist eine Aufnahme von einer Vogelstimmen-CD.

: Bearbeitet durch User
von Vlad T. (vlad_tepesch)


Lesenswert?

Uhu Uhuhu schrieb:
> Das mach ich doch

Ach so. Ich dachte, du schaust Dir nur vielfache von 80 an.

Dann ist es ja fast das gleiche, nur das ich die Werte dazwischen auch 
berücksichtigen würde.

Uhu Uhuhu schrieb:
> Mein Programm bekommt die einzelnen Rufe nicht auf dem Silbertablett
> serviert, sondern soll sie aus dem Datenstrom im .wav rausfischen und
> rechnet das für jedes einzelne Sample.

also was jetzt? Hast du das komplette File dada, oder trudeln einzelne 
Samples in Echtzeit ein?

Im ersten Fall brauchst Du ja keinen Ringpuffer.
wenn du bei den rechteckigen filtern bleibst, kommst du vielleicht 
besser, wenn du in einem Puffer dass integral des Signals mitführst. 
Dann lassen sich beliebige gleitende Mittelwerte ohne weiteren Aufwand 
berechnen.

: Bearbeitet durch User
von Uhu U. (uhu)


Lesenswert?

Vlad Tepesch schrieb:
> also was jetzt? Hast du das komplette File dada, oder trudeln einzelne
> Samples in Echtzeit ein?

Es ist ein .wav-File, aber ich behandle ihn Pufferweise¹, womit er im 
Prinzip wie ein Echtzeitsignal aussieht. Nur für Echtzeit ist das 
Ruby-Programm definitiv zu langsam; das ist auch nicht gefragt.

Sinn der Übung ist die Extraktion individueller Rufermerkmale, z.B. die 
Anzahl Bursts pro Ruf und das Timing dazu.

Ob man dabei Fehler macht, ist erst mal nicht so wichtig, so lange man 
überall dieselben macht und keine störenden Artefakte dabei entstehen.


-----

¹) das bietet das verwendete .wav-Gem so an. Man könnte zwar den Puffer 
so groß machen, dass die ganze Datei hinein passt, aber dann müsste man 
sich um die Größe kümmern.

von Possetitjel (Gast)


Lesenswert?

Uhu Uhuhu schrieb:

> Was heißt da abgelehnt?

Na eben: Abgelehnt. Das hast Du doch.

> Offensichtlich ist doch der "schlechtere" Phasengang
> meines rekursiven Tiefpasses schlicht wurscht [...]

Jein.

Du hast ursprünglich beklagt, dass ein Filter, das die kleinen
Schwankungen hinreichend unterdrückt, auch die Bursts selbst
so stark einebnet.
Das liegt einfach daran, dass Du extrem einfache Filter
verwendest und die "Stärke" des Filters nur über seine
Grenzfrequenz einstellen kannst.
Für das Ergebnis besser wäre aber, wenn Du die Ordnung des
Filters erhöhen würdest, weil Du dann die hochfrequenten
Anteile unterdrücken kannst, ohne die niederfrequenten
zu verfälschen.

Je höher die Filterordnung wird, desto stärker sind aber
die Auswirkungen eines schlechten Phasenganges auf das
Impulsverhalten. Hier sind FIR-Filter im Vorteil.

Bei Udos ersten Antworten war ja noch gar nicht klar, dass
Dein einfaches Verfahren für Dich funktioniert (sonst hättest
Du ja nicht zu fragen brauchen).

von Uhu U. (uhu)


Lesenswert?

Possetitjel schrieb:
> Du hast ursprünglich beklagt

Ich habe garnichts beklagt, sondern gefragt, ob es was besseres gibt als 
das, was ich mir überlegt hatte.

Und wie die Debatte gezeigt hat, ist dieses Besser mit viel höherem 
Rechenaufwand verbunden, dem hier offenbar kein Nutzen gegenüber steht. 
Das ist auch eine Erkenntnis und eine, die nicht gerade beklagenswert 
ist...

von Udo S. (urschmitt)


Lesenswert?

Jetzt streitet euch mal nicht.

Vlad hat mehr Ahnung von Filtern als ich je hatte :-)

Uhu Uhuhu schrieb:
> Und wie die Debatte gezeigt hat, ist dieses Besser mit viel höherem
> Rechenaufwand verbunden, dem hier offenbar kein Nutzen gegenüber steht.

Der Rechenaufwand des gleitenden Mittelwert ist nicht unbedingt höher.
Du musst halt nur ein dem Fenster entsprechend großen Ringpuffer haben 
und die letzte berechnete Summe speichern. Dann reicht es bei jedem 
neuen Wert von der alten Summe den ältesten Wert abzuziehen, den neuen 
dazuzuaddieren, und den ältesten Wert mit dem neuen überschreiben.
Das sind 1 Leseoperation, eine Schreiboperation, eine Subtraktion und 
eine Addition, sowie das Lesen und Überschreiben des Summenwertes.
Gut dann noch den Mittelwert aus der Summe, also eine Division, aber die 
brauchst du bei deinem IIR Ansatz genauso.

Viel Erfolg

Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.