Länge eines Array bestimmen für Mittelwertbildung

OP #1974460
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:
1
unsigned char filterung(unsigned char input, unsigned char array[], unsigned char *position)
2
{
3
  unsigned int filterwert = 0;
4

5
  array[*position] = input;
6
  *position++;
7

8
  if(*position > (sizeof(array) - 1))
9
  {
10
    *position = 0;
11
  }
12

13
  for(unsigned char x = 0; x < sizeof(array); x++)
14
  {
15
    filterwert += array[x];
16
  }
17

18
  // und jetzt?!?
19

20
return (unsigned char)filterwert;
21
}

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

6
else if(sizeof(array) == 4)
7
{
8
filterwert >>= 2;
9
}
10
.
11
.
12
.

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

Danke schonmal,
Gruß
OP #1974546
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 :)
#1974554
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.
Gast #1974555
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.
Gast #1974568
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.
#1974674
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:
1
unsigned char output=0;
2

3
void filterung(unsigned int input)
4
{
5
   unsigned char diff;
6

7
   diff=output - input;
8
   diff/=10;
9
   output+=diff;
10
}

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
#1975948
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:
1
#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:
1
#define is_nonzero_power_of_two(val) ((val) && (((val) & ((val) - 1))) == 0))

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