/******************************************************************************* * SDR Trunk * Copyright (C) 2014 Dennis Sheirer * * This program is free software: you can redistribute it and/or modify * it under the terms of the GNU General Public License as published by * the Free Software Foundation, either version 3 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 General Public License for more details. * * You should have received a copy of the GNU General Public License * along with this program. If not, see <http://www.gnu.org/licenses/> ******************************************************************************/ package dsp.filter; import dsp.filter.Window.WindowType; /** * Implements the Goertzel Filter as described in * http://en.wikipedia.org/wiki/Goertzel_algorithm * * Calculates the magnitude of a specific frequency component within a window of * samples, using a Goertzel Filter (ie an optimized DFT). */ public class GoertzelFilter { private int mSampleRate; private long mTargetFrequency; private int mBlockSize; private double[] mWindowCoefficients; private double mCoefficient; /** * Constructs the Goertzel Filter to use for block processing of * time-domain signal samples. * * @param sampleRate * - sample rate (Hz) * @param targetFrequency * - target frequency (Hz) * @param blockSize * - number of samples per block of processing * @param window * - window to apply against the samples prior to calculating * the magnitude */ public GoertzelFilter( int sampleRate, long targetFrequency, int blockSize, WindowType window ) { mSampleRate = sampleRate; mTargetFrequency = targetFrequency; mBlockSize = blockSize; mWindowCoefficients = Window.getWindow( window, blockSize ); init(); } /** * Establish the pre-calculated values to use in the filter */ private void init() { double normalizedFrequency = (double) mTargetFrequency / mSampleRate; mCoefficient = 2.0D * Math.cos( 2 * Math.PI * normalizedFrequency ); } /** * Returns the power (dB) of the target frequency within the block of * samples as normalized against the bin(0) magnitude value * * @param samples * - array of time-domain samples -- array size must be the same * size as the windowSize parameter passed upon construction * * @return - power measurement in dB * @throws IllegalArgumentException if the sample array size is not equal * to the defined block size */ public int getPower( float[] samples ) throws IllegalArgumentException { // Verify size of samples array against block size if ( samples.length != mBlockSize ) { throw new IllegalArgumentException( "Sample array size does not equal Block Size" ); } // Apply the window against the samples samples = Window.apply( mWindowCoefficients, samples ); // Process the samples double s = 0.0D; double s_prev = 0.0D; double s_prev2 = 0.0D; for ( int x = 0; x < samples.length; x++ ) { s = samples[x] + ( mCoefficient * s_prev ) - s_prev2; s_prev2 = s_prev; s_prev = s; } //power = s_prev2 * s_prev2 + s_prev * s_prev - coeff * s_prev * s_prev2 ; double magnitude = ( s_prev2 * s_prev2 ) + ( s_prev * s_prev) - (mCoefficient * s_prev * s_prev2); int binZero = getBinZeroPower( samples ); int power = (int) (20 * Math.log10( magnitude / binZero ) ); return power; } /** * Sums all of the sample values to derive the bin 0 power */ private int getBinZeroPower( float[] samples ) { int retVal = 0; for( int x = 0; x < samples.length; x++ ) { retVal += samples[ x ]; } return retVal; } /** * @return the Sample Rate */ public int getSampleRate() { return mSampleRate; } /** * @return the Target Frequency */ public long getTargetFrequency() { return mTargetFrequency; } /** * @return the Block Size */ public int getBlockSize() { return mBlockSize; } }