Forum: Mikrocontroller und Digitale Elektronik Effizente Mittelwertberechnung über 24bit (3x8Byte) ADC daten


von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

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?

: Bearbeitet durch User
von Pandur S. (jetztnicht)


Lesenswert?

24bit ist doch nur die hoeheren, oder niederen 3 byte eines 32 bit 
integers. Was soll da der Aufwand ?

von Peter II (Gast)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

Jetzt Nicht schrieb:
> 24bit ist doch nur die hoeheren, oder niederen 3 byte eines 32 bit
> integers. Was soll da der Aufwand ?

so einfach ist das leider nicht, weil das signed im höchsten bit ist, 
das muss erst verschoben werden.

von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

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

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Alex V. L. schrieb:
> Das alleine schon aber mit einer datenrate über spi von
> mindestens 60kbit/s, eher 100kbit/s.

das sind doch nur 4000 Datensätze pro Sekunde? Das bekommt man doch fast 
mit einen kleinen tiny hin.

von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

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?

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

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

von Pandur S. (jetztnicht)


Lesenswert?

Ich denke es sind weniger operationen. Auf einem Mega ist es vieleicht 
15 Byte operationen pro Sample. Im Wesentlichen Schieben & Addieren.

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Peter II schrieb:
> sign verschieben

Du musst kein sign verschieben wenn du von int32 nach int24 castest. Nur 
das höchste Byte wegwerfen oder ignorieren.

von Peter II (Gast)


Lesenswert?

Bernd K. schrieb:
> Du musst kein sign verschieben wenn du von int32 nach int24 castest. Nur
> das höchste Byte wegwerfen oder ignorieren.

wie soll das denn gehen?

von Bernd K. (prof7bit)


Lesenswert?

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.

von casterfrager (Gast)


Lesenswert?

Bernd K. schrieb:
> Du musst kein sign verschieben wenn du von int32 nach int24 castest.

Wie soll das Casten funktionieren? Dazu bräuchte man einen
24 Bit Datentyp, den es meines "Erachtens" (für Mikrocontroller)
nicht gibt.

von Peter II (Gast)


Lesenswert?

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.

von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

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?!)

von sdg (Gast)


Lesenswert?

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.

von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

sdg schrieb:
> wie soll es denn schneller gehen?
> Und Bitverschiebeaktionen gehen ganz ohne Division.

wohl kaum schneller, wobei ich wette, dass der compiler aus div/2 oder 
div/4 eh einen bitshift macht (und der sam4s auch effiziente division 
beherrscht). Das problem ist ja immernoch die Umrechnung von und auf 24 
bit.

: Bearbeitet durch User
von Pandur S. (jetztnicht)


Lesenswert?

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.

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

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.

von Peter II (Gast)


Lesenswert?

Korrektur:

Peter II schrieb:
> schau dir doch mal die bits für 24 und 32bit unsiged "-1" mal an.

schau dir doch mal die bits für 24 und 32bit siged "-1" mal an.

von Pandur S. (jetztnicht)


Lesenswert?

Signed :

5    00 ... 0101
4    00 ... 0100
3    00 ... 0011
2    00 ... 0010
1    00 ... 0001
0    00 ... 0000
-1   FF ... FFFF
-2   FF ... FFFE
-3   FF ... FFFD
-4   FF ... FFFC

Da kann man vorne soviel wegwerfen wie identisch ist
Ob das nun 64, 32, 16 bit sind

: Bearbeitet durch User
von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

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

von Peter II (Gast)


Lesenswert?

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?

von Pandur S. (jetztnicht)


Lesenswert?

Ja, negative Zahlen habe eine eins als hoechstes bit, und positive eine 
null. Und dann kann man mit nullen und einsen fuer den naechst 
groesseren datentyp auffuellen.

von Pandur S. (jetztnicht)


Lesenswert?

Das hoechste byte in die Tonne. Weglassen.

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

Jetzt Nicht schrieb:
> Ja, negative Zahlen habe eine eins als hoechstes bit, und positive eine
> null. Und dann kann man mit nullen und einsen fuer den naechst
> groesseren datentyp auffuellen.

also doch nicht einfach casten.

von Pandur S. (jetztnicht)


Lesenswert?

Das hoechste byte is links. Man uebertraegt es einfach nicht. So einfach 
ist das. Kein cast, kein nichts.

: Bearbeitet durch User
von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

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..?

von Peter II (Gast)


Lesenswert?

Jetzt Nicht schrieb:
> Das hoechste byte is links. Manuebertraegt es einfach nicht. So einfach
> ist das. Kein cast, kein nichts.

es geht erst mal von 24 auf 32bit - um die Vergrößerung zum Rechnen.

von Pandur S. (jetztnicht)


Lesenswert?

-1
16bit   0b                   111111111111
24bit   0b        11111111111111111111111
32bit   0b1111111111111111111111111111111

1
16bit   0b                    00000000001
24bit   0b        00000000000000000000001
32bit   0b0000000000000000000000000000001

etwa so.

: Bearbeitet durch User
von Peter II (Gast)


Lesenswert?

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.

von Pandur S. (jetztnicht)


Lesenswert?

Das SNR Wird besser wenn man die Bandbreite reduziert. Und das macht man 
mit einem Tiefpass. Es wird sogar besser als mit langsamer sampeln, denn 
man gewinnt bits. Mit der Wurzel der Samples. In diesem Falls kommen die 
neuen bits von den geschobenen, niederwerigeren, zusaetzlichen bits.

Zur Implementierung siehe :
http://www.ibrtses.com/embedded/exponential.html

von Pandur S. (jetztnicht)


Lesenswert?

>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

von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

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?

von Pandur S. (jetztnicht)


Lesenswert?

Du kannst dann ja jede 2. Berechnung wegwerfen, dh zwar ausfuehren, aber 
nicht uebertragen. resp 3 von 4 wegwerfen , oder 7 von 8 wegwerfen. 
Wichtig ist, dass der Tiefpass weiterlaeuft, wie ein RC-tiefpass.

: Bearbeitet durch User
von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

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.

von ado (Gast)


Lesenswert?

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.

von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

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.

von Jim M. (turboj)


Lesenswert?

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.

von Alex V. (bastel_alex) Benutzerseite


Lesenswert?

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?

: Bearbeitet durch User
von Bernd K. (prof7bit)


Lesenswert?

Peter II schrieb:
> nein nicht bei signed.

Doch. Einfach das oberste Byte weglassen, fertig.

von Bernd K. (prof7bit)


Lesenswert?

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]

: Bearbeitet durch User
Bitte melde dich an um einen Beitrag zu schreiben. Anmeldung ist kostenlos und dauert nur eine Minute.
Bestehender Account
Schon ein Account bei Google/GoogleMail? Keine Anmeldung erforderlich!
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.