/* * FIR.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; /** A Finite Impulse Response (FIR) filter. */ public class FIR implements Filter { /** The length of the filter (number of coefficients). */ private int m_nLength; /** The filter coefficients. */ private float[] m_afCoefficients; /** The buffer for past input values. This stores the input values needed for convolution. The buffer is used as a circular buffer. */ private float[] m_afBuffer; /** The index into m_afBuffer. Since m_afBuffer is used as a circular buffer, a buffer pointer is needed. */ private int m_nBufferIndex; /** Init a FIR filter with coefficients. @param afCoefficients The array of filter coefficients. */ public FIR(float[] afCoefficients) { m_nLength = afCoefficients.length; m_afCoefficients = new float[m_nLength]; System.arraycopy(afCoefficients, 0, m_afCoefficients, 0, m_nLength); m_afBuffer = new float[m_nLength]; m_nBufferIndex = 0; } /** Process an input sample and calculate an output sample. Call this method to use the filter. */ public float process(float fInput) { m_nBufferIndex = (m_nBufferIndex + 1) % m_nLength; m_afBuffer[m_nBufferIndex] = fInput; int nBufferIndex = m_nBufferIndex; float fOutput = 0.0F; for (int i = 0; i < m_nLength; i++) { fOutput += m_afCoefficients[i] * m_afBuffer[nBufferIndex]; nBufferIndex--; if (nBufferIndex < 0) { nBufferIndex += m_nLength; } } return fOutput; } /** Returns the length of the filter. This returns the length of the filter (the number of coefficients). Note that this is not the same as the order of the filter. Commonly, the 'order' of a FIR filter is said to be the number of coefficients minus 1: Since a single coefficient is only an amplifier/attenuator, this is considered order zero. @return The length of the filter (the number of coefficients). */ private int getLength() { return m_nLength; } /** Get the frequency response of the filter at a specified frequency. This method calculates the frequency response of the filter for a specified frequency. Calling this method is allowed at any time, even while the filter is operating. It does not affect the operation of the filter. @param dOmega The frequency for which the frequency response should be calculated. Has to be given as omega values ([-PI .. +PI]). @return The calculated frequency response. */ public double getFrequencyResponse(double dOmega) { double dReal = 0.0; double dImag = 0.0; for (int i = 0; i < getLength(); i++) { dReal += m_afCoefficients[i] * Math.cos(i * dOmega); dImag += m_afCoefficients[i] * Math.sin(i * dOmega); } double dResult = Math.sqrt(dReal * dReal + dImag * dImag); return dResult; } /** Get the phase response of the filter at a specified frequency. This method calculates the phase response of the filter for a specified frequency. Calling this method is allowed at any time, even while the filter is operating. It does not affect the operation of the filter. @param dOmega The frequency for which the phase response should be calculated. Has to be given as omega values ([-PI .. +PI]). @return The calculated phase response. */ public double getPhaseResponse(double dOmega) { double dReal = 0.0; double dImag = 0.0; for (int i = 0; i < getLength(); i++) { dReal += m_afCoefficients[i] * Math.cos(i * dOmega); dImag += m_afCoefficients[i] * Math.sin(i * dOmega); } double dResult = Math.atan2(dImag, dReal); return dResult; } } /*** FIR.java ***/