sikoried / jstk

Java Speech Toolkit
Other
10 stars 6 forks source link

Error in Butterworth.java #2

Closed GoogleCodeExporter closed 9 years ago

GoogleCodeExporter commented 9 years ago
There is an Error in Butterworth.computeScale(), line 286:

fomega = Math.sin(omega / 2.0);

For the highpass filter cos() must be used instead of sin():

Original issue reported on code.google.com by chdheu@gmail.com on 17 Jul 2013 at 10:44

GoogleCodeExporter commented 9 years ago
That is correct. This is the corrected line 286:

   fomega = lowp ? Math.sin(omega / 2.0) : Math.cos(omega/2.0);

I have developed a Butterworth testing suite using R results which I am 
attaching below. The high pass filter is the one affected by the bug and it is 
fixed by my patch above. 

import static org.junit.Assert.assertArrayEquals;
import static org.junit.Assert.assertEquals;

import java.io.IOException;
import java.util.Arrays;

import org.junit.Test;

import de.fau.cs.jstk.sampled.AudioBuffer;
import de.fau.cs.jstk.sampled.filters.Butterworth;
import de.fau.cs.jstk.sampled.filters.IIRFilter;

public class TestJstk {
    @Test
    public void testButter_lp() throws IOException {
        double[] x = new double[] { 16, 8, 12, 9, 3, 26, 20, 4, 112, 93, 80, 69, 68, 63, 58, 27, 25, 25, 18, 11, 22, 9, 5, 8, 16, 17, 17, 44, 63, 24, 47 };

        double[] b = new double[] { 0.1550510, 0.3101021, 0.1550510 };
        double[] a = new double[] { 1.0000000, -0.6202041, 0.2404082 };
        final AudioBuffer audioBuffer = new AudioBuffer(x, 2);
        final Butterworth butterworth = new Butterworth(audioBuffer, 2, 1.0 / 3.0, true);
        final double[] bb = butterworth.getB();
        final double[] aa = butterworth.getA();
        assertArrayEquals(b, bb, 0.001);
        assertArrayEquals(a, aa, 0.001);
    }

    @Test
    public void testButter_hp() throws IOException {
        double[] x = new double[] { 16, 8, 12, 9, 3, 26, 20, 4, 112, 93, 80, 69, 68, 63, 58, 27, 25, 25, 18, 11, 22, 9, 5, 8, 16, 17, 17, 44, 63, 24, 47 };
        double[] b = new double[] {   0.3468218, -1.3872872,  2.0809308 ,-1.3872872,  0.3468218};
        double[] a = new double[] {  1.0000000, -1.9684278,  1.7358607 ,-0.7244708,  0.1203896 };
        double[] expected = new double[] {5.54914892555101,-8.49892230051391,-0.003607008408407,-0.309157749925311,0.549327031269458,12.3495446861587,-8.08187252527558,-10.2052018545226,42.7060615954128,-39.089626413168,-24.3177046211387,4.63980949957661,22.0464798879164,14.8012776797776,3.39742596116234,-13.9965761769389,2.71278575409631,1.87605737037402,-5.32246810936881,-4.53394312207378,5.16192117527652,-6.85997635444255,0.903951634058044,5.83406457378732,4.32350630835867,-3.60407519394749,-4.23879071781233,7.97239236467143,-1.93029751372985,-25.4779281018646,18.4450453439678};
        final AudioBuffer audioBuffer = new AudioBuffer(x, 2);
        final Butterworth butterworth = new Butterworth(audioBuffer, 4, 1.0 / 4.0, false);
        final double[] bb = butterworth.getB();
        final double[] aa = butterworth.getA();
        assertArrayEquals(b, bb, 0.001);
        assertArrayEquals(a, aa, 0.001);
        double[] buf = new double[x.length];
        butterworth.read(buf);
        assertArrayEquals(expected,buf,0.001);
    }

    @Test
    public void testButter_pass() throws IOException {
        double[] x = new double[] { 16, 8, 12, 9, 3, 26, 20, 4, 112, 93, 80, 69, 68, 63, 58, 27, 25, 25, 18, 11, 22, 9, 5, 8, 16, 17, 17, 44, 63, 24, 47 };
        double[] b = new double[] {0.0113248654051871,0,-0.0339745962155614,0,0.0339745962155614,0,-0.0113248654051871};
        double[] a = new double[] {1,-4.4496959232013,8.65581123827227,-9.42446288516026,6.06410161513775,-2.18695422340435,0.346410161513775};
        double[] expected = new double[] {0.181197846482994,0.896874242029731,2.01470814785898,2.73948388646281,2.27456568741899,0.61421917906726,-1.10462841953745,-1.93525406304157,-1.20621974366979,2.97278152595629,10.4303214872243,15.8822139387219,13.500760000539,2.38976099657175,-13.0801776390542,-26.72484049744,-34.2082480470628,-33.9079541732019,-26.2232727370073,-13.4714856847578,0.832951218316903,13.5117163981764,22.3047800227293,26.10958732738,25.5807316155666,22.6911775250397,19.1878576681426,15.9125835498727,13.4444260301878,11.4840807655145,7.8900683896338};
        final AudioBuffer audioBuffer = new AudioBuffer(x, 2);
        final Butterworth butterworth = new Butterworth(audioBuffer, 3, 1.0/12.0, 1.0 / 4.0, true);
        final double[] bb = butterworth.getB();
        final double[] aa = butterworth.getA();
        assertArrayEquals(b, bb, 0.001);
        assertArrayEquals(a, aa, 0.001);
        double[] buf = new double[x.length];
        butterworth.read(buf);
        assertArrayEquals(expected,buf,0.001);
    }

    @Test
    public void testButter_stop() throws IOException {
        double[] x = new double[] { 16, 8, 12, 9, 3, 26, 20, 4, 112, 93, 80, 69, 68, 63, 58, 27, 25, 25, 18, 11, 22, 9, 5, 8, 16, 17, 17, 44, 63, 24, 47 };
        double[] b = new double[] {0.588675134594813,-3.16675012051762,7.44448637286709,-9.72761279073067,7.44448637286709,-3.16675012051762,0.588675134594813};
        double[] a = new double[] {1,-4.4496959232013,8.65581123827227,-9.42446288516026,6.06410161513775,-2.18695422340435,0.346410161513775};
        double[] expected = new double[] {9.418802153517,-4.04779530757917,1.30305080730625,0.813444393440761,0.965738818071003,19.6437242012142,4.34025997546248,-5.19657906701005,70.0443383235965,4.92086998914045,-1.28503403301326,17.889553459591,44.7825129396512,54.6764469627152,55.1946954891815,36.2067494827069,49.6219341707565,54.3906737102908,50.2874318711772,49.6467626996213,61.0675149513866,47.3383697081128,47.5252796021205,48.7946668297596,46.0251122981386,33.6941987816225,24.7182348816676,35.7429020098952,29.4434367841126,-8.57798891169426,26.4753213522642};
        final AudioBuffer audioBuffer = new AudioBuffer(x, 2);
        final Butterworth butterworth = new Butterworth(audioBuffer, 3, 1.0/12.0, 1.0 / 4.0, false);
        final double[] bb = butterworth.getB();
        final double[] aa = butterworth.getA();
        assertArrayEquals(b, bb, 0.001);
        assertArrayEquals(a, aa, 0.001);
        double[] buf = new double[x.length];
        butterworth.read(buf);
        assertArrayEquals(expected,buf,0.001);
    }

    @Test
    public void testButter2() throws IOException {
        double[] x = new double[] { 16, 8, 12, 9, 3, 26, 20, 4, 112, 93, 80, 69, 68, 63, 58, 27, 25, 25, 18, 11, 22, 9, 5, 8, 16, 17, 17, 44, 63, 24, 47 };
        //
        // double[] b = new double[] { 0.1550510, 0.3101021, 0.1550510 };
        // double[] a = new double[] { 1.0000000, -0.6202041, 0.2404082 };
        final AudioBuffer audioBuffer = new AudioBuffer(x, 2);
        final Butterworth butterworth = new Butterworth(audioBuffer, 3, 1./12., 1.0 / 4.0, true);
        final double[] bb = butterworth.getB();
        final double[] aa = butterworth.getA();
        System.out.println(Arrays.toString(bb));
        System.out.println(Arrays.toString(aa));
        // assertArrayEquals(b,bb,0.001);
        // assertArrayEquals(a,aa,0.001);
    }

    @Test
    public void testFilter() throws Exception {
        double[] x = new double[] { 16, 8, 12, 9, 3, 26, 20, 4, 112, 93, 80, 69, 68, 63, 58, 27, 25, 25, 18, 11, 22, 9, 5, 8, 16, 17, 17, 44, 63, 24, 47 };
        double[] expected = new double[] { 2.480816, 7.740654, 11.026622, 11.334931, 9.495764, 9.521394, 15.251175, 18.023392, 29.218818, 63.560039, 91.005041, 91.087775, 78.959247, 68.626275, 62.652705, 54.29965, 39.856636, 27.480371, 21.881322, 18.128053, 15.595807, 15.237716,
                12.678430, 8.386320, 7.890119, 11.715253, 15.757417, 21.686219, 35.710242, 47.013993, 45.071298 };
        double[] b = new double[] { 0.1550510, 0.3101021, 0.1550510 };
        double[] a = new double[] { 1.0000000, -0.6202041, 0.2404082 };
        final IIRFilter iirFilter = new IIRFilter(new AudioBuffer(x, 2), b, a);
        double[] buf = new double[x.length + 1];
        final int read = iirFilter.read(buf);
        assertEquals(x.length, read);
        assertArrayEquals(expected, Arrays.copyOfRange(buf, 0, x.length), 0.0001);
    }

} 

Original comment by pjfu...@gmail.com on 27 Sep 2013 at 12:42

GoogleCodeExporter commented 9 years ago
This JSTK project seems to be abandoned.
I have written another port of the Exstrom Butterworth IIR filter design module:
http://www.source-code.biz/dsp/java

Original comment by chdheu@gmail.com on 27 Sep 2013 at 10:23

GoogleCodeExporter commented 9 years ago
Thanks for your help, and sorry for the delay-- didn't get notified by gcode. 
Fixed in r258.

Original comment by korbini...@gmail.com on 10 Nov 2014 at 6:16

sikoried commented 9 years ago

Already fixed.