be.tarsos.dsp.wavelet.lift.LineWavelet Maven / Gradle / Ivy
package be.tarsos.dsp.wavelet.lift;
/**
*
* Line (with slope) wavelet
*
*
*
* The wavelet Lifting Scheme "LineWavelet" wavelet approximates the data set
* using a LineWavelet with with slope (in contrast to the HaarWavelet wavelet
* where a LineWavelet has zero slope is used to approximate the data).
*
*
*
* The predict stage of the LineWavelet wavelet "predicts" that an odd point
* will lie midway between its two neighboring even points. That is, that the
* odd point will lie on a LineWavelet between the two adjacent even points. The
* difference between this "prediction" and the actual odd value replaces the
* odd element.
*
*
*
* The update stage calculates the average of the odd and even element pairs,
* although the method is indirect, since the predict phase has over written the
* odd value.
*
*
*
* Copyright and Use
*
*
* You may use this source code without limitation and without fee as long as
* you include:
*
* This software was written and is copyrighted by Ian Kaplan, Bear
* Products International, www.bearcave.com, 2001.
*
* This software is provided "as is", without any warrenty or claim as to its
* usefulness. Anyone who uses this source code uses it at their own risk. Nor
* is any support provided by Ian Kaplan and Bear Products International.
*
* Please send any bug fixes or suggested source changes to:
*
*
* [email protected]
*
*
* @author Ian Kaplan
*/
public class LineWavelet extends LiftingSchemeBaseWavelet {
/**
*
* Calculate an extra "even" value for the LineWavelet wavelet algorithm at
* the end of the data series. Here we pretend that the last two values in
* the data series are at the x-axis coordinates 0 and 1, respectively. We
* then need to calculate the y-axis value at the x-axis coordinate 2. This
* point lies on a LineWavelet running through the points at 0 and 1.
*
*
* Given two points, x1, y1 and x2,
* y2, where
*
*
*
* x1 = 0
* x2 = 1
*
*
* calculate the point on the LineWavelet at x3, y3,
* where
*
*
*
* x3 = 2
*
*
* The "two-point equation" for a LineWavelet given x1,
* y1 and x2, y2 is
*
*
*
* . y2 - y1
* (y - y1) = -------- (x - x1)
* . x2 - x1
*
*
* Solving for y
*
*
*
* . y2 - y1
* y = -------- (x - x1) + y1
* . x2 - x1
*
*
* Since x1 = 0 and x2 = 1
*
*
*
* . y2 - y1
* y = -------- (x - 0) + y1
* . 1 - 0
*
*
* or
*
*
*
* y = (y2 - y1)*x + y1
*
*
* We're calculating the value at x3 = 2, so
*
*
*
* y = 2*y2 - 2*y1 + y1
*
*
* or
*
*
*
* y = 2*y2 - y1
*
*/
private float new_y(float y1, float y2) {
float y = 2 * y2 - y1;
return y;
}
/**
*
* Predict phase of LineWavelet Lifting Scheme wavelet
*
*
*
* The predict step attempts to "predict" the value of an odd element from
* the even elements. The difference between the prediction and the actual
* element is stored as a wavelet coefficient.
*
*
* The "predict" step takes place after the split step. The split step will
* move the odd elements (bj) to the second half of the array,
* leaving the even elements (ai) in the first half
*
*
*
* a0, a1, a1, a3, b0, b1, b2, b2,
*
*
* The predict step of the LineWavelet wavelet "predicts" that the odd
* element will be on a LineWavelet between two even elements.
*
*
*
* bj+1,i = bj,i - (aj,i + aj,i+1)/2
*
*
* Note that when we get to the end of the data series the odd element is
* the last element in the data series (remember, wavelet algorithms work on
* data series with 2n elements). Here we "predict" that the odd
* element will be on a LineWavelet that runs through the last two even
* elements. This can be calculated by assuming that the last two even
* elements are located at x-axis coordinates 0 and 1, respectively. The odd
* element will be at 2. The new_y() function is called to do this
* simple calculation.
*
*/
protected void predict(float[] vec, int N, int direction) {
int half = N >> 1;
float predictVal;
for (int i = 0; i < half; i++) {
int j = i + half;
if (i < half - 1) {
predictVal = (vec[i] + vec[i + 1]) / 2;
} else if (N == 2) {
predictVal = vec[0];
} else {
// calculate the last "odd" prediction
predictVal = new_y(vec[i - 1], vec[i]);
}
if (direction == forward) {
vec[j] = vec[j] - predictVal;
} else if (direction == inverse) {
vec[j] = vec[j] + predictVal;
} else {
System.out.println("predictline::predict: bad direction value");
}
}
} // predict
/**
*
* The predict phase works on the odd elements in the second half of the
* array. The update phase works on the even elements in the first half of
* the array. The update phase attempts to preserve the average. After the
* update phase is completed the average of the even elements should be
* approximately the same as the average of the input data set from the
* previous iteration. The result of the update phase becomes the input for
* the next iteration.
*
*
* In a HaarWavelet wavelet the average that replaces the even element is
* calculated as the average of the even element and its associated odd
* element (e.g., its odd neighbor before the split). This is not possible
* in the LineWavelet wavelet since the odd element has been replaced by the
* difference between the odd element and the mid-point of its two even
* neighbors. As a result, the odd element cannot be recovered.
*
*
* The value that is added to the even element to preserve the average is
* calculated by the equation shown below. This equation is given in Wim
* Sweldens' journal articles and his tutorial (Building Your Own
* Wavelets at Home) and in Ripples in Mathematics. A somewhat
* more complete derivation of this equation is provided in Ripples in
* Mathematics by A. Jensen and A. la Cour-Harbo, Springer, 2001.
*
*
* The equation used to calculate the average is shown below for a given
* iteratin i. Note that the predict phase has already completed, so
* the odd values belong to iteration i+1.
*
*
*
* eveni+1,j = eveni,j op (oddi+1,k-1 + oddi+1,k)/4
*
*
* There is an edge problem here, when i = 0 and k = N/2 (e.g., there is no
* k-1 element). We assume that the oddi+1,k-1 is the same as
* oddk. So for the first element this becomes
*
*
* (2 * oddk)/4
*
*
* or
*
*
*
* oddk/2
*
*/
protected void update(float[] vec, int N, int direction) {
int half = N >> 1;
for (int i = 0; i < half; i++) {
int j = i + half;
float val;
if (i == 0) {
val = vec[j] / 2.0f;
} else {
val = (vec[j - 1] + vec[j]) / 4.0f;
}
if (direction == forward) {
vec[i] = vec[i] + val;
} else if (direction == inverse) {
vec[i] = vec[i] - val;
} else {
System.out.println("update: bad direction value");
}
} // for
}
} // LineWavelet