In the previous section, we created
classes that allowed histograms to become the source and destination
for streams. Here we look at classes that filter data streams on
their way to histograms. (See Chapter
9: Java : Sources, Destinations, and Filters for a discussion
of stream filtering.)
The class HistFilterOutputStream
extends FilterOutputStream
and overrides the method write(int
datum). (See the source code below.) Via the constructor
it obtains an instance of HistogramOutputStream
obtained from StreamedHistPanel.
The write method carries out the calibration operation on the datum
value before writing it to the HistogramOutputStream.
We create the program HistFilterStreamApplet.java
that adds an instance of a FilterOutputStream
subclass to the stream going to the histogram. The job of this filter
is to "calibrate" the data as it streams through the filter.
The demonstration program below follows closely to that of the previous
Histogram Stream demo except
that the filter acts on the simulated sensor data to remove the
effects of pedestal and response slopes that differ from channel
to channel.
The applet below shows three StreamedHistPanel
displays with the histograms at the top using uncalibrated data
as in the previous demo. The three
histograms below these show data streamed through instances of HistFilterOutputStream
that use the calibration constants for the corresponding sensor
channel.
HistFilterStreamApplet.java
-
This applet/application resembles HistStreamApplet
but adds 3 extra StreamedHistPanels whose input streams
are each wrapped by a HistFilterOutputStream. These
panels (shown in the bottom row) display data for the
same 3 sensors (shown in the top row) but calibrated
by the HistFilterOutputStream.
+ New classes:
HistFilterOutputStream.java
-
Wraps an OutputStream and overrides the write(int datum)
method.
The write method makes a slope and pedestal correction
to the data value and then writes it to the OutputStream.
+
Previous classes:
Chapter
9:Tech: MakeSensorData.java,
StreamedHistPanel.java
Chapter
6:Tech: Histogram.java,
HistPanel.java
Chapter
6:Tech: PlotPanel.java,
PlotFormat.java
|
/**
* This filter class wraps an OutputStream,
assumed to be
* an instance of StreamedHistPanel,
and "calibrates" the
* data by removing the effects of the
hardware slope and
* pedestal variations.
* For this demonstration, only the
write (int b) method is
* overridden. Also, the full 4 bytes
of the integer argument
* are used rather than only the lower
byte as usual.
**/
import java.io.*;
public class HistFilterOutputStream extends FilterOutputStream
{
double fSlope = 0.0, fPedestal = 0.0;
/**
* @param out the wrapped stream.
* @param slope calibration constant
for the sensor response.
* @param pedestal calibration offset
for the sensor.
**/
public HistFilterOutputStream (OutputStream out,
double slope,
double pedestal) {
super (out);
fSlope = slope;
fPedestal = pedestal;
} // ctor
/**
* Override the write (int b) method
but use the full integer value
* rather than only the lowest byte
as usual with this method.
* Carryout the calibration and then
write the resulting value as
* an integer to the output stream.
**/
public void write (int b) {
double val = ((double)b)/100.0;
int ival = (int) (100.0 * ((val -
fPedestal)/fSlope));
try {
out.write (ival);
} catch (IOException ioe) {}
} // write
// Not overrriding the other write methods in
FilterOutputStream.
} // class HistFilterOutputStream |
import
javax.swing.*;
import java.awt.*;
import java.awt.event.*;
import java.io.*;
/**
* This applet/application closely resembles HistStream_JApplet11
but
* 3 extra StreamedHistPanels are added. These
will hold data for the
* same 3 sensors but after the data is calibrated
by instances of
* HistFilterOutputStream, which wrap StreamedHistPanel
streams.
**/
public class HistFilterStreamApplet extends JApplet
implements ActionListener, Updateable
{
final static int NUM_HISTS = 3;
// Histograms for the panels.
Histogram [] fHistogram = new Histogram[2*NUM_HISTS];
// The HistPanel subclass that accept data streams.
StreamedHistPanel [] fHistPanel = new StreamedHistPanel[2*NUM_HISTS];
// Create a panel to hold the histogram sub-panels
JPanel fHistsPanel = null;
// Array of treams to the panels
OutputStream [] fDataOut = new OutputStream[2*NUM_HISTS];
// Constants for three channels of sensor data
plus
// the copies of the channels for calibration.
double [] fSlope = {0.6,
1.2, 1.1, 0.6, 1.2, 1.1};
double [] fPedestal = {2.4, 1.3, 3.4, 2.4, 1.3,
3.4};
int fNumDataPoints = 100;
boolean fMakingHist =
false;
boolean fUpdateDisplay = false;
MakeSensorData fMakeData = null;
// Use the java.util Timer and TimerTask combo
// for timing events.
java.util.Timer fTimer = null;
// A text field for input strings
JTextField fTextField = null;
// Flag for whether the applet is in a browser
// or running via the main () below.
boolean fInBrowser=true;
//Buttons
JButton fGoButton = null;
JButton fClearButton = null;
JButton fExitButton = null;
public void init () {
Container content_pane = getContentPane
();
JPanel panel = new JPanel (new BorderLayout
());
// Use a textfield for an input parameter.
fTextField =
new JTextField (Integer.toString
(fNumDataPoints), 10);
// If return hit after entering text,
the
// actionPerformed will be invoked.
fTextField.addActionListener (this);
fGoButton = new JButton ("Go");
fGoButton.addActionListener (this);
fClearButton = new JButton ("Clear");
fClearButton.addActionListener (this);
fExitButton = new JButton ("Exit");
fExitButton.addActionListener (this);
JPanel control_panel = new JPanel
();
control_panel.add (fTextField);
control_panel.add (fGoButton);
control_panel.add (fClearButton);
control_panel.add (fExitButton);
// Create a panel to hold the histogram
sub-panels
fHistsPanel = new JPanel (new GridLayout
(2,3));
// Create the HistPanels and their
histograms.
for (int i=0; i < NUM_HISTS; i++) {
fHistogram[i]
= new Histogram ("Sensor "+i,
"Data",
25,0.0,10.0);
fHistPanel[i]
= new StreamedHistPanel (fHistogram[i]);
// Add the
histogram panels to the container panel
fHistsPanel.add
(fHistPanel[i]);
// Get the
output streams for each panel.
fDataOut[i]
= fHistPanel[i].getOutputStream ();
}
// Create the HistPanels for the calibrated
sensor histograms.
for (int i=0; i < NUM_HISTS; i++)
{
fHistogram[i+NUM_HISTS]
= new Histogram (" Calibrated Sensor "+i,
"Data",
25,0.0,10.0);
fHistPanel[i+NUM_HISTS]
=
new
StreamedHistPanel (fHistogram[i+NUM_HISTS]);
// Add the
histogram panels to the container panel
fHistsPanel.add
(fHistPanel[i+NUM_HISTS]);
// Get the
output streams for each panel and wrap them in
// a filter
that will calibrate the stream data.
fDataOut[i+NUM_HISTS]
=
new
HistFilterOutputStream (
fHistPanel[i+NUM_HISTS].getOutputStream
(),
fSlope[i],fPedestal[i]);
}
makeHist ();
fGoButton.setText ("Stop");
fClearButton.setEnabled (false);
if (fInBrowser) fExitButton.setEnabled
(false);
panel.add (fHistsPanel,BorderLayout.CENTER);
panel.add (control_panel,BorderLayout.SOUTH);
// Add text area with scrolling to
the contentPane.
content_pane.add (panel);
} // init
/** Stop the filling if the browser page unloaded.
**/
public void stop ()
{
fGoButton.setText ("Go");
fClearButton.setEnabled (true);
fMakingHist = false;
} // stop
public void actionPerformed (ActionEvent e) {
Object source = e.getSource ();
if (source == fGoButton || source
== fTextField) {
String strNumDataPoints
= fTextField.getText ();
try {
fNumDataPoints
= Integer.parseInt (strNumDataPoints);
}
catch (NumberFormatException
ex) {
// Could open
an error dialog here but just
// display
a message on the browser status line.
showStatus
("Bad input value");
return;
}
if (!fMakingHist) {
makeHist ();
fGoButton.setText
("Stop");
fClearButton.setEnabled
(false);
} else {
// Stop button
has been pushed
stop ();
}
} else if (source == fClearButton) {
for (int i=0;
i < 2*NUM_HISTS; i++)
{
fHistogram[i].clear ();}
repaint ();
} else if (!fInBrowser)
System.exit
(0);
} // actionPerformed
/** Create the histogram and the timers. **/
void makeHist () {
// only allow for one data maker at
a time.
if (fMakingHist) return;
fMakingHist = true;
// Create the runnable object to fill
the histograms
// The data will simualte sensors
that return data with
// slightly different slopes and pedestals.
// The maximum delay between data
readings will be 500msecs.
fMakeData =
new MakeSensorData (this,
fDataOut, fNumDataPoints,
fSlope, fPedestal, 500);
Thread data_thread = new Thread (fMakeData);
// Before starting the filling, create
the timer task
// that will cause the histogram display
to update
// during the filling.
// Create a timer. TimerTask created
in MakeHist ()
fTimer = new java.util.Timer ();
// Start the timer after 100ms and
then repeat calls
// to run in PaintHistTask object
every 250ms.
fTimer.schedule (new PaintHistTask
(), 100, 250);
// Now start the data filling.
data_thread.start ();
return;
} // makeHist
/**
* Use the inner class technique to
define the
* TimerTask subclass for signalling
that the display
* should be updated.
**/
class PaintHistTask extends java.util.TimerTask
{
public void run () {
fUpdateDisplay = true;
}
} // class PaintHistTask
/**
* Repaint the histogram
display and turn off the
* update display flag.
Return the makingHist flag
* to indicate if updating
should continue.
**/
public boolean update (Object obj) {
// Don't update the display until
the timer
// turns on the updateDisplay flag.
if ( fUpdateDisplay) {
// Possible this method
called before outputPanel
// created in the init
(). So check if it exists
// before attempting to
repaint.
if (fHistsPanel != null)
fHistsPanel.repaint ();
fUpdateDisplay = false;
}
return fMakingHist;
} // update
/** Called when the histogram filling is finished.
**/
public void done () {
fMakingHist = false;
// Stop the histogram display updates.
fTimer.cancel ();
// Update one last time
fHistsPanel.repaint ();
// Reset the buttons.
fGoButton.setText ("Go");
fClearButton.setEnabled (true);
} // done
public static void main (String[] args) {
int frame_width=500;
int frame_height=600;
HistFilterStreamApplet applet = new
HistFilterStreamApplet ();
applet.fInBrowser = false;
applet.init ();
// Following anonymous class used
to close window & exit program
JFrame f = new JFrame ("Demo");
f.setDefaultCloseOperation (JFrame.EXIT_ON_CLOSE);
// Add applet to the frame
f.getContentPane ().add ( applet);
f.setSize (new Dimension (frame_width,frame_height));
f.setVisible (true);
} // main
} // class HistFilterStreamApplet |
References & Web
Resources
Latest update: Nov. 14, 2004
|