![]() |
Frequenzen erkennen, CRC - Check, Timer zu langsam?!
Hallo liebes Delphi-PRAXIS Forum!
Jetzt hab ich schon lange Zeit hier im Forum nach Tipps geschaut um mein Vorhaben realisieren zu können. Prinzipiell funktioniert es auch schon, jedoch nicht wirklich "sauber". Was ich vor habe: - Über die Soundkarte (Micro, Line-In oder Stereo - Mix) kommt ein Signal - Dieses Signal soll decodiert werden. Speziell interessiere ich mich für Telegramme, welche in diesem Signal aufgebaut sind: Hierbei handelt es sich um Telegramme welche per FSK codiert sind. FSK: Signalrate 1200 baud Low - Level: 1800 Hz (Logisch 0) High - Level: 1200 Hz (Logisch 1) Insgesamt besteht solch ein Telegramm aus 68 Bit. Siehe: ![]() Wobei 1 bit eine Länge von 0,8 ms hat. Meine Fragen: 1. Ist es per FFT möglich solch "kurze" Signale zu analysieren? 2. Kann die BASS.DLL dafür verwendet werden, oder gibt es bessere Komponenten etc.? Ich habe nämlich festgestellt, dass mir immer nur ein paar "Werte" ausgegeben werden und, dass diese zudem variieren. Sprich: Bei einem und dem selben Signal habe ich mal 10001, dann 10101 etc....zudem fehlen dort allerhand bit. Meine Vermutung ist deshalb, dass entweder die FFT zu langsam abläuft, oder einfach, der Timer, der die FFT aufruft zu langsam ist oder zu ungenau arbeitet. Anders kann ich mir es nicht erklären, dass immer wieder bits fehlen. Schließlich müssten es 68 sein und nicht 4 bis 10. Wie kann man, wenn man festgestellt hat, dass es entweder eine 1 oder eine 0 ist, dieses Ergebnis, natürlich in richtiger Reihenfolge speichern? Für Antworten und Hilfen bedanke ich mich bereits im Vorraus. Mario |
Re: Frequenzen erkennen, CRC - Check, Timer zu langsam?!
Nutzt du einen WindowsTimer? (TTimer und alles was mit Windows[Timer]API zu tun hat)
Diese Timer haben nur eine Auflösung von etwa 10ms (auf älteren System sogar nur kanpp 20ms) |
Re: Frequenzen erkennen, CRC - Check, Timer zu langsam?!
Nein ich benutze den CairnTimer. Aber mir scheint, dass auch dieser nicht schnell genug arbeitet. Ich bräuchte einen Timer der im µs Bereich arbeitet.
|
Re: Frequenzen erkennen, CRC - Check, Timer zu langsam?!
Wenn Dein Signal keine anderen Hintergrundgeräusche hat, dann ging folgendes: Da beide Frequenzen mit unterscheidlichen Lautstärkepegeln arbeiten, könntes Du auch diese Pegel abfragen und so das Signal erkennen.
Grüße / Martin |
Re: Frequenzen erkennen, CRC - Check, Timer zu langsam?!
![]() Zitat:
|
Re: Frequenzen erkennen, CRC - Check, Timer zu langsam?!
Normalerweise nimmt man dazu in Software sogeannte Lock-In-Amplifier oder PSD -> Phase Sensitive Devices oder PPLs -> Phase Locked Loops.
Bei all diesen Verfahren geht es darum das AC Signal mit Hilfe eines "synchonen" Vergleichsignal zu filtern und daraus ein DC Signal zu erzeugen das angibt wie hoch die Übereinstimmung dieser Signale ist. Das geht in Hardware und auch als Software in sogennate DSPs/FPGA/ASICs usw. umzusetzen. Auf PC ist das auch möglich. Die Performance ist weit besser als bei einer FFT, defakto ist es sogar so das beide Verfahren auf den gleichen math. Grundlagen beruhen. Wie macht man das nun ? Man erzeugt zwei Rechtecksignale mit jeweils 1800Hz und 2100Hz Frequenz. Davon werden 2 weitere Signale um 90 Grad in der Phase verschoben erzeugt, also zeitlich versetzt. Nun werden alle 4 Signale mit dem eingehenden Signal verknüpft. Raus kommen 4 kummulierte Werte=Zahlen. Jeweils ein Signal X für die Amplitude=Stärke der Übereinstimmung und das Signal Y für Phasenverschiebung. Mit r =Wurzel(X^2 + Y^2) hat man nun einen DC Wert für die Übereinstimmung der Referenzsignale zum Eingangssignal. Man hat dann also zwei Werte r1800 und r2100 die die Signalstärke dieser Frequenzen im EIngangssignal darstellen. In deinem Falle müsste immer nur eine dieser Variablen einen großen Wert haben und die andere einen kleinen Wert. Auf grund des Nyquist-Theorems muß man natürlich das EIngangssignal ca. 3mal schneller abtatsten als die Frequenzen die man untersuchen möchte. Hinzukommt noch das solche Lock-In-Amplifier selber eine gewisse Zeit zum einschwingen benötigen. Dh. dein Eingangssignal sollte mit mindestens 10Khz gesampelt werden. Eventuell finde ich die Zeit einen kleinen Source zu bauen, versprechen kann ich es dir aber nicht :( Es ist aber eine wirklich einfache Sache sowas, sich kompliziert anhörendes, in Software zu machen. Gruß Hagen |
Re: Frequenzen erkennen, CRC - Check, Timer zu langsam?!
Stimmt, von PLL hab ich auch mal was gehört. Ich weiß, dass Funkscanner oder sogar einfache Scanner-Radios PLL verwenden. Wie soetwas in Software, speziell Delphi realisiert werden soll ist relativ klar. Doch wie erzeuge ich die "Referenz - Frequenzen". Es ist einleuchtend, dass PLL schneller läuft als FFT. Wie FFT prinzipiell funktioniert ist mir auch bekannt. Jedoch wäre eine kleine Hilfe sicher ratsam.
So habe ich es bisher verstanden: - Referenz erstellen mit 1200 Hz und 1800 Hz. Zusätzlich beide Signale um 90° verschoben. Bedeutet das, dass sich eine stehende Welle ergibt?? Mein Physik LK ist nun auch schon etwas her. Oder löschen sich dann beide Wellen aus und addieren sich zu Null?? @negaH: Was genau stellt "r" denn nun dar? Ein kleiner Source wäre wunderbar. In wie weit lässt sich das mit der Bass.Dll realisieren? Jetzt komm ich grad selber etwas durcheinander. Wenn ich eine Samplerate von 44100 Hz habe, bedeutet das doch, dass ich pro Sekunde 44100 Samples habe, oder? Also unterteile ich das Signal, das per Micro reinkommt innerhalb von einer Sekunde in 44100 Stücke?? *confused* Also: 1. Per BASS.DLL Stream aus Microeingang generieren 2. Referenz-Signale (Frequenzen) erstellen mit PLL (wie hätte ich gerne nochmal erklärt; wäre super) 3. Aktuelles Signal mit Referenz vergleichen. 4. Vergleich zwischen Pegel f1200 und f1800. Wenn Pegel(f1800) > Pegel(f1200) dann '0'. Wenn Pegel(f1800) < Pegel(f1200) dann '1'. Naja gut. Ich finde es super, dass eine hier so schnell und auch ausführlich geantwortet wird. Jetzt hab ich nur das Problem, dass ich soviel gelesen habe, dass ich verschiedenes durcheinander bringe. Eins steht zumindest fest: Mit FFT und BASS.DLL lässt sich kein befriedigendes Ergebnis erzielen. Es erscheint mir fast so, als wenn das Hanning - Window der BASS.DLL unwichtige Signale durchlässt und wichtige unterdrückt. Von der Resolution her ist die BSS.DLL glaub ich zu ungenau und alles, was ich an Timern kenne zu langsam. Nun denn, Danke bis hierher für die bereits erfolgten Antworten. Ich bin gespannt, was Euch sonst noch so einfällt. Grüße Mario |
Re: Frequenzen erkennen, CRC - Check, Timer zu langsam?!
ok, du bekommst dein Signal mit 44Khz gesampelt. Bei einer Frequenz von 1800Hz, Rechteck, müsst du also eine Variable von -1 auf +1 alle 44000/1800 Samples negieren. So einfach und fertig ist unser Referenztakt von 1.8Khz. Nun das um 90Grad Phasenverschobene Signal: das wäre 1/4 an Takten verzögert, also 44000/1800 = 24.4 / 4 = 6.1 Samples verzögert.
Nun machst du folgendes: Eine Variable die -1 oder +1 enthalten kann. Du multiplizierst dein aktuelles Sample mit dieser Variablen und addierst diesen Wert zu einem Akkumulator = Variable = X. Nach exakt 24 Samples negierst du diese Variable. Nach 48 Samples haben wir ja eine komplette Welle der 1.8KHz durch und führestens zu diesem Zeitpunkt können wir den Akkumulator auswerten. Normalerweise macht man dies aber so das man auf merheren Wellen ausrichtet, also zb. nach 48*10 Samples, was dann 10 Schwingungen a 1.8KHz wären. Das gleiche machst du mit einem Akumulator Y für die Phase. Wieder eine Variable mit -1,+1 aber diesesmal 6 Samples später negiert. Nun wieder Akkumulator Y die Summe aus -1,+1 * Sample addiert. Nach zb. 48*10 Samples werden die Akkumulatoren ausgewertet. r := Sqrt(X^2 + Y^2). R ist dann ein Wert der die Abhängigeit=Übereinstimung unserer Refernezfrequenz zum Inputsignal darstellt. Je höher dieser Wert ist desto mehr Anteile der 1.8Khz sind im Signal. Gut, Nachteil dabei ist das wir immer erst nach zb. 48*10 Samples einen Wert ermiteln und dieser NICHT fließend ist. Aber auch das ist möglich. Wir nehmen einen Filter wie bei Durschnittsberechnungen möglich. Denn im Grunde genommen berehcnen wir ja nur den Durchschnitt von 480 Samples die aber im Takt von 1.8Khz ständig negiert werden. Stelle es dir vor wie ein Gleichrichter der enen Sinus gleichrichtet. Nur das unser Gleichrichter exakt im Takt von 1.8KHz gleichrichtet. Ist das Input-Rechecksignal exakt synchron zu 1.8Khz so entsteht eine Gleichspannung, da ja nun alle negativen Halbwellen des Sinus negiert wurden. Sieht dann aus wie ein Pulsirendes Signal, aber immer im positiven Bereich. Nun verschieden wir unseren 1.8Khz Takt um 90 Grad. Das dadurch entstehende Signal zeigt uns ob wir in der Phase synchron sind. Je geringer dieser Wert also ist um so synchroner gleichrichten wir das Sgnal, um so exakter sind wir Phasensynchron mit unserem Refernezsignal zum Inputsignal. Je länger deine Samplingphase ist (48 * 10) um so kleinere Signal kannst du detektieren. Denn diese Methode hat den Vorteil das du selbst aus einem Rauschsignal das unser Nutzsignal enthält dieses detektieren kanst. Du kanst davon ausgehen das alle heutigen Hochfrequenzverfahren auf dieser Idee basieren, GPS, GSM usw. wären ohne garnicht denkbar. Damit du dein Signal fließend auswerten kannst benutzt man einen Ring-Buffer. In unserem Falle zb. 48*10=480 Werte groß. Über diese 480 Werte berechnet du die Summe zu unserem 1.8Khz Takt. Diese Summe in einer Variablen gespeichert, sie ist ja Akkumulator X. Bei einem neuen Sample subtrahierst du das älteste Sample im Ringbuffer vom Akkumulator und addierst das bearbeite Sample dazu. Dieses Speicherst du im Ringbuffer als letzten Wert. Der Akkumulator reprsentiert also die summme der letzten 480 Samples, kontinuierlich und im RingBuffer stehen die letzten 480 Werte die im Akkumulator addiert wurden. In unserem Falle also die Samples multipliziert mit (-1,+1) im Takt unserer 1.8Khz. Da du aber sowieso ein WAV als Input hast benötigst du keinen RingBuffer mehr. Stattdessen wissen wir ja das das 480'te letzte Sample exakt synchon zu unseren 1.8KHz sind. Wir müssen also nur dieses Sample ebenfalls mit unsere Refernezfrequenzvariablen die alle 48 Samples negiert wird ausrechnen un vom Akkumulator X subtrahieren (rausrechnen). Das aktuelle Sample wird danach ebenfalls mit (-1,+1) multpiliziert und auf den Akkumulator addiert. Pseudcode
Delphi-Quellcode:
Mit obigem Code würde man auf 44000/44 = 1Khz filtern. Die Phasenverschiebung unseres Referenztaktes wird durch die 90 Grad Verschiebung und der Formel r = Sqrt(x^2 + y^2) beseitigt. Es ist also unwichtig wann du anfängst deine Samples auszuwerten (bei welchen Inxdex) bzw. wie die Phasenverschiebung des Inputsignales ist. Und wie man sieht hat dieser Code zwei Vorteile
var
Samples: array of SmallInt; ProcessSample; var r: Double; aX,aY: Double; rX,rY: Integer; cX,cY: Integer; begin aX := 0; aY := 0; rX := -1; rY := -1; cX := 0; cY := 11; for I := 44 to High(Samples) do begin aX := aX - Samples[I - 44] * rX; aY := aY - Samples[I - 44] * rY; aX := aX + Samples[I] * rX; aY := aY + Samples[I] * rY; Inc(cX); if cX >= 22 then begin cX := 0; rX := -rX; end; Inc(cY); if cY >= 22 then begin cY := 0; rY := -rY; end; r := Sqrt(Sqr(aX) + Sqr(aY)); end; end; 1.) kontinuierliche Auswertung ist möglich, maximal eine Welle später als unsere Referenzfrequenz 2.) die Laufzeit sollte wesentlich höher sein als eine FFT Statt wie oben mit einem Rechtecksignal zu arbeiten kannst du auch ein Sinus als Referenz benutzen, ist aber nicht notwendig, erhöht nur die Genauigkeit wenn unser Signal ebenfalls mit Sinus FSK moduliert wurde. Gruß Hagen PS: Tippfehler gehören euch, ich hasse Laptop Tastaturen. |
Re: Frequenzen erkennen, CRC - Check, Timer zu langsam?!
hm vielleicht nochmal einfacher :)
Wenn du ein 1Khz Signal mit 44Khz samplest dann heist dies das nach exakt 44000/1000 Samples eine Schwingung eines 1Khz Signales rum ist. Nach exakt 22 Samples also eine Halbwelle dieser 1Khz. Ziel ist es nun die 1'te positive Halbwelle durchzulassen und die 2'te negative Halbwelle zu invertieren -> gleichzurichten -> zu spiegeln. Statt einem Sinus erhalten wir eine gepulste Gleichspannung mit einer Frequenz von 2Khz ;) Nun addieren wir einfach diese Samples in einem Akkumulator. Da wir aber eventuell zum falschen Zeitpunkt negieren müssen wir wissen ob wie Phasensynchron sind. Dazu verschieben wir unser 1Khz exakt um 90 Grad also 11 Takte und berechnen ebenfalls den Durchschnitt. Mit der Formal r = Sqrt(X^2 + Y^2) beider Akkumuatren errechnen wir die effektive Übereinstimmung unseres 1Khz Signales mit dem Inputsignal. Fertig. Je länger du nun den Akkumulator inkrementierst zb. statt 44 mal eben 44*10 je größer wird der Gain = Verstärkung und um so stärker verrauschte Signale kann man dekodieren. [edit] ganz vergessen zu erwähnen, dein Inputsignal muß bipolar sein, heist zb. im Bereich von -127 bis +127 gehen [/edit] Gruß Hagen |
Re: Frequenzen erkennen, CRC - Check, Timer zu langsam?!
Also der Source-Code ließ sich hervorragend implementieren. Er ist enorm schneller als FFT, liefert auch bessere Werte. Jedoch variieren diese immernoch, was ich mir nicht erklären kann. Mit einem Testgenerator lasse ich stets die gleiche Folge über die Soundkarte laufen, und immer sind die Werte unterschiedlich. Zudem besteht noch das Timerproblem. Ich hab's mit dem MMTimer versucht. Auf 1ms eingestellt (minimum). Folge: Programm friert ein, Rechner am Boden.....Stelle ich den Wert auf 3 ms, so bekomme ich augenscheinlich nur jeden 3. Wert. Eigentlich müsste ich ja unter 0,8 ms um ordentlich Werte zu erzielen.
Auf jeden Fall erstmal vielen Dank für den Source und die äußerst ausführliche Erklärung. Es muss doch irgendwie eine Möglichkeit geben das Ganze in (annäherend) Echtzeit laufen zu lassen. Schließlich dauert das ja wohl nicht so lange ein Array der Größe 44000 mit Werten zu füllen. Und schon garnicht auf heutigen Rechnern-....Was mache ich nur falsch? Hier mal die Analyse:
Delphi-Quellcode:
Der Timer ruft obige Funktion alle X-ms auf.
function RecordingCallback():TData;
var Samples: TData; r_a,r_b: Double; aX,aY,aX_B,aY_B: Double; rX,rY,rX_B,rY_B: Integer; cX,cY,cX_B,cY_B: Integer; I,l: integer; begin BASS_ChannelGetData(Channel, @Samples,44000); result:=Samples; aX := 0; aY := 0; rX := -1; rY := -1; cX := 0; cY := 9; for I := 36 to 36*2 do begin aX := aX - Samples[I - 36] * rX; aY := aY - Samples[I - 36] * rY; aX := aX + Samples[I] * rX; aY := aY + Samples[I] * rY; Inc(cX); if cX >= 18 then begin cX := 0; rX := -rX; end; Inc(cY); if cY >= 18 then begin cY := 0; rY := -rY; end; r_a := Sqrt(Sqr(aX) + Sqr(aY)); end; form1.Edit1.Text:=FloatToStr(r_a); if r_B > 4 THEN BEGIN cou:=cou+1; form1.Edit2.Text:=IntToStr(cou); END; aX_B := 0; aY_B := 0; rX_B := -1; rY_B := -1; cX_B := 0; cY_B := 6; for I := 24 to 24*2 do begin aX_B := aX_B - Samples[I - 24] * rX_B; aY_B := aY_B - Samples[I - 24] * rY_B; aX_B := aX_B + Samples[I] * rX_B; aY_B := aY_B + Samples[I] * rY_B; Inc(cX_B); if cX_B >= 12 then begin cX_B := 0; rX_B := -rX_B; end; Inc(cY_B); if cY_B >= 12 then begin cY_B := 0; rY_B := -rY_B; end; r_B := Sqrt(Sqr(aX_B) + Sqr(aY_B)); if r_B > 4 THEN BEGIN cou:=cou+1; form1.Edit3.Text:=IntToStr(cou); END; end; end; Hier die Record-Initialisierung:
Delphi-Quellcode:
procedure StartRecording();
begin BASS_ChannelStop(Channel); // Nil or @ThresholdRecorder Channel:=BASS_RecordStart(44000, 2,BASS_SAMPLE_FLOAT,nil, 0); //BASS_RECORD_PAUSE if Channel=0 then begin Error('Couldn''t start recording'); Exit; end; //BASS_ChannelPlay(Channel, false); end; |
Re: Frequenzen erkennen, CRC - Check, Timer zu langsam?!
Delphi-Quellcode:
Du benutzt zur Auswertung nur eine Welle deiner Referenzfrequenz. Das ist das Minimalste was noch Sinn macht. Bei diesem Verfahren gelten die gleichen Regeln wie bei einer FFT oder dem Sampling, das Nyquist-Theorem. Das bedeutet das du mindestens 3 Wellen -> 36 to 36 + 36 * 3, auswerten solltest.Um so größer dieser abgetastete Bereich um so "glatter" deine errechneten Werte. Sie werden also weniger schwanken. Dazu solltest du aber in der Berchnung r =Sqrt(x^2 + y^2), x und y reduzieren um einen Durchschnitt zu ermitteln, also so r = Sqrt((x/10)^2 + (y/10)^2) wenn du zb. 36 * 10 Samples auswertest.
for I := 36 to 36*2 do
Je mehr Samples du berücksichtigst, also je länger dein Window wird, desto 1.) mehr Gain hast du, je mehr Verstärkung, je empfindlicher kannst du die Signale messen 2.) mehr glättest du die Ausgabewerte, dh. je stabiler wird deine DC Gleichspannung oder in unserem Softwarefall schwanken diese Werte weniger Leider bin ich auf diesem Gebiet auch nocht nicht so fit, eigentlich ist das eines meiner nächsten "Lernziele" falls ich mal Freizeit haben sollte. Dh. ich bin selber noch am rumbasteln und lernen ;) Denoch freut es mich das das alles so aus der Theorie heraus funktioniert hat. Nun noch was zu deinem "API basierten Überbau": 1.) vergiß Multimedia Timer und das damit realisierte Polling deinerseits 2.) falls Bass.dll keine andere Möglichkeit bietet als das was ich in deinem Source sehe, dann vergiß Bass.dll ganz schnell 3.) du benötigst eine asynchrone Aufnahme deines Signales 4.) dann 2-16 Buffer a 44000, 22000, 11000 oder 5500 Bytes 5.) du zeichnest nun asynchron in diese Buffer auf, dh. dem API teilst du mit das es in 1 deiner Buffer aufzeichnen soll -> asynchron im Hintergrund 6.) das API wird dich informieren wenn es diesen Buffer fertig hat 7.) in der Zwischenzeit führst du deine Berechnungen durch auf den Buffer der aktuell ausgewertet werden soll 8.) auf Grund der mehrfachen Buffer (Ringbuffer übrigens) und auf Grund dessen das deine Auswertung schneller als das Füllen eines Buffers geht kommst du zu einer kontinuierlichen Auswertung und Aufzwichnung im Hintergrund Nun, auch hier musst du defakto nicht mit 16 einzelnen Buffern arbeiten, sondern nur mit 1 Buffer der dann in 16 Teile zerlegt wird. Deine Auswertung geht immer über diesen Buffer und das Aufzeichen nacheinander in diesen 16 Teilbereichen. Die Buffergröße sollte am besten ein Mehrfaches/Teilbares aus allen auszuwertende Frequenzen sein. Beispiel: 44000Hz Samplerate 1800Hz 1.Freq 2100Hz 2.Freq 16 Teilbuffer für die Aufzeichung 44000/1800 = 24 Samples 44000/2100 = 20 Samples 20*24 = 480 Samples 480 * 10 ~Gain = 4800 Samples 4800 Samples * 16 = 76800 Samples pro Sample 1 Byte = 76.8 KByte sollte dein Buffer groß sein. Aufnehmen tust du in Stücken a 4.8 KByte reihum in den Buffer, das erfolgt asynchron im Hintergrund. 4800 Bytes / 44000 Saples/sec * 1000 = 109 Millisekunden benötigt unser Aufnahme um diese 4800 Bytes zu füllen. Damit es also nicht dazu kommt das deine Berechnungen zu einem Buffer-Überlauf führt muß diese Berechung also in maximal 100 Millisekunden fertig sein. 100ms zu schaffen sollte absolut KEIN Problem sein, ergo liegen deine jetzigen Probleme nur darin begründet das deine Aufnahmemethode schlecht ist->eventuell eben die Bass.dll Nochwas zur Schleife: wir benutzen ja zb.
Delphi-Quellcode:
Das ist natürlich nur ein Beispiel meinerseits gewesen um die Sache einfacher darzustellen. In real musst du natürlich mit
for I := 36 to 36 * x do
Delphi-Quellcode:
rechnen. Das führt aber in der Schleife dazu das mit I - 36 -> 0 -36 -> -36 Index auf den Buffer zugegriffen wird und eine AV erzeugen würde. Da unser Buffer aber ein Ringbuffer ist bedeutet dies das alle negatoiven Indizes auf Daten am Ende des Buffers zeigen.
for I := 0 to 36 * x -1 do
Die Schleife sähe also so richtiger aus
Delphi-Quellcode:
Wenn das dann alles funktioniert und du in 4 Schleifen über den Buffer gehst dann müssen wir nun noch diese Schleifen zueinander synchronisieren.BufferLength := Length(Buffer); NextBufferIndex := xyz; LastBufferIndex := xyz - 36 * 10; if LastBufferIndex < 0 then Inc(LastBufferIndex, BufferLength); for I := 0 to 36 * 10 -1 do begin aX := aX - Buffer[LastBufferIndex] * ...; aX := aX + Buffer[NextBufferIndex] * ...; Inc(LastBufferIndex); if LastBufferIndex >= BufferLength then LastBufferIndex := BufferLength; Inc(NextBufferIndex); if NextBufferIndex >= BufferLength then NextBufferIndex := BufferLength; end; Wir haben ja einmal 44000/1800 = 24 und 44000/2100 = 20, und einen Bufferteilbereich von 20*24*10 = 4800 Bytes. Unsere Schleifen gehen also for I := 0 to 4800-1 do und damit werden für 1800Hz = 200 Wellen und für 2100Hz = 240 Wellen ausgewertet. Wichtig ist dabei nur das alle Schleifen zueinander synchron laufen und alle Samples in unserem Buffer auch berücksichtigen. Als letzte Optimierung wirst du also alle 4 Schleifen in eine einzigste Schleife bauen und der Zugriff auf den Buffer erfolgt dann nur einmal pro Sample. Das könte so aussehen
Delphi-Quellcode:
Fast alle obigen Variablen (ausser I,bL,bN) sind global und werden nur beim Start deiner Aufnahme initialisiert. Danach rotieren sie kontinuierlich.
lbI := BufferIndex;
Inc(BufferIndex, BufferLength div 16); // div 16 weil unser Buffer aus 16'Teilen besteht if BufferIndex >= BufferLength then BufferIndex := 0; lbI := BufferIndex; for I := 0 to BufferLength div 16 -1 do begin bL := Buffer[lbI]; Inc(lbI); bN := Buffer[nbI]; Inc(nbI); aX_1800 := aX_1800 - bL * rX_1800 + bN * rX_1800; aX_2100 := aX_2100 - bL * rX_2100 + bN * rX_2100; aY_1800 := aY_1800 - bL * rY_1800 + bN * rY_1800; aY_2100 := aY_2100 - bL * rY_2100 + bN * rY_2100; Inc(cX_1800); if cX_1800 >= 24 then begin cX_1800 := 0; rX_1800 := -rX_1800; end; Inc(cX_2100); if cX_2100 >= 20 then begin cX_2100 := 0; rX_2100 := -rX_2100; end; Inc(cY_1800); if cY_1800 >= 24 then begin cY_1800 := 0; rY_1800 := -rY_1800; end; Inc(cY_2100); if cY_2100 >= 20 then begin cY_2100 := 0; rY_2100 := -rY_2100; end; r_1800 := Sqrt(Sqr(aX_1800 / 200) + Sqr(aY_1800 / 200)); r_2100 := Sqrt(Sqr(aX_2100 / 240) + Sqr(aY_2100 / 240)); end; Wir haben hier schon einiges an Vereinfachungen reingebaut. ZB. eben das der Buffer ein Mehrfaches in der Länge ist von unseren Referenzfrequenzen. Das muß man nicht so machen und wird bei der Auswertung zb. von 16 Frequenzen immer komplizierter. Ich werde mal ein Beispiel bauen das ohne obige "Vereinfachungen" arbeitet, mit beliebigen Frequenzen. BufferIndex springt bei jeder Berechung also um 4800 Samples weiter, und 4800 * 16 Samples ist der Buffer komplett groß. Nachdem nun unser API Aufnahmegerät ein Buffer a 4800 Samples fertig hat rufen wir unsere Schleife so lange auf bis BufferIndex auf den Anfang des Teilbuffers zeigt der gerade jetzt asynchron durchs API gefüllt wird. Wenn also 4800 Samples bei 44Khz ca. 100 Millisekunden benötigen und wir 16 Teilbuffer haben und davon immer 1 Buffer gefüllt wird dann haben wir 15 * 100 Millisekunden Zeit bevor wir unsere Auswertungen beginnen, also eine Reserve von 1.5 Sekunden ohne das wir Verzögerungen produzieren. Wenn die API Aufnahmefunktion meldet das sie fertig ist erhöhen wir einen RecordBufferIndex um +4800 Bytes und lassen den nächsten der 16 Teilbuffer aufnehmen. Danach rufen wir unsere Auswertungsschleife wiederholt auf bis BufferIndex == RecordBufferIndex ist. Gruß Hagen |
Alle Zeitangaben in WEZ +1. Es ist jetzt 10:59 Uhr. |
Powered by vBulletin® Copyright ©2000 - 2025, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz