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

OP Persönliche Seite #4109239
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?
Gast #4109244
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.
OP Persönliche Seite #4109249
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
OP Persönliche Seite #4109263
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?
Gast #4109277
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
#4109292
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.
Gast #4109296
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.
OP Persönliche Seite #4109299
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?!)
#4109322
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.
OP Persönliche Seite #4109332
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
Gast #4109339
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?
OP Persönliche Seite #4109347
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..?
OP Persönliche Seite #4109358
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?
OP Persönliche Seite #4109370
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.
#4109382
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.
OP Persönliche Seite #4109391
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?

Antwort schreiben

Bitte melde dich an, um einen Beitrag zu schreiben.

oder

Mit Google-Account einloggen

Die Registrierung ist kostenlos und dauert nur eine Minute.

Jetzt registrieren