/** * Taken from GPL code from within JavaSpeechToolkit * http://code.google.com/p/jstk/source/browse/trunk/jstk/src/de/fau/cs/jstk/sampled/filters/Butterworth.java?r=176 */ /* Copyright (c) 2011 Speech Group at Informatik 5, Univ. Erlangen-Nuremberg, GERMANY Korbinian Riedhammer This file is part of the Java Speech Toolkit (JSTK). The JSTK 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. The JSTK 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 the JSTK. If not, see . */ package org.das2.math.filter; import java.util.Arrays; import org.das2.datum.Units; import org.das2.datum.UnitsUtil; import org.das2.qds.ArrayDataSet; import org.das2.qds.FlattenWaveformDataSet; import org.das2.qds.QDataSet; import org.das2.qds.SemanticOps; /** * Java Speech Toolkit code modified to use QDataSets. * @author jbf */ public class AbstractFilter { QDataSet source; AbstractFilter( QDataSet source ) { this.source= source; } /** * return the units of the timetags of the dataset, as an offset. * @return the units of the timetags of the dataset, as an offset. */ protected Units getTimeOffsetUnits() { QDataSet timeDomainTags= (QDataSet) source.property(QDataSet.DEPEND_0); Units u= SemanticOps.getUnits(timeDomainTags); return u.getOffsetUnits(); } /** * return the sample rate in the given units. * @param source the signal, containing DEPEND_0 timetags. * @param units the target units. * @return the sample rate in the given units. (E.g. Units.hertz) */ protected double getSampleRate( QDataSet source, Units units ) { QDataSet timeDomainTags= (QDataSet) source.property(QDataSet.DEPEND_0); Units u= getTimeOffsetUnits(); u= UnitsUtil.getInverseUnit(u); return u.convertDoubleTo( units, 1 / ( timeDomainTags.value(1) - timeDomainTags.value(0) ) ); } /** i/o pointer for input signal ringbuffer */ private int px; /** i/o pointer for output signal ringbuffer */ private int py; /** input signal ringbuffer */ private double [] xv; /** output signal ringbuffer */ private double [] yv; /** filter coefficients A (applied to prevously filtered signal) */ private double [] a; /** filter coefficients B (applied to input signal */ private double [] b; /** * Set the filter coefficients stored in Matlab style. If a[0] not equal 1, * the filter coefficients are normalized by a[0]. * * @param b * @param a */ public void setCoefficients(double [] b, double [] a) { this.b = Arrays.copyOf(b,b.length); this.a = Arrays.copyOf(a,a.length); xv = new double [ this.b.length + 1 ]; yv = new double [ this.a.length + 1 ]; if (this.a[0] == 1.) { for (int i = 1; i < this.a.length; ++i) this.a[i] /= this.a[0]; for (int i = 0; i < this.b.length; ++i) this.b[i] /= this.a[0]; } } public QDataSet filter() { if ( source.rank()==2 ) { source= new FlattenWaveformDataSet(source); } ArrayDataSet buf; Class c= ArrayDataSet.guessBackingStore(source); if ( c==float.class || c==double.class ) { buf= ArrayDataSet.copy(source); } else { buf= ArrayDataSet.copy( float.class, source ); } // apply the filter for (int i = 0; i < source.length(); ++i) { // get the new sample xv[px] = source.value(i); // compute the output buf.putValue(i, b[0] * xv[px]); for (int j = 1; j < b.length; ++j) buf.putValue( i, buf.value(i) + ( b[j] * xv[(px - j + xv.length) % xv.length ] ) ); for (int j = 1; j < a.length; ++j) buf.putValue( i, buf.value(i) - ( a[j] * yv[(py - j + yv.length) % yv.length] ) ); // save the result yv[py] = buf.value(i); // increment the index of the ring buffer px = (px + 1) % xv.length; py = (py + 1) % yv.length; } return buf; } @Override public String toString() { return "b = " + Arrays.toString(b) + " a = " + Arrays.toString(a); } }