FSK demodulation
- VB.NET
- .NET (FX) 4.5–4.8
Sie verwenden einen veralteten Browser (%browser%) mit Sicherheitsschwachstellen und können nicht alle Funktionen dieser Webseite nutzen.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Hier erfahren Sie, wie einfach Sie Ihren Browser aktualisieren können.
Es gibt 108 Antworten in diesem Thema. Der letzte Beitrag () ist von ~blaze~.
-
-
Das habe ich geändert und ich habe eine "Funktion" eingebaut, welche mir die MinRate und die MaxRate anzeigt. Die Werte liegen zwischen 8820 und 22050 (in einem Zeitraum von ca. 2 Minuten) trotz empfangener Telegramme. Da ist irgendwo noch der Wurm drin. Zwischenzeitlich habe ich den anderen Weg über die Zeit versucht:
Aber auch das passt nicht - es kommen weder 1en noch 0en. -
-
Habs hiermit versucht:
VB.NET-Quellcode
- src = New CSCore.Streams.SoundInSource(cs)
- src.Read(buf, 0, buf.Length)
- For i = 0 To buf.GetUpperBound(0) - 4 Step 4
- ReDim Preserve tempBuf((i / 4) + i)
- tempBuf((i / 4) + i) = BitConverter.ToSingle(buf, i)
- tempCounter += 1
- If (tempCounter = cs.WaveFormat.SampleRate) Then
- _queue.Enqueue(tempBuf)
- ReDim tempBuf(0)
- tempCounter = 0
- End If
- Next
VB.NET-Quellcode
- AddHandler cs.DataAvailable, AddressOf datas
- Private Sub datas(sender As Object, e As CSCore.SoundIn.DataAvailableEventArgs)
- For i = 0 To e.Data.GetUpperBound(0) - 4 Step 4
- ReDim Preserve tempBuf((i / 4) + i)
- tempBuf((i / 4) + i) = BitConverter.ToSingle(e.Data, i)
- tempCounter += 1
- If (tempCounter = cs.WaveFormat.SampleRate) Then
- _queue.Enqueue(tempBuf)
- ReDim tempBuf(0)
- tempCounter = 0
- End If
- Next
- End Sub
-
Upperbounds sind in "normalen", eindimensionalen .Net-Arrays stets Array.Length - 1. Nicht-Eindimensionale Arrays mit veränderter unterer Grenze sind nicht als T() darstellbar. D.h. du kannst das weglassen.
ReDim und ReDim Preserve sind veraltet und werden durch Array.Resize ersetzt, das sollte hier aber nicht notwendig sein.
Die Abfrage tempCounter = cs.WaveFormat.SampleRate verstehe ich nicht ganz. Warum behältst du eine Sekunde drin?
Ich würde sogar die Kopierroutine einfach streichen und die Algorithmen vereinen: buf(i) bzw. buf(i + 1) entsprechen eben dem i-ten Single-Eintrag im Puffer. Das kannst du eben mit BitConverter.ToSingle erledigen. Anschließend noch auf 0-Durchgänge überprüfen, wie ich's dir gezeigt hatte.
Viele Grüße
~blaze~ -
Mit
tempCounter = cs.WaveFormat.SampleRate
bewirke ich, dass ich grundsätzlich einen Puffer mit einer Sekunde analysiere. Du hattest doch erwähnt, dass 1 Single = 4 Byte oder täusche ich mich da? Deswegen mache ich diese Schleife und kopiere in einen temporären Puffer. Natürlich kann es auch sein, dass ich da einen Fehler mache und deswegen die Single-Werte nicht passen. -
Du solltest eigentlich wohl nur jedes 8. Byte ein Single abgreifen, da es sich um einen Stereo-Kanal handelt, oder?
Ja, jedes Single besteht aus 4 Bytes, damit hast du recht. Der temporäre Puffer ist eigentlich überflüssig.
Gib mal die Gleitkommazahlen grafisch aus und zeichne sie oder lade ein paar Daten der Gleitkommazahlen hoch. Die sollten sich immer zwischen -1 und 1 bewegen.
Viele Grüße
~blaze~ -
Hier mal 50 aufeinander folgende (berechnete) Single-Werte:
Quellcode
- 0,1229858
- 0,08224487
- -0,03594971
- -0,02468872
- 0,001586914
- 0,03967285
- 0,06295776
- 0,09417725
- 0,1112976
- 0,1123047
- 0,1181641
- 0,1199646
- 0,1096497
- 0,07992554
- 0,02432251
- 0,0138855
- 0,04318237
- 0,07516479
- 0,1079712
- 0,1295166
- 0,1436768
- 0,1693726
- 0,166626
- 0,164917
- 0,1835938
- 0,1517944
- 0,04434204
- 0,002593994
- -0,002746582
- 0,01577759
- 0,04684448
- 0,05935669
- 0,04406738
- 0,01306152
- 0,01864624
- 0,05001831
- 0,08026123
- 0,1069641
- 0,0819397
- 0,05679321
- 0,072052
- 0,09375
- 0,05944824
- -0,03012085
- -0,04336548
- -0,01785278
- 0,01318359
- 0,01287842
- -0,08056641
Diese Werte wurden bei "Rauschen" auf dem Line-In aufgezeichnet. Diese Werte stellen quasi kein Telegramm dar.
-
Leider ist das nicht sehr aussagekräftig. Es wäre praktisch, eine echte Aufnahme oder Simulation zu erhalten. Das auslesen der Single-Werte ist übrigens weniger das Problem. Ausserdem: Rauschen sorgt dafür, dass der Nullstellenalgorithmus nicht korrekt arbeitet. Den müsste man dann anpassen, das Signal glätten o.ä. Mensch, das würde mir fast nen heiden Spaß machen...
Viele Grüße
~blaze~ -
So.... Ich habe die Tage ein wenig gebastelt und Fehler gesucht und gefunden. Ich hatte einen Fehler in der Berechnung der Singlewerte (das mit dem tempBuffer hat nicht gepasst). Ich habe jetzt den Quellcode angepasst und bin eigentlich der Meinung, dass soweit alles passen sollte:
VB.NET-Quellcode
- Dim queueData As New Queue(Of Byte())
- Dim q1 As New Queue(Of Single)
- Dim rate As Long
- Dim minrate As Long = 1000000
- Dim maxrate As Long = 0
- Dim o As Integer = Integer.MinValue
- Dim lastSgn As Single
- Private Sub Button2_Click(sender As Object, e As EventArgs) Handles Button2.Click
- If (Button2.Tag = 1) Then
- cs.Stop()
- Button2.Tag = 0
- Else
- o = Integer.MinValue
- Button2.Tag = 1
- cs.Device = devs(ComboBox1.SelectedIndex)
- cs.Initialize()
- cs.Start()
- AddHandler cs.DataAvailable, AddressOf datas
- Dim t As New Threading.Thread(AddressOf proccessData)
- t.Start()
- t = New Threading.Thread(AddressOf proc1)
- t.Start()
- End If
- End Sub
- Private Sub datas(sender As Object, e As CSCore.SoundIn.DataAvailableEventArgs)
- SyncLock queueData
- queueData.Enqueue(e.Data)
- End SyncLock
- End Sub
- Private Sub proccessData()
- Dim x As Single = 0
- While (Button2.Tag = 1 Or queueData.Count > 0)
- If (queueData.Count > 0) Then
- SyncLock queueData
- If (Button2.Tag <> 1 And queueData.Count = 0) Then Exit While
- Dim eData() As Byte = queueData.Dequeue
- Dim i As Integer
- For i = 0 To eData.Length - 1 Step (cs.WaveFormat.Channels * 4)
- wert = BitConverter.ToSingle(eData, i)
- SyncLock q1
- q1.Enqueue(wert)
- End SyncLock
- Next
- End SyncLock
- End If
- End While
- End Sub
- Private Sub proc1()
- Dim sr As Integer = cs.WaveFormat.SampleRate
- Dim c1200 As Integer = 0
- Dim c1800 As Integer = 0
- While (Button2.Tag = 1 Or q1.Count > 0)
- If (q1.Count > 0) Then
- SyncLock q1
- Dim wert1 As Single = q1.Dequeue
- If Math.Sign(lastSgn) <> Math.Sign(wert1) Then
- If o <> Integer.MinValue Then
- rate = sr \ o
- If Math.Abs(rate - 1200) <= NumericUpDown1.Value Then 'NumericUpDown1 entspricht RateEqualityThreshold (eingebaut um zur Laufzeit verschiedene Werte zu testen
- c1200 += 1
- c1800 = 0
- If (c1200 = 2) Then
- c1200 = 0
- test &= "1"
- End If
- End If
- If Math.Abs(rate - 1800) <= NumericUpDown1.Value Then 'NumericUpDown1 entspricht RateEqualityThreshold (eingebaut um zur Laufzeit verschiedene Werte zu testen
- c1800 += 1
- c1200 = 0
- If (c1800 = 3) Then
- c1800 = 0
- test &= "0"
- End If
- End If
- If (rate > maxrate) Then maxrate = rate
- If (rate < minrate) Then If (rate > 0) Then minrate = rate
- If (test.Length > 68) Then
- test = test.Substring(1, 68)
- End If
- Dim temp1 As String = test
- If (temp1.Substring(0, 20) = "11111111111100011010") Then
- threadDecoder = New Threading.Thread(AddressOf decoder)
- threadDecoder.Start(temp1.Substring(20, 48))
- End If
- End If
- o = 0
- End If
- lastSgn = wert1
- If o <> Integer.MinValue Then o += 1
- End SyncLock
- End If
- End While
- End Sub
Nun ist es so, dass 1en und 0en "raus kommen", aber dennoch kein "sinnvolles Telegramm" dargestellt wird. Ich habe ein wenig mit dem RateEqualityThreshold (bzw. NumericUpDown) gespielt und es haut immer noch nicht hin. Teilweise sieht die Abfolge von 1en und 0en aus wie ein FMS-Telegramm - allerdings passt der Telegrammvorlauf und die Bitsynchronisation nicht. Ich habe den Verdacht, dass irgendwo noch ein kleiner winziger Fehler liegt.
Testweise habe ich die Single-Werte als Wave in einer PictureBox dargstellt (was allerdings den Thread fast einschlafen lässt - die QueueCount steigt binnen 2 Sekunden auf über 100.000). Wenn FMS-Telegramme gesendet werden, dann ist in der PictureBox die Sinus-Welle schön zu erkennen.
Gedankenzug von mir: in dem Moment wo die erste 1 (im Telegrammvorlauf - bestehend aus zwölf 1en) kommt entsteht eine Einschwingphase und beim lezten Bit vom Telegramm entsteht ein Abfall. Diese beiden "Sonderfälle" werden in der Berechnung nicht beachtet - oder täusche ich mich da? Nun kann man aber auch nicht klar definieren wie die "rate" für das Einschwingen und den Abfall aussehen muss, da man nie weiß welche Frequenz vor der ersten Frequenz (1200 Hz für logisch 1) gesendet wird.
vb-paradise.de/index.php/User/2203-blaze/
Aber dennoch bin ich / sind wir einen rießigen Schritt vorwärts gekommen - Danke @~blaze~
Edit: Das Schlussbit ist irrelevant, da es sowieso nicht ausgewertet wird. Und für das erste Bit frage ich einfach beide Möglichkeiten ab - somit überprüfe ich, ob der Telegrammvorlauf "11111111111100011010" oder "01111111111100011010" ist. Die Sicherheit, ob es sich um ein FMS-Telegramm handelt, ergibt sich durch die CRC-Prüfung (welche allerdings noch programmiert werden muss - da muss ich noch ettliches lesen....)
Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „dietzi“ ()
-
CRC ist bestimmt schon im Framework enthalten. Ich schau mir den Quellcode später an. Ich schätze aber tatsächlich, dass es durch die zusätzliche Nullstelle bei 1800hz kommt. Vielleicht benutzt du einfach eine Boolean-Variable, in die du speicherst, ob die nächste Nullstelle ausgewertet werden soll.
Viele Grüße
~blaze~Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „~blaze~“ ()
-
CRC ist in der CScore-Lib nicht enthalten. Die CRC-Prüfung erfolgt mittels der letzten 7 Bits im Telegramm. Das ist aber erstmal noch Zukunft. Testweise habe ich jetzt mal mein Handy mit einer Soundgenerator-App an den Line-In angeschlossen. Sende ich eine Frequenz in Höhe von 1200 Hz, dann wird diese nicht erkannt. Mache ich vielleicht doch einen Fehler bei der Berechnung der Single-Werte?
-
Gibt nur crc8 und crc16 implementierungen in CSCore.
Die sind aber eigentlich auch als nicht öffentlich gekennzeichnet und nicht für die Verwendung von außen gedacht.
Ich denke @~blaze~ meinte mit Framework das .NET Framework, welches meines Wissens dies auch nicht hat. Dürfte aber auch keine Hexerei sein, da einen Algo aufzutreiben. Ist ja recht trivial. -
@thefiloe Das eigentliche Problem ist eigentlich immernoch die richtige Analyse des Buffers. Weiter oben steht mein Quellcode. Wandel ich dich Bytes richtig in Single um? Gibt es vielleicht eine direkte Methode in CSCore um die Single-Werte zu bekommen? Ich gehe aktuell davon aus, dass in dem Buffer e.Data einzelne Samples im Abstand von 4 Bytes (umgerechnet 1 Single-Wert) enthält und dass immer rechts und dann links übertragen wird. Also 1 Block besteht aus 8 Bytes?
-
-
-
Achtung: Das Mithören vom BOS-Funk ist soweit ich weiß illegal!
Dieser Beitrag wurde bereits 3 mal editiert, zuletzt von „Neoner“ ()
-
Den Beitrag Nummer 58 habe ich entsprechend geändert. Das Mithören und Mitschneiden ist illegal für "normale" Bürger. Es gibt aber auch gewisse Außnahmen.
@thefiloe: ich möchte dich bitten ein kurzes Beispiel zu geben, wie man mittels der CSCore-Lib die Single-Werte eines Samples ermittelt. Ich denke, dass ich es richtig mache - aber ich weiß es nicht. Ein Beispiel wäre gut, damit ich das mit meinem aktuellen Source vergleichen kann.
Zur Zeit verwende ich diesen Code:
VB.NET-Quellcode
- Dim stepper As Integer = (cs.WaveFormat.BlockAlign / cs.WaveFormat.Channels)
- Dim bufLeft(stepper - 1) As Byte
- Dim bufRight(stepper - 1) As Byte
- Dim eData() As Byte = queueData.Dequeue
- Dim temp123((eData.Length / cs.WaveFormat.BlockAlign) - 1) As Single
- For i = 0 To eData.Length - 1 - cs.WaveFormat.BlockAlign Step cs.WaveFormat.BlockAlign
- For j = 0 To stepper - 1
- bufLeft(j) = eData(i + j)
- bufRight(j) = eData((i + stepper) + j)
- Next
- wert = 0
- wert += BitConverter.ToSingle(bufLeft, 0)
- wert += BitConverter.ToSingle(bufRight, 0)
- wert = wert / 2
- temp123(i / cs.WaveFormat.BlockAlign) = wert
- Next
- SyncLock q1
- q1.Enqueue(temp123)
- End SyncLock
Dieser Beitrag wurde bereits 1 mal editiert, zuletzt von „dietzi“ ()
-
So.... Ich bin einiges weiter gekommen. Nun ist es aber so, dass durch die Formel von @~blaze~ der "Frequenzübergang" nicht berücksichtigt wird. Das heißt gezwungenermaßen muss ich eine PLL einbauen. Jetzt habe ich schon einiges gelesen, habe es aber nicht geschafft, das Gelesene in VB.NET zu "übersetzen". Könnte mir hier bitte jemand weiter helfen eine PLL zu programmieren bzw. kennt jemand vielleicht eine andere Möglichkeit aus der Anzahl der Samples und der vorherig berechneten Frequenz auf die eigentliche Frequenz zu schließen?
-