Benutzer-Werkzeuge

Webseiten-Werkzeuge


Seitenleiste

ss15:taktrueckgewinnung_1.2

Taktrückgewinnung 1.2

takt_finder

Wie der Name schon sagt, soll dieser Code den hinterlegten Takt in unserer Aufnahme in Form von Zeitpunkten ausgeben, der ja durch unsere mitgespielte Takt-Frequenz erkennbar ist. Hierfür wird unsere Aufnahme um unsere Takt-Frequenz gefiltert, in Beträge umgewandelt und die Hillbert-Funktion angewendet. Die Hillbert-Funktion sorgt für eine Konturlinie um die Aufnahme der gefilterten Frequenz. Am Ende erhalten wir eine Funktion der Intensität von der Takt-Frequenz.

ursprüngliche Aufnahme Filterung der Takt-Frequenz Umwandlung in Beträge Hillbert-Kurve

def takt_finder(y):
	'''liefert Liste mit Indizes der Taktflanken'''
	takt = 0.05*RATE
	f_takt = 12600
	mind = 0.005
	minl = 16
	idx = []
 
	b, a = signal.butter(4, [(f_takt-100)*2./RATE, (f_takt+100)*2./RATE], btype="bandpass") # Parameter für Butterworth-Filter
	yf = signal.lfilter(b,a,y) # Taktfrequenzfilter
	yh = np.abs(signal.hilbert(y)) # Hilbert-Transformation
	# [...]

Somit können wir feststellen, wann die Takt-Frequenz gespielt wurde oder nicht, da bei Auslassung die Lautstärke gegen Null geht. Nun wollen wir eben diese Zeitpunkte von diesem Wechsel zwischen 'An' und 'Aus' der Takt-Frequenz herauslesen.

Unterschiede zur Taktrückgewinnung 1.1

Die Taktrückgewinnung 1.1 gibt nur einen Wert, die Taktverschiebung, zurück. Die Version 1.2 liefert dagegen eine Liste mit den konkreten Indizes an welchen sich Taktgrenzen befinden. Daraus ergibt sich ein großer Vorteil der neuen Methode: Es werden nur die Indizes geliefert, an denen auch wirklich etwas gesendet wurde und damit wird auch nicht versucht Aufnahmeabschnitte ohne Signal zu decodieren. Das kann auch dabei helfen verlorene Bits zu vermeiden, wenn weder eine 0 oder 1 erkannt wird und dadurch weniger Bits ankommen als gesendet wurden. Diese ganzen Vorteile setzen aber voraus, dass der Erkennungsprozess zuverlässig funktioniert. Nachfolgend ist aufgeführt welche Probleme auftreten können und was wir turn um sie zu vermeiden.

1. Problem:

Wie eine Lautstärke-Grenze setzen, bei dessen Über- und Unterschreitung ganz klar ein Wechsel von An zu Aus stattfindet und diese auch immer von Flanken durchlaufen wird?

Variante 1

Dazu muss ein absoluter Wert als Grenze gesetzt werden, der jedoch schwer festzusetzen ist, da immer unterschiedliche Lautstärken verwendet werden könnten. Dazu vereinheitlichen wir die bisher gewonnen Aufnahme (siehe ye). Egal mit welcher Lautstärke der Sender sendet, wir erhalten immer das ungefähr gleiche Bild einer Funktion in ihrem Maximum (ca. 0.0034 bei guten Aufnahmen). Dazu setzen wir eine möglichst kleine Grenze mit einem kleinen Intervall als Bedingung, die nun unsere Takt-Flanken erkennt.

Resultat einer guten Aufnahme keine Beeinflussung durch einzelne Extrema

ye = (1/(np.linalg.norm(yf)))*yh # Vereinheitlichung der Hillbertkurve für jede Lautstärke
idx = np.where(np.abs(ye-0.001)<0.00002) # Grenze 0.001 im Toleranzbereich 0.00002 enthält ca. 3 indices an einer Flanke
v.extend(np.array(idx).flatten().tolist())




Variante 2

Die Variante 1 wirft allerdings ein Problem auf: Wurde im untersuchten Abschnitt kein Signal aufgenommen, d.h. es herrscht nahezu Stille auf der Taktfrequenz, wird diese Stille mit ihrem ganz geringen Grundrauschen trotzdem auf den üblichen Wert verstärkt. Das führt dann aber dazu, dass Takt-Flanken erkannt werden wo gar keine sind. Deshalb erachte ich es für sinnvoller eine feste minimale Grenze zu definieren, ab dem das Taktsignal als vorhanden gewertet wird und die Grenze zur Erkennung wie gehabt über das Maximum oder ähnlich zu berechnen.

# [...]
ma = max(yh)
if ma > mind:
	s = ma/5
	tol = 0.002 * ma
	idx = np.where(np.abs(yh-s)<tol)
	# [...]

2. Problem:

Wie können wir unsere 'richtigen' Takt-Flanken von den 'falschen' Takt-Flanken unterscheiden und herausfiltern? Denn es können bei unschönen Aufnahmen immer Fehler entstehen, die mit unserer einfachen Grenzsetzung einhergehen.

Wir haben somit erstmal nur eine Sammlung von sehr vielen potentiellen 'richtigen' Flanken. Zum einen enthält das Intervall um die Grenze mehrere Indices für nur eine gewollte Flanke und zum anderen müssen diese Indices auch in dem vorgegebenen Taktzeitabstand passen! Und dazu wird die Rohliste v überprüft.

Per for-Schleife werden die 'richtigen' Flanken in eine neue Liste übertragen. Der momentane Index wird mit dem nächstkommenden Index auf seinen Abstand überprüft und nur als 'richtig' übertragen, wenn diese im Taktabstand mit einer Toleranz von +-5% vom Taktabstand zueinander stehen. Somit fallen sofort alle Indizes raus, deren Abstand ungleich des Taktabstandes zum nächsten Index ist, also die der gleichen Flanke angehören oder die den 'falschen' Flanken angehören, die sich zwischenmogeln könnten. Da Flanken nur als 'richtig' gelten, wenn es die nächste bestätigt, werden hier 'falsche' Flanken ein Problem. Obwohl eine Flanke 'richtig' wäre, würde sie nicht bestätigt werden können. Dazu gibt es einen Zähler k, der später auf diese versäumte Flanke zurückführt, sobald die nächste 'richtige' Flanke gefunden wurde. So würde die gegenwärtige Flanke in der Liste zur Bestätigung für eine versäumte Flanke werden.










3. Problem:

Die letzte Flanke muss ja auch noch erkannt werden, jedoch geht das schlecht ohne eine nachfolgende Flanke nach bisherigem System.

Das System wird da einfach umgedreht. Die Liste v wird dabei nun rückwärts durchlaufen bis es zu einer Bestätigung kommt. Hierbei wurde uns klar, dass das letzte Bit natürlich auch von Flanken eingeschlossen werden muss. So mussten wir unsere code-Funktion umschreiben. Vorher endete unsere Takt-Frequenz nämlich mit Aus. Nun mit An.

4. Problem:

Trotz aller Takterkennungsmaßnahmen könnten ja sicherlich einfach durch eine schlechte Übertragung/Aufnahme wichtige Flanken fehlen, die dann rekonstruiert werden müssten.

Dies geschieht durch nochmalige Überprüfung der Taktabstände aller Indices der Liste h. Lücken werden dabei durch einfaches Addieren des Taktabstandes mit Indices gefüllt.

# [...]
v=[] # alle Indices um Grenze
h=[] # Sortierung der Indices aus v nach nur richtigen Takt-Flanken
e=[] # Hilfliste zur Ergänzung von Takt-Flanken, falls richtige Takt-Flanken nicht auffindbar (Lückenliste)
n=0 # Zähler für v-Liste
m=0 # Zähler für h-Liste
k=0 # Zähler für falsche Takt-Flanken in v-Liste
 
v.extend(np.array(idx).flatten().tolist())
 
for x in v:
    n+=1
    if n==len(v):
        for x in sorted(v,reverse=True): # v-liste von hinten nochmal durchgehen, damit letzte Takt-Flanke noch in h hinzugefügt wird
            if h[-1]+takt+0.1*takt>x and h[-1]+takt-0.05*takt<x:
                h.append(x) # die letzte richtige Taktflanke
                break
    elif x+takt+0.05*takt>v[n] and x+takt-0.05*takt<v[n]: # nächste Flanke ist einen Takt mit Toleranz von +-5% entfernt
        if k!=0 and v[n-k-1]+takt+0.05*takt>x and v[n-k-1]+takt-0.05*takt<x:
            h.append(v[n-k-1]) # vergangene richtige Takt-Flanke, die nun durch einer nachfolgenden Takt-Flanke gefunden wurde
        h.append(x)
        k=0 # Neustart nach neuer gefundenen richtigen Takt-Flanke
    else:
        k+=1 # merke um wieviele Flanken wir uns von pot. richtigen Takt-Flanke entfernen
 
for x in h: # Lückenfüller von richtigen Takt-Flanken
    m+=1
    if m==len(h):
        h=sorted(h+e) # fülle Lücken in der richtigen Takt-Liste
        break
    elif not (x+takt+0.05*takt>h[m] and x+takt-0.05*takt<h[m]): # findet Lücken
        e.append(int(x+takt))
return h

Resultat:

Wir erhalten die genauen Zeitpunkte eines Wechsels der Lautstärke der Takt-Frequenz und damit lässt sich die Takteinteilung des Signals ablesen.

ss15/taktrueckgewinnung_1.2.txt · Zuletzt geändert: 2016/05/10 14:46 (Externe Bearbeitung)