aktuellste Werte in Array und aufsummieren

Gast #4802775
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:
1
summe=summe+ADC-wertDerAusArrayRausgeschobenWurde;

Ist das soweit okay?
Ich habe momentan noch deutliche Geschwindigkeitsprobleme (ISR wird auf 
2kHz ausgebremst)

Gruß
Dennis
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.
(Firma: Vescomp)
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.
Moderator (Firma: Titel) Persönliche Seite
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.
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?
(Firma: Vescomp)
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
5
        if(TailPtr >= MaxSamples)  TailPtr = 0;
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)
(Firma: Vescomp)
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...

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 9 Jahre alt. Stell sie in einem eigenen Thread – dort lesen mehr Leute mit, und sie wird öfter und schneller beantwortet.

Neuen Thread starten

Eine Lösung, Ergänzung oder Rückmeldung zu diesem Thread? Dann antworte hier.

Formatierung
  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] – Link zu einem Artikel
  • Verweis auf einen anderen Beitrag: Rechtsklick auf dessen Beitrags-ID (#8078628), „Adresse kopieren“, in den Text einfügen

Mehr zur Formatierung

Längeren Sourcecode als Anhang, nicht in den Text. JPG nur für Fotos und Scans; Zeichnungen und Screenshots als PNG oder GIF. Siehe Bildformate.

Schon registriert? Anmelden

Wird nicht angezeigt. Wir schicken dir einen Link; sobald du damit bestätigst, erscheint dein Beitrag.

Mit dem Abschicken legst du einen kostenlosen Account an und erkennst die Nutzungsbedingungen und die Datenschutzerklärung an.