Ringbuffer 30 Sekunden
-
Hallo,
ich habe ein Problem. Ich habe ein Programm mit dem ständig Daten aufgezeichnet werden und wenn ein bestimmter Fall eintritt, dann wird ein Trigger-Event ausgelöst und von der Situation dann genau 15 Sekunden zurück und 15 Sekunden danach Daten aufgezeichnet. Am Ende erhalte ich also eine 30 Sekunden-Datei mit den Daten die 15 Sekunden vor dem Triggerereignis aufgeteren sind und die Daten welche 15 Sekunden nach dem Triggerereignis aufgetreten sind.
Das ganze muss ich jetzt programmieren. Ich habe mir überlegt einen Ringbuffer zu schreiben, welcher ständig diese Daten aufzeichnet. Und bei einem Trigger-Event soll er dann vom Buffer die 15000 Einträge vor dem Trigger-Event rausnehmen, und dann soll er noch weitere 15 Sekunden aufzeichnen und diese 15000 Einträge dann zu den anderen 15000 Packen und als gesamtes Array ausgeben.
Wie soll ich das aber konkret umsetzen? Ich muss es nicht unbedingt mit einem Ringbuffer lösen. Bin für andere Vorschläge offen. Mein Ziel ist einfach bei einem Trigger-event Daten zu bekommen die 15 Sekunden vor, und 15 Sekunden nach dem Triggerereignis aufgezeichnet wurden..
-
Was genau ist jetzt die Frage?
-
Statt selbst einen Ringbuffer zu schreiben kannst du evtl. auch std::deque benutzen.
-
Hallo Kartal66,
ich würde mal sowas probieren (nicht getestet!)
#include <deque> struct MeasData { time_t timeStamp; // TODO define Data }; typedef std::deque<MeasData> DataBuffer; class foo { public: ... void RecordData (MeasData data, bool trigger = false); private: DataBuffer mData; }; void foo::RecordData (MeasData measData, bool trigger) { time_t t = measData.timeStamp; data.push_back (measData); if (!trigger) { if ((t - data[0].timeStamp) > PreTriggerTime) data.pop_front (); return; } else if ((t - data[0].timeStap) > (PreTriggerTime + PostTriggerTime)) { // TODO Send Data to customer } }Herzliche Grüsse
Walter
-
Nachdem der Ringbuffer ja ne fixe Größe hat, würd ich einfach ein Array benutzen und fertig...
-
Statt selbst einen Ringbuffer zu schreiben kannst du evtl. auch std::deque benutzen.
Ringbuffer = feste grosse, schnelles einfuegen unter verlust der ältesten daten, aka verhindern einer allokation (new/malloc) zur laufzeit.
was hat das jetzt mit einer dequeue zu tun ? Implementierung und verhalten sind grundverschieden.
ich wuerd zur Implementation eines Ringbuffers auch eher nen vector ranziehen.
@weicher
DU rufst nie push_front an der deq auf, welchen vorteil haette die in deinem Fall gegenueber einem vector ?Ciao ...
-
Implementierung ist wenn man eine deque aus verbundenen kleineren arrays zusammensetzt grundverschieden, ja.
Das Verhalten ist aber ähnlich meiner Meinung nach.
Die Funktionalität einer deque ist mehr oder weniger eine obermenge der funktionalität eines ringbuffers, zumindest biete eine deque alles, was hier als anforderungen beschrieben wurde. Es geht zwar ein wenig auf kosten der performance, aber was sagt man noch über vorzeitige optimierung? Und warum einen eigenen container schreiben, falls es mit deque schnell genug läuft (muss natürlich erstmal getestet werden)?P.S.: In der Algorithmen-Vorlesung haben wir übrigens deques als dynamischen ringbuffer implementiert.
Der vorteil gegenüber einem normalen vector (ohne ringbuffer wrapper) ist, dass pop_front bei einer deque wesentlich effizienter sein sollte
Hat boost evtl. nen fertigen ringbuffer?
-
Q schrieb:
Der vorteil gegenüber einem normalen vector (ohne ringbuffer wrapper) ist, dass pop_front bei einer deque wesentlich effizienter sein sollte
So wie ich da seh will hier aber niemand was pushen oder poppen

-
kartal66 schrieb:
Und bei einem Trigger-Event soll er dann vom Buffer die 15000 Einträge vor dem Trigger-Event rausnehmen
Da haste schon pop.
Natürlich bräuchte man bei einem ringbuffer nicht wirklich etwas an der größe verändern sondern nur ein paar pointer oder ints oder so umsetzen, ich hatte aber extra etwas von vector ohne ringbuffer wrapper geschrieben.
-
Q schrieb:
Hat boost evtl. nen fertigen ringbuffer?
Klar: http://www.boost.org/doc/libs/1_48_0/libs/circular_buffer/doc/circular_buffer.html
-
Der vorteil gegenüber einem normalen vector (ohne ringbuffer wrapper) ist, dass pop_front bei einer deque wesentlich effizienter sein sollte
und push_front auch, dequeue ist einfach nen Array was in 2 richtungen geht.
Das einzige was Ringpuffer und dequeue gemeinsam haben, ist die "manipulation" der indizies.Es geht zwar ein wenig auf kosten der performance, aber was sagt man noch über vorzeitige optimierung?
Das die auswahl des richtigen "Containers" wesentlich ist fuer die Performance. Wenn man die randbedingungen kennst, sollte es kein Problem sein, von Haus aus scho den fuer den einsatzfall performantesten container zu nehmen ???
Und wenn der TE schon "Ringpuffer" als Implementation erwaehnt, sollten da scho Performance-Abwägungen gelaufen sein. Also Ihm kommt es auf eine vermeidung von Allokations an ... sonst würd er nicht "Ringpuffer" sagen.
Also nochmal, ringpuffer und deq haben vom verhalten her, ned viel gemeinsam.
Ne deq erweitert sich dynamisch. das besondere der deq ist, das anfügen am Anfang aehnlich performant ist, als wie am ende. Dafuer werden die indizies manipuliert (das ist die gemeinsamkeit mit dem Ringpuffer).Der ringpuffer ist per definition nicht wirklich dynamisch. Er wird mit einer initialen groese erzeugt, die wird sich nie aendern. ein ringpuffer expandiert nicht, ein ringpuffer allokiert zu seiner laufzeit niemals !!!
sondern er ueberschreibt seinen eigenen speicher, und manipuliert die indizies.
Es gibt also nicht wirklich einen "dynamischen" ringpuffer.
wobei man schon unterschieden muss, zwischen ringpuffer mit fester groesse (kann zur laufzeit des programms nicht veraendert werden) und Ringpuffer die man zur laufzeit einstellen kann, (beispiel wenn der user die groesse des ringpuffers selber definieren kann /soll ... weil er besser ueber den verfuegbaren speicher bescheid weiss).
Ansonsten ist der ringpuffer eher statisch ! eine anederung der Groesse zur laufzeit ist eigentlich entgegen der Philosophie des Ringpuffers ...Ciao ...
-
Ok, ich hab grad mal mit Kollegen drüber disskutiert, und in wikis mal nachgeschaut. Mir sträuben sich grad die Nackenhaare ^^
Also, alle Nichtinformatiker, aka Elektrotechniker, Mechaniker, Maschinenbauer ... sind meiner Meinung. (ok, ich bin eigentlich auch Maschinenbauer):
ein Ringbuffer ist definiert, das er die älteren Daten ersetzt wenn er voll ist. Sinn eines Ringpuffers ist es, allokationen zu vermeiden (Praktisches Denken ! ).Die Informatiker sind gespalten. Eine Haelfte ist auf unserer Seite, die andere Haelfte meint, das z.b. ne dqueue auch nen ringpuffer waer.
Fuer die ist nen Ringpuffer kein Praktisch ableitbares Verhalten, sondern beschreibt nur die sichtweisse auf einen Puffer. Am Ende kann fuer die jede Liste, jeder Vector ein ringpuffer sein, mann muss sich nur muehe geben und den als solches betrachten ... so zumindest hab ich sie verstanden.und wiki gibt denen Recht

Für mich bleibt als Nicht-Informatiker, und damit wahrscheinlich eher praktisch denkender Mensch, der Sinn des Wortes "Ringpuffer" nun zweifelhaft. ^^
(der erste Ringpuffer, der auch wirklich als solches bezeichnet wurde, war mechanischer natur, und war wirklich ne trommel, wo Informationen abgelegt wurden. Die Mechaniker habens halt doch eher praktisch drauf ^^ aber wie kann man so was schoenes fest definiertes durch erweiterung und aufweichung der Definitionen so total verhunzen ?
).Intressant war auch die darauffolgende weiterfuehrende Diskussion, die dann in Richtung ging "Warum sollte man Informatiker niemals Lastenhefte schreiben lassen ... und Spezifikationen soweiso nich ... "
Ciao ...
-
Hallo RHBaum,
Kartal66 will gar keinen Ringbuffer

Er will die Daten x Sekunden vor und y Sekunden nach einem Trigger.
Er will das x und y 15 Sekunden sind.
Bei 15 Sekunden pre und post Trigger liegt es sehr nahe, dass die Aufzeichnungsrate eher bei Sekunden als bei nanosekunden liegt.Edit: Habe gerade gesehen, dass Kartal66 von einem Interval von 1mSec spricht. Das sollte die Deque eigentlich locker schaffen.
Mit der Deque ist die Lösung kurz, einfach und wahrscheinlich genügend schnell.
Herzliche Grüsse
Walter
-
weicher schrieb:
Bei 15 Sekunden pre und post Trigger liegt es sehr nahe, dass die Aufzeichnungsrate eher bei Sekunden als bei nanosekunden liegt.
Nicht ganz richtig, der OP will Millisekunden.
-
Hallo,
es hat mich in den Fingern gejuckt

30'000 deque.push_back (double) 0.031 Sekunden
gemessen auf DELL INSPIRION M6500 Intel Core i7 X920 2GHz 8MB RAM 64Bit Win7
Herzliche Grüsse
Walter
-
DELL INSPIRION M6500 Intel Core i7 X920 2GHz 8MB RAM 64Bit Win7
Heul ... warum sitz ich immer an der falschen stelle

Kollege mir gegenueber hat grad einen "Brandneuen" Rechner (Leasingvertrag) bekommen. (wirklich alles orginalverpackt !!!)
Prozessor: Intel Pentium D 960 irgendwas

RAM: 2 GB DDR2
HD: 120 GB
BS: klar, Windows XP (Musterclient).
....und der muss nun die naechsten 3 Jahre mit auskommen ... und ja, der iss auch Entwickler

Wo kriegen die diese Antiquitaeten nur her ?
Naja, vielleicht schau ich deshalb auch mehr auf die Performance, und geb mich mit ner deq ned zufrieden, wenn ich nen Ringpuffer(nach meiner Definition) brauch.
Und wir haben ähnliche Problemstellung. wir brauchen auch 10 sek vor und nach trigger, aber die 10 sek sind nur ca. ... die sind definitiv verhandlungssache.
Wichtiger bei uns ist, das da ca 8 Mbit nutzdaten durchlaufen, die echtzeit decodiert werden muessen. Das heisst unser "Ringpuffer" darf in erster linie keine Rechenleistung fressen und muss trotzdem hinterher kommen ... dyn. allokation waere da das aus ...
Ciao ...
-
RHBaum, versteh nicht was du hast. Sein i7 920 hat nur 2GHz, der Pentium D 960 gleich 3,6GHz. Seine Kiste hat auch nur 8MB Ram, die von dir genannte gleich 2GB...

(Schreibfehler und Architekturunterschiede wurden in diese Wertung nicht einbezogen)
-
jetzt wo Du es sagst ...
win7 + 8 MByte RAM ... man, nu bin ich wieder Happy !
Ciao ...
-
Hallo RHBaum,
ist natürlich
DELL INSPIRION M6500 Intel Core i7 X920 2GHz 8GB RAM 64Bit Win7Unsere Zielsysteme sind Industrie PC's im 19" Gehäuse:
Intel Core2 Duo E8500 3.17GHz RAM 2GB 32Bit Win7 für ca. CHF1500.--
eine "lahme Ente" kostet mindestens CHF1200.--, da kannst du knapp 4 Stunden optimieren danach kommt die schnellere Hardware wieder billiger.
und wenn man dann noch die Erweiterungskarten betrachtet:
GPIB CHF800.--
Motion Control CHF745.--
Analog Digital IO CHF1200.--
FrameGrabber CHF955.--und das ganze dann Maschinen steuert welche zwischen CHF150'000...CHF500'000 kosten, dann macht das einsparen von CHF300.-- beim PC einfach keinen Sinn.
Herzliche Grüsse
Walter
-
weicher schrieb:
Hallo,
es hat mich in den Fingern gejuckt

30'000 deque.push_back (double) 0.031 Sekunden
gemessen auf DELL INSPIRION M6500 Intel Core i7 X920 2GHz 8MB RAM 64Bit Win7
Herzliche Grüsse
Walter#include <iostream> #include <ctime> #include <deque> #include <boost/circular_buffer.hpp> int main() { { typedef boost::circular_buffer<double> buffer_t; clock_t start = clock(); buffer_t container(100); for(int i = 0; i < 100; i++) { container.push_back(i); } for(int i = 100; i < 1000000000; i++) { container.pop_front(); container.push_back(i); } clock_t end = clock(); double cpu_time_used = (static_cast<double>(end - start)) / CLOCKS_PER_SEC; std::cout << "Finished. CPU-Time: " << cpu_time_used << '\n'; for(buffer_t::const_iterator it = container.begin(); it != container.end(); ++it) { std::cout << (*it) << '\n'; } } { typedef std::deque<double> buffer_t; clock_t start = clock(); buffer_t container; for(int i = 0; i < 100; i++) { container.push_back(i); } for(int i = 100; i < 1000000000; i++) { container.pop_front(); container.push_back(i); } clock_t end = clock(); double cpu_time_used = (static_cast<double>(end - start)) / CLOCKS_PER_SEC; std::cout << "Finished. CPU-Time: " << cpu_time_used << '\n'; for(buffer_t::const_iterator it = container.begin(); it != container.end(); ++it) { std::cout << (*it) << '\n'; } } }boost::cirular_buffer: Finished. CPU-Time: 4.088 std:deque: Finished. CPU-Time: 10.953VS2010