Click here to Skip to main content
15,884,962 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 gnu.jel.CompilationException;
import gnu.jel.CompiledExpression;
import gnu.jel.Evaluator;
import gnu.jel.Library;

import java.awt.Color;

/**
 * 
 * * Class responsibility: Provide a container for xy data and methods for
 * creating xy data sets. Also provide ways to plot and/or tabulate the values.
 * * A few public static methods for determining minima and maxima of sequence
 * arrays are also included. *
 */

public class Signal {

	double[][] xy;
	String function;
	XYForm dataForm;
	Color color;
	int pointSize;

	/**
	 * Construct using sequential x and y data.
	 * 
	 * @param x
	 * @param y
	 */
	public Signal(double[] x, double[] y) {
		int n = x.length;
		xy = new double[2][n];
		for (int i = 0; i < n; i++) {
			xy[0][i] = x[i];
			xy[1][i] = y[i];
		}
	}

	public Signal(double[] x, double[] y, String title) {
		int n = x.length;
		xy = new double[2][n];
		for (int i = 0; i < n; i++) {
			xy[0][i] = x[i];
			xy[1][i] = y[i];
		}
		this.function = title;
	}

	/**
	 * Alternative constructor that takes both x and y in one array object
	 * 
	 * @param xy
	 *            a double[][] such that: x = xy[0] and y = xy[1]
	 */
	public Signal(double[][] xy) {
		this.xy = xy;
	}

	/**
	 * Alternative constructor that takes both x and y in one array object and
	 * also takes a String that may be used as a label or in a subsequent JEL
	 * compilation. *
	 * 
	 * @param xy
	 *            a double[][] such that: x = xy[0] and y = xy[1]
	 * @param name
	 *            a label or JEL expression for subsequent use.
	 */
	public Signal(double[][] xy, String name) {
		this.xy = xy;
		this.function = name;
	}

	/**
	 * Alternative constructor for computing sequential xy data conditionally at
	 * run time. X data is computed using parameter values of either: {x
	 * minimum, x maximum, signal length} or {x minimum, delta x, signal length}
	 * 
	 * @param xMin
	 *            Starting (lowest) value for range (x).
	 * @param rangeParameter
	 *            Interpreted as x maximum when rangeOption is MinMax and as
	 *            delta x when rangeOption is Incremental
	 * @param length
	 *            total number of values
	 * @param function
	 *            A JEL compatible String representing the expression used to
	 *            compute y = f(x) For example, 2*sin(x)
	 * @param rangeOption
	 *            either RangeOption.MinMax or RangeOption.Incremental
	 */
	public Signal(double xMin, double rangeParameter, int length,
			String function, RangeOption rangeOption) {
		this.function = function;
		if (rangeOption == RangeOption.MinMax) {
			double dx = dxFromCountRange(rangeParameter, xMin, length);
			createXY(xMin, dx, length);
		} else {
			double xMax = rangeParameter;
			createXY(xMin, xMax, length);
		}
	}

	public double[][] getXY() {
		return xy;
	}

	public double[] getX() {
		return xy[0];
	}

	public double[] getY() {
		return xy[1];
	}

	public int count() {
		return xy[0].length;
	}

	public void plot(Color color, int pointSize) {
		if (xy != null) {
			this.color = color;
			this.pointSize = pointSize;
			PlotFrame plot = new PlotFrame(600, 600, 10);
			plot.formTitle = function;
			plot.pointSize = pointSize;
			plot.addSinglePlot(xy[0], xy[1], color, function);
		}
	}

	public void createTable() {
		dataForm = new XYForm(xy = MatrixOps.transpose(xy), function, 0);
	}

	/**
	 * Call samplingFunction() to create x = xy[0] and use JEL to determine y =
	 * xy[1]
	 * 
	 * @param xMin
	 * @param dx
	 * @param length
	 */
	private void createXY(double xMin, double dx, int length) {
		xy = new double[2][];
		xy[0] = xSamplingFunction(xMin, dx, length);
		try {
			xy[1] = compileExpression(xy[0], function);
		} catch (CompilationException e) {
			e.printStackTrace();
		}
	}

	/**
	 * Populate x using range parameters.
	 * 
	 * @param xMin
	 * @param dx
	 *            delta x
	 * @param count
	 * @return
	 */
	public static double[] xSamplingFunction(double xMin, double dx, int count) {
		int n = count;
		double[] x = new double[n];
		double element = xMin;
		for (int i = 0; i < n; i++) {
			x[i] = element;
			element += dx;
		}
		return x;
	}

	/**
	 * This method provides the interface to JEL. "x" is used as the variable
	 * here but it may refer to "t" from the calling function
	 * 
	 * @see "JEL Documentation at GNU Project"
	 * @param x
	 *            vector containing x values
	 * @param expr
	 *            String representation of function e.g. sin(2*pi*16*x)
	 * @return a vector containing the f(x) values
	 * @throws CompilationException
	 */
	public static double[] compileExpression(double[] x, String expr)
			throws CompilationException {
		if (!(expr.contains("x") || expr.contains("t"))) {
			expr = "(0.0*x)+(" + expr + ")";
		}
		int n = x.length;
		double[] fX = new double[n];
		// Set up class for Java Math namespace
		@SuppressWarnings("rawtypes")
		Class[] staticLib = new Class[1];
		try {
			staticLib[0] = Class.forName("java.lang.Math");
		} catch (ClassNotFoundException e) {
			System.out.print("1");
		}
		// Setup class for variables
		@SuppressWarnings("rawtypes")
		Class[] dynamicLib = new Class[1];
		VariableProvider variables = new VariableProvider();
		Object[] context = new Object[1];
		context[0] = variables;
		dynamicLib[0] = variables.getClass();
		Library lib = new Library(staticLib, dynamicLib, null, null, null);
		// // Commented because we have stateless members
		// // See http://www.gnu.org/software/jel/api/index.html
		// try {
		// lib.markStateDependent("random", null);
		// } catch (Exception e) {
		// System.out.print("1");
		// }
		CompiledExpression expr_c = null;
		try {
			expr_c = Evaluator.compile(expr, lib);
		} catch (CompilationException ce) {
			System.err.print("--- COMPILATION ERROR :");
			System.err.println(ce.getMessage());
			System.err.print("                       ");
			System.err.println(expr);
			int column = ce.getColumn(); // Column, where error was found
			for (int i = 0; i < column + 23 - 1; i++)
				System.err.print(' ');
			System.err.println('^');
		}
		if (expr != null) {
			try {
				for (int i = 0; i < n; i++) {
					variables.xvar = x[i]; // Value of the variable
					fX[i] = (double) expr_c.evaluate(context);
				}
			} catch (Throwable e) {
				System.err.println("Exception emerged from JEL compiled"
						+ " code (IT'S OK) :"); // Konstantin's message
				System.err.print(e);
			}
		}
		return fX;
	}

	/**
	 * This method provides the interface to JEL. "x" is used as the variable
	 * here but it may refer to "t" from the calling function
	 * 
	 * @see "JEL Documentation at GNU Project"
	 * @param x
	 *            vector containing x values
	 * @param expr
	 *            String representation of function e.g. sin(2*pi*16*x)
	 * @return f(x) where f is defined by expr
	 * @throws CompilationException
	 */
	public static double compileExpression(double x, String expr)
			throws CompilationException {
		if (!(expr.contains("x") || expr.contains("t"))) {
			expr = "(0.0*x)+(" + expr + ")";
		}
		double fX = 0;
		// Set up class for Java Math namespace
		@SuppressWarnings("rawtypes")
		Class[] staticLib = new Class[1];
		try {
			staticLib[0] = Class.forName("java.lang.Math");
		} catch (ClassNotFoundException e) {
			System.out.print("1");
		}
		// Setup class for variables
		@SuppressWarnings("rawtypes")
		Class[] dynamicLib = new Class[1];
		VariableProvider variables = new VariableProvider();
		Object[] context = new Object[1];
		context[0] = variables;
		dynamicLib[0] = variables.getClass();
		Library lib = new Library(staticLib, dynamicLib, null, null, null);
		// // Commented because we have stateless members
		// // See http://www.gnu.org/software/jel/api/index.html
		// try {
		// lib.markStateDependent("random", null);
		// } catch (Exception e) {
		// System.out.print("1");
		// }
		CompiledExpression expr_c = null;
		try {
			expr_c = Evaluator.compile(expr, lib);
		} catch (CompilationException ce) {
			System.err.print("--- COMPILATION ERROR :");
			System.err.println(ce.getMessage());
			System.err.print("                       ");
			System.err.println(expr);
			int column = ce.getColumn(); // Column, where error was found
			for (int i = 0; i < column + 23 - 1; i++)
				System.err.print(' ');
			System.err.println('^');
		}
		if (expr != null) {
			try {
				variables.xvar = x;
				fX = (double) expr_c.evaluate(context);

			} catch (Throwable e) {
				System.err.println("Exception emerged from JEL compiled"
						+ " code (IT'S OK) :"); // Konstantin's message
				System.err.print(e);
			}
		}
		return fX;
	}

	public static double dxFromCountRange(double max, double min, int count) {
		double dCount = (double) count;
		double dx = (max - min) / (dCount - 1.0);
		return dx;
	}

	public static void plotComplex(ComplexNumber[][] cmplxXy) {
		if (cmplxXy != null) {
			double[][][] plots = new double[3][2][];
			double[] yReal = MatrixOps.getRealPart(cmplxXy[1]);
			double[] yImaginary = MatrixOps.getImaginaryPart(cmplxXy[1]);
			double[] modulus = MatrixOps.modulus(cmplxXy[1]);
			plots[0][0] = plots[1][0] = plots[2][0] = MatrixOps.getRealPart(cmplxXy[0]);
  			plots[0][1] = yReal;
			plots[1][1] = yImaginary;
			plots[2][1] = modulus;
			Color[] clrs = new Color[3];
			clrs[0] = Color.blue;
			clrs[1] = Color.red;
			clrs[2] = Color.black;
			String[] labels = new String[3];
			labels[0] = "real";
			labels[1] = "imaginary";
			labels[2] = "modulus";
			PlotFrame pf = new PlotFrame(600, 600, 8);
			pf.addMultiplePlots(plots, clrs, labels);
		}
	}

	/**
	 * 
	 * @param xMin
	 *            Lower domain value for x or t
	 * @param xMax
	 *            Upper domain value for x or t
	 * @param dx
	 *            Sampling increment
	 * @return double[] sampled domain x or t = {xMin, xMin + dx, xMin + 2dx, ..
	 *         xt(n)} where xMax <= xt(n) >= xMax - dx
	 */
	public static double[] samplingFunction(double xMin, double xMax, double dx) {
		int n = (int) Math.floor((xMax - xMin) / dx);
		double[] x = new double[n + 1];
		double element = xMin;
		for (int i = 0; i <= n; i++) {
			x[i] = element;
			element += dx;
		}
		return x;
	}

	public static enum RangeOption implements Runnable {
		Incremental {
			@Override
			public void run() {
				isMinMax(false);
			}
		},
		MinMax {
			@Override
			public void run() {
				isMinMax(true);
			}
		};
		private static boolean isMinMax(boolean value) {
			return value;
		}
	}

}

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