Package gov.sns.tools.dsp

Source Code of gov.sns.tools.dsp.DigitalFilter

/**
*
*/
package gov.sns.tools.dsp;

import gov.sns.tools.collections.FixedSizeBuffer;
import JSci.maths.Complex;


/**
* <p>
* Implements the fundamental behavior and characteristics of a
* Linear, Time-Invariant (LTI) digital
* filter of finite order with real coefficients.  Child classes can
* implement methods for
* determining the filter coefficients for desired bandwidth and other
* transfer characteristics (i.e., Butterworth, Chebychev, etc.).  Once the
* filter coefficients are determined this class contains most of the
* common behavior of a general digital filter.
* </p>
* <p>
* The transfer characteristics for an <i>N</i><sup>th</sup> order digital
* filter are given by the following:
* <br>
* <br>&nbsp;&nbsp;  <i>b</i><sub>0</sub>y<sub>n</sub></i>
*                 + <i>b</i><sub>1</sub><i>y<sub>n</i>-1</sub>
*                 + &hellip;
*                 + <i>b<sub>N</sub></i><i>y<sub>n-N</i></sub>
*                 = <i>a</i><sub>0</sub>x<sub>n</sub></i>
*                 + <i>a</i><sub>1</sub><i>x<sub>n</i>-1</sub>
*                 + &hellip;
*                 + <i>a<sub>N</sub></i><i>x<sub>n-N</i></sub>
*                 <br>
* <br>
* where <i>n</i> is the current ("time") index, the {<i>x<sub>k</sub></i>} are the
* inputs to the filter at time <i>k</i>, the {<i>a<sub>k</sub></i>} are the input
* coefficients, the {<i>y<sub>k</sub></i>} are the filter outputs at time <i>k</i>,
* and the {<i>b<sub>k</sub></i>} are the output coefficients.  The equation can be
* rearranged to explicitly demonstrate the current output <i>y<sub>n</sub></i> in terms
* of the past <i>N</i> inputs and output
* <br>
* <br>&nbsp;&nbsp;  <i>y<sub>n</sub></i> 
*                 = (
*                 <i>a</i><sub>0</sub>x<sub>n</sub></i>
*                 + <i>a</i><sub>1</sub><i>x<sub>n</i>-1</sub>
*                 + &hellip;
*                 + <i>a<sub>N</sub></i><i>x<sub>n-N</i></sub>
*                 - <i>b</i><sub>1</sub><i>y<sub>n</i>-1</sub>
*                 - &hellip;
*                 - <i>b<sub>N</sub></i><i>y<sub>n-N</i></sub>
*                 )/<i>b</i><sub>0</sub>
*                 <br>
* <br>
* Note that the coefficient <i>b</i><sub>0</sub> is essentially just an attenuation/amplification
* factor.  (In fact, a zeroth-order digital filter is just that.)  The current class initializes
* itself with the value <i>b</i><sub>0</sub> = 1.0.  This case
* is the only nonzero initial value for the input and output coefficients and is done simply to
* avoid a filter without any response. 
* </p>
* <p>
* Taking the <i>Z</i> transform of the above equations yields the transfer function
* <i>H</i>(<i>z</i>)
* where <i>z</i> is the transform variable (whose domain is the unit circle in the complex
* plane).  The transfer function has the general form
* <br>&nbsp;&nbsp;
*                  <table>
*                    <tr>
*                      <td/>
*                      <td>
*                          <i>a</i><sub>0</sub>
*                        + <i>a</i><sub>1</sub><i>z</i><sup>-1</sup>
*                        + &hellip;
*                        + <i>a<sub>N</sub></i><i>z</i><sup>-N</sup>
*                      </td>
*                    </tr>
*                    <tr>
*                      <td> <i>H</i>(<i>z</i>) = </td>
*                      <td>-------------------------</td>
*                    </tr>
*                    <tr>
*                      <td/>
*                      <td>
*                          <i>b</i><sub>0</sub>
*                        + <i>b</i><sub>1</sub><i>z</i><sup>-1</sup>
*                        + &hellip;
*                        + <i>b<sub>N</sub></i><i>z</i><sup>-N</sup>
*                      </td>
*                    </tr>
*                  </table>
* Clearly then the filter is linear.  Note that for the Discrete Fourier Transform (DFT)
* and the frequencies <i>&nu;</i> = 1,&hellip;,<i>&Nu;</i>-1 the transform variable is equal
* to <i>z<sub>&nu;</sub> = <i>e</i><sup><i>i</i>2<i>&pi;&nu;</i>/<i>&Nu;</sup>.
* </p>
*
* @author Christopher K. Allen
*
* @deprecated
*/
public class DigitalFilter {

    /*
     * Local Attributes
     */
  
    /** filter order */
    private int             intOrder;
   
    /** size of the coefficient arrays (order + 1) */
    private int             szArray;
   
    /** the current output index */
    private int             cntOut;
   
    /** input signal coefficients */
    private double[]        arrCoefInp;
   
    /** output signal coefficients */
    private double[]        arrCoefOut;
   
    /** input signal buffer */
    private FixedSizeBuffer<Double> bufInput;
   
    /** output signal buffer */
    private FixedSizeBuffer<Double> bufOutput;
   
   
   
   
    /*
     * Initialization
     */
   
    /**
     * Create a new filter object for processing discrete functions (i.e.,
     * objects of type <code>double[]</code>).
     *
     * @param intOrder  filter order
     */
    public DigitalFilter(int intOrder)   {
        this.initialize(intOrder);
    }
   
   
    /**
     * Sets an output signal coefficient.  Note that since an index
     * of zero represents the current output it is an inverse scaling
     * value.
     *
     * @param   index   delay index of the coefficient
     * @param   dblVal  coefficient value
     *
     * @throws IndexOutOfBoundsException     index outside interval [0,Order]
     */
    public void setOutputCoefficient(int index, double dblVal) throws IndexOutOfBoundsException {
        this.checkIndex(index);
        this.arrCoefOut[index] = dblVal;
    }
   
    /**
     * Sets an input signal coefficient. 
     *
     * @param index     delay index of the coefficient
     * @param dblVal    coefficient value
     *
     * @throws IllegalArgumentException index outside interval [0,Order]
     */
    public void setInputCoefficient(int index, double dblVal) throws IllegalArgumentException {
        this.checkIndex(index);
        this.arrCoefInp[index] = dblVal;
    }
   
   
    /**
     * Attribute Query
     */
   
    /**
     * Returns the order of the digital filter.
     *
     * @return      filter order
     */
    public int  getOrder()  {
        return this.intOrder;
    }
   
    /**
     * Returns the size of the coefficient arrays.  This values is one larger
     * than the filter order.
     *
     * @return  size of coefficient arrays (i.e., DigitalFilter#getOrder() + 1)
     */
    public int getCoefficientSize()   {
        return this.szArray;
    }
   
    /**
     * Return the value of the current output index.  This value is the number
     * of signal values processed (by a call to {@link DigitalFilter#response(double)})
     * since the last call to {@link DigitalFilter#reset()}.
     * After calling <code>reset()</code> the returned index is zero.  Thus, after
     * calling <code>response(double)</code> for the first time the returned value is 1.
     *
     * @return  the current signal index ("time" index)
     *
     * @see DigitalFilter#reset()
     * @see DigitalFilter#response(double)
     */
    public int  getOutputIndex()    {
        return this.cntOut;
    }
   
    /**
     * Operations
     */
   
   
    /**
     * <p>
     * Compute and return the response of the filter to the given
     * input.  The returned response is assumed to be part of a
     * train of values with depends upon the previous inputs to
     * this method.  The number of previous input values to which
     * the output depends is given by the order of this filter.
     * </p>
     * <p>
     * To begin processing a new input signal train the method
     * <code>DigitalFilter.{@link #reset()} should be called.
     * </p>
     *
     * @param dblInput  current input signal
     *
     * @return          response of this filter to the given signal
     *
     * @see DigitalFilter#reset()
     * @see DigitalFilter#getOrder()
     */
    public double   response(double dblInput) {
       
        int     index;              // current coefficient array index
        double  dblOutput = 0.0;    // current output value
       
       
        // process the inputs
        index = 0;
        dblOutput += this.arrCoefInp[index++]*dblInput;
        for (Double dblInpDel : this.bufInput) {
            double  dblCoef = this.arrCoefInp[index++];
           
            dblOutput += dblCoef*dblInpDel;
        }
       
        // process the outputs
        index = 1;
        for (Double dblOutDel : this.bufOutput) {
            double  dblCoef = this.arrCoefOut[index++];
           
            dblOutput -= dblCoef*dblOutDel;
        }
        dblOutput = dblOutput/this.arrCoefOut[0];
       
       
        // Load buffers, update the index, and return
        this.bufInput.add(dblInput);
        this.bufOutput.add(dblOutput);
        this.cntOut++;
       
        return dblOutput;
    }
   
    /**
     * Convenience function for computing the response of this filter to
     * an input signal train.  This method simply calls
     * {@link DigitalFilter#response(double)} sequentially by increasing index
     * for each element of the argument <var>arrTrain</var>.  Thus, the
     * returned response depends upon the initial state of the filter when
     * this method is called.
     *
     * @param arrTrain  array of input signal
     *
     * @return  output signal response of the this filter to given input
     *
     * @see DigitalFilter#response(double)
     */
    public double[] response(double[] arrTrain) {
        int     N = arrTrain.length;
       
        double[]    arrResp = new double[N];
        for (int n=0; n<N; n++)
            arrResp[n] = this.response(arrTrain[n]);
       
        return arrResp;
    }
   
    /**
     * Compute and return the value of the discrete transfer function
     * for the given value of z, the Z-transform variable. 
     *
     * @param   z   Z-transform variable (lies on the unit circle)
     *
     * @return      value of this filter's transfer function at z
     */
    public Complex  transferFunction(Complex z) {
        Complex cpxZpwr  = Complex.ONE;     // power of z
        Complex cpxDenom = Complex.ZERO;   // transfer function denominator
        Complex cpxNumer = Complex.ZERO;   // transfer function numerator
       
        for (int index=0; index<this.getCoefficientSize(); index++)    {
            double  a = this.arrCoefInp[index];
            double  b = this.arrCoefOut[index];
           
            cpxNumer = cpxNumer.add( cpxZpwr.multiply(a) );
            cpxDenom = cpxDenom.add( cpxZpwr.multiply(b) );
           
            cpxZpwr  = cpxZpwr.divide(z);
        }
       
        return cpxNumer.divide(cpxDenom);
    }

    /**
     * Clears the input and output buffers, resetting filter for
     * a new signal.
     */
    public void reset() {
        this.cntOut = 0;
        this.bufInput.clear();
        this.bufOutput.clear();
    }
   
   
    /**
     * Write out the configuration and state of this filter
     * as a string for inspection.
     *
     * @return      configuration and state of this filter in text form
     *
     * @see java.lang.Object#toString()
     */
    @Override
    public String toString() {
        String  strBuffer = "";
       
        strBuffer += "filter order  = " + this.getOrder() + "\n";
        strBuffer += "current index = " + this.getOutputIndex() + "\n";
        strBuffer += "input coefficients :  " + this.arrCoefInp.toString() + "\n";
        strBuffer += "output coefficients: " + this.arrCoefOut.toString() + "\n";
        strBuffer += "input buffer\n";
        strBuffer += this.bufInput.toString() + "\n";
        strBuffer += "output buffer\n";
        strBuffer += this.bufOutput + "\n";
       
        return strBuffer;
    }



    /*
     * Internal Support
     */
   
    /**
     * Initialize the filter coefficients and filter buffers.
     *
     * @param intOrder      filter order
     */
    private void initialize(int intOrder) {
        this.cntOut   = 0;
        this.intOrder = intOrder;
        this.szArray  = intOrder + 1;
       
        this.arrCoefInp = new double[intOrder + 1];
        this.arrCoefOut = new double[intOrder + 1];

        this.bufInput   = new FixedSizeBuffer<Double>(intOrder);
        this.bufOutput  = new FixedSizeBuffer<Double>(intOrder);
       
        for (int index=0; index<=intOrder; index++)  {
            this.arrCoefInp[index] = 0.0;
            this.arrCoefOut[index] = 0.0;
        }
       
        this.arrCoefOut[0] = 1.0;
    }
   
    /**
     * Check the given coefficient array index for bounds
     * errors.
     *
     * @param index     coefficient array index
     *
     * @throws IndexOutOfBoundsException    index outside bounds
     */
    private void checkIndex(int index) throws IndexOutOfBoundsException {
        if ((index<0) || (index>this.getOrder()))
            throw new IllegalArgumentException(
                            "DigitalFiler#checkIndex(): "
                          + "index outside domain [0,"
                          + this.getOrder()
                          + "]"
                            );
       
    }
   
   
}
TOP

Related Classes of gov.sns.tools.dsp.DigitalFilter

TOP
Copyright © 2018 www.massapi.com. All rights reserved.
All source code are property of their respective owners. Java is a trademark of Sun Microsystems, Inc and owned by ORACLE Inc. Contact coftware#gmail.com.