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
24bit ist doch nur die hoeheren, oder niederen 3 byte eines 32 bit integers. Was soll da der Aufwand ?
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.
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.
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
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.
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
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
Ich denke es sind weniger operationen. Auf einem Mega ist es vieleicht 15 Byte operationen pro Sample. Im Wesentlichen Schieben & Addieren.
:
Bearbeitet durch User
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.
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?
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.
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.
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.
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?!)
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.
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 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
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.
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.
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
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
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?
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.
Das hoechste byte in die Tonne. Weglassen.
:
Bearbeitet durch User
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.
Das hoechste byte is links. Man uebertraegt es einfach nicht. So einfach ist das. Kein cast, kein nichts.
:
Bearbeitet durch User
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..?
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.
-1 16bit 0b 111111111111 24bit 0b 11111111111111111111111 32bit 0b1111111111111111111111111111111 1 16bit 0b 00000000001 24bit 0b 00000000000000000000001 32bit 0b0000000000000000000000000000001 etwa so.
:
Bearbeitet durch User
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.
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
>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
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?
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
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.
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.
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.
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.
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
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
Mit Google-Account einloggen
Noch kein Account? Hier anmelden.