AGB  ·  Datenschutz  ·  Impressum  







Anmelden
Nützliche Links
Registrieren
Zurück Delphi-PRAXiS Sprachen und Entwicklungsumgebungen Object-Pascal / Delphi-Language Delphi Frequenzen erkennen, CRC - Check, Timer zu langsam?!
Thema durchsuchen
Ansicht
Themen-Optionen

Frequenzen erkennen, CRC - Check, Timer zu langsam?!

Offene Frage von "MotoNero112"
Ein Thema von MotoNero112 · begonnen am 8. Sep 2006 · letzter Beitrag vom 9. Sep 2006
Antwort Antwort
Seite 2 von 2     12   
Benutzerbild von negaH
negaH

Registriert seit: 25. Jun 2003
Ort: Thüringen
2.950 Beiträge
 
#11

Re: Frequenzen erkennen, CRC - Check, Timer zu langsam?!

  Alt 9. Sep 2006, 12:05
for I := 36 to 36*2 do 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.

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.
for I := 36 to 36 * x do Das ist natürlich nur ein Beispiel meinerseits gewesen um die Sache einfacher darzustellen. In real musst du natürlich mit

for I := 0 to 36 * x -1 do 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.

Die Schleife sähe also so richtiger aus

Delphi-Quellcode:

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;
Wenn das dann alles funktioniert und du in 4 Schleifen über den Buffer gehst dann müssen wir nun noch diese Schleifen zueinander synchronisieren.

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:
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;
Fast alle obigen Variablen (ausser I,bL,bN) sind global und werden nur beim Start deiner Aufnahme initialisiert. Danach rotieren sie kontinuierlich.

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
  Mit Zitat antworten Zitat
Antwort Antwort
Seite 2 von 2     12   


Forumregeln

Es ist dir nicht erlaubt, neue Themen zu verfassen.
Es ist dir nicht erlaubt, auf Beiträge zu antworten.
Es ist dir nicht erlaubt, Anhänge hochzuladen.
Es ist dir nicht erlaubt, deine Beiträge zu bearbeiten.

BB-Code ist an.
Smileys sind an.
[IMG] Code ist an.
HTML-Code ist aus.
Trackbacks are an
Pingbacks are an
Refbacks are aus

Gehe zu:

Impressum · AGB · Datenschutz · Nach oben
Alle Zeitangaben in WEZ +1. Es ist jetzt 14:57 Uhr.
Powered by vBulletin® Copyright ©2000 - 2024, Jelsoft Enterprises Ltd.
LinkBacks Enabled by vBSEO © 2011, Crawlability, Inc.
Delphi-PRAXiS (c) 2002 - 2023 by Daniel R. Wolf, 2024 by Thomas Breitkreuz