Forum: Mikrocontroller und Digitale Elektronik aktuellste Werte in Array und aufsummieren


Announcement: there is an English version of this forum on EmbDev.net. Posts you create there will be displayed on Mikrocontroller.net and EmbDev.net.
von Dennis (Gast)


Bewertung
0 lesenswert
nicht lesenswert
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

von Volker S. (vloki)


Bewertung
2 lesenswert
nicht lesenswert
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?

von Jim M. (turboj)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
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.

: Bearbeitet durch User
von Lothar M. (lkmiller) (Moderator) Benutzerseite


Bewertung
1 lesenswert
nicht lesenswert
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.

: Bearbeitet durch Moderator
von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Walter S. (avatar)


Bewertung
0 lesenswert
nicht lesenswert
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?

von Noch nicht Rentner (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Vergiss diesen gleitenden Mittelwert, nimm den exponentiellen 
Mittelwert, der benoetigt nur eine einzige Speicherstelle.

von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
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;

von Volker S. (vloki)


Bewertung
0 lesenswert
nicht lesenswert
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)

von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
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...

von Volker S. (vloki)


Bewertung
0 lesenswert
nicht lesenswert
Mir erschließt sich der Sinn von zwei Zeigern einfach nicht...

von Marc V. (Firma: Vescomp) (logarithmus)


Bewertung
0 lesenswert
nicht lesenswert
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.

von Dennis (Gast)


Bewertung
0 lesenswert
nicht lesenswert
Ich habe jetzt ein Ringpuffer verwendet und es funktioniert soweit ganz 
gut. Vielen Dank für die nützlichen Anregungen!

Antwort schreiben

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

Formatierung (mehr Informationen...)

  • [c]C-Code[/c]
  • [code]Code in anderen Sprachen, ASCII-Zeichnungen[/code]
  • [math]Formel in LaTeX-Syntax[/math]
  • [[Titel]] - Link zu Artikel
  • Verweis auf anderen Beitrag einfügen: Rechtsklick auf Beitragstitel,
    "Adresse kopieren", und in den Text einfügen




Bild automatisch verkleinern, falls nötig
Bitte das JPG-Format nur für Fotos und Scans verwenden!
Zeichnungen und Screenshots im PNG- oder
GIF-Format hochladen. Siehe Bildformate.
Hinweis: der ursprüngliche Beitrag ist mehr als 6 Monate alt.
Bitte hier nur auf die ursprüngliche Frage antworten,
für neue Fragen einen neuen Beitrag erstellen.

Mit dem Abschicken bestätigst du, die Nutzungsbedingungen anzuerkennen.