Hallo zusammen,
ich habe folgendes Problem:
Ein AVR32 liefert mit Werte vom ADC. Diese werden mit 44kHz abgetastet
(Audio-Signal). Programmiert wird in C. Ich möchte nun immer die N
aktuellsten Werte in einem Array vorhalten und gleichzeitig mit den
44kHz die Summe über diese Werte zur Verfügung haben.
Ich habe bisher versucht pro ISR-Durchgang des Timers alle Array-Werte
eins nach rechts zu schieben und den neuen ADC-Wert dann auf die erste
Position zu setzen.
Die Summe habe ich wie folgt berechnet:
Dennis schrieb:> Ich habe bisher versucht pro ISR-Durchgang des Timers alle Array-Werte> eins nach rechts zu schieben und den neuen ADC-Wert dann auf die erste> Position zu setzen.
Wie wäre es mit einem Ringspeicher?
Dennis schrieb:> Ist das soweit okay?
Nö, vieeeel zu lahm.
> Ich habe momentan noch deutliche Geschwindigkeitsprobleme (ISR wird auf> 2kHz ausgebremst)
Kein Wunder, Du musst ja sinnlos durchs Array durch für das memmove().
Einfacher ist eine Indextransformation, d.h. Du merkst Dir den Index des
auszutaschenden Wertes und zählst nur diesen jeweils hoch. Dann musst Du
die restlichen Werte im Array nicht jedes Mal anfassen.
Volker S. schrieb:> Dennis schrieb:>> Ich habe bisher versucht pro ISR-Durchgang des Timers alle Array-Werte>> eins nach rechts zu schieben und den neuen ADC-Wert dann auf die erste>> Position zu setzen.>> Wie wäre es mit einem Ringspeicher?
Ja, HeadPtr und TailPtr dazu und fertig ist die Laube.
HeadPtr zeigt auf Adresse in Buffer wo reingeschrieben wird, TailPtr
zeigt auf Adresse in Buffer wessen Wert abgezogen wird.
Beim Start ist Arrayinhalt = 0,
HeadPtr beliebig,
TailPtr = HeadPtr + n(Anzahl Werte) - 1.
Oder umgekehrt, ist egal.
Nur bei den ersten n Samples must du aufpassen.
Dennis schrieb:> Ich habe bisher versucht pro ISR-Durchgang des Timers alle Array-Werte> eins nach rechts zu schieben und den neuen ADC-Wert dann auf die erste> Position zu setzen.
Das ist wie wenn du beim Baden zur siebten Umkleidekabine willst, dazu
einfach stehen bleibst und sagst: schiebt die ersten 6 Umkleidekabinen
an mir vorbei.
Ein eher praktisch veranlagter Mensch wird an den Kabinen 1 bis 6
vorbeigehen und in die 7. eintreten.
Sprich: du speicherst einfach den neuen Wert in die nächste Zelle,
addierst den Wert zu der Summe und subtrahierst von der Summe den um N
Speicherplätze zurückliegenden Wert.
Und weil du nicht unendlich viele Speicherplätze hast, musst du
irgendwann wieder von vorn anfangen.
BTW: die Arithmetik wird simpel, wenn N eine Zweierpotenz ist. Denn dann
gibt es kein Head und Tail-Herumgeeiere, sondern einfach nur einen
einzigen Pointer, der auf den ältesten Wert zeigt, der subtrahiert und
dann vom neuesten Wert überschrieben wird.
Marc V. schrieb:> Nur bei den ersten n Samples must du aufpassen.
Wenn beim Start der TailPtr auf Buffer[0] und HeadPtr auf Buffer[n-1]
zeigt, nicht mal das.
Lothar M. schrieb:> BTW: die Arithmetik wird simpel, wenn N eine Zweierpotenz ist. Denn dann> gibt es kein Head und Tail-Herumgeeiere, sondern einfach nur einen> einzigen Pointer, der auf den ältesten Wert zeigt, der subtrahiert und> dann vom neuesten Wert überschrieben wird
und warum geht das nicht auch wenn N==23 ist?
Lothar M. schrieb:> BTW: die Arithmetik wird simpel, wenn N eine Zweierpotenz ist. Denn dann> gibt es kein Head und Tail-Herumgeeiere, sondern einfach nur einen> einzigen Pointer, der auf den ältesten Wert zeigt, der subtrahiert und> dann vom neuesten Wert überschrieben wird.
Auch so wird es nicht übermässig kompliziert:
1
Buffer[HeadPtr]=LastSample;
2
Summe+=LastSample-Buffer[TailPtr];
3
HeadPtr++;TailPtr++;
4
if(HeadPtr>=MaxSamples)HeadPtr=0;// Modulo MaxSamples ist wahrscheinlich langsamer
Lothar M. schrieb:> BTW: die Arithmetik wird simpel, wenn N eine Zweierpotenz ist. Denn dann> gibt es kein Head und Tail-Herumgeeiere, sondern einfach nur einen> einzigen Pointer, der auf den ältesten Wert zeigt, der subtrahiert und> dann vom neuesten Wert überschrieben wird.
Was jetzt die Anzahl der Pointer mit N zu tun hat verstehe ich zwar
nicht,
aber ich wäre auch für nur einen Pointer.
(Die Abfrage auf einen bestimmten Wert für das Rücksetzten entfällt
natürlich bei einer Zweierpotenz, weil man das dann einfach mit einer
Bitmaskierung erledigen kann)
Volker S. schrieb:> aber ich wäre auch für nur einen Pointer.> (Die Abfrage auf einen bestimmten Wert für das Rücksetzten entfällt> natürlich bei einer Zweierpotenz, weil man das dann einfach mit einer> Bitmaskierung erledigen kann)
Maskieren (mit const) braucht 1 Cy.
Vergleichen (mit const) braucht 1Cy, das anschliessende überspringen
oder durchfallen mit CLR braucht in beiden Fällen 2Cy mehr.
Für 2 Pointer sind das 4Cy oder 250ns mehr bei 16MHz.
Wird der Wert für zweiten Pointer in RAM aufbewahrt, sind es nochmal
4Cy (LDS/STS) oder 2Cy(über Indexregister).
Ergibt im ungünstigstem Fall insgesammt 8Cy mehr oder 500ns - WOW.
Man kann es auch übertreiben, vor allem da das Ganze in C geschrieben
ist...
Volker S. schrieb:> Mir erschließt sich der Sinn von zwei Zeigern einfach nicht...
Mein Denkfehler, ich hatte an einen Buffer mit Schreib- und Lesepointer
gedacht.
In diesem Fall geht es selbstverständlich auch mit nur einem Pointer.
Die Angabe einer E-Mail-Adresse ist freiwillig. Wenn Sie automatisch per E-Mail über Antworten auf Ihren Beitrag informiert werden möchten, melden Sie sich bitte an.
Wichtige Regeln - erst lesen, dann posten!
Groß- und Kleinschreibung verwenden
Längeren Sourcecode nicht im Text einfügen, sondern als Dateianhang