Window.java :  » UnTagged » moonblink » org » hermit » dsp » Android Open Source

Android Open Source » UnTagged » moonblink 
moonblink » org » hermit » dsp » Window.java

/**
 * dsp: various digital signal processing algorithms
 * <br>Copyright 2009 Ian Cameron Smith
 *
 * <p>This program is free software; you can redistribute it and/or modify
 * it under the terms of the GNU General Public License version 2
 * as published by the Free Software Foundation (see COPYING).
 * 
 * <p>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.
 */


package org.hermit.dsp;


/**
 * A windowing function for a discrete signal.  This is used to
 * pre-process a signal prior to FFT, in order to improve the frequency
 * response, essentially by eliminating the discontinuities at the ends
 * of a block of samples.
 */
public final class Window {

    // ******************************************************************** //
    // Public Constants.
    // ******************************************************************** //

    /**
     * Definitions of the available window functions.
     */
    public enum Function {
        /** A simple rectangular window function.  This is equivalent to
         * doing no windowing. */
        RECTANGULAR,
        
        /** The Blackman-Harris window function. */
        BLACKMAN_HARRIS,
        
        /** The Gauss window function. */
        GAUSS,
        
        /** The Weedon-Gauss window function. */
        WEEDON_GAUSS,
    }
    
    
    // ******************************************************************** //
    // Constructor.
    // ******************************************************************** //

    /**
     * Create a window function for a given sample size.  This preallocates
     * resources appropriate to that block size.
     * 
     * @param   size        The number of samples in a block that we will
     *                      be asked to transform.
     */
    public Window(int size) {
        this(size, DEFAULT_FUNC);
    }

    
    /**
     * Create a window function for a given sample size.  This preallocates
     * resources appropriate to that block size.
     * 
     * @param   size        The number of samples in a block that we will
     *                      be asked to transform.
     * @param   function    The window function to use.  Function.RECTANGULAR
     *                      effectively means no transformation.
     */
    public Window(int size, Function function) {
        blockSize = size;

        // Create the window function as an array, so we do the
        // calculations once only.  For RECTANGULAR, leave the kernel as
        // null, signalling no transformation.
        kernel = function == Function.RECTANGULAR ? null : new double[size];

        switch (function) {
        case RECTANGULAR:
            // Nothing to do.
            break;
        case BLACKMAN_HARRIS:
            makeBlackmanHarris(kernel, size);
            break;
        case GAUSS:
            makeGauss(kernel, size);
            break;
        case WEEDON_GAUSS:
            makeWeedonGauss(kernel, size);
            break;
        }
    }

    
    // ******************************************************************** //
    // Window Functions.
    // ******************************************************************** //

    private void makeBlackmanHarris(double[] buf, int len) {
        final double n = (double) (len - 1);
        for (int i = 0; i < len; ++i) {
            final double f = Math.PI * (double) i / n;
            buf[i] = BH_A0 -
                     BH_A1 * Math.cos(2.0 * f) +
                     BH_A2 * Math.cos(4.0 * f) -
                     BH_A3 * Math.cos(6.0 * f);
        }
    }
    
    
    private void makeGauss(double[] buf, int len) {
        final double k = (double) (len - 1) / 2;
        
        for (int i = 0; i < len; ++i) {
            final double d = (i - k) / (0.4 * k);
            buf[i] = Math.exp(-0.5 * d * d);
        }
    }
    

    private void makeWeedonGauss(double[] buf, int len) {
        final double k = (-250.0 * 0.4605) / (double) (len * len);
        final double d = (double) len / 2.0;
        
        for (int i = 0; i < len; ++i) {
            final double n = (double) i - d;
            buf[i] = Math.exp(n * n * k);
        }
    }
    

    // ******************************************************************** //
    // Data Transformation.
    // ******************************************************************** //

    /**
     * Apply the window function to a given data block.  The data in
     * the provided buffer will be multiplied by the window function.
     * 
     * @param   input       The input data buffer.  This data will be
     *                      transformed in-place by the window function.
     * @throws  IllegalArgumentException    Invalid data size.
     */
    public final void transform(double[] input) {
        transform(input, 0, input.length);
    }
    

    /**
     * Apply the window function to a given data block.  The data in
     * the provided buffer will be multiplied by the window function.
     * 
     * @param   input       The input data buffer.  This data will be
     *                      transformed in-place by the window function.
     * @param   off         Offset in the buffer at which the data to
     *                      be transformed starts.
     * @param   count       Number of samples in the data to be
     *                      transformed.  Must be the same as the size
     *                      parameter that was given to the constructor.
     * @throws  IllegalArgumentException    Invalid data size.
     */
    public final void transform(double[] input, int off, int count) {
        if (count != blockSize)
            throw new IllegalArgumentException("bad input count in Window:" +
                                               " constructed for " + blockSize +
                                               "; given " + input.length);
        if (kernel != null)
            for (int i = 0; i < blockSize; i++)
                input[off + i] *= kernel[i];
    }
    
    
    // ******************************************************************** //
    // Private Constants.
    // ******************************************************************** //

    // Default window function.
    private static final Function DEFAULT_FUNC = Function.BLACKMAN_HARRIS;
    
    // Blackman-Harris coefficients.  These sum to 1.0.
    private static final double BH_A0 = 0.35875;
    private static final double BH_A1 = 0.48829;
    private static final double BH_A2 = 0.14128;
    private static final double BH_A3 = 0.01168;

        
    // ******************************************************************** //
    // Private Data.
    // ******************************************************************** //

    // The size of an input data block.
    private final int blockSize;
    
    // The window function, as a pre-computed array of multiplication factors.
    // If null, do no transformation -- this is a unity rectangular window.
    private final double[] kernel;

}

java2s.com  | Contact Us | Privacy Policy
Copyright 2009 - 12 Demo Source and Support. All rights reserved.
All other trademarks are property of their respective owners.