/* * FilterDesign.java * * This file is part of Tritonus: http://www.tritonus.org/ */ /* * Copyright (c) 2002 by Matthias Pfisterer * * This program is free software; you can redistribute it and/or modify * it under the terms of the GNU Library General Public License as published * by the Free Software Foundation; either version 2 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 Library General Public License for more details. * * You should have received a copy of the GNU Library General Public * License along with this program; if not, write to the Free Software * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA. */ /* |<--- this code is formatted to fit into 80 columns --->| */ package org.tritonus.lowlevel.dsp; import org.tritonus.share.TDebug; /** Several methods to design digital filters. This is a design method for FIR filters. */ public class FilterDesign { public static final int WINDOW_UNKNOWN = -1; public static final int WINDOW_RECTANGULAR = 0; public static final int WINDOW_HAMMING = 1; private static final Window[] WINDOWS = { new RectangularWindow(), new HammingWindow(), }; private static final boolean DEBUG = false; /** Filter design by frequency sampling. This is a design method for FIR filters. It allows to design filters with arbitrary frequency response. */ public static double[] designFrequencySampling(double[] adFrequencyResponse) { int nHalfLength = adFrequencyResponse.length; int nFullLength = nHalfLength * 2; Complex[] aFrequencyResponse = new Complex[nFullLength]; //double dScaleFactor = (double) (nFullLength - 1) / (double) nFullLength; for (int k = 0; k < nHalfLength; k++) { //double dPhase = -Math.PI * k * dScaleFactor; } // TODO: middle point has to be 0 // TOO: check loop bounds for (int k = nHalfLength; k < nFullLength; k++) { //double dPhase = Math.PI - Math.PI * k * dScaleFactor; } Complex[] aComplexCoefficients = Util.IDFT(aFrequencyResponse); double[] aRealCoefficients = new double[nFullLength]; for (int i = 0; i < nFullLength; i++) { aRealCoefficients[i] = aComplexCoefficients[i].real(); if (DEBUG) { TDebug.out("FilterDesign.designFrequencySampling(): coefficient, imaginary part: " + aComplexCoefficients[i].imag()); } } return aRealCoefficients; } /////////////////////////////////////////////////// // // Rectangular Window methods // /////////////////////////////////////////////////// /** nOrder should be odd. */ public static double[] designRectangularLowPass(int nOrder, double dCornerOmega) { double[] adH = new double[nOrder]; int nMiddle = nOrder / 2; for (int n = 0; n < nOrder; n++) { adH[n] = Math.sin(dCornerOmega * (n - nMiddle)) / (Math.PI * (n - nMiddle)); } return adH; } /** nOrder should be odd. */ public static double[] designRectangularHighPass(int nOrder, double dCornerOmega) { double[] adH = new double[nOrder]; int nMiddle = nOrder / 2; for (int n = 0; n < nOrder; n++) { adH[n] = 1.0 - Math.sin(dCornerOmega * (n - nMiddle)) / (Math.PI * (n - nMiddle)); } return adH; } /** nOrder should be odd. o1 < o2 required */ public static double[] designRectangularBandPass(int nOrder, double dCornerOmega1, double dCornerOmega2) { double[] adH = new double[nOrder]; int nMiddle = nOrder / 2; for (int n = 0; n < nOrder; n++) { adH[n] = (Math.sin(dCornerOmega2 * (n - nMiddle)) - Math.sin(dCornerOmega1 * (n - nMiddle))) / (Math.PI * (n - nMiddle)); } return adH; } /** nOrder should be odd. */ public static double[] designRectangularBandStop(int nOrder, double dCornerOmega1, double dCornerOmega2) { double[] adH = new double[nOrder]; int nMiddle = nOrder / 2; for (int n = 0; n < nOrder; n++) { adH[n] = 1.0 - (Math.sin(dCornerOmega2 * (n - nMiddle)) - Math.sin(dCornerOmega1 * (n - nMiddle))) / (Math.PI * (n - nMiddle)); } return adH; } /////////////////////////////////////////////////// // // Window methods // /////////////////////////////////////////////////// public static double[] designWindowLowPass(int nOrder, double dCornerOmega, int nWindow) { Window window = WINDOWS[nWindow]; return designWindowLowPass(nOrder, dCornerOmega, window); } public static double[] designWindowHighPass(int nOrder, double dCornerOmega, int nWindow) { Window window = WINDOWS[nWindow]; return designWindowHighPass(nOrder, dCornerOmega, window); } public static double[] designWindowBandPass(int nOrder, double dCornerOmega1, double dCornerOmega2, int nWindow) { Window window = WINDOWS[nWindow]; return designWindowBandPass(nOrder, dCornerOmega1, dCornerOmega2, window); } public static double[] designWindowBandStop(int nOrder, double dCornerOmega1, double dCornerOmega2, int nWindow) { Window window = WINDOWS[nWindow]; return designWindowBandStop(nOrder, dCornerOmega1, dCornerOmega2, window); } public static double[] designWindowLowPass(int nOrder, double dCornerOmega, Window window) { double[] adRectangular = designRectangularLowPass(nOrder, dCornerOmega); double[] adWindow = window.getWindow(nOrder); double[] adH = Util.multiply(adRectangular, adWindow); return adH; } public static double[] designWindowHighPass(int nOrder, double dCornerOmega, Window window) { double[] adRectangular = designRectangularHighPass( nOrder, dCornerOmega); double[] adWindow = window.getWindow(nOrder); double[] adH = Util.multiply(adRectangular, adWindow); return adH; } public static double[] designWindowBandPass(int nOrder, double dCornerOmega1, double dCornerOmega2, Window window) { double[] adRectangular = designRectangularBandPass( nOrder, dCornerOmega1, dCornerOmega2); double[] adWindow = window.getWindow(nOrder); double[] adH = Util.multiply(adRectangular, adWindow); return adH; } public static double[] designWindowBandStop(int nOrder, double dCornerOmega1, double dCornerOmega2, Window window) { double[] adRectangular = designRectangularBandStop( nOrder, dCornerOmega1, dCornerOmega2); double[] adWindow = window.getWindow(nOrder); double[] adH = Util.multiply(adRectangular, adWindow); return adH; } } /*** FilterDesign.java ***/