Click here to Skip to main content
15,883,954 members
Articles / Web Development / HTML

Continuous Wavelet Transforms, a Java Implementation

Rate me:
Please Sign up or sign in to vote.
4.31/5 (5 votes)
7 Mar 2015CPOL12 min read 29.8K   1.3K   10  
This article presents a Java example application that performs continuous wavelet transforms.
/**
 * Author Mark Bishop; 2014
 * License GNU v3; 
 * This class is free software: you can redistribute it and/or modify
    it under the terms of the GNU General Public License as published by
    the Free Software Foundation, either version 3 of the License, or
    (at your option) any later version.

    This program is distributed in the hope that it will be useful,
    but WITHOUT ANY WARRANTY; without even the implied warranty of
    MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
    GNU General Public License for more details.

    You should have received a copy of the GNU General Public License
    along with this program.  If not, see <http://www.gnu.org/licenses/>.
 */

import java.util.Random;

/**
 * Class responsibility: Provide examples of certain signals, some of which are
 * not analytic. All public members return xy as a double[][] such that xy[0] =
 * x and xy[1] = y. X is computed on [min:max] in increments dx = (max - min +
 * 1) / (count);
 */

public class Examples {

	/**
	 * An impulse at x = nearly 0, elsewhere 0. Min, max, and count must be chosen so
	 * that x = 0 +/- dt occurs in the sequence, eg., min = -8, max = 7, count = 16
	 * produces a sequence that includes x = 0 at x[8]
	 */
	public static double[][] delta(double min, double max, int count) {
		double dt = Signal.dxFromCountRange(max, min, count);
		double[][] xy = new double[2][count];
		double x = min;
		for (int i = 0; i < count; i++) {
			xy[0][i] = x;
			if (x<dt/2&&x>-dt/2) {
				xy[1][i] = 1.0;
			}
			x += dt;
		}
		return xy;
	}

	public static double[][] triangle(double t0, double A, double min,
			double max, int count) {
		double dx = Signal.dxFromCountRange(max, min, count);
		double[][] xy = new double[2][count];
		double slope = -A * A / (-2 * t0);
		double x = min;
		for (int i = 0; i < count; i++) {
			if (x > -2 * t0 && x < 2 * t0) {
				if (x < 0) {
					xy[1][i] = slope * x+A*A;
				} else {
					xy[1][i] = -slope * x+A*A;
				}
			} else {
				xy[1][i] = 0;
			}
			xy[0][i] = x;
			x += dx;
		}
		return xy;
	}
	
	public static double[][] box(double t0, double A, double min,
			double max, int count) {
		double dx = Signal.dxFromCountRange(max, min, count);
		double[][] xy = new double[2][count];		
		double x = min;
		for (int i = 0; i < count; i++) {
			if (x > -t0 && x < t0) {				
					xy[1][i] = A;
				
			} else {
				xy[1][i] = 0;
			}
			xy[0][i] = x;
			x += dx;
		}
		return xy;
	}


	public static double[][] chirp(double min, double max, int count) {
		double dx = Signal.dxFromCountRange(max, min, count);
		double[][] xy = new double[2][count];
		double x = min;
		for (int i = 0; i < count; i++) {
			xy[0][i] = x;
			xy[1][i] = Math.sin(10 * x * x);
			x += dx;
		}
		return xy;
	}

	/**
	 * To show the impulses; min, max, and count must be chosen such that there
	 * will exist x values where x[i] mod T = 0.
	 * 
	 * @param min
	 * @param max
	 * @param count
	 * @param T
	 *            the interval between impulses
	 * @return An impulse whenever x mod T = 0, elsewhere 0.
	 */
	public static double[][] shah(double min, double max, int count, int T) {
		double[][] xy = new double[2][count];
		double x = min;
		double dx = Signal.dxFromCountRange(max, min, count);
		for (int i = 0; i < count; i++) {
			xy[0][i] = x;
			if (Math.abs(xy[0][i] % T) < dx) {
				xy[1][i] = 1.0;
			}
			x += dx;
		}
		return xy;
	}

	/**
	 * Gaussian modified mixed sinusoids. Gaussian centered at 0 with stdev =
	 * 128, sinusoids = sin(x) +sin(x/64)
	 */
	public static double[][] gaussModSin(double min, double max, int count) {
		double[][] xy = new double[2][count];
		double mean = 0.0;
		double stdev = 128;
		String function = "(1/(pow(2*pi,0.5)*" + stdev + "))*exp(-pow((" + mean
				+ "-x),2)/(2*pow(" + stdev + ",2)))";
		xy = new Signal(min, max, count, function, Signal.RangeOption.MinMax).xy;
		double dx = Signal.dxFromCountRange(max, min, count);
		double x = min;
		for (int i = 0; i < count; i++) {
			double y = 0.2 * Math.sin(x) + Math.sin(x / 64);
			xy[1][i] *= y;
			x += dx;
		}
		return xy;
	}

	public static double[][] gaussian(double mean, double stdev, double min,
			double max, int count) {
		double[][] xy = new double[2][count];
		String function = "(1/(pow(2*pi,0.5)*" + stdev + "))*exp(-pow((" + mean
				+ "-x),2)/(2*pow(" + stdev + ",2)))";
		xy = new Signal(min, max, count, function, Signal.RangeOption.MinMax).xy;
		return xy;
	}

	public static double[][] gaussianDerivative(double mean, double stdev,
			double min, double max, int count, int m) {
		double[][] xy = new double[2][count];
		double[][] gauss = gaussian(mean, stdev, min, max, count);
		double[] x = gauss[0];
		int n = x.length;
		double f1 = Math.pow(-1, m + 1);
		double gamma = 1 / Gamma.gamma(m + .5);
		double hermite = 0;
		for (int i = 0; i < n; i++) {
			hermite = Hermite.probabilistHermitePoly(m, x[i] / (stdev));
			xy[1][i] = f1 * gamma * hermite * gauss[1][i] / Math.exp(m * m);

		}
		xy[0] = x;
		return xy;
	}

	/**
	 * n = 1024, x[0] = 0, x[n-1] = 40 Sinusoidal frequencies at 1.4, 1/2, and
	 * 1/9. However, but y is momentarily forced to zero at x[459], producing a
	 * singularity.
	 */
	public static double[][] signalDropout() {
		double min = 0;
		double max = 40;
		int count = 1024;
		double[] freq = new double[] { 1.4, 0.5, 1.0 / 3.0 };
		double[][] xy = new double[2][count];
		String function = "sin(2*pi*" + freq[0] + "*x)+sin(2*pi*" + freq[1]
				+ "*x)+0.3*sin(2*pi*" + freq[2] + "*x)";
		xy = new Signal(min, max, count, function, Signal.RangeOption.MinMax).xy;
		xy[1][459] = 0;
		return xy;
	}

	/**
	 * Devil's staircase
	 * 
	 * @param min
	 *            prefer 0
	 * @param max
	 *            prefer 1
	 * @param count
	 * @return Cantor function
	 */
	public static double[][] cantor(double min, double max, int count) {
		double[][] xy = new double[2][count];
		double dx = Signal.dxFromCountRange(max, min, count);
		double x = min;
		for (int i = 0; i < count; i++) {
			xy[0][i] = x;
			x += dx;
		}
		xy[1] = cantorFn(xy[0]);
		return xy;
	}

	/**
	 * Singular everywhere.
	 * 
	 * @param min
	 * @param max
	 * @param count
	 * @return a random sequence.
	 */
	public static double[][] random(double min, double max, int count) {
		Random r = new Random();
		double[][] xy = new double[2][count];
		double dx = Signal.dxFromCountRange(max, min, count);
		double x = min;
		for (int i = 0; i < count; i++) {
			xy[0][i] = x;
			x += dx;
			xy[1][i] = r.nextDouble();
		}
		return xy;
	}

	/**
	 * Notes for the following methods: In string representations of fractional
	 * values in bases other than 10, a colon (:) is used instead of a decimal
	 * point. All methods target positive bases only.
	 */

	/**
	 * Compute the Cantor function using a method of typographic substitution.
	 * 
	 * @param x
	 *            sequence for x axis
	 * @return
	 */
	private static double[] cantorFn(double[] x) {
		int n = x.length;
		double[] y = new double[n];
		String one = "1";
		String zero = "0";
		String point = ":";
		boolean isNegative = false;
		for (int i = 0; i < n; i++) {
			double base10 = x[i];
			// Express in base 3.
			String strB3 = base10ToBase(base10, 8, 3);
			if (strB3.contains("-")) {
				isNegative = true;
				strB3 = strB3.replaceFirst("-", "");
			} else {
				isNegative = false;
			}
			char[] charB3 = strB3.toCharArray();
			int l = charB3.length;
			boolean isFirst1 = true;
			for (int j = 0; j < l; j++) {
				// If it contains a 1, replace every digit after the first 1 by
				// 0.
				if (charB3[j] == one.charAt(0) && isFirst1) {
					isFirst1 = false;
					continue;
				} else if (!isFirst1 && charB3[j] != point.charAt(0)) {
					charB3[j] = zero.charAt(0);
				}
			}
			String strTransit = new String(charB3);
			// Replace all 2s with 1s
			strTransit = strTransit.replaceAll("2", "1");
			// Interpret the result as a binary number.
			y[i] = baseToBase10(strTransit, 2);
			if (isNegative) {
				y[i] *= -1.0;
			}
		}
		return y;
	}

	/**
	 * @return x Using the first "precision" places to the right of the decimal,
	 *         express x in base = newBase
	 */
	private static String base10ToBase(double x, int precision, int newBase) {
		String result = "";
		if (x < 0) {
			result += "-";
		}
		int characteristic = (int) x;
		char[] cCharacteristic = toBase((int) Math.abs(x), newBase);
		result += (new String(cCharacteristic) + ":");
		// discard digits below precision
		double mantissa = Math
				.abs((int) (Math.pow(10, precision) * (x - characteristic))
						/ Math.pow(10, precision));
		double interimProduct = mantissa;
		for (int i = 0; i < precision; i++) {
			double nextProduct = interimProduct * newBase;
			if ((int) nextProduct < 10) {
				result += (int) nextProduct;
			} else {
				result += Integer.toString((int) nextProduct, newBase);
			}
			interimProduct = nextProduct - (int) nextProduct;
		}
		return result.trim();
	}

	private static double baseToBase10(String strB2, int initialBase) {
		boolean isNegative = false;
		if (strB2.contains("-")) {
			isNegative = true;
			strB2 = strB2.replaceFirst("-", "");
		}
		double b10 = 0;
		String[] split = strB2.split(":");
		int characteristic = Integer.valueOf(split[0], initialBase);
		b10 += characteristic;
		if (split.length > 1) {
			char[] mantissa = split[1].toCharArray();
			int n = mantissa.length;
			for (int i = 0; i < n; i++) {
				double d = (double) (Character.getNumericValue(mantissa[i]));
				if (d != 0) {
					b10 += d * Math.pow(initialBase, -(i + 1));
				}
			}
		}
		if (isNegative) {
			b10 *= -1.0;
		}
		return b10;
	}

	/**
	 * Integers only.
	 * 
	 * @param x
	 *            an integer in base 10
	 * @param base
	 *            the base in which to re-express x
	 * @return x in base as a character array
	 */
	private static char[] toBase(int x, int base) {
		String strB = Integer.toString(x, base);
		char[] charB = strB.toCharArray();
		return charB;
	}

}

By viewing downloads associated with this article you agree to the Terms of Service and the article's licence.

If a file you wish to view isn't highlighted, and is a text file (not binary), please let us know and we'll add colourisation support for it.

License

This article, along with any associated source code and files, is licensed under The Code Project Open License (CPOL)


Written By
Founder PEI Watershed Alliance, Inc.
United States United States
I am an analytical chemist and an educator. I program primarily to perform matrix computations for regression analysis, process signals, acquire data from sensors, and to control devices.

I participate in many open source development communities and Linux user forums. I do contract work for an environmental analytical laboratory, where I am primarily focused on LIMS programming and network administration.

I am a member of several community-interest groups such as the Prince Edward Island Watershed Alliance, the Lot 11 and Area Watershed Management Group, and the Petersham Historic Commission.

Comments and Discussions