Docjar: A Java Source and Docuemnt Enginecom.*    java.*    javax.*    org.*    all    new    plug-in

Quick Search    Search Deep

Source code: marf/Preprocessing/FFTFilter/FFTFilter.java


1   package marf.Preprocessing.FFTFilter;
2   
3   import java.util.Vector;
4   
5   import marf.MARF;
6   import marf.Preprocessing.IFilter;
7   import marf.Preprocessing.IPreprocessing;
8   import marf.Preprocessing.Preprocessing;
9   import marf.Preprocessing.PreprocessingException;
10  import marf.Storage.ModuleParams;
11  import marf.Storage.Sample;
12  import marf.math.Algorithms;
13  import marf.math.MathException;
14  import marf.util.Arrays;
15  
16  
17  /**
18   * <p>FFTFilter class implements filtering using the FFT algorithm.</p>
19   * <p>Derivatives must set frequency response based on the type of filter they are.</p>
20   *
21   * $Id: FFTFilter.java,v 1.23 2005/08/05 22:19:55 mokhov Exp $
22   *
23   * @author Stephen Sinclair
24   * @author Serguei Mokhov
25   * @version $Revision: 1.23 $
26   * @since 0.0.1
27   */
28  public abstract class FFTFilter
29  extends Preprocessing
30  implements IFilter 
31  {
32    /**
33     * Default size of the frequency response vector, 128.
34     */
35    public static transient final int DEFAULT_FREQUENCY_RESPONSE_SIZE = 128;
36  
37    /**
38     * Frequency repsonse to be multiplied by the incoming value.
39     */
40    protected transient double[] adFreqResponse = null;
41  
42    /**
43     * Pipelined constructor.
44     * @param poPreprocessing followup preprocessing module
45     * @throws PreprocessingException
46     * @since 0.3.0.3
47     */
48    public FFTFilter(IPreprocessing poPreprocessing)
49    throws PreprocessingException
50    {
51      super(poPreprocessing);
52      genereateResponseCoefficients();
53    }
54  
55    /**
56     * FFTFilter Constructor.
57     * @param poSample incoming sample
58     * @throws PreprocessingException
59     */
60    public FFTFilter(Sample poSample)
61    throws PreprocessingException
62    {
63      super(poSample);
64      genereateResponseCoefficients();
65    }
66  
67    /**
68     * FFTFilter implementation of <code>preprocess()</code>.
69     * <p>It does call <code>removeNoise()</code> and <code>removeSilence()</code>
70     * if they were explicitly requested by an app <em>before</em> applying filtering.</p>
71     *
72     * <b>NOTE</b>: it alters inner Sample by resetting its data array to the new
73     * filtered values.
74     *
75     * @return <code>true</code> if there was something filtered out
76     * @throws PreprocessingException if the frequency response is null
77     */
78    public boolean preprocess()
79    throws PreprocessingException
80    {
81      if(this.adFreqResponse == null)
82        throw new PreprocessingException
83        (
84          "FFTFilter.preprocess() - frequency response is null"
85        );
86  
87      boolean bChanges = normalize();
88  
89      double[] adSampleData = this.oSample.getSampleArray();
90      double[] adFilteredData = new double[adSampleData.length];
91  
92      // By default we do not remove noise or silence
93      boolean bRemoveNoise = false;
94      boolean bRemoveSilence = false;
95  
96      // Exract any additional params if supplied
97  
98      ModuleParams oModuleParams = MARF.getModuleParams();
99  
100     if(oModuleParams != null)
101     {
102       Vector oParams = oModuleParams.getPreprocessingParams();
103 
104       if(oParams.size() > 0)
105       {
106         bRemoveNoise = ((Boolean)oParams.elementAt(0)).booleanValue();
107         bRemoveSilence = ((Boolean)oParams.elementAt(1)).booleanValue();
108       }
109     }
110 
111     if(bRemoveNoise == true)
112       bChanges |= removeNoise();
113 
114     if(bRemoveSilence == true)
115       bChanges |= removeSilence();
116 
117     bChanges |= filter(adSampleData, adFilteredData);
118 
119     this.oSample.setSampleArray(adFilteredData);
120 
121     return bChanges;
122   }
123 
124   /**
125    * Sets frequency response.
126    * Derivatives must call this method before any preprocessing occurs.
127    *
128    * @param padPesponse desired frequency response coefficients
129    */
130   public final void setFrequencyResponse(final double[] padPesponse)
131   {
132     this.adFreqResponse = new double[padPesponse.length * 2];
133 
134     // Forward copy
135     Arrays.copy(this.adFreqResponse, 0, padPesponse);
136 
137     // Backward copy
138     for(int i = 0; i < padPesponse.length; i++)
139     {
140       this.adFreqResponse[this.adFreqResponse.length - i - 1] = padPesponse[i];
141     }
142   }
143 
144   /**
145    * Perform a filter by the following algorithm:
146    * (1) sample -&gt; window -&gt; FFT -&gt; buffer<br />
147    * (2) buffer * frequency response<br />
148    * (3) buffer -&gt; IFFT -&gt; window -&gt; sample.
149    *
150    * Window used is square root of Hamming window, because
151    * the sum at half-window overlap is a constant, which
152    * avoids amplitude distortion from noise.
153    *
154    * Also, start sampling at <code>-responseSize/2</code>, in order to avoid
155    * amplitude distortion of the first half of the first window.
156    *
157    * @param padSample incoming sample analog data
158    * @param padFiltered will contain data after the filter was applied.
159    * "filtered" must be at least as long as "sample".
160    *
161    * @return <code>true</code> if some filtering actually happened
162    *
163    * @throws PreprocessingException if the filtered and sample data
164    * arrays are not of the same size, the frequency response was not
165    * set, or there was an underlying FeatureExctractionException while
166    * executing the underlying FFT algorithm.
167    */
168   public final boolean filter(final double[] padSample, double[] padFiltered)
169   throws PreprocessingException
170   {
171     try
172     {
173       int iResponseSize = this.adFreqResponse.length;
174 
175       double[] adBuffer = new double[iResponseSize];
176       double[] adBufferImag = new double[iResponseSize];
177       double[] adOutputReal = new double[iResponseSize];
178       double[] adOutputImag = new double[iResponseSize];
179 
180       if(padFiltered.length < padSample.length)
181         throw new PreprocessingException
182         (
183           "FFTFilter: Output buffer not long enough (" +
184           padFiltered.length + " < " + padSample.length + ")."
185         );
186 
187       int i;
188 
189       int iPosition = -iResponseSize / 2;
190 
191       while(iPosition < padSample.length)
192       {
193         for(i = 0; i < iResponseSize; i++)
194         {
195           if(((iPosition + i) < padSample.length) && ((iPosition + i) >= 0))
196             adBuffer[i] = padSample[iPosition + i] * Algorithms.Hamming.sqrtHamming(i, iResponseSize);
197           else
198             adBuffer[i] = 0;
199 
200           adBufferImag[i] = 0;
201         }
202 
203         Algorithms.FFT.doFFT(adBuffer, adBufferImag, adOutputReal, adOutputImag, 1);
204 
205         for(i = 0; i < iResponseSize; i++)
206         {
207           adOutputReal[i] *= this.adFreqResponse[i];
208           adOutputImag[i] *= this.adFreqResponse[i];
209         }
210 
211         Algorithms.FFT.doFFT(adOutputReal, adOutputImag, adBuffer, adBufferImag, -1);
212 
213         // Copy & normalize
214         for(i = 0; (i < iResponseSize) && ((iPosition + i) < padSample.length); i++)
215         {
216           if((iPosition + i) >= 0)
217             padFiltered[iPosition + i] +=
218               adBuffer[i] * Algorithms.Hamming.sqrtHamming(i, iResponseSize) / (double)iResponseSize;
219         }
220 
221         iPosition += iResponseSize / 2;
222       }
223 
224       return true;
225     }
226     catch(NullPointerException e)
227     {
228       throw new PreprocessingException("FFTFilter: frequency response hasn't been set.");
229     }
230     catch(MathException e)
231     {
232       throw new PreprocessingException("FFTFilter: " + e.getMessage());
233     }
234   }
235 
236   /**
237    * Creates frequency response coefficients and sets applies
238    * them to the frequency response vector. Must be overridden
239    * by individual filters.
240    *
241    * @since 0.3.0
242    */
243   public abstract void genereateResponseCoefficients();
244 
245   /**
246    * Returns source code revision information.
247    * @return revision string
248    * @since 0.3.0.2
249    */
250   public static String getMARFSourceCodeRevision()
251   {
252     return "$Revision: 1.23 $";
253   }
254 }
255 
256 // EOF