plectrum

Plectrum: instrument tuner for Android
Log | Files | Refs | README | LICENSE

PolynomialWavelets.java (8436B)


      1 package be.tarsos.dsp.wavelet.lift;
      2 
      3 /**
      4  * <p>
      5  * Polynomial wavelets
      6  * </p>
      7  * <p>
      8  * This wavelet transform uses a polynomial interpolation wavelet (e.g., the
      9  * function used to calculate the differences). A HaarWavelet scaling function
     10  * (the calculation of the average for the even points) is used.
     11  * </p>
     12  * <p>
     13  * This wavelet transform uses a two stage version of the lifting scheme. In the
     14  * "classic" two stage Lifting Scheme wavelet the predict stage preceeds the
     15  * update stage. Also, the algorithm is absolutely symetric, with only the
     16  * operators (usually addition and subtraction) interchanged.
     17  * </p>
     18  * <p>
     19  * The problem with the classic Lifting Scheme transform is that it can be
     20  * difficult to determine how to calculate the smoothing (scaling) function in
     21  * the update phase once the predict stage has altered the odd values. This
     22  * version of the wavelet transform calculates the update stage first and then
     23  * calculates the predict stage from the modified update values. In this case
     24  * the predict stage uses 4-point polynomial interpolation using even values
     25  * that result from the update stage.
     26  * </p>
     27  * 
     28  * <p>
     29  * In this version of the wavelet transform the update stage is no longer
     30  * perfectly symetric, since the forward and inverse transform equations differ
     31  * by more than an addition or subtraction operator. However, this version of
     32  * the transform produces a better result than the HaarWavelet transform
     33  * extended with a polynomial interpolation stage.
     34  * </p>
     35  * 
     36  * <p>
     37  * This algorithm was suggested to me from my reading of Wim Sweldens' tutorial
     38  * <i>Building Your Own Wavelets at Home</i>.
     39  * </p>
     40  * 
     41  * </p>
     42  * 
     43  * <pre>
     44  *   <a href="http://www.bearcave.com/misl/misl_tech/wavelets/lifting/index.html">
     45  *   http://www.bearcave.com/misl/misl_tech/wavelets/lifting/index.html</a>
     46  * </pre>
     47  * 
     48  * <h4>
     49  * Copyright and Use</h4>
     50  * 
     51  * <p>
     52  * You may use this source code without limitation and without fee as long as
     53  * you include:
     54  * </p>
     55  * <blockquote> This software was written and is copyrighted by Ian Kaplan, Bear
     56  * Products International, www.bearcave.com, 2001. </blockquote>
     57  * <p>
     58  * This software is provided "as is", without any warrenty or claim as to its
     59  * usefulness. Anyone who uses this source code uses it at their own risk. Nor
     60  * is any support provided by Ian Kaplan and Bear Products International.
     61  * <p>
     62  * Please send any bug fixes or suggested source changes to:
     63  * 
     64  * <pre>
     65  *      iank@bearcave.com
     66  * </pre>
     67  * 
     68  * @author Ian Kaplan
     69  */
     70 public class PolynomialWavelets extends LiftingSchemeBaseWavelet {
     71 	final static int numPts = 4;
     72 	private PolynomialInterpolation fourPt;
     73 
     74 	/**
     75 	 * PolynomialWavelets class constructor
     76 	 */
     77 	public PolynomialWavelets() {
     78 		fourPt = new PolynomialInterpolation();
     79 	}
     80 
     81 	/**
     82 	 * <p>
     83 	 * Copy four points or <i>N</i> (which ever is less) data points from
     84 	 * <i>vec</i> into <i>d</i> These points are the "known" points used in the
     85 	 * polynomial interpolation.
     86 	 * </p>
     87 	 * 
     88 	 * @param vec
     89 	 *            the input data set on which the wavelet is calculated
     90 	 * @param d
     91 	 *            an array into which <i>N</i> data points, starting at
     92 	 *            <i>start</i> are copied.
     93 	 * @param N
     94 	 *            the number of polynomial interpolation points
     95 	 * @param start
     96 	 *            the index in <i>vec</i> from which copying starts
     97 	 */
     98 	private void fill(float vec[], float d[], int N, int start) {
     99 		int n = numPts;
    100 		if (n > N)
    101 			n = N;
    102 		int end = start + n;
    103 		int j = 0;
    104 
    105 		for (int i = start; i < end; i++) {
    106 			d[j] = vec[i];
    107 			j++;
    108 		}
    109 	} // fill
    110 
    111 	/**
    112 	 * <p>
    113 	 * The update stage calculates the forward and inverse HaarWavelet scaling
    114 	 * functions. The forward HaarWavelet scaling function is simply the average
    115 	 * of the even and odd elements. The inverse function is found by simple
    116 	 * algebraic manipulation, solving for the even element given the average
    117 	 * and the odd element.
    118 	 * </p>
    119 	 * <p>
    120 	 * In this version of the wavelet transform the update stage preceeds the
    121 	 * predict stage in the forward transform. In the inverse transform the
    122 	 * predict stage preceeds the update stage, reversing the calculation on the
    123 	 * odd elements.
    124 	 * </p>
    125 	 */
    126 	protected void update(float[] vec, int N, int direction) {
    127 		int half = N >> 1;
    128 
    129 		for (int i = 0; i < half; i++) {
    130 			int j = i + half;
    131 			// double updateVal = vec[j] / 2.0;
    132 
    133 			if (direction == forward) {
    134 				vec[i] = (vec[i] + vec[j]) / 2;
    135 			} else if (direction == inverse) {
    136 				vec[i] = (2 * vec[i]) - vec[j];
    137 			} else {
    138 				System.out.println("update: bad direction value");
    139 			}
    140 		}
    141 	}
    142 
    143 	/**
    144 	 * <p>
    145 	 * Predict an odd point from the even points, using 4-point polynomial
    146 	 * interpolation.
    147 	 * </p>
    148 	 * <p>
    149 	 * The four points used in the polynomial interpolation are the even points.
    150 	 * We pretend that these four points are located at the x-coordinates
    151 	 * 0,1,2,3. The first odd point interpolated will be located between the
    152 	 * first and second even point, at 0.5. The next N-3 points are located at
    153 	 * 1.5 (in the middle of the four points). The last two points are located
    154 	 * at 2.5 and 3.5. For complete documentation see
    155 	 * </p>
    156 	 * 
    157 	 * <pre>
    158 	 *   <a href="http://www.bearcave.com/misl/misl_tech/wavelets/lifting/index.html">
    159 	 *   http://www.bearcave.com/misl/misl_tech/wavelets/lifting/index.html</a>
    160 	 * </pre>
    161 	 * 
    162 	 * <p>
    163 	 * The difference between the predicted (interpolated) value and the actual
    164 	 * odd value replaces the odd value in the forward transform.
    165 	 * </p>
    166 	 * 
    167 	 * <p>
    168 	 * As the recursive steps proceed, N will eventually be 4 and then 2. When N
    169 	 * = 4, linear interpolation is used. When N = 2, HaarWavelet interpolation
    170 	 * is used (the prediction for the odd value is that it is equal to the even
    171 	 * value).
    172 	 * </p>
    173 	 * 
    174 	 * @param vec
    175 	 *            the input data on which the forward or inverse transform is
    176 	 *            calculated.
    177 	 * @param N
    178 	 *            the area of vec over which the transform is calculated
    179 	 * @param direction
    180 	 *            forward or inverse transform
    181 	 */
    182 	protected void predict(float[] vec, int N, int direction) {
    183 		int half = N >> 1;
    184 		float d[] = new float[numPts];
    185 
    186 		// int k = 42;
    187 
    188 		for (int i = 0; i < half; i++) {
    189 			float predictVal;
    190 
    191 			if (i == 0) {
    192 				if (half == 1) {
    193 					// e.g., N == 2, and we use HaarWavelet interpolation
    194 					predictVal = vec[0];
    195 				} else {
    196 					fill(vec, d, N, 0);
    197 					predictVal = fourPt.interpPoint(0.5f, half, d);
    198 				}
    199 			} else if (i == 1) {
    200 				predictVal = fourPt.interpPoint(1.5f, half, d);
    201 			} else if (i == half - 2) {
    202 				predictVal = fourPt.interpPoint(2.5f, half, d);
    203 			} else if (i == half - 1) {
    204 				predictVal = fourPt.interpPoint(3.5f, half, d);
    205 			} else {
    206 				fill(vec, d, N, i - 1);
    207 				predictVal = fourPt.interpPoint(1.5f, half, d);
    208 			}
    209 
    210 			int j = i + half;
    211 			if (direction == forward) {
    212 				vec[j] = vec[j] - predictVal;
    213 			} else if (direction == inverse) {
    214 				vec[j] = vec[j] + predictVal;
    215 			} else {
    216 				System.out
    217 						.println("PolynomialWavelets::predict: bad direction value");
    218 			}
    219 		}
    220 	} // predict
    221 
    222 	/**
    223 	 * <p>
    224 	 * Polynomial wavelet lifting scheme transform.
    225 	 * </p>
    226 	 * <p>
    227 	 * This version of the forwardTrans function overrides the function in the
    228 	 * LiftingSchemeBaseWavelet base class. This function introduces an extra
    229 	 * polynomial interpolation stage at the end of the transform.
    230 	 * </p>
    231 	 */
    232 	public void forwardTrans(float[] vec) {
    233 		final int N = vec.length;
    234 
    235 		for (int n = N; n > 1; n = n >> 1) {
    236 			split(vec, n);
    237 			update(vec, n, forward);
    238 			predict(vec, n, forward);
    239 		} // for
    240 	} // forwardTrans
    241 
    242 	/**
    243 	 * <p>
    244 	 * Polynomial wavelet lifting Scheme inverse transform.
    245 	 * </p>
    246 	 * <p>
    247 	 * This version of the inverseTrans function overrides the function in the
    248 	 * LiftingSchemeBaseWavelet base class. This function introduces an inverse
    249 	 * polynomial interpolation stage at the start of the inverse transform.
    250 	 * </p>
    251 	 */
    252 	public void inverseTrans(float[] vec) {
    253 		final int N = vec.length;
    254 
    255 		for (int n = 2; n <= N; n = n << 1) {
    256 			predict(vec, n, inverse);
    257 			update(vec, n, inverse);
    258 			merge(vec, n);
    259 		}
    260 	} // inverseTrans
    261 
    262 } // PolynomialWavelets
    263