php-resource




Archiv verlassen und diese Seite im Standarddesign anzeigen :
Oszilloskop in Java


 
graf
20-04-2003, 00:52 
 
Ich möchte eine Art Oszilloskop mit Java realisieren.
Momentan mache ich es so, dass ich auf einem Panel ein Image plaziere und auf dessen Graphics (Content) Punkte zeichne und dann halt nach jedem Durchlauf des Thread, Graphics nach links verschiebe und den nächsten Punkt an der "gleichen" x-Position zeichne.
Das ganze bewegt sich also scheinbar von rechts nach links.

Soo, nun ist die Sache mit dem Image zeichnen natürlich ziemlich speicherfressend und braucht jedesmal ca. 5 ms. Ich suche evtl. nach einer Alternative.

Hat jemand von Euch eine Idee, wie man sowas noch realiseren kann?
Allerdings auch so, dass es im Hintergrund (nicht ständig sichtbar) laufen kann.

 
Blaster
20-04-2003, 15:15 
 
Hi!

Also was die Geschwindigkeit angeht, da ist Java vielleicht die falsche Wahl.
Echtzeitdarstellungen in der Messtechnik sollten vielleicht in compilierten Sprachen dargestellt werden.
In denen würde ich vielleicht eine auf JNI basierte Bridge zu Java bilden.
Dann ist allerdings die Typensicherheit von Java zum Teufel - ist klar.

Was Darstellung angeht so fallen mir zwei Möglichkeiten ein:
java 2D (java.awt.Graphics2D)
Also für Fourier-Transformationen würde ich Bezierkurven wählen. Dabei werden zwei Endpunkte festgelegt und mit Kontollpunkten Amplitude bzw. Elongation festgelgt. (java.awt.geom.CubicCurve2D.*)

Die zweite Idee wäre eine Polygon-Darstellung
(java.awt.geom.Polygon), wobei Du den funktionalen Zusammenhang explizit selbst deklarieren kannst.

Hoffe, konnte Dir helfen. :)

Blaster

P.S.: " Für solche 'Hardcore'-Fragen kann ich Dir
www.c-plusplus.de/forumstart.htm -"Rund um die Programmierung" empfehlen.

 
goth
20-04-2003, 15:31 
 
Nicht nur vielleicht ... Blaster ... nicht nur vielleicht ... :D

 
Blaster
20-04-2003, 16:44 
 
@goth: Hmmpf... :dontknow:

http://www.rtj.org/doc/index.html

http://www.c-plusplus.de/ubb/cgi-bin/ultimatebb.cgi?ubb=get_topic&f=16&t=001758&p=1

 
goth
20-04-2003, 17:25 
 
Ich denke das gerade der Thread im c-plusplus Forum relativ klare Auskünfte gibt ... ich habe bisher noch nie ein Java - Programm gesehen das schnell war ...

und ich habe mehrere Jahre im Bereich In-Circuit-Emulatoren RT-Software entwickelt ... auf Java wäre dabei mit Sicherheit niemals meine Wahl gefallen ... da hilft auch keine RT-Spec ... :huep:

 
Blaster
20-04-2003, 17:54 
 
@goth:
Ich bin eigentlich auch chronischer C++-ler ... bin deshalb wohl befangen ...:D

 
graf
20-04-2003, 18:05 
 
Also es ist so, dass die Darstellung schon in Java erfolgen MUSS. Festlegung, nicht meine Idee! :D
Was ich darstelle sind Messwerte, die ich mir per JNI aus einer Karte hole.

Momentane mache ich es so, dass ich alle 20 ms einen Wert aus der Karte hole und ihn auf Graphics2D eines VolatileImage zeichne.
Dann verschieb ich Graphics über copyArea quasi und zeichne das VolatileImage über drawImage neu.
Da es sich nach einiger Zeit um tausende Messwerte handelt, will und kann ich diese nicht irgendwie speichern, heisst ich kann das gesamt Plot nicht rekonstruieren.

Jetzt ist die Frage, ob ihr vielleicht eine Idee für einen komplett anderen Ansatz habt unter der Maßgabe, dass es eben so viele Meßwerte sind?

Für das bisherige Kopfzerbrechen schonmal danke.

 
Blaster
20-04-2003, 18:52 
 
Mir sind jetzt so einige Sache nicht klar :dontknow: :

1) Warum gehst Du nicht über BufferedImage (java.awt.image.BufferedImage) und schenkst Dir die copyArea Geschichte und und implementierst Arbeits-Iterator, der Dir das aktuelle Signal anzeigt und dann erst drawed? Außerhalb der Bereiches setzt Du den Iterator wieder auf 0 (zurück) ;)

2) Soll die Oszillation eine stehende Welle anzeigen? Wenn ja, lass doch das drawImage routieren. So vermeidest Du auch ein Memory-Overflow und die Geschwindigkeit bleibt konstant.

3) Bei laufender Welle: Mein vorgeschlagen Polygon-Ansatz bringt einen Area -Begrenzung. Jeder Messpunkt ist eine Ecke. Der letzte Punkt wird auf der Nulllinie zurückgezeichnet.

4) Mit Bezierkurven sieht es noch schöner aus. Ist aber schwerer zu coden.

5) VolatileImage ?! :confused:

6) Für eine Rekonstruktion musst Du schon eine Persistenz einfügen.

</brain storming>

Blaster

 
graf
20-04-2003, 19:20 
 
hmm ..
zu 1.) damit weiß ich leider nicht viel anzufangen
zu 3.) ja, es ist eine laufende Welle.

und ich hab es bisher so gemacht, weil ich leider, leider noch nicht allzuviel mit Java gemacht habe und mir die meisten Basis-klassen bisher verschlossen geblieben sind.

Wenn es Dir nichts ausmachst ... könntest Du mir evtl. ein paar mehr Hinweise geben, wie Du die Sache mit den Polygonen oder Bezierkurven angedacht hast? Dann könnte ich ich damit näher beschäftigen.

 
Blaster
20-04-2003, 19:48 
 
Eigentlich bin ich gerade dabei die "Putzfrau-Sperrzonen" in meinen Büro sauber zu machen. Ist mega überfällig ... :D

http://java.sun.com/j2se/1.3/docs/guide/2d/spec/j2d-image.fm3.html

http://java.sun.com/j2se/1.3/search.html

Ja, ja! - Wer nicht mindests 3-4 Jahre Javaerfahrung hat und meint er könne Java .... (ich kann somit auch kein Java :D)

Vielleicht habe ich heute Abend ein bischen Zeit ... kommt darauf an wie es hier staubt ... :D

*huhst*

Blaster

 
graf
20-04-2003, 19:59 
 
Wäre toll, allerdings ist ab und zu aufräumen auch toll. :D

Ich lese derweil einfach mal.

 
Blaster
20-04-2003, 22:49 
 
So! - Kein Bock mehr ... :D

:teach:
zu 1) Ein BufferedImage repräsentiert ein Bild als rechteckiges Array von Pixeln in einen Raster-Objekt und einen ColorModel-Objekt, das die Pixelwerte des Raster-Obj interpretieren kann. Ein BuffererdImage speichert seine Daten jedoch immer im Speicher.

Nachdem ein BufferedImage-Obj erzeugt wurde, erhält man duch Aufruf von createGraphics() ein Graphics2D-Objekt, mit dem man in das Bild (z.B. Koordinatenlinien) zeichen kann (drawImage()) Ein B.I. - Obj kann bearbeitet werden, indem die filter() Methode eines beliebigen BufferedImageOp-Obj übergeben wird.

Schließlich können einzelne Pixel oder Pixelblöcke eines Bufferedimage mit getRGB() und setRGB() bearbeitet werden.

B.I. implementiert das Interface WritableRenderedImage, das seinerseits RenderImage implementiert. Dieses Interface wird in erster Linie vom Java-Advanced-Imaging-API (javax.jai.* [jdk 1.4] ) verwendet. Mit dessen Methoden kann ein Bild in mehrere rechteckige Kacheln zerlegt werden.
Die klasse B.I. definiert jedes Bild als eine einzelne Kachel, so dass diese Methode triviale Implementierungen besitzen.

Glossar:
Raster -Die Klasse repräsentiert ein rechteckiges Array von Pixeln. Das Raster besteht einen DataBuffer, der die "rohen" Pixeldaten enthält, und einen passenden SampleModel, mit dem die Pixeldaten aus dem DataBuffer extrahiert werden können.
Raster besitzt verschiedene methoden, um einzelne Pixel oder Pixelblöcke auszulesen. Es gibt jedoch keine Methode zu setzen, dazu muss die Unterklasse WritableRaster verwendet werden.

BufferImageOp - Die beschreibt eine Operation, die verschiedene B.I.-Obj verarbeiten kann. filter () bildet aus dem Source B.I. eine Destiantion Graphics2D
Für mehr Details siehe package java.awt.image.Bufferedimage
etc.
http://java.sun.com/j2se/1.3/docs/api/


Meine Idee war das B.I. , das deine aktuellen Messwerte enthält, in Pixelblöcken zerlegt wird z.B.:
x 0 1 2 3 4 5 6 ...
y 5 6 8 7 5 3 2 ...

Unter der Annahme, das x=6 der letzte Messwert ist, liegt der Iterator = 6;
U. d. A. einer rechtsläufigen Welle werden, dann die Blöcke:
x 6 5 4 3 2 1 in der Graphics2D gebildet.
Hat ein Block den Rand des Oszilloskops erreicht, kann x=0 überschieben werden, indem der Iterator = 0 wird. So bleibt der Heap und die Laufzeit konstant.

to be continue ... :cool:

 
Blaster
20-04-2003, 23:28 
 
zu 3) Die Klasse java.awt.Polygon definiert ein Array von Punkten(x,y). Diese können mit der Methode addPoint() angegeben werden. Sie können dann mit der Methode drawPolygon() von Graphics(2D) gezeichnet werden.

Meine Überlegung war den ersten und letzten Punkt als (0, x) auf der x-Achse zu verbinden. Dabei soll neue Punkte in (x=1,y) eingeführt werden und alle anderen werden eine Einheit nach rechts verschoben (x++, y) der Punkt (x=n-1,y) ist der Punkt wo das Polygon den Sichtbereich verlassen würden und der Punkt kann überschrieben werden.

Da die Ansicht von Polygonen etwas "eckig" ist, kam mir die Idee zu den Bezierkurven:

zu 4) Bezierkurven "glätten" das Krümmungsverhalten zwischen zwei Punkten, wie bei einen Kurvenlinial. Die Klasse
java.awt.geom.CubicCurve2D.* ist eine abstrakte Klasse eines java.awt.Shape-Obj, das eine glatte kubische Bezierkurve zwischen zwei Endpunkten p1(x1,y1) und P2 (x2,y2) repräsentiert. Die genaue Form der Kurve wird durch zwei Kontollpunkte cp1(cx1,cy1) und cp2 (cx2, cy2) definiert. Die konkreten Unterklassen lauten CubicCurve2D.Double bzw. .float

Für Details siehe wieder in die API-DOC.

zu 6) Wenn Du ein "ScreenShot" der B.I. speichern willst (zur Auswertung) , empfehle ich das graphics2D ein als JavaBean auszulagern.

So - Ich habe fertig :)

Noch frohe Ostern und dicke Eier! :D

Blaster

 
graf
20-04-2003, 23:58 
 
Wow,
normalerweise würde ich jetzt ein bis 16 Bier ausgeben. Also vielen Dank (erstmal?).
Ich werd's mir das ganze jetzt genau anschauen und sehen, wie ich es verwerten kann (versprochen, die Arbeit war nicht umsonst).
Vielleicht kann ich ja, wenns fertig ist, einen screenshot präsentieren.

PS: drawImage() ... ist das so rechenintensiv oder war es mein altes copyArea()?

 
goth
21-04-2003, 00:36 
 
Jau ... der ist schon Klasse ... der Blaster ... :teach:

 
Blaster
22-04-2003, 12:45 
 
Morjen!

Dir sollte klar sein, dass alles was ich spontan "aus dem Putzlappen geschüttelt habe", nicht gleich hoch optimiert ist.

copyArea() bildet wie der Name schon sagt eine runtime eine deep Copy der Bitmap zur Verarbeitung. Und das kostet Zeit, deshalb das arbeiten mit dem Iterator als "Pointer" (ich sagte doch ich bin chronischer Cpp-ler :D)

IMHO wird das ploten von Punkten und Linien und dem zugehörigen Überschreiben, die schnellste Variante sein. Wenn auch nicht die bequemste.

Was ist überhaupt schnell?! - Bei welchen CPU Takt? - 15ms sind in Java eigentlich nicht viel. Ich würde ein paar JUnit Testcase mehr implementieren und den Code auch ordentlich refaktoisieren.

cu

Blaster

 
graf
23-04-2003, 02:24 
 
So wirklich richtig verstehe ich ja nicht was du sagst ...

also was ich jetzt gemacht habe und was bis hierher auch recht gut funktioniert:
die messwerte kommen in ein array, die ich dann mit drawPolyline auf Graphics2D von dem BI zeichne. (eigentlich kommen sie in eine ArrayList aus der ich vor dem zeichnen ein array mache)
Bei jedem neuen Messwert, werden die werte im array 1 nach links verschoben (aus[1] wird [0] usw.)

Die Sachen mit dem DataSet etc. wollten nicht in meinen kleinen Kopf rein.

Mein Problem ist aber noch folgendes.
Das Image kommt auf Graphics von einem JPanel, das wiederum auf der ContentPane von einem JInternalFrame sitzt.
Die Klasse extends JinternalFrame und implements Runnable.
Das Zeichnen etc. läuft in run() ab.

Wenn der Thread nicht mehr läuft, und ich mache irgendwas an dem sch*** InternalFrame, dann is das BI weg, und egal was ich bisher auch angestellt habe bzgl. InternalFrameListener ... bis auf ein kurzes Flackern seh ich nie wieder was von dem Image

Vielleicht hast du dazu auch 'ne Idee? :confused:

 
graf
23-04-2003, 13:41 
 
Wenn ich einen AncestorListener nehme und bei ancestorMoved das Image neu zeichne, funktioniert es, wenn ich den InternalFrame verschiebe.
Bei den zusatzlichen InternalFrameListener, kann ich bei internalFrameDeactivated etc. das gleiche hinschrieben, das Resultat ist nur ein kurzes Flackern des Images, dann ist es auch schon wieder weg.

Beide Listener sind zu this (also einem InternalFrame geadded). Das kann's doch auch nicht sein, dass es einmal funktioniert und das andere mal nicht!?

 
Blaster
26-04-2003, 19:57 
 
Hi!

Sorry! - War jetzt ein paar Tage "auf Montage". :D

Original geschrieben von graf
So wirklich richtig verstehe ich ja nicht was du sagst ...
Was?! JUnit und Refaktorisierung?!
Oh, Sorry! - Naja, so "grün" scheinst Du ja nicht zu sein, deshalb hatte ich etwas "höher angelegt". :D
:teach:
JUnit - http://www.junit.org/index.htm

Um mehr darüber zu erfahren, wozu es gut ist:
www.andrena.de/Objektforum/Archiv/Download/2002-04-KA_TestFirstAnsatz.pdf
http://www.artima.com/intv/testdriven.html

Refactoring (Refaktorisierung):
Du kennst das sicher: Da hat man tagelang an eine Klasse gestrickt, die endlich genau die Funktionalität gewährleistet, die man haben wollte und schon muss den Code wieder auf den Kopf stellen, weil er schnell genug ist, schlecht strukturiert, völlig unübersichlich etc. Man schon hat schon fast "Angst davor" kritische Bereiche des Codes anzufassen. Rectoring beschreiben Techniken und Regeln wieder, wie man Schritt f. Schritt vom Ist-Zustand in den Sollzustand gelangt, ohne dass sich das äußere Verhalten deiner Klasse je ändert.
Wenn Dich das interessiert, in aktuellen OBJEKTspektrum Nr.3 2003 beschäftigt sich überwiegend mit, diesen Thema.
Warnung: Die Zeitschrift ist ziemlich anspruchsvoll, weil dei Autoren überwiegend "Großkampfkaliber" in der Softwareentwicklung sind:
http://www.sigs-datacom.de/sd/publications/os/index.htm
Es gibt auch ein Standardwerk dazu: http://www.refactoring.com/

Ich dachte einfach - 'Du kennst das alles' - weil mir die Laufzeit in ms angeben konntest.


Original geschrieben von graf
also was ich jetzt gemacht habe und was bis hierher auch recht gut funktioniert:
die messwerte kommen in ein array, die ich dann mit drawPolyline auf Graphics2D von dem BI zeichne. (eigentlich kommen sie in eine ArrayList aus der ich vor dem zeichnen ein array mache)
Bei jedem neuen Messwert, werden die werte im array 1 nach links verschoben (aus[1] wird [0] usw.)

Die Sachen mit dem DataSet etc. wollten nicht in meinen kleinen Kopf rein.

Macht nix .. hört sich doch ganz gut an.
Ich wollte mit Polygonen arbeiten, weil Du bei einen Oszilloskop nicht nur funktionale Linien hast, sondern auch z.B. Hysterese- oder Tesla-Schleifen.

Original geschrieben von graf
Mein Problem ist aber noch folgendes.
Das Image kommt auf Graphics von einem JPanel, das wiederum auf der ContentPane von einem JInternalFrame sitzt.
Die Klasse extends JinternalFrame und implements Runnable.
Das Zeichnen etc. läuft in run() ab.

Wenn der Thread nicht mehr läuft, und ich mache irgendwas an dem sch*** InternalFrame, dann is das BI weg, und egal was ich bisher auch angestellt habe bzgl. InternalFrameListener ... bis auf ein kurzes Flackern seh ich nie wieder was von dem Image

Vielleicht hast du dazu auch 'ne Idee? :confused:

Ja, man sollte hier die Anhängigkeiten erstmal klarstellen:
Graphics extends java.awt*;
BI extends java.awt.image.*;
JPanel extends javax.swing;
JInternalFrame extends JComponent (javax.swing) implements Accessible, RootPaneContainer, WindowConstants;

So - Swing erbt von AWT. Und jetzt gibst Du mit deiner Instanz von JInternalFrame extends Runnable einen eigenen Thread. D.h. die Verbindung über das JComponent wird nicht mehr synchroniziert. Die Gabrage löscht dann das ThreadObjekt deiner BI .
Die meisten Swing-Komponenten speichern Ihre Zustandsinformationen in einen Modellobjekt. Die Methoden, die dieses Zustandsobjekt steuern
implementieren müssen, sind in diversen Interfaces definiert, die Ihrerseits von diversen konkreten oder abstrakten Klassen implementiert werden.
(s. API-Doc)

Wenn Du jetzt neue Swing-Listener bildest und "den InternalFrame verschiebe" :confused: , bildest Du wieder ein Thread aus AWT (neue Instanz). Und nach einer kurzen Fummelre (Thread-Übergabe)i wir es wieder dunkel ... :D

cu

Blaster


Alle Zeitangaben in WEZ +2. Es ist jetzt 03:58 Uhr.