Hallo, ich möchte die die Anzahl von Impulsen/Minute dynamisch bestimmen. Ich habe einen Impulsgeber der Werte zwischen 0 und 120 Impulse pro Minute ausgibt (Durchschnitt bei etwa 60). Für den Durchschnittswert möchte ich jede Sekunde auslesen können, wieviele Impulse in den letzten 60 Sekunden aufgezeichnet wurden. Ich hätte dies, mit einem Stack gelöst, der die millis() der Impulse speichert, sowie seine Größe. Immer bei einer Abfrage würden dann alle Elemente, die älter als 60 Sekunden sind gelöscht und die große zurückgeben. Leider habe ich keine Erfahrung mit ADT auf Mikrocontrollern, sowie mit OOP auf Mikrocontrollern
Das geht nur wenn Du wirklich 60 verschiedene Werte speicherst, sonst weisst Du nach n paar sekunden nichtmehr was zu löschen wäre.. wenn Du sicher bsit, dass kein Aktueller Wert grösser sein kann als 127. DANN (und nur dann) kannst Du mit nur 4bit pro Wert auskommen, also 30byte 240bit bei jedem speichervorgang überschreibst du schlicht die folgenden 4 bit mit deinem gelesenen Wert (mod 240 quasi wie ein endlos magnet band) und merkst Dir nur die position. (bei 240bit reicht dann ein byte [255] für die zeigerposition) Dann machst Du eine volle rotation (liest 60 mal 4bit) und errechnest den Durchschnitt und sobald ein neuer Wert eintrudelt, überschreibst Du die nächsten vier bit, der Zeiger rückt um vier vor (immer mod 240 natürlich) usw usf
Moin, Da wuerd' ich einfach eine Datenbank in der Cloud dazu hernehmen. Und in Java ein paar Front/Back/Obendrueber- und von HintendurchdieBrustinsAuge-Ends schreiben. Duck&Wech WK
Der naive Ansatz: Array von 60 Zahlen, element 0 kommt jede Sekunde der aktuelle Wert rein, und davor wird Elemente 58 nach 59 verschoben, 57 nach 58, ... 0 nach 1. Danach alle 60 aufsummieren. Zweite Verbesserung: memmove. Dritte Verbesserung: ringbuffer Vierte: nicht immer neu aufsummieren, sondern neuen wert zum Summenzähler addieren, ältesten subtrahieren. Und dann, ... ja dann stellst Du fest, dass so ein Mittelwert meist wenig hilfreich ist.
1 | volatile uint8_t pulses; |
2 | |
3 | void
|
4 | pulse_irq() // interrupt context |
5 | {
|
6 | pulses++; |
7 | }
|
8 | |
9 | static uint8_t |
10 | get_pulses() // get number of pulses since last call |
11 | {
|
12 | // Instead of resetting pulses (needs atomic read-and-clear)
|
13 | // remember the last value and take the difference to now.
|
14 | static uint8_t last; |
15 | |
16 | uint8_t x = pulses; |
17 | x -= last; |
18 | last += x; |
19 | return x; |
20 | }
|
21 | |
22 | static uint8_t |
23 | get_pulse_avg() // returns pulse average over last 60 calls |
24 | {
|
25 | static uint8_t history[60]; |
26 | static uint8_t pos; |
27 | static uint16_t avg; |
28 | |
29 | uint8_t x = get_pulses(); |
30 | |
31 | avg -= history[pos]; |
32 | avg += x; |
33 | histoy[pos++] = x; |
34 | if (pos == 60) |
35 | pos = 0; |
36 | |
37 | return avg / 60; |
38 | }
|
39 | |
40 | void
|
41 | every_second() |
42 | {
|
43 | printf("pulse average: %d\n", get_pulse_avg()); |
44 | }
|
Vergiss den Murks. Dafuer verwendet man einen tiefpass. Wie zB beschrieben unter : https://www.ibrtses.com/embedded/exponential.html Dabei nimmt der Anteil des aktuellen Wertes am Mittelwert mit der Zeit exponentiell ab.
Der gleitende Mittelwert über 60s ist halt ein extremer (FIR-)Tiefpass, der nur langfristige Änderungen durchlässt. Mit einem exponentiellen (IIR-)Tiefpass wie unter werden eher die Flanken "runder". Was man braucht ist Anwendungssache. Zum Vergleichen/Rumexperimentieren:
1 | volatile uint8_t pulses; |
2 | |
3 | void
|
4 | pulse_irq() // interrupt context |
5 | {
|
6 | pulses++; |
7 | }
|
8 | |
9 | static uint8_t |
10 | get_pulses() // get number of pulses since last call |
11 | {
|
12 | // Instead of resetting pulses (needs atomic read-and-clear)
|
13 | // remember last value and take the difference to now
|
14 | static uint8_t last; |
15 | |
16 | uint8_t x = pulses; |
17 | x -= last; |
18 | last += x; |
19 | return x; |
20 | }
|
21 | |
22 | static uint8_t |
23 | avg_60(uint8_t x) // returns average of x over last 60 calls |
24 | {
|
25 | static uint8_t history[60]; |
26 | static uint8_t pos; |
27 | static uint16_t avg; |
28 | |
29 | avg -= history[pos]; |
30 | avg += x; |
31 | history[pos++] = x; |
32 | if (pos == 60) |
33 | pos = 0; |
34 | return avg / 60; |
35 | }
|
36 | |
37 | static uint8_t |
38 | avg_exp(uint8_t x) // returns exponential average of x |
39 | {
|
40 | static int avg; |
41 | |
42 | avg += ((int)x * 4 - avg + 1) / 2; |
43 | return avg / 4; |
44 | }
|
45 | |
46 | void
|
47 | every_second() |
48 | {
|
49 | uint8_t p = get_pulses(); |
50 | |
51 | printf("pulses: %d, 60s-average: %d, exp-average: %d\n", p, avg_60(p), avg_exp(p)); |
52 | }
|
53 | |
54 | // test
|
55 | int
|
56 | main(int argc, char **argv) |
57 | {
|
58 | int x = 0; |
59 | |
60 | for (int i=0; i < 70; ++i) |
61 | {
|
62 | pulses += 50 + 50*sin(x++ * .2); |
63 | //pulses += 50 + 3*(x++%8 < 2);
|
64 | every_second(); |
65 | }
|
66 | |
67 | return 0; |
68 | }
|
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.