mikrocontroller.net

Forum: Compiler & IDEs Länge eines Array bestimmen für Mittelwertbildung


Autor: Joachim B. (jojo84)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo Forum!

Ich habe mal wieder einen prinzipielle Frage zu souveränem 
Programmieren.

Folgendes hab ich vor: ich lade ein Array mit Messwerten. Der älteste 
Wert wird immer verworfen, und gegen den neuen Messwert ersetzt.
Dann summiere ich alle Array-Elemente auf, und teile dann durch die 
Anzahl der Elemente (normal, Tiefpass-Filter).
Weil ich mehrere verschiedene Dinge messe habe ich eine 
Filterungsfunktion, die das Aufsummieren und Teilen übernimmt. Dieser 
Funktion übergebe ich also u.A. das jeweilige Array mit den letzten x 
Messwerten (und dem neusten).

Jetzt würde ich natürlich gern die Division durch die Anzahl der 
Arrayelemente gegen eine Shift-Operation ersetzen, wenn die Anzahl der 
Array-Elemente ein 2er-Komplement ist. Aber wie stell ich das fest?!

Bisher hab ich das:
unsigned char filterung(unsigned char input, unsigned char array[], unsigned char *position)
{
  unsigned int filterwert = 0;

  array[*position] = input;
  *position++;

  if(*position > (sizeof(array) - 1))
  {
    *position = 0;
  }

  for(unsigned char x = 0; x < sizeof(array); x++)
  {
    filterwert += array[x];
  }

  // und jetzt?!?

return (unsigned char)filterwert;
}

Klar kann ich schreiben:
if(sizeof(array) == 2)
{
filterwert >>= 1;
}

else if(sizeof(array) == 4)
{
filterwert >>= 2;
}
.
.
.

Aber schön ist auch anders :) . Wie komme ich geschickt an diese 
Information?!

Danke schonmal,
Gruß

Autor: Rufus Τ. Firefly (rufus) (Moderator) Benutzerseite
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Du musst Deiner Funktion die Anzahl der Arrayelemente explizit 
mitteilen, denn auch wenn Du "unsigned char array[]" im 
Funktionsprotoypen verwendest, ist das hier exakt gleichbedeutend mit 
"unsigned char *array" - und aus einem Pointer kann man nicht die Größe 
des zugehörigen Speicherbereichs extrahieren.

Autor: Joachim B. (jojo84)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Danke für die Antwort!

Jo, stelle auch grad fest, daß das so nicht geht. Zum Test hab ich mal 
den Simulator angeschmissen und mir die Inhalte der Variablen angeguckt. 
Da sagt er mir, daß sizeof(array) = 2 wäre. Das wundert mich etwas. Ich 
hätte da eigentlich 1 erwartet. Es ist ja ein char-Array...  Kannst du 
mir das vielleicht erklären?

PS: den Fehler mit *pointer++ hab ich selbst schon gefunden :)

Autor: Roland Praml (pram)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
> sizeof(array) = 2

Array ist ein 16bit Pointer nehme ich mal an.


Ob ein Wert eine 2er-Potenz ist, kannst du ggf so feststellen:

i = arrLength;
while (!(i & 0x01)) { i = i >> 1); //  solange schieben, bis ein 
gesetztes Bit kommt
if (i == 1) { ... arrLength ist ein Binärwert }


Gruß
Roland.

Autor: Huch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
>Da sagt er mir, daß sizeof(array) = 2 wäre. Das wundert mich etwas. Ich
>hätte da eigentlich 1 erwartet. Es ist ja ein char-Array...

Nein. Karl Heinz hat ja geschrieben, dass unsigned char *array.
array ist ein Zeiger. Und der Zeiger ist zwei Byte gross.

Namen von Arrays in Ausdrücken sind immer erstmal Zeiger auf Arrays. 
Nicht das Array selbst oder das nullte Element.
Durch die eckigen Klammern wird vor allem ermöglicht solche Arrays ihrer 
Grösse nach zu vereinbaren. Sonst gäbe es nämlich nur noch malloc und 
Konsorten.
Konsequenterweise (oder auch nicht) kann man auch die Index-Schreibweise 
benutzen um Elemente zu adressieren. Aber eigentlich ist das nur ein 
Synonym zur Zeigerarithmetik.

Autor: Huch (Gast)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ich möchte Dir noch einen Vorschlag machen, der die Mittelwertbildung im 
stationären Fall deutlich beschleunigen wird.

Du schreibst:

>Dann summiere ich alle Array-Elemente auf, und teile dann durch die
>Anzahl der Elemente (normal, Tiefpass-Filter).

Eigentlich ist es nicht nötig, jedesmal bei eintreffen eines neuen 
Wertes die Summe aller Array-Elemente zu bilden.
Du kannst, wie Du es schon fast hast, einen Ringpuffer verwenden.
Wenn der Ringbuffer voll ist, dann ist der älteste Wert jeweils der auf 
den neuen Werte folgende, bzw. der Nullte, falls der neue an das Ende 
des Arrays geschrieben wird.
Bei eintreffen eines neuen Wertes, muss nur der älteste Wert von der 
Gesamtsumme abgezogen werden und der neue addiert. Das Array musst Du 
natürlich trotzdem halten um die alten Werte immer wieder subtrahieren 
zu können.

Autor: Michael P. (michael_p)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Hallo,

der eleganteste Weg ein Tiefpass-Filter (also PT1-Filter) zu machen ist 
immer nur einen Bruchteil der Differenz aus neuem Eingangswert und 
Ausgangswert, zum Ausgangswert zu addieren.

zB so:
unsigned char output=0;

void filterung(unsigned int input)
{
   unsigned char diff;

   diff=output - input;
   diff/=10;
   output+=diff;
}


So brauchst du dir nicht unzählige alte Werte zu merken.
Wenn dich die Codegröße wegen der Division stört, dann dividier halt 
nicht durch 10 sondern schiebe paarmal (also /8 oder /16).

lg,
Michael

Autor: Joachim B. (jojo84)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Ok, danke euch allen!

Hab wieder was dazugelernt :) .

Klarheit beseitigt :)

Gruß und gute n8

Autor: Michael Buesch (mb_)
Datum:

Bewertung
0 lesenswert
nicht lesenswert
Roland Praml schrieb:
> Ob ein Wert eine 2er-Potenz ist, kannst du ggf so feststellen:
>
> i = arrLength;
> while (!(i & 0x01)) { i = i >> 1); //  solange schieben, bis ein
> gesetztes Bit kommt
> if (i == 1) { ... arrLength ist ein Binärwert }

Das geht wesentlich effizienter:
#define is_power_of_two(val) (((val) & ((val) - 1))) == 0)

Das gibt auch true für 0 zurück. Wenn man das nicht will, dann:
#define is_nonzero_power_of_two(val) ((val) && (((val) & ((val) - 1))) == 0))

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]
  • [avrasm]AVR-Assembler-Code[/avrasm]
  • [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.