[Passband] a useful self-contained model?
David Berry
dsb at ast.man.ac.uk
Tue Jun 8 08:28:08 PDT 2004
Martin,
> > A passband is basically a recipe for transforming an input scalar
> > value (a spectral axis value) into an output scalar value (transmission).
> > Now we have the general purpose Mapping model which can be used to
> > describe such numerical transformations, so why not use a Mapping as a
> > component of a passband? Compound passbands are then simply catered for by
> > using a SeriesMap/CompositeMap as the Mapping.
> (snip)
>
> Ah, that's different :-) My feeling is that the DM group models what we need to
> know, and *only* what we *need* to know. If implementors decide that they want
> to create a passband out of Frames and Mappings that's fine; but if someone
> wants to implement it using a graph, or a formulae, or a simple central fravergy
> + width, then that should be fine too.
Mappings are a generalisation of graphs, formula, simple central values,
etc. All these things are forms of Mappings (a Mapping is anything which
takes in one or more input values and returns one or more output values).
If we say that a PassBand simply aggregates a Mapping plus a SpecFrame
then you cover yourself for any strange future Mappings which people may
want to use in a PassBand. Your current definition of a PassBand
effectively restricts PasssBands to using a specific list of Mapping types.
Another consequence of this approach is that it requires a whole new
subclass if someone wants to use a Mapping which you havn't thought of.
> If you would like to model a Passband built from Frames & Mappings (but
> conforming to the Passband interface) I would be very interested.
To illustrate my ideas I have knocked together a quick Java implementation
of PassBand based on the JNI interface to the Starlink AST library
(serialisation not yet included). The JavaDocs are at:
http://www.starlink.ac.uk/~dsb/VOpassband/
and the code is at:
http://www.starlink.ac.uk/~dsb/VOpassband/PassBand.java
It compliles and runs and passes the simple tests in the "main" method. I
have based it on the current contents of your PassBand page, but I have
taken a few liberties:
1) Some trivial names changed (e.g. "passrate" goes to "transmission")
2) My API is neutral about the spectral system in use, so I have changed
Max/MinWavelength to Max/MinSpec. The calls indicates what spectral system
they want to use by invoking the modifySpecFrame method on the PassBand.
3) There is only a single PassBand class, instead of having many different
subclasses for simple, graph, formula, chained, etc. All these types are
modelled in the same way - as a Mapping and a Frame - but each type has a
dedicated PassBand constructor.
4) I have also done away with the idea of the Photon and Wave classes.
Instead, each PassBand expects input spectral values in a user-specified
spectral system which may be changed at any time by invoking the
modifySpecFrame method. This means that arrays of primitives can be used
instead of arrays of Objects to hold the spectral positions.
To illustrate these points, the following is the "main" method from
PassBand.java which performs some simple tests of the PassBand class
(n.b. I happen to like left justified code comments!):
public static void main( String[] args ) {
System.out.println( "\nTesting class PassBand..." );
/* Create a simple top hat passband which has a transmission value of 1.0 between
* 100 and 200 microns. Retain the SpecFrame defaults for other attributes
* such as standard of rest (default is heliocentric) source position,
* observer position, etc. These are not needed for the current illustrative
* purpose, but could be set if required. */
PassBand pb1 = new PassBand( "unit=um", 100, 200 );
/* Create a "graph" passband which has a varying transmission value between
* 1666666.67 and 4333333.33 MHz (topocentric frequency). Again, retain
* the SpecFrame defaults for other attributes such as source position,
* observer position, etc. The "lut" array holds the transmission values. */
double[] lut = new double[] { 0.2, 0.4, 0.5, 0.35, 0.15, 0.05 };
PassBand pb2 = new PassBand( "system=freq,unit=MHz,stdofrest=topo", lut,
2.16666667E6, 0.333333E6 );
/* Combine these two PassBands into a "chained" PassBand. The spectral system
* of the resulting PassBand is inherited from pb1. Note, pb2 uses a different
* spectral system to pb1, but this difference is taken into account by
* this constructor when selecting corresponding transmission values from
* each PassBand. */
PassBand pb3 = new PassBand( pb1, pb2 );
/* Check that the upper and lower limits of this chained Passband are correct. */
assert Math.abs( pb3.getMaxSpec() - 149.8815486516362 ) < 0.000001 : "Failure 1";
assert Math.abs( pb3.getMinSpec() - 100.0 ) < 0.000001 : "Failure 2";
assert Math.abs( pb3.getCentralSpec() - 127.89938699346865 ) < 0.000001 : "Failure 3";
/* Check the transmission value at 160 um is zero, and at 138.3522 um (the heliocentric
* wavelenth corresponding to centre of the first bin in the pb2 graph) is 0.2. */
double[] trans = pb3.getTransmission( new double[] { 160.0, 138.3522 } );
assert trans[ 0 ] == 0.0 : "Failure 4";
assert Math.abs( trans[ 1 ] - 0.2 ) < 0.000001 : "Failure 5";
/* Create a "formula" passband based on an algebraic expression. Use heliocentric
* energy in eV as the spectral system. */
PassBand pb4 = new PassBand( "system=energy,unit=eV", "y=1.0-0.25E12*(x-1.0E-5)**2",
0.9E-5, 1.2E-5 );
/* Modify the PassBand to use heliocentric frequency in Hz. This re-maps
the transmission values to take account of the change in spectral system. */
pb4.modifySpecFrame( "system=freq,unit=Hz" );
/* Check that the upper and lower limits of the modified Passband are at the correct
* frequencies. */
assert Math.abs( pb4.getMaxSpec() - 2901586008.18841 ) < 0.01 : "Failure 6";
assert Math.abs( pb4.getMinSpec() - 2176189506.1413 ) < 0.01 : "Failure 7";
assert Math.abs( pb4.getCentralSpec() - 2538887757.1648 ) < 0.01 : "Failure 8";
/* Check the transmission value at 3000000000 Hz is zero, and at 2417988340.15701
* Hz (the frequency at the centre of the parabolic transmission curve) is 1.0. */
trans = pb4.getTransmission( new double[] { 3.0E9, 2.41798834015701E9 } );
assert trans[ 0 ] == 0.0 : "Failure 9";
assert Math.abs( trans[ 1 ] - 1.0 ) < 0.000001 : "Failure 10";
/* All tests done. */
System.out.println( "Testing complete." );
}
David
----------------------------------------------------------------------
Dr David S. Berry (dsb at ast.man.ac.uk)
STARLINK project | Centre for Astrophysics
(http://www.starlink.ac.uk/) | University of Central Lancashire
Rutherford Appleton Laboratory | PRESTON
DIDCOT | United Kingdom
United Kingdom | PR1 2HE
OX11 0QX Tel. 01772 893733
01257 273192
More information about the dm
mailing list