/**************************************************************************** Copyright (c) 2005, Colorado School of Mines and others. All rights reserved. This program and accompanying materials are made available under the terms of the Common Public License - v1.0, which accompanies this distribution, and is available at http://www.eclipse.org/legal/cpl-v10.html ****************************************************************************/ package edu.mines.jtk.dsp; import edu.mines.jtk.util.Cdouble; import edu.mines.jtk.util.Check; import static edu.mines.jtk.util.ArrayMath.isRegular; /** * Recursive 2nd-order filter. This filter solves a linear, 2nd-order, * constant-coefficient difference equation in either forward or reverse * directions along any dimension of a 1-D, 2-D, or 3-D array. *

* Application of the filter in the forward direction computes *

 * y[i] = b0*x[i]+b1*x[i-1]+b2*x[i-2]-a1*y[i-1]-a2*y[i-2],
 * 
* for i = 0, 1, 2, ..., n-1, where x[i] = y[i] = 0 for i<0. * Application of the filter in the reverse direction computes *
 * y[i] = b0*x[i]+b1*x[i+1]+b2*x[i+2]-a1*y[i+1]-a2*y[i+2],
 * 
* for i = n-1, n-2, ..., 0, where x[i] = y[i] = 0 for i>=n. * @author Dave Hale, Colorado School of Mines * @version 2005.11.22 */ public class Recursive2ndOrderFilter { /** * Constructs a recursive 2nd-order filter with specified coefficients. * If some of the coefficients are zero, the filter may be of only 1st * or even 0th order. * @param b0 a filter coefficient. * @param b1 a filter coefficient. * @param b2 a filter coefficient. * @param a1 a filter coefficient. * @param a2 a filter coefficient. */ public Recursive2ndOrderFilter( float b0, float b1, float b2, float a1, float a2) { _b0 = b0; _b1 = b1; _b2 = b2; _a1 = a1; _a2 = a2; } /** * Constructs a recursive 2nd-order filter from pole, zero, and gain. * This filter is actually a 1st-order filter, because it has only * one (real) pole and zero. * @param pole the pole. * @param zero the zero. * @param gain the filter gain. */ public Recursive2ndOrderFilter(double pole, double zero, double gain) { _b0 = (float)(gain); _b1 = (float)(-gain*zero); _a1 = (float)(-pole); } /** * Constructs a recursive 2nd-order filter from poles, zeros, and gain. * The poles must be real or conjugate pairs; likewise for the zeros. * @param pole1 the 1st pole. * @param pole2 the 2nd pole. * @param zero1 the 1st zero. * @param zero2 the 2nd zero. * @param gain the filter gain. */ public Recursive2ndOrderFilter( Cdouble pole1, Cdouble pole2, Cdouble zero1, Cdouble zero2, double gain) { Check.argument(pole1.i==0.0 && pole2.i==0.0 || pole2.r==pole1.r && -pole2.i==pole1.i, "poles are real or conjugate pair"); Check.argument(zero1.i==0.0 && zero2.i==0.0 || zero2.r==zero1.r && -zero2.i==zero1.i, "zeros are real or conjugate pair"); _b0 = (float)(gain); _b1 = (float)(-(zero1.r+zero2.r)*gain); _b2 = (float)((zero1.times(zero2)).r*gain); _a1 = (float)(-(pole1.r+pole2.r)); _a2 = (float)((pole1.times(pole2)).r); } /** * Applies this filter in the forward direction. *

* Input and output arrays may be the same array, but must have equal * lengths. * @param x the input array. * @param y the output array. */ public void applyForward(float[] x, float[] y) { checkArrays(x,y); int n = y.length; // Special case b1 = b2 = a2 = 0. if (_b1==0.0f && _b2==0.0f && _a2==0.0f) { float yim1 = 0.0f; for (int i=0; i * Input and output arrays may be the same array, but must have equal * lengths. * @param x the input array. * @param y the output array. */ public void applyReverse(float[] x, float[] y) { checkArrays(x,y); int n = y.length; // Special case b1 = b2 = a2 = 0. if (_b1==0.0f && _b2==0.0f && _a2==0.0f) { float yip1 = 0.0f; for (int i=n-1; i>=0; --i) { float xi = x[i]; float yi = _b0*xi-_a1*yip1; y[i] = yi; yip1 = yi; } } // Special case b2 = a2 = 0. else if (_b2==0.0f && _a2==0.0f) { float xip1 = 0.0f; float yip1 = 0.0f; for (int i=n-1; i>=0; --i) { float xi = x[i]; float yi = _b0*xi+_b1*xip1-_a1*yip1; y[i] = yi; yip1 = yi; xip1 = xi; } } // Special case b2 = 0. else if (_b2==0.0f) { float xip1 = 0.0f; float yip1 = 0.0f; float yip2 = 0.0f; for (int i=n-1; i>=0; --i) { float xi = x[i]; float yi = _b0*xi+_b1*xip1-_a1*yip1-_a2*yip2; y[i] = yi; yip2 = yip1; yip1 = yi; xip1 = xi; } } // Special case b0 = 0. else if (_b0==0.0f) { float xip1 = 0.0f; float xip2 = 0.0f; float yip1 = 0.0f; float yip2 = 0.0f; for (int i=n-1; i>=0; --i) { float xi = x[i]; float yi = _b1*xip1+_b2*xip2-_a1*yip1-_a2*yip2; y[i] = yi; yip2 = yip1; yip1 = yi; xip2 = xip1; xip1 = xi; } } // General case. else { float xip1 = 0.0f; float xip2 = 0.0f; float yip1 = 0.0f; float yip2 = 0.0f; for (int i=n-1; i>=0; --i) { float xi = x[i]; float yi = _b0*xi+_b1*xip1+_b2*xip2-_a1*yip1-_a2*yip2; y[i] = yi; yip2 = yip1; yip1 = yi; xip2 = xip1; xip1 = xi; } } } /** * Applies this filter in the forward direction, accumulating the output. * This method filters the input, and adds the result to the output; it * is most useful when implementing parallel forms of recursive filters. *

* Input and output arrays may be the same array, but must have equal * lengths. * @param x the input array. * @param y the output array. */ public void accumulateForward(float[] x, float[] y) { checkArrays(x,y); int n = y.length; // Special case b1 = b2 = a2 = 0. if (_b1==0.0f && _b2==0.0f && _a2==0.0f) { float yim1 = 0.0f; for (int i=0; i * Input and output arrays may be the same array, but must have equal * lengths. * @param x the input array. * @param y the output array. */ public void accumulateReverse(float[] x, float[] y) { checkArrays(x,y); int n = y.length; // Special case b1 = b2 = a2 = 0. if (_b1==0.0f && _b2==0.0f && _a2==0.0f) { float yip1 = 0.0f; for (int i=n-1; i>=0; --i) { float xi = x[i]; float yi = _b0*xi-_a1*yip1; y[i] += yi; yip1 = yi; } } // Special case b2 = a2 = 0. else if (_b2==0.0f && _a2==0.0f) { float xip1 = 0.0f; float yip1 = 0.0f; for (int i=n-1; i>=0; --i) { float xi = x[i]; float yi = _b0*xi+_b1*xip1-_a1*yip1; y[i] += yi; yip1 = yi; xip1 = xi; } } // Special case b2 = 0. else if (_b2==0.0f) { float xip1 = 0.0f; float yip1 = 0.0f; float yip2 = 0.0f; for (int i=n-1; i>=0; --i) { float xi = x[i]; float yi = _b0*xi+_b1*xip1-_a1*yip1-_a2*yip2; y[i] += yi; yip2 = yip1; yip1 = yi; xip1 = xi; } } // Special case b0 = 0. else if (_b0==0.0f) { float xip1 = 0.0f; float xip2 = 0.0f; float yip1 = 0.0f; float yip2 = 0.0f; for (int i=n-1; i>=0; --i) { float xi = x[i]; float yi = _b1*xip1+_b2*xip2-_a1*yip1-_a2*yip2; y[i] += yi; yip2 = yip1; yip1 = yi; xip2 = xip1; xip1 = xi; } } // General case. else { float xip1 = 0.0f; float xip2 = 0.0f; float yip1 = 0.0f; float yip2 = 0.0f; for (int i=n-1; i>=0; --i) { float xi = x[i]; float yi = _b0*xi+_b1*xip1+_b2*xip2-_a1*yip1-_a2*yip2; y[i] += yi; yip2 = yip1; yip1 = yi; xip2 = xip1; xip1 = xi; } } } /////////////////////////////////////////////////////////////////////////// // 2-D /** * Applies this filter in 1st dimension in the forward direction. *

* Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void apply1Forward(float[][] x, float[][] y) { checkArrays(x,y); int n2 = y.length; for (int i2=0; i2 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void apply1Reverse(float[][] x, float[][] y) { checkArrays(x,y); int n2 = y.length; for (int i2=0; i2 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void apply2Forward(float[][] x, float[][] y) { checkArrays(x,y); int n2 = y.length; int n1 = y[0].length; // Special case b1 = b2 = a2 = 0. if (_b1==0.0f && _b2==0.0f && _a2==0.0f) { float[] yim1 = new float[n1]; for (int i2=0; i2 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void apply2Reverse(float[][] x, float[][] y) { checkArrays(x,y); int n2 = y.length; int n1 = y[0].length; // Special case b1 = b2 = a2 = 0. if (_b1==0.0f && _b2==0.0f && _a2==0.0f) { float[] yip1 = new float[n1]; for (int i2=n2-1; i2>=0; --i2) { float[] xi = x[i2]; float[] yi = y[i2]; for (int i1=0; i1=0; --i2) { float[] x2 = x[i2]; float[] yi = y[i2]; for (int i1=0; i1=0; --i2) { float[] x2 = x[i2]; float[] yi = y[i2]; for (int i1=0; i1=0; --i2) { float[] x2 = x[i2]; float[] yi = y[i2]; for (int i1=0; i1=0; --i2) { float[] x2 = x[i2]; float[] yi = y[i2]; for (int i1=0; i1 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void accumulate1Forward(float[][] x, float[][] y) { checkArrays(x,y); int n2 = y.length; for (int i2=0; i2 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void accumulate1Reverse(float[][] x, float[][] y) { checkArrays(x,y); int n2 = y.length; for (int i2=0; i2 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void accumulate2Forward(float[][] x, float[][] y) { checkArrays(x,y); int n2 = y.length; int n1 = y[0].length; // Special case b1 = b2 = a2 = 0. if (_b1==0.0f && _b2==0.0f && _a2==0.0f) { float[] yim1 = new float[n1]; float[] yi = new float[n1]; for (int i2=0; i2 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void accumulate2Reverse(float[][] x, float[][] y) { checkArrays(x,y); int n2 = y.length; int n1 = y[0].length; // Special case b1 = b2 = a2 = 0. if (_b1==0.0f && _b2==0.0f && _a2==0.0f) { float[] yip1 = new float[n1]; float[] yi = new float[n1]; for (int i2=n2-1; i2>=0; --i2) { float[] xi = x[i2]; float[] y2 = y[i2]; for (int i1=0; i1=0; --i2) { float[] x2 = x[i2]; float[] y2 = y[i2]; for (int i1=0; i1=0; --i2) { float[] x2 = x[i2]; float[] y2 = y[i2]; for (int i1=0; i1=0; --i2) { float[] x2 = x[i2]; float[] y2 = y[i2]; for (int i1=0; i1=0; --i2) { float[] x2 = x[i2]; float[] y2 = y[i2]; for (int i1=0; i1 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void apply1Forward(float[][][] x, float[][][] y) { checkArrays(x,y); int n3 = y.length; for (int i3=0; i3 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void apply1Reverse(float[][][] x, float[][][] y) { checkArrays(x,y); int n3 = y.length; for (int i3=0; i3 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void apply2Forward(float[][][] x, float[][][] y) { checkArrays(x,y); int n3 = y.length; for (int i3=0; i3 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void apply2Reverse(float[][][] x, float[][][] y) { checkArrays(x,y); int n3 = y.length; for (int i3=0; i3 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void apply3Forward(float[][][] x, float[][][] y) { checkArrays(x,y); int n3 = y.length; int n2 = y[0].length; int n1 = y[0][0].length; float[][] xy = new float[n3][n1]; for (int i2=0; i2 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void apply3Reverse(float[][][] x, float[][][] y) { checkArrays(x,y); int n3 = y.length; int n2 = y[0].length; int n1 = y[0][0].length; float[][] xy = new float[n3][n1]; for (int i2=0; i2 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void accumulate1Forward(float[][][] x, float[][][] y) { checkArrays(x,y); int n3 = y.length; for (int i3=0; i3 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void accumulate1Reverse(float[][][] x, float[][][] y) { checkArrays(x,y); int n3 = y.length; for (int i3=0; i3 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void accumulate2Forward(float[][][] x, float[][][] y) { checkArrays(x,y); int n3 = y.length; for (int i3=0; i3 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void accumulate2Reverse(float[][][] x, float[][][] y) { checkArrays(x,y); int n3 = y.length; for (int i3=0; i3 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void accumulate3Forward(float[][][] x, float[][][] y) { checkArrays(x,y); int n3 = y.length; int n2 = y[0].length; int n1 = y[0][0].length; float[][] xy = new float[n3][n1]; for (int i2=0; i2 * Input and output arrays may be the same array, but must be * regular and have equal lengths. * @param x the input array. * @param y the output array. */ public void accumulate3Reverse(float[][][] x, float[][][] y) { checkArrays(x,y); int n3 = y.length; int n2 = y[0].length; int n1 = y[0][0].length; float[][] xy = new float[n3][n1]; for (int i2=0; i2