Effizente Mittelwertberechnung über 24bit (3x8Byte) ADC daten

OP Persönliche Seite #4109239
Vom ADC kommen 24Bit pakete über SPI an meinem SAM4S an.
Zur Verbesserung des SNR und zum Datenrate/Energiesparen (Bluetooth), 
möchte ich noch auf dem µC downsamplen über einen Mittelwert aus den 
jeweils letzten 2 oder 4 Samples.

Derzeit (noch ohne mittelwert) hole ich mir die 24bit SPI daten aus dem 
uint8_t buffer noch einzeln und schiebe sie zusammen in eins der 32bit 
register des µC. Natürlich ist mittelwert berechnen da einfach, nur:

Wenn die daten über Bluetooth rausgehen, sollen es wieder 24bit sein 
(datenrate sparen) - und da wäre es ja naheliegend sich den ganzen shift 
in eine 32bit variable - mitteln - und dann wieder in 3x8bit stücken 
rausziehen - zu sparen:

Wie berechne ich effizient (und vorallem korrekt) einen Mittelwert aus 2 
bzw. 4 samples à 24bit signed (zweierkomplement) jeweils verpackt in 
3x8byte paketen?
Gast #4109244
Mach es bei einen SAM4S überhaupt sinn über die paar Takte nachzudenken? 
Bluetooth wird wohl eh der Engpass sein. Da wird dieser µC wohl genug 
zeit für die Berechnung haben.

Ich denke man braucht für einen Zwischenschritt eh mehr als 24bit und 
das nächste sind nun mal 32bit - und bei einer 32bit CPU ist es so ideal 
zu rechnen.
OP Persönliche Seite #4109249
Peter II schrieb:
> Mach es bei einen SAM4S überhaupt sinn über die paar Takte nachzudenken?

Die große Frage. Der SAM4S läuft auf 120MHz, macht aber noch eine ganze 
menge nebenher als nur von spi holen, mitteln und in den uart buffer 
schieben. Das alleine schon aber mit einer datenrate über spi von 
mindestens 30kbit/s, eher 60kbit/s.

 Wahrscheinlich macht es keinen Sinn, aber bevor ich dann zum schluss 
irgendwo tics zu wenig habe, dachte ich: lieber gleich möglichst überall 
minimalistisch.

Peter II schrieb:
> so einfach ist das leider nicht, weil das signed im höchsten bit ist,
> das muss erst verschoben werden.

jup
OP Persönliche Seite #4109263
Peter II schrieb:
> Das bekommt man doch fast mit einen kleinen tiny hin.

Da zeigt sich meine fehlende Erfahrung bezüglich der architekturen/bzw. 
was der compiler daraus macht:

Für mich waren das pro datenpaket schon mindestens
 4 tics (3 bitshifts + sign extension)
+5 tics (4x addition + division)
+4 tics (3 backshifts + sign verschieben)
= 13 tics

und damit bei 4000 datensätzen schon 52ktics. Auch wenn das noch wenig 
ist (~0,5%) - habe ich oben wohl auch zu hoch geschätzt? Wie viel wird 
der sam4s tatsächlich brauchen?
Gast #4109277
Alex V. L. schrieb:
> Für mich waren das pro datenpaket schon mindestens
>  4 tics (3 bitshifts + sign extension)
> +5 tics (4x addition + division)
> +4 tics (3 backshifts + sign verschieben)
> = 13 tics

wenn du aber den Mittelwert von 4 werten willst, dann brauchst du die 
Division und das Rückrechnen nur einmal nach 4 werten.

> Wie viel wird der sam4s tatsächlich brauchen?
keine Ahnung
#4109292
Du brauchst für ein gleitendes Mittel (egal wie groß das Fenster) pro 
eingehendem Wert nur genau

* eine Subtraktion (der Wert der kraft seines Alters aus dem Fenster 
rausfällt)
* eine Addition (der gerade gemessene neue Wert)
* Eine Division (für das Ergebnis)

und einem Ringpuffer der so gross ist wie das Fenster.
Gast #4109296
Bernd K. schrieb:
> Du brauchst für ein gleitendes Mittel (egal wie groß das Fenster) pro
> eingehendem Wert nur genau
>
> * eine Subtraktion (der Wert der kraft seines Alters aus dem Fenster
> rausfällt)
> * eine Addition (der gerade gemessene neue Wert)
> * Eine Division (für das Ergebnis)
>
> und einem Ringpuffer der so gross ist wie das Fenster.

und die Umrechnung von 24 auf 32bit - darum geht es ja hier.
OP Persönliche Seite #4109299
Peter II schrieb:
> und die Umrechnung von 24 auf 32bit - darum geht es ja hier.

jup! ;)

Bernd K. schrieb:
> Du brauchst für ein gleitendes Mittel

ich habe das "Gleiten" des Mittelwerts wieder für mich verworfen, weil 
die benachbarten samples dann voneinander linear abhängig sind - deshalb 
wirds wohl eher ein Mittelwert aus den letzten 2/4 samples - und dann 
buffer füllen bis zum nächsten mal. (also, sofern ich das richtig sehe, 
sauberes downsamplen - allerdings weiß ich gar nicht was da konvention 
ist?!)
Gast #4109300
naiver Ansatz:
a+b=c [ergebnis 32bit]

c = c>>1 [Mittelwert von 2 Werten: 2^1 ]

wie soll es denn schneller gehen?
Und Bitverschiebeaktionen gehen ganz ohne Division.
#4109322
Von 32 bit unsigned oder signed auf 24 bit unsigned oder signed 
schmeisst man das hoechstwertige byte weg, uebertraegt nur die unteren 3 
byte.

Und zum Mitteln verwendet man einen Tiefpass, als exponentielles Mittel 
mit genau einer Speicherstelle. Da kann man einstellen wie stark er 
wirken soll. zB 4, 8 oder 16 Werte. Alles andere bringt nicht mehr.
Gast #4109323
Jetzt Nicht schrieb:
> Von 32 bit unsigned oder signed auf 24 bit unsigned oder signed
> schmeisst man das hoechstwertige byte weg, uebertraegt nur die unteren 3
> byte.

nein nicht bei signed.

schau dir doch mal die bits für 24 und 32bit unsiged "-1" mal an.
OP Persönliche Seite #4109332
Ich bin hier wirklich nicht der experte auf dem gebiet, aber

> Von 32 bit unsigned oder signed auf 24 bit unsigned oder signed
> schmeisst man das hoechstwertige byte weg, uebertraegt nur die unteren 3
> byte.

stimmt (hat mich dann doch überrascht) - oder nicht?!


dec 1223344
bin (00000000)000100101010101010110000

dec -1223344
bin (11111111)111011010101010101010000
Gast #4109339
Jetzt Nicht schrieb:
> Da kann man vorne soviel wegwerfen wie identisch ist
> Ob das nun 64, 32, 16 bit sind

-1
24bit   0b11111111111111111111111
32bit   0b1111111111111111111111111111111

1
24bit   0b00000000000000000000001
32bit   0b0000000000000000000000000000001

Wie kommst du denn jetzt einfach von 24bit auf 32bit?
OP Persönliche Seite #4109347
In Ordnung, also überzeugt: Ich behalte die sign extension für 3x8bit 
auf 32bit bei, rechne dann den mittelwert (/2(4) geht mit bitshift) auf 
den 32bitvariablen und dann werden einfach die letzten drei byte des 
ergebnisses übertragen.

Das klingt schon recht minimalistisch, großartig!

Jetzt Nicht schrieb:
> einen Tiefpass, als exponentielles Mittel mit genau einer Speicherstelle.

Das ist mir allerdings noch unklar: Wenn du exponentielle glättung des 
gleitendem MW meinst, stellt sich mir eben die Frage, ob "zusammenfassen 
von jeweils 4 samples" nicht korrekter ist, als (gleitendes) 
tiefpassfiltern.

Das Argument eben: Ich möchte rohdaten mit besserem SNR, so als ob sie 
mit niedrigerer samplefrequenz erfasst wurden - und nicht filtern in dem 
sinne, dass alle samples von ihren nachbarn abhängig (weil exponentiell 
mit eingeflossen) sind... Ich habe aber auch hier den Verdacht, dass 
ichi nicht weit genug denke..?
Gast #4109352
Jetzt Nicht schrieb:
> -1
> 24bit   0b        11111111111111111111111
> 32bit   0b1111111111111111111111111111111
>
> 1
> 24bit   0b        00000000000000000000001
> 32bit   0b0000000000000000000000000000001
>
> etwa so.

und im code?

also mindestens eine Sprungbedingungen, also schon 2-3 Takte.
#4109356
>und im code?
also mindestens eine Sprungbedingungen, also schon 2-3 Takte.

Im Falle von sign extend von 24 auf 32 bit ?
Oder im Falle von 32 bit nach 24 bit ?

Also schieben ist nicht angesagt. Weglassen oder zufuegen.
Zufuege von 0xFF wenn negative und 0x00 wenn positiv
OP Persönliche Seite #4109358
Jetzt Nicht schrieb:
> Zur Implementierung siehe :
> http://www.ibrtses.com/embedded/exponential.html

Wie ich damit die Bandbreite begrenze ist verständlich, nur möchte ich 
ja nicht nur die bandbreite des signals begrenzen, sondern auch z.B: 2:1 
/ 4:1 downsamplen (siehe datenrate zu beginn).. dahingehend ist mir noch 
unklar wie dein vorschlag genau aussehen soll?
OP Persönliche Seite #4109370
Verstehe. Mir ist nur noch unklar, wieso das exponential averaging 
besser sein soll als 4:1 averaging, wenn der sam4s division beherrscht. 
In summe nimmt sich in diesem Fall

(Sample1+Sample2+Sample3+Sample4)/4 = Ergebnis -> übertragen

von der effizienz gegenüber

4 x (output:=input shr 5  + output - output shr  5); jeden 4. output -> 
übertragen

ja nicht so viel. Ich frage mich bei meinem 4:1 averaging nur, ob / wie 
sich die "sprünge" zwischen den 4er paketen zB im frequenzbereich 
deutlich machen und deshalb ein kontinuierlicher Ansatz wie deiner 
vorzuziehen wäre.
Mir ist klar, dass averaging über zwei samples das snr um sqrt(2) 
verbessert, nur nicht wie das konkret beim exponential averaging 
tiefpassfilter aussieht.
Gast #4109373
Anstelle des Mittelwerts, kannst du den Median-Wert nehmen.

Z.B. Du Samplest 5 mal, sortierst die 5 Werte nach der Größe und nimmst 
den Medianwert, in diesem Fall einfach den dritten Wert.
OP Persönliche Seite #4109377
Ich will das signal ja nicht median-glätten!

Ich messe ein biosignal - das ich möglichst roh zur weiterverarbeitung 
übermitteln will. medianfiltern etc. muss später passieren. Ich will den 
informationsgehalt des signals nicht schon beeinflussen - nur das snr 
erhöhen und dazu auf bandbreite verzichten.
#4109382
Peter II schrieb:
> also mindestens eine Sprungbedingungen, also schon 2-3 Takte.

Sind wir bei AVR oder Cortex M4 mit GCC?

Für Cortex M3 und M4 geht folgendes:
1
static inline int32_t expandSign24BitU (uint32_t val){
2
  int32_t result;
3
  asm  ("SBFX %[R0], %[R1], %[Bits0], %[nBits]" : [R0] "=r" (result) : [Bits0] "I" (0), [nBits] "I"(24), [R1] "r" (val) );
4
  return result;
5
}

Durch das "static inline" generiert der Compiler nur die eine SBFX 
Instruktion.
OP Persönliche Seite #4109391
Jim Meba schrieb:
> AVR oder Cortex M4 mit GCC?

ja! sam4s mit avr studio 6 und gcc

Ich muss zugeben, die funktion fällt mir aber schwer zu lesen (bin nicht 
allzu frisch in assembler). Dass ich das richtig verstehe: Sie ist zur 
sign extension von 24 auf 32bit vorgesehen? Ich habe meine 24bit ja in 
3x8Byte paketen - die müssten dann vorher noch in ein uint32 gemerged 
werden?
Falls ja:

Bisher ists bei so umgesetzt (MSB mit sign first im buffer) - s.u.
1
// Sign extension to 32 Bits
2
temp = ((uint32_t)rxbuffer[0] << 16) | ((uint32_t)rxbuffer[1] << 8) | rxbuffer[2];
3
  if(rxbuffer[0] & 0x80) temp |= 0xFF000000;
4
  measurement->ch[0]= (int32_t) temp;

das einzige, was dann nach dem mergen in eine uint32 ja noch passiert 
ist die if abfrage mit der maske - lohnt sich dafür dann deine funktion 
noch?
#4109437
Alex V. L. schrieb:
> rechne dann den mittelwert (/2(4) geht mit bitshift)

Vorsicht! Shift-right für negative Zahlen ist undefined behavior. Nimm 
den ganz normalen Divisions-Operator dann weiß der Compiler in jedem 
Falle was zu tun ist.

[Edit] Aber andererseits Du wirfst das oberste Byte ja eh weg, also ists 
doch wieder egal.[/edit]

Antwort schreiben

Eine eigene Frage? Dieser Thread ist über 11 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.