001 package util.wavelet;
002 import java.util.List;
003 import java.util.Collections;
004
005 /** A wrapper for an array of signal values and their coordinate.
006 * @author John Talbot
007 */
008 public class SignalAndCoordinate extends Signal {
009
010 /** Coordinates stored as a list permits the use of {@link Collections#binarySearch}. */
011 java.util.List<Float> coordinates;
012
013 /**
014 * Construct using the given signal array, noise array and coordinate positions.
015 *
016 * @param value signal value array
017 * @param noise the noise array
018 * @param noiseMultiplier noise multiplier (when sigmas = 3.0 confidence = 99.9 percent)
019 * @param coordinates x positions
020 */
021 public SignalAndCoordinate(float[] value, float[] noise, float noiseMultiplier, java.util.List<Float> coordinates) {
022 super(value, noise, noiseMultiplier);
023 this.coordinates = coordinates;
024 }
025
026 /**
027 * Get the x coordinate for the given position. The coordinate is read-only.
028 *
029 * @param position the position for which the coordinate is sought
030 * @return the x coordinate at the given position
031 */
032 public float getCoordinate(int position) {
033 return coordinates.get(position);
034 }
035
036 /*
037 * Get the interpolated or extrapolated signal value at the given coordinate.
038 *
039 * @param coordinate the coordinate (must be within range)
040 * @return the interpolated value at coordinate
041 */
042 public float getValueAtCoordinate(float coordinate) {
043 int position = Collections.binarySearch(coordinates, coordinate);
044 if (position >= 0 && position < size()) {
045 // TODO: second order approximation using float coordinate0 = getCoordinate(position-1);
046 float coordinate1 = getCoordinate(position);
047 float coordinate2 = getCoordinate(position + 1);
048 float value1 = getValue(position);
049 float value2 = getValue(position + 1);
050 if (coordinate1 == coordinate2) return value1; // pre-condition failure (should not happen) TODO: throw exception here
051 else return (value2 - value1) / (coordinate2 - coordinate1) / (coordinate - coordinate1) + value1;
052 } else { // out of range coordinate
053 if (position == -1)
054 return getValue(0); // TODO: extrapolation
055 else if (position == size())
056 return getValue(size() - 1); // TODO: extrapolation
057 else
058 return 0f; // should never happen
059 }
060 }
061 }