Hallo! Ich habe folgendes Problem und mir fällt kein Algorithmus dazu ein. Ich muss eine Anzahl von Ereignissen innerhalb der letzten Stunde zählen. Timer usw hab ich ja schon programmiert. So, wenn in der ersten Stunde die Ereignisse eintreten, ist das kein Problem. Nur, wenn die Stunde rum ist, wie muss ich dann weiter machen?? Zum Beispiel: In den ersten 5min der Messung tritt 20 mal dieses Ereignis ein. In der ersten Stunde insgesamt 200. In den 5min nach der ersten Stunde sind es 5. Dann muss die aktuelle Anzahl nach 1 Stunde und 5min 185 betragen. Meine Fragen: - Was soll ich nach Erreichen der 1. Stunde mit dem Timerwert machen? - Wie kann ich wirklich nur die Ereignisse innerhalb der letzten stunde zählen?
>- Wie kann ich wirklich nur die Ereignisse innerhalb der letzten stunde >zählen? Timeoutzähler pro Ereignis. Wenn eine Stunde abgelaufen ist, Ereignis löschen und Speicher freigeben.
Jedes Ereigniss abspeichern und mit einem Zeitwert versehen. Sobald ein Wert älter als eine Stunde ist diesen rauswerfen.
Hmm, naja - als erstes brauchst du eine Zeitbasis, um überhaupt das Vergehen einer Stunde erkennen zu können. Da du nicht weißt, wieviele Ereignisse insgesamt auftreten können, wäre eine Liste als Datenstruktur ganz sinnvoll. In dieser Liste stehen aufsteigende nach Zeitstempeln geordnet deine Ereignisse. Alte stehen am Anfang, neue werden hinten angefügt. Bei jedem Tick deiner (wie auch immer gearteten Zeitbasis) werden die Ereignisse, deren Lebenszeit abgelaufen ist, vom Listenanfang entfernt. So sollte die Liste zu jedem diskreten Zeitpunkt nur Elemente enthalten, die innerhalb der letzten Stunde aufgetreten sind. Wenn eine zeitliche Auflösung von einer Minute ausreicht, kommt dabei niemand ins Schwitzen. Da du keine Angaben über die maximale Anzahl der Ereignisse, ihren minimalen zeitlichen Abstand usw. gegeben hast, ist das zwar eine naive, aber in Grenzen sinnvolle Lösung... Grüsse
Oder wenn du viele Ereignisse hast und die zeitliche Auflösung nicht so wichtig ist: Ereignisse pro Minute Ein Array von 60 uint32_t, ein total, ein Array index. Nach jeder Minute wird das Gesamtergebnis um den Array Inhalt an der aktuellen Position reduziert, die Anzahl der letzten minute in das Array geschrieben, auf das Gesdamtergebnis addiert und der Array index erhöht. Array index läuft natürlich immer nur von 0-60 in der Runde. Hat ne fixe Speicherlast für eine fixe Auflösung und braucht nur ein paar Takte pro minute. Geht natürlich auch pro Sekunde mit einen Array von 3600 ints
Hallo, wie viel Speicher hast du? Wie oft tritt das Ereignis auf? Wie geanu muss die Zeitliche Auflösung sein? Wenn du es nur Minuten ganau brauchst würde ich ein Arry nehmen und jede Minute das den Index erhöhen. (Ringbuffer) Wenn du es genauer brauchst aber es weniger Ereignisse sein würde ich eine Liste nutzen, Jedes Ereignis bekommt ein Element.
Hallo, einen Ringspeicher verwenden. Den Wert jede Minute Speichern dann müssen nur 60 Werte gespeichert werden. Oder alle 5min oder 10min je nachdem wie genau man es brauch. Gruß Uli
Okay, ich werde es mal versuchen, den Zeitwert immer in einem Array abzuspeichern. Hm, frühestens könnte jede 0,5 sekunden ein Ereignis eintreten :D Aber nur theoretisch...1 sekunde möglich, aber auch nur selten. Am liebsten wäre mir, wenn man es dann direkt sehen würde. Dann versuche ich es mal mit einem Riesen-Array mit ner Größe von 3600 :D
Pseudo Code:
1 | #define RESOLUTION 60
|
2 | |
3 | uint32_t samples[RESOLUTION] |
4 | uint32_t total = 0; |
5 | uint16_t index = 0; |
6 | |
7 | // Setup
|
8 | void setup(){ |
9 | for(int i = 0; i < RESOLUTION; i++) { |
10 | samples[i] = 0; |
11 | }
|
12 | }
|
13 | |
14 | |
15 | //Pro minute ausführen
|
16 | void step(uint32_t count){ |
17 | total -= samples[index]; |
18 | total += count; |
19 | samples[index] = count; |
20 | index = (++index % RESOLUTION); |
21 | }
|
jörg k- schrieb: > Dann versuche ich es mal mit einem Riesen-Array mit ner Größe von 3600 Naja Riesengroß ist das nicht in einem PC oder MC mit SDRam ist das nicht viel. Auf einem Atmega oder MSP340 mit 4k ist das gewaltig mit. Wenn du ein Byte in 2Bit Felder aufteilst kannst du eine 2 sec (max 4 Ereignisse) Auflösung erreichen und hast nur 450 Byte verbraucht. Sind schonmal mehr als 80% gespart :)
jörg k- schrieb: > Okay, ich werde es mal versuchen, den Zeitwert immer in einem Array > abzuspeichern. Wenn nur selten Ereignisse auftreten (wobei durchaus mal zwei kurz hintereinander dabei sein dürfen, nur eben nicht permanent), dann ist das ein probater Weg. Wenn die Ereignisse aber meistens dicht aufeinanderfolgen, dann verbrauchst du so unnötig eine ganze Menge Speicher, besser ist dann ein Ringbuffer, der die Ereignisse pro Zeitintervall zählt. Wenn höchstens ein Ereignis pro 0,5 Sekunden auftritt (deine Angabe), und du ca. 1kB Speicher erübrigen kannst, kann man das z.B. so machen:
1 | #include <stdint.h> |
2 | #include <stdbool.h> |
3 | |
4 | bool event_occurred; // wird gesetzt, wenn ein Event auftritt |
5 | uint16_t half_second; // 0..7199, zaehlt "Halbsekunden" |
6 | uint16_t event_count; |
7 | uint8_t event_bitmap[7200/8]; |
8 | |
9 | void every_half_second(void) |
10 | {
|
11 | uint16_t map_index = half_second/8; |
12 | uint8_t map_shift = half_second%8; |
13 | uint8_t map_bit = 1<<map_shift; |
14 | |
15 | if ((event_bitmap[map_index]&map_bit) != (event_occurred<<map_shift)) { |
16 | event_bitmap[map_index] ^= map_bit; |
17 | event_count += event_occurred?1:-1; |
18 | }
|
19 | |
20 | event_occurred = false; |
21 | half_second = (half_second+1)%7200; |
22 | }
|
Wenn ein Event auftritt, muss event_occurred auf true gesetzt werden, ausserdem muss (z.B. via Timer) dafür gesorgt werden, dass every_half_second() genau jede halbe Sekunde aufgerufen wird. Je nach Plattform und restlichem Code müssen die Variablen natürlich noch zumindest teilweise volatile deklariert werden. Andreas
wow, also mit dem ersten quelltext klappt es jedenfalls!! Mit dem Speicher muss ich mal gucken. Werde dann sicherlich auch die speichersparende Variante versuchen!! Besten Dank für die Beispiele!
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.