24 |
25 |
26 |
27 |
--------------------------------------------------------------------------------
/python-design/plot_impulse_fresponse.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | import matplotlib.pyplot as plt
4 | import scipy
5 | import numpy as np
6 |
7 | # Plots the impulse response of the Bandstop and its frequency response
8 |
9 | def plot_if(name,figtitle,fs = 1000):
10 | plt.suptitle(figtitle)
11 | y = np.loadtxt(name);
12 | plt.subplot(311)
13 | plt.title("Impulse response")
14 | plt.plot(y);
15 | #
16 | # Fourier Transform
17 | yf = np.fft.fft(y)
18 | plt.subplot(312)
19 | fx = np.linspace(0,fs,len(yf))
20 | plt.plot(fx,20*np.log10(abs(yf)))
21 | plt.xlim(0,fs/2)
22 | plt.title("Frequency response")
23 | plt.ylabel("gain/dB")
24 |
25 | plt.subplot(313)
26 | p = -np.diff(np.unwrap(np.angle(yf))) / np.diff(fx * 2 * np.pi)
27 | plt.plot(np.linspace(0,fs,len(yf)-1),p)
28 | plt.xlim(0,fs/2)
29 | plt.title("Phase response")
30 | if fs == 1:
31 | plt.xlabel("f/1/samples")
32 | plt.ylabel("delay/samples")
33 | plt.ylim(-200,200)
34 | else:
35 | plt.ylim(-0.075,0.075)
36 | plt.xlabel("f/Hz")
37 | plt.ylabel("delay/secs")
38 |
39 | plot_if("app/elliptic.dat","Elliptic filter")
40 |
41 | plt.show()
42 |
--------------------------------------------------------------------------------
/plot_impulse_fresponse.py:
--------------------------------------------------------------------------------
1 | #!/usr/bin/python3
2 |
3 | import matplotlib.pyplot as plt
4 | import numpy as np
5 | import sys
6 |
7 | # Plots the impulse response of the Bandstop and its frequency response
8 |
9 | def plot_if(figno,name,figtitle):
10 | plt.figure(figno)
11 | plt.suptitle(figtitle)
12 | fs = 250
13 | y = np.loadtxt(name);
14 | plt.subplot(311)
15 | plt.title("Impulse response")
16 | plt.plot(y);
17 | #
18 | # Fourier Transform
19 | yf = np.fft.fft(y)
20 | plt.subplot(312)
21 | fx = np.linspace(0,fs,len(yf))
22 | plt.plot(fx,20*np.log10(abs(yf)))
23 | plt.xlim(0,fs/2)
24 | plt.title("Frequency response")
25 | plt.xlabel("f/Hz")
26 | plt.ylabel("gain/dB")
27 |
28 | plt.subplot(313)
29 | p = -np.diff(np.unwrap(np.angle(yf))) / np.diff(fx * 2 * np.pi)
30 | plt.plot(np.linspace(0,fs,len(yf)-1),p)
31 | plt.xlim(0,fs/2)
32 | plt.ylim(-0.075,0.075)
33 | plt.title("Phase response")
34 | plt.xlabel("f/Hz")
35 | plt.ylabel("delay/secs")
36 |
37 | if len(sys.argv) < 2:
38 | print("Specify which filter shall be plotted: butterworth, bessel, chebyshevI, chebyshevII.")
39 | quit()
40 |
41 | prefix = "target/surefire-reports/"+sys.argv[1]+"/"
42 |
43 | plot_if(1,prefix+"lp.txt","Lowpass")
44 |
45 | plot_if(2,prefix+"hp.txt","Highpass")
46 |
47 | plot_if(3,prefix+"bs.txt","Bandstop")
48 |
49 | plot_if(4,prefix+"bp.txt","Bandpass")
50 |
51 | plt.show()
52 |
--------------------------------------------------------------------------------
/src/main/java/uk/me/berndporr/iirj/BiquadPoleState.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | * Copyright (c) 2009 by Vinnie Falco
18 | * Copyright (c) 2016 by Bernd Porr
19 | */
20 |
21 | package uk.me.berndporr.iirj;
22 |
23 |
24 | import org.apache.commons.math3.complex.Complex;
25 |
26 | /**
27 | * PoleZeroPair with gain factor
28 | */
29 | public class BiquadPoleState extends PoleZeroPair {
30 |
31 |
32 | public BiquadPoleState(Complex p, Complex z) {
33 | super(p, z);
34 | }
35 |
36 | public BiquadPoleState(Complex p1, Complex z1,
37 | Complex p2, Complex z2) {
38 | super(p1, z1, p2, z2);
39 | }
40 |
41 | double gain;
42 |
43 | }
44 |
--------------------------------------------------------------------------------
/src/main/java/uk/me/berndporr/iirj/DirectFormAbstract.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | * Copyright (c) 2009 by Vinnie Falco
18 | * Copyright (c) 2016 by Bernd Porr
19 | */
20 |
21 | package uk.me.berndporr.iirj;
22 |
23 | /**
24 | * Abstract form of the a filter which can have different state variables
25 | *
26 | * Direct form I or II is derived from it
27 | */
28 | public abstract class DirectFormAbstract {
29 |
30 | public DirectFormAbstract () {
31 | reset();
32 | }
33 |
34 | public abstract void reset();
35 |
36 | public abstract double process1 (double in, Biquad s);
37 |
38 | public static final int DIRECT_FORM_I = 0;
39 | public static final int DIRECT_FORM_II = 1;
40 |
41 | };
42 |
--------------------------------------------------------------------------------
/docs/legal/ASSEMBLY_EXCEPTION:
--------------------------------------------------------------------------------
1 |
2 | OPENJDK ASSEMBLY EXCEPTION
3 |
4 | The OpenJDK source code made available by Oracle America, Inc. (Oracle) at
5 | openjdk.java.net ("OpenJDK Code") is distributed under the terms of the GNU
6 | General Public License version 2
7 | only ("GPL2"), with the following clarification and special exception.
8 |
9 | Linking this OpenJDK Code statically or dynamically with other code
10 | is making a combined work based on this library. Thus, the terms
11 | and conditions of GPL2 cover the whole combination.
12 |
13 | As a special exception, Oracle gives you permission to link this
14 | OpenJDK Code with certain code licensed by Oracle as indicated at
15 | http://openjdk.java.net/legal/exception-modules-2007-05-08.html
16 | ("Designated Exception Modules") to produce an executable,
17 | regardless of the license terms of the Designated Exception Modules,
18 | and to copy and distribute the resulting executable under GPL2,
19 | provided that the Designated Exception Modules continue to be
20 | governed by the licenses under which they were offered by Oracle.
21 |
22 | As such, it allows licensees and sublicensees of Oracle's GPL2 OpenJDK Code
23 | to build an executable that includes those portions of necessary code that
24 | Oracle could not provide under GPL2 (or that Oracle has provided under GPL2
25 | with the Classpath exception). If you modify or add to the OpenJDK code,
26 | that new GPL2 code may still be combined with Designated Exception Modules
27 | if the new code is made subject to this exception by its copyright holder.
28 |
--------------------------------------------------------------------------------
/docs/jquery-ui.overrides.css:
--------------------------------------------------------------------------------
1 | /*
2 | * Copyright (c) 2020, 2022, Oracle and/or its affiliates. All rights reserved.
3 | * DO NOT ALTER OR REMOVE COPYRIGHT NOTICES OR THIS FILE HEADER.
4 | *
5 | * This code is free software; you can redistribute it and/or modify it
6 | * under the terms of the GNU General Public License version 2 only, as
7 | * published by the Free Software Foundation. Oracle designates this
8 | * particular file as subject to the "Classpath" exception as provided
9 | * by Oracle in the LICENSE file that accompanied this code.
10 | *
11 | * This code is distributed in the hope that it will be useful, but WITHOUT
12 | * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 | * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License
14 | * version 2 for more details (a copy is included in the LICENSE file that
15 | * accompanied this code).
16 | *
17 | * You should have received a copy of the GNU General Public License version
18 | * 2 along with this work; if not, write to the Free Software Foundation,
19 | * Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
20 | *
21 | * Please contact Oracle, 500 Oracle Parkway, Redwood Shores, CA 94065 USA
22 | * or visit www.oracle.com if you need additional information or have any
23 | * questions.
24 | */
25 |
26 | .ui-state-active,
27 | .ui-widget-content .ui-state-active,
28 | .ui-widget-header .ui-state-active,
29 | a.ui-button:active,
30 | .ui-button:active,
31 | .ui-button.ui-state-active:hover {
32 | /* Overrides the color of selection used in jQuery UI */
33 | background: #F8981D;
34 | border: 1px solid #F8981D;
35 | }
36 |
--------------------------------------------------------------------------------
/docs/script-dir/jquery-ui.min.css:
--------------------------------------------------------------------------------
1 | /*! jQuery UI - v1.13.1 - 2022-05-12
2 | * http://jqueryui.com
3 | * Includes: core.css, autocomplete.css, menu.css
4 | * Copyright jQuery Foundation and other contributors; Licensed MIT */
5 |
6 | .ui-helper-hidden{display:none}.ui-helper-hidden-accessible{border:0;clip:rect(0 0 0 0);height:1px;margin:-1px;overflow:hidden;padding:0;position:absolute;width:1px}.ui-helper-reset{margin:0;padding:0;border:0;outline:0;line-height:1.3;text-decoration:none;font-size:100%;list-style:none}.ui-helper-clearfix:before,.ui-helper-clearfix:after{content:"";display:table;border-collapse:collapse}.ui-helper-clearfix:after{clear:both}.ui-helper-zfix{width:100%;height:100%;top:0;left:0;position:absolute;opacity:0;-ms-filter:"alpha(opacity=0)"}.ui-front{z-index:100}.ui-state-disabled{cursor:default!important;pointer-events:none}.ui-icon{display:inline-block;vertical-align:middle;margin-top:-.25em;position:relative;text-indent:-99999px;overflow:hidden;background-repeat:no-repeat}.ui-widget-icon-block{left:50%;margin-left:-8px;display:block}.ui-widget-overlay{position:fixed;top:0;left:0;width:100%;height:100%}.ui-autocomplete{position:absolute;top:0;left:0;cursor:default}.ui-menu{list-style:none;padding:0;margin:0;display:block;outline:0}.ui-menu .ui-menu{position:absolute}.ui-menu .ui-menu-item{margin:0;cursor:pointer;list-style-image:url("data:image/gif;base64,R0lGODlhAQABAIAAAAAAAP///yH5BAEAAAAALAAAAAABAAEAAAIBRAA7")}.ui-menu .ui-menu-item-wrapper{position:relative;padding:3px 1em 3px .4em}.ui-menu .ui-menu-divider{margin:5px 0;height:0;font-size:0;line-height:0;border-width:1px 0 0 0}.ui-menu .ui-state-focus,.ui-menu .ui-state-active{margin:-1px}.ui-menu-icons{position:relative}.ui-menu-icons .ui-menu-item-wrapper{padding-left:2em}.ui-menu .ui-icon{position:absolute;top:0;bottom:0;left:.2em;margin:auto 0}.ui-menu .ui-menu-icon{left:auto;right:0}
--------------------------------------------------------------------------------
/src/main/java/uk/me/berndporr/iirj/PoleZeroPair.java:
--------------------------------------------------------------------------------
1 | package uk.me.berndporr.iirj;
2 |
3 | /*
4 | * Licensed to the Apache Software Foundation (ASF) under one or more
5 | * contributor license agreements. See the NOTICE file distributed with
6 | * this work for additional information regarding copyright ownership.
7 | * The ASF licenses this file to You under the Apache License, Version 2.0
8 | * (the "License"); you may not use this file except in compliance with
9 | * the License. You may obtain a copy of the License at
10 | *
11 | * http://www.apache.org/licenses/LICENSE-2.0
12 | *
13 | * Unless required by applicable law or agreed to in writing, software
14 | * distributed under the License is distributed on an "AS IS" BASIS,
15 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
16 | * See the License for the specific language governing permissions and
17 | * limitations under the License.
18 | *
19 | * Copyright (c) 2009 by Vinnie Falco
20 | * Copyright (c) 2016 by Bernd Porr
21 | */
22 |
23 | import org.apache.commons.math3.complex.Complex;
24 |
25 | /**
26 | *
27 | * It's written on the tin.
28 | *
29 | */
30 | public class PoleZeroPair {
31 |
32 | public ComplexPair poles;
33 | public ComplexPair zeros;
34 |
35 | // single pole/zero
36 | public PoleZeroPair(Complex p, Complex z) {
37 | poles = new ComplexPair(p);
38 | zeros = new ComplexPair(z);
39 | }
40 |
41 | // pole/zero pair
42 | public PoleZeroPair(Complex p1, Complex z1, Complex p2, Complex z2) {
43 | poles = new ComplexPair(p1, p2);
44 | zeros = new ComplexPair(z1, z2);
45 | }
46 |
47 | public boolean isSinglePole() {
48 | return poles.second.equals(new Complex(0, 0))
49 | && zeros.second.equals(new Complex(0, 0));
50 | }
51 |
52 | public boolean is_nan() {
53 | return poles.is_nan() || zeros.is_nan();
54 | }
55 | };
56 |
--------------------------------------------------------------------------------
/src/main/java/uk/me/berndporr/iirj/DirectFormII.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | * Copyright (c) 2009 by Vinnie Falco
18 | * Copyright (c) 2016 by Bernd Porr
19 | */
20 |
21 | package uk.me.berndporr.iirj;
22 |
23 | /**
24 | *
25 | * Implementation of a Direct Form II filter with its states. The coefficients
26 | * are supplied from the outside.
27 | *
28 | */
29 |
30 | public class DirectFormII extends DirectFormAbstract {
31 |
32 | public DirectFormII() {
33 | reset();
34 | }
35 |
36 | public void reset() {
37 | m_v1 = 0;
38 | m_v2 = 0;
39 | }
40 |
41 | public double process1(double in,
42 | Biquad s) {
43 | if (s != null) {
44 | double w = in - s.m_a1 * m_v1 - s.m_a2 * m_v2;
45 | double out = s.m_b0 * w + s.m_b1 * m_v1 + s.m_b2 * m_v2;
46 |
47 | m_v2 = m_v1;
48 | m_v1 = w;
49 |
50 | return out;
51 | } else {
52 | return in;
53 | }
54 | }
55 |
56 | double m_v1; // v[-1]
57 | double m_v2; // v[-2]
58 | }
59 |
--------------------------------------------------------------------------------
/src/main/java/uk/me/berndporr/iirj/DirectFormI.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | * Copyright (c) 2009 by Vinnie Falco
18 | * Copyright (c) 2016 by Bernd Porr
19 | */
20 |
21 | package uk.me.berndporr.iirj;
22 |
23 | /**
24 | *
25 | * Implementation of a Direct Form I filter with its states. The coefficients
26 | * are supplied from the outside.
27 | *
28 | */
29 | public class DirectFormI extends DirectFormAbstract {
30 |
31 | public DirectFormI() {
32 | reset();
33 | }
34 |
35 | public void reset() {
36 | m_x1 = 0;
37 | m_x2 = 0;
38 | m_y1 = 0;
39 | m_y2 = 0;
40 | }
41 |
42 | public double process1(double in, Biquad s) {
43 |
44 | double out = s.m_b0 * in + s.m_b1 * m_x1 + s.m_b2 * m_x2
45 | - s.m_a1 * m_y1 - s.m_a2 * m_y2;
46 | m_x2 = m_x1;
47 | m_y2 = m_y1;
48 | m_x1 = in;
49 | m_y1 = out;
50 |
51 | return out;
52 | }
53 |
54 | double m_x2; // x[n-2]
55 | double m_y2; // y[n-2]
56 | double m_x1; // x[n-1]
57 | double m_y1; // y[n-1]
58 | };
59 |
--------------------------------------------------------------------------------
/python-design/app/src/main/java/elliptic/App.java:
--------------------------------------------------------------------------------
1 | /*
2 | * This Java source file was generated by the Gradle 'init' task.
3 | */
4 | package elliptic;
5 |
6 | import uk.me.berndporr.iirj.*;
7 | import java.io.*;
8 |
9 | public class App {
10 |
11 | /**
12 | * elliptic_design.py:
13 | *
14 | * from scipy import signal
15 | * # sampling rate
16 | * fs = 1000
17 | * # cutoff
18 | * f0 = 100
19 | * # order
20 | * order = 4
21 | * # passband ripple
22 | * pr = 5
23 | * # minimum stopband rejection
24 | * sr = 40
25 | * coeff = signal.ellip(order, pr, sr, f0/fs*2, 'low', output='sos')
26 | *
27 | * The contents of coeff have been copied into coeff2 below.
28 | **/
29 |
30 | final double[][] coeff2 =
31 | {
32 | {1.665778210826693306e-02,
33 | -3.926235536821644570e-03,
34 | 1.665778210826693653e-02,
35 | 1.000000000000000000e+00,
36 | -1.715406458784182631e+00,
37 | 8.100524568939508896e-01},
38 | {1.000000000000000000e+00,
39 | -1.369802526921778174e+00,
40 | 9.999999999999997780e-01,
41 | 1.000000000000000000e+00,
42 | -1.605880898184007588e+00,
43 | 9.538687377533192624e-01}
44 | };
45 |
46 | /**
47 | * Calculates the impulse response of the filter and writes it to elliptic.dat.
48 | **/
49 | public void calcImpulse() {
50 | try {
51 | FileOutputStream os = new FileOutputStream("elliptic.dat");
52 | SOSCascade cust = new SOSCascade();
53 | cust.setup(coeff2);
54 | PrintStream bp = new PrintStream(os);
55 | // let's do an impulse response
56 | for (int i = 0; i < 500; i++) {
57 | double v = 0;
58 | if (i == 10)
59 | v = 1;
60 | v = cust.filter(v);
61 | bp.println("" + v);
62 | }
63 | os.close();
64 | } catch (FileNotFoundException e) {
65 | e.printStackTrace();
66 | } catch (IOException e){
67 | e.printStackTrace();
68 | }
69 | }
70 |
71 | public static void main(String[] args) {
72 | new App().calcImpulse();
73 | }
74 | }
75 |
--------------------------------------------------------------------------------
/docs/legal/jqueryUI.md:
--------------------------------------------------------------------------------
1 | ## jQuery UI v1.12.1
2 |
3 | ### jQuery UI License
4 | ```
5 | Copyright jQuery Foundation and other contributors, https://jquery.org/
6 |
7 | This software consists of voluntary contributions made by many
8 | individuals. For exact contribution history, see the revision history
9 | available at https://github.com/jquery/jquery-ui
10 |
11 | The following license applies to all parts of this software except as
12 | documented below:
13 |
14 | ====
15 |
16 | Permission is hereby granted, free of charge, to any person obtaining
17 | a copy of this software and associated documentation files (the
18 | "Software"), to deal in the Software without restriction, including
19 | without limitation the rights to use, copy, modify, merge, publish,
20 | distribute, sublicense, and/or sell copies of the Software, and to
21 | permit persons to whom the Software is furnished to do so, subject to
22 | the following conditions:
23 |
24 | The above copyright notice and this permission notice shall be
25 | included in all copies or substantial portions of the Software.
26 |
27 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
28 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
29 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
30 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
31 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
32 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
33 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
34 |
35 | ====
36 |
37 | Copyright and related rights for sample code are waived via CC0. Sample
38 | code is defined as all source code contained within the demos directory.
39 |
40 | CC0: http://creativecommons.org/publicdomain/zero/1.0/
41 |
42 | ====
43 |
44 | All files located in the node_modules and external directories are
45 | externally maintained libraries used by this software which have their
46 | own licenses; we recommend you read them, as their terms may differ from
47 | the terms above.
48 |
49 | ```
50 |
--------------------------------------------------------------------------------
/docs/legal/ADDITIONAL_LICENSE_INFO:
--------------------------------------------------------------------------------
1 | ADDITIONAL INFORMATION ABOUT LICENSING
2 |
3 | Certain files distributed by Oracle America, Inc. and/or its affiliates are
4 | subject to the following clarification and special exception to the GPLv2,
5 | based on the GNU Project exception for its Classpath libraries, known as the
6 | GNU Classpath Exception.
7 |
8 | Note that Oracle includes multiple, independent programs in this software
9 | package. Some of those programs are provided under licenses deemed
10 | incompatible with the GPLv2 by the Free Software Foundation and others.
11 | For example, the package includes programs licensed under the Apache
12 | License, Version 2.0 and may include FreeType. Such programs are licensed
13 | to you under their original licenses.
14 |
15 | Oracle facilitates your further distribution of this package by adding the
16 | Classpath Exception to the necessary parts of its GPLv2 code, which permits
17 | you to use that code in combination with other independent modules not
18 | licensed under the GPLv2. However, note that this would not permit you to
19 | commingle code under an incompatible license with Oracle's GPLv2 licensed
20 | code by, for example, cutting and pasting such code into a file also
21 | containing Oracle's GPLv2 licensed code and then distributing the result.
22 |
23 | Additionally, if you were to remove the Classpath Exception from any of the
24 | files to which it applies and distribute the result, you would likely be
25 | required to license some or all of the other code in that distribution under
26 | the GPLv2 as well, and since the GPLv2 is incompatible with the license terms
27 | of some items included in the distribution by Oracle, removing the Classpath
28 | Exception could therefore effectively compromise your ability to further
29 | distribute the package.
30 |
31 | Failing to distribute notices associated with some files may also create
32 | unexpected legal consequences.
33 |
34 | Proceed with caution and we recommend that you obtain the advice of a lawyer
35 | skilled in open source matters before removing the Classpath Exception or
36 | making modifications to this package which may subsequently be redistributed
37 | and/or involve the use of third party software.
38 |
--------------------------------------------------------------------------------
/src/main/java/uk/me/berndporr/iirj/ComplexPair.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | * Copyright (c) 2009 by Vinnie Falco
18 | * Copyright (c) 2016 by Bernd Porr
19 | */
20 |
21 |
22 | package uk.me.berndporr.iirj;
23 |
24 | import org.apache.commons.math3.complex.Complex;
25 |
26 | /**
27 | *
28 | * A complex pair
29 | *
30 | */
31 | public class ComplexPair {
32 |
33 | public Complex first;
34 | public Complex second;
35 |
36 | ComplexPair (Complex c1,
37 | Complex c2) {
38 | first = c1;
39 | second = c2;
40 | }
41 |
42 | ComplexPair (Complex c1) {
43 | first = c1;
44 | second = new Complex(0,0);
45 | }
46 |
47 | boolean isConjugate () {
48 | return second.equals(first.conjugate());
49 | }
50 |
51 | boolean isReal () {
52 | return first.getImaginary() == 0 && second.getImaginary() == 0;
53 | }
54 |
55 | // Returns true if this is either a conjugate pair,
56 | // or a pair of reals where neither is zero.
57 | boolean isMatchedPair () {
58 | if (first.getImaginary() != 0)
59 | return second.equals(first.conjugate());
60 | else
61 | return second.getImaginary() == 0 &&
62 | second.getReal() != 0 &&
63 | first.getReal() != 0;
64 | }
65 |
66 | boolean is_nan()
67 | {
68 | return first.isNaN() || second.isNaN();
69 | }
70 | };
71 |
--------------------------------------------------------------------------------
/src/main/java/uk/me/berndporr/iirj/MathSupplement.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | * Copyright (c) 2009 by Vinnie Falco
18 | * Copyright (c) 2016 by Bernd Porr
19 | */
20 |
21 | package uk.me.berndporr.iirj;
22 |
23 | import org.apache.commons.math3.complex.Complex;
24 |
25 | /**
26 | *
27 | * Useful math functions which come back over and over again
28 | *
29 | */
30 | public class MathSupplement {
31 |
32 | public static double doubleLn10 =2.3025850929940456840179914546844;
33 |
34 | public static Complex solve_quadratic_1(double a, double b, double c) {
35 | return (new Complex(-b).add(new Complex(b * b - 4 * a * c, 0)).sqrt())
36 | .divide(2. * a);
37 | }
38 |
39 | public static Complex solve_quadratic_2(double a, double b, double c) {
40 | return (new Complex(-b).subtract(new Complex(b * b - 4 * a * c, 0))
41 | .sqrt()).divide(2. * a);
42 | }
43 |
44 | public static Complex adjust_imag(Complex c) {
45 | if (Math.abs(c.getImaginary()) < 1e-30)
46 | return new Complex(c.getReal(), 0);
47 | else
48 | return c;
49 | }
50 |
51 | public static Complex addmul(Complex c, double v, Complex c1) {
52 | return new Complex(c.getReal() + v * c1.getReal(), c.getImaginary() + v
53 | * c1.getImaginary());
54 | }
55 |
56 | public static Complex recip(Complex c) {
57 | double n = 1.0 / (c.abs() * c.abs());
58 |
59 | return new Complex(n * c.getReal(), n * c.getImaginary());
60 | }
61 |
62 | public static double asinh(double x) {
63 | return Math.log(x + Math.sqrt(x * x + 1));
64 | }
65 |
66 | public static double acosh(double x) {
67 | return Math.log(x + Math.sqrt(x * x - 1));
68 | }
69 |
70 | }
71 |
--------------------------------------------------------------------------------
/src/main/java/uk/me/berndporr/iirj/LowPassTransform.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | * Copyright (c) 2009 by Vinnie Falco
18 | * Copyright (c) 2016 by Bernd Porr
19 | */
20 |
21 |
22 | package uk.me.berndporr.iirj;
23 |
24 | import org.apache.commons.math3.complex.Complex;
25 |
26 | /**
27 | * Transforms from an analogue lowpass filter to a digital lowpass filter
28 | */
29 | public class LowPassTransform {
30 |
31 | private double f;
32 |
33 | private Complex transform(Complex c) {
34 | if (c.isInfinite())
35 | return new Complex(-1, 0);
36 |
37 | // frequency transform
38 | c = c.multiply(f);
39 |
40 | Complex one = new Complex(1, 0);
41 |
42 | // bilinear low pass transform
43 | return (one.add(c)).divide(one.subtract(c));
44 | }
45 |
46 | public LowPassTransform(double fc, LayoutBase digital, LayoutBase analog) {
47 | digital.reset();
48 |
49 | if (fc < 0) {
50 | throw new ArithmeticException("Cutoff frequency cannot be negative.");
51 | }
52 |
53 | if (!(fc < 0.5)) {
54 | throw new ArithmeticException("Cutoff frequency must be less than the Nyquist frequency.");
55 | }
56 |
57 | // prewarp
58 | f = Math.tan(Math.PI * fc);
59 |
60 | int numPoles = analog.getNumPoles();
61 | int pairs = numPoles / 2;
62 | for (int i = 0; i < pairs; ++i) {
63 | PoleZeroPair pair = analog.getPair(i);
64 | digital.addPoleZeroConjugatePairs(transform(pair.poles.first),
65 | transform(pair.zeros.first));
66 | }
67 |
68 | if ((numPoles & 1) == 1) {
69 | PoleZeroPair pair = analog.getPair(pairs);
70 | digital.add(transform(pair.poles.first),
71 | transform(pair.zeros.first));
72 | }
73 |
74 | digital.setNormal(analog.getNormalW(), analog.getNormalGain());
75 | }
76 |
77 | }
78 |
--------------------------------------------------------------------------------
/src/main/java/uk/me/berndporr/iirj/HighPassTransform.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | * Copyright (c) 2009 by Vinnie Falco
18 | * Copyright (c) 2016 by Bernd Porr
19 | */
20 |
21 | package uk.me.berndporr.iirj;
22 |
23 | import org.apache.commons.math3.complex.Complex;
24 |
25 | /**
26 | * Transforms from an analogue lowpass filter to a digital highpass filter
27 | */
28 | public class HighPassTransform {
29 |
30 | double f;
31 |
32 | public HighPassTransform(double fc, LayoutBase digital, LayoutBase analog) {
33 | digital.reset();
34 |
35 | if (fc < 0) {
36 | throw new ArithmeticException("Cutoff frequency cannot be negative.");
37 | }
38 |
39 | if (!(fc < 0.5)) {
40 | throw new ArithmeticException("Cutoff frequency must be less than the Nyquist frequency.");
41 | }
42 |
43 | // prewarp
44 | f = 1. / Math.tan(Math.PI * fc);
45 |
46 | int numPoles = analog.getNumPoles();
47 | int pairs = numPoles / 2;
48 | for (int i = 0; i < pairs; ++i) {
49 | PoleZeroPair pair = analog.getPair(i);
50 | digital.addPoleZeroConjugatePairs(transform(pair.poles.first),
51 | transform(pair.zeros.first));
52 | }
53 |
54 | if ((numPoles & 1) == 1) {
55 | PoleZeroPair pair = analog.getPair(pairs);
56 | digital.add(transform(pair.poles.first),
57 | transform(pair.zeros.first));
58 | }
59 |
60 | digital.setNormal(Math.PI - analog.getNormalW(), analog.getNormalGain());
61 | }
62 |
63 | private Complex transform(Complex c) {
64 | if (c.isInfinite())
65 | return new Complex(1, 0);
66 |
67 | // frequency transform
68 | c = c.multiply(f);
69 |
70 | // bilinear high pass transform
71 | return new Complex(-1).multiply((new Complex(1)).add(c)).divide(
72 | (new Complex(1)).subtract(c));
73 | }
74 |
75 | }
76 |
--------------------------------------------------------------------------------
/src/main/java/uk/me/berndporr/iirj/SOSCascade.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | * Copyright (c) 2009 by Vinnie Falco
18 | * Copyright (c) 2021 by Bernd Porr
19 | */
20 |
21 |
22 | package uk.me.berndporr.iirj;
23 |
24 | import org.apache.commons.math3.complex.Complex;
25 | import org.apache.commons.math3.complex.ComplexUtils;
26 |
27 | /**
28 | * User facing class which contains two methods
29 | * to create Custom SOS filters, in particular where
30 | * the filter coefficients have been generated by
31 | * Python's scipy signal library for example:
32 | * sos = signal.butter(4, 0.1, output='sos').
33 | * Call one of the setup() methods below to
34 | * set the SOS coefficients. See the unit
35 | * test for examples how to set the coefficients.
36 | */
37 | public class SOSCascade extends Cascade {
38 |
39 | /**
40 | * Sets directly the coefficients of the chain of
41 | * 2nd order filters. The layout of the array is
42 | * excatly how the scipy python design functions
43 | * output the sos coeffcients:
44 | * [b0,b1,b2,a0,a1,a2],[b0,b1,b2,a0,a1,a2],...
45 | * The filter type can be either DirectFormAbstract.DIRECT_FORM_II
46 | * or DirectFormAbstract.DIRECT_FORM_I.
47 | * @param sosCoefficients SOS coefficients
48 | * @param directFormType Direct form type (I or II).
49 | **/
50 | public void setup(final double[][] sosCoefficients,
51 | final int directFormType) {
52 | setSOScoeff(sosCoefficients,directFormType);
53 | }
54 |
55 | /**
56 | * Sets directly the coefficients of the chain of
57 | * 2nd order filters. The layout of the array is
58 | * excatly how the scipy python design functions
59 | * output the coeffcients:
60 | * [b0,b1,b2,a0,a1,a2],[b0,b1,b2,a0,a1,a2],...
61 | * The filter type is DIRECT_FORM_II.
62 | * @param sosCoefficients SOS coefficients
63 | **/
64 | public void setup(final double[][] sosCoefficients) {
65 | setSOScoeff(sosCoefficients,DirectFormAbstract.DIRECT_FORM_II);
66 | }
67 | }
68 |
--------------------------------------------------------------------------------
/docs/uk/me/berndporr/iirj/class-use/ChebyshevI.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Uses of Class uk.me.berndporr.iirj.ChebyshevI (uk.me.berndporr:iirj 1.7 API)
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
21 |
24 |
25 |
26 |
47 |
48 |
49 |
50 |
51 |
Uses of Class uk.me.berndporr.iirj.ChebyshevI
52 |
53 | No usage of uk.me.berndporr.iirj.ChebyshevI
54 |
58 |
67 |
68 |
69 |
--------------------------------------------------------------------------------
/python-design/gradlew.bat:
--------------------------------------------------------------------------------
1 | @rem
2 | @rem Copyright 2015 the original author or authors.
3 | @rem
4 | @rem Licensed under the Apache License, Version 2.0 (the "License");
5 | @rem you may not use this file except in compliance with the License.
6 | @rem You may obtain a copy of the License at
7 | @rem
8 | @rem https://www.apache.org/licenses/LICENSE-2.0
9 | @rem
10 | @rem Unless required by applicable law or agreed to in writing, software
11 | @rem distributed under the License is distributed on an "AS IS" BASIS,
12 | @rem WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 | @rem See the License for the specific language governing permissions and
14 | @rem limitations under the License.
15 | @rem
16 |
17 | @if "%DEBUG%" == "" @echo off
18 | @rem ##########################################################################
19 | @rem
20 | @rem Gradle startup script for Windows
21 | @rem
22 | @rem ##########################################################################
23 |
24 | @rem Set local scope for the variables with windows NT shell
25 | if "%OS%"=="Windows_NT" setlocal
26 |
27 | set DIRNAME=%~dp0
28 | if "%DIRNAME%" == "" set DIRNAME=.
29 | set APP_BASE_NAME=%~n0
30 | set APP_HOME=%DIRNAME%
31 |
32 | @rem Resolve any "." and ".." in APP_HOME to make it shorter.
33 | for %%i in ("%APP_HOME%") do set APP_HOME=%%~fi
34 |
35 | @rem Add default JVM options here. You can also use JAVA_OPTS and GRADLE_OPTS to pass JVM options to this script.
36 | set DEFAULT_JVM_OPTS="-Xmx64m" "-Xms64m"
37 |
38 | @rem Find java.exe
39 | if defined JAVA_HOME goto findJavaFromJavaHome
40 |
41 | set JAVA_EXE=java.exe
42 | %JAVA_EXE% -version >NUL 2>&1
43 | if "%ERRORLEVEL%" == "0" goto execute
44 |
45 | echo.
46 | echo ERROR: JAVA_HOME is not set and no 'java' command could be found in your PATH.
47 | echo.
48 | echo Please set the JAVA_HOME variable in your environment to match the
49 | echo location of your Java installation.
50 |
51 | goto fail
52 |
53 | :findJavaFromJavaHome
54 | set JAVA_HOME=%JAVA_HOME:"=%
55 | set JAVA_EXE=%JAVA_HOME%/bin/java.exe
56 |
57 | if exist "%JAVA_EXE%" goto execute
58 |
59 | echo.
60 | echo ERROR: JAVA_HOME is set to an invalid directory: %JAVA_HOME%
61 | echo.
62 | echo Please set the JAVA_HOME variable in your environment to match the
63 | echo location of your Java installation.
64 |
65 | goto fail
66 |
67 | :execute
68 | @rem Setup the command line
69 |
70 | set CLASSPATH=%APP_HOME%\gradle\wrapper\gradle-wrapper.jar
71 |
72 |
73 | @rem Execute Gradle
74 | "%JAVA_EXE%" %DEFAULT_JVM_OPTS% %JAVA_OPTS% %GRADLE_OPTS% "-Dorg.gradle.appname=%APP_BASE_NAME%" -classpath "%CLASSPATH%" org.gradle.wrapper.GradleWrapperMain %*
75 |
76 | :end
77 | @rem End local scope for the variables with windows NT shell
78 | if "%ERRORLEVEL%"=="0" goto mainEnd
79 |
80 | :fail
81 | rem Set variable GRADLE_EXIT_CONSOLE if you need the _script_ return code instead of
82 | rem the _cmd.exe /c_ return code!
83 | if not "" == "%GRADLE_EXIT_CONSOLE%" exit 1
84 | exit /b 1
85 |
86 | :mainEnd
87 | if "%OS%"=="Windows_NT" endlocal
88 |
89 | :omega
90 |
--------------------------------------------------------------------------------
/README.md:
--------------------------------------------------------------------------------
1 | # iirj
2 |
3 | An IIR filter library written in JAVA.
4 |
5 | Highpass, lowpass, bandpass and bandstop as
6 | Butterworth, Bessel and Chebyshev Type I/II.
7 |
8 | You can also calculate the filter coefficients with Python's
9 | scipy and then create your custom IIR filter.
10 | See the `python-design` subdirectory.
11 |
12 | It's based on the IIR1 library [https://github.com/berndporr/iir1]
13 | which in turn is based on Vinnie Falco's DSPFilters [https://github.com/vinniefalco/DSPFilters].
14 |
15 | 
16 |
17 | ## Usage
18 |
19 | `import uk.me.berndporr.iirj.*;`
20 |
21 | ### Constructor
22 |
23 | `Butterworth butterworth = new Butterworth();`
24 |
25 | ### Initialisation
26 | 1. Bandstop
27 |
28 | `butterworth.bandStop(order,Samplingfreq,Center freq,Width in frequ);`
29 |
30 | 2. Bandpass
31 |
32 | `butterworth.bandPass(order,Samplingfreq,Center freq,Width in frequ);`
33 |
34 | 3. Lowpass
35 |
36 | `butterworth.lowPass(order,Samplingfreq,Cutoff frequ);`
37 |
38 | 4. Highpass
39 |
40 | `butterworth.highPass(order,Samplingfreq,Cutoff frequ);`
41 |
42 | ### Filtering
43 | Sample by sample for realtime processing:
44 |
45 | ```
46 | v = butterworth.filter(v)
47 | ```
48 |
49 | ## Coding examples
50 | See the `*Test.java` files for complete examples
51 | for all filter types. Run them with `mvn test`. These test programs
52 | write the different impulse responses of the filters to text files.
53 |
54 | ## Installation
55 |
56 | ## Local install
57 | - Clone this repository
58 | - Run `mvn install` to add it to your local maven respository
59 |
60 | ## Maven central
61 |
62 | At [](https://central.sonatype.com/artifact/uk.me.berndporr/iirj)
63 | click on the iirj version number and then choose the appropriate installation option, for
64 | example for Android studio.
65 |
66 | ## Android Studio
67 | ```
68 | dependencies {
69 | implementation group: 'uk.me.berndporr', name:'iirj', version: '1.7'
70 | }
71 | ```
72 | Android studio will automatically notify you if a new IIR library is available.
73 |
74 | ## Documentation
75 | * Online: https://berndporr.github.io/iirj/
76 | * `mvn javadoc:javadoc` generates the JavaDocs
77 | * `mvn site` generates the web pages containing the documentation
78 | under `target/site` describing all commands in detail.
79 |
80 | ## Testing
81 | `mvn test` creates impulse responses in the subdirectories
82 | for the different filters: `target/surefire-reports`.
83 |
84 | To see the impulse and frequency responses run:
85 | ```
86 | python3 ./plot_impulse_fresponse.py
87 | ```
88 | where is is butterworth, bessel, chebyshevI or chebyshevII.
89 |
90 | The script DetectorTest uses a bandpass filter to detect the
91 | heartbeats of an ECG recording faking a matched filter which could
92 | be also seen as a 1st approximation of a wavelet. The heartrate is
93 | stored in hr.txt.
94 |
95 |
96 |
97 | Have fun
98 |
99 | /Bernd Porr
100 | [http://www.berndporr.me.uk]
101 |
102 |
--------------------------------------------------------------------------------
/docs/legal/jquery.md:
--------------------------------------------------------------------------------
1 | ## jQuery v3.6.0
2 |
3 | ### jQuery License
4 | ```
5 | jQuery v 3.6.0
6 | Copyright OpenJS Foundation and other contributors, https://openjsf.org/
7 |
8 | Permission is hereby granted, free of charge, to any person obtaining
9 | a copy of this software and associated documentation files (the
10 | "Software"), to deal in the Software without restriction, including
11 | without limitation the rights to use, copy, modify, merge, publish,
12 | distribute, sublicense, and/or sell copies of the Software, and to
13 | permit persons to whom the Software is furnished to do so, subject to
14 | the following conditions:
15 |
16 | The above copyright notice and this permission notice shall be
17 | included in all copies or substantial portions of the Software.
18 |
19 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
20 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
21 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
22 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
23 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
24 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
25 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
26 |
27 | ******************************************
28 |
29 | The jQuery JavaScript Library v3.6.0 also includes Sizzle.js
30 |
31 | Sizzle.js includes the following license:
32 |
33 | Copyright JS Foundation and other contributors, https://js.foundation/
34 |
35 | This software consists of voluntary contributions made by many
36 | individuals. For exact contribution history, see the revision history
37 | available at https://github.com/jquery/sizzle
38 |
39 | The following license applies to all parts of this software except as
40 | documented below:
41 |
42 | ====
43 |
44 | Permission is hereby granted, free of charge, to any person obtaining
45 | a copy of this software and associated documentation files (the
46 | "Software"), to deal in the Software without restriction, including
47 | without limitation the rights to use, copy, modify, merge, publish,
48 | distribute, sublicense, and/or sell copies of the Software, and to
49 | permit persons to whom the Software is furnished to do so, subject to
50 | the following conditions:
51 |
52 | The above copyright notice and this permission notice shall be
53 | included in all copies or substantial portions of the Software.
54 |
55 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
56 | EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
57 | MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
58 | NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
59 | LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
60 | OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
61 | WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
62 |
63 | ====
64 |
65 | All files located in the node_modules and external directories are
66 | externally maintained libraries used by this software which have their
67 | own licenses; we recommend you read them, as their terms may differ from
68 | the terms above.
69 |
70 | *********************
71 |
72 | ```
73 |
--------------------------------------------------------------------------------
/src/test/java/uk/me/berndporr/iirj/DetectorTest.java:
--------------------------------------------------------------------------------
1 | package uk.me.berndporr.iirj;
2 | /*
3 | * Licensed to the Apache Software Foundation (ASF) under one or more
4 | * contributor license agreements. See the NOTICE file distributed with
5 | * this work for additional information regarding copyright ownership.
6 | * The ASF licenses this file to You under the Apache License, Version 2.0
7 | * (the "License"); you may not use this file except in compliance with
8 | * the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 |
20 |
21 | import java.io.File;
22 | import java.io.PrintStream;
23 | import java.io.FileOutputStream;
24 | import java.util.Scanner;
25 |
26 | import uk.me.berndporr.iirj.Butterworth;
27 |
28 | import org.junit.Assert;
29 | import org.junit.Test;
30 |
31 | // Detect the heartbeat in an ECG
32 | // The idea is to create a matched filter for ECG which in turn is
33 | // a bandpass and which in turn could be understood as a wavelet.
34 | // The center and bandwidth here are experimental results so that the
35 | // impulse response resembles the timing of an R peak.
36 | public class DetectorTest {
37 |
38 | static String prefix="target/surefire-reports/detector/";
39 |
40 | void createDir() {
41 | File dir = new File(prefix);
42 | dir.mkdirs();
43 | }
44 |
45 |
46 | @Test
47 | public void detTest() throws Exception {
48 | createDir();
49 |
50 | Butterworth butterworth = new Butterworth();
51 | // this fakes an R peak so we have a matched filter!
52 | butterworth.bandPass(2,250,20,15);
53 |
54 | FileOutputStream os = new FileOutputStream(prefix+"det.txt");
55 | PrintStream bp = new PrintStream(os);
56 |
57 | FileOutputStream heartrate = new FileOutputStream(prefix+"hr.txt");
58 | PrintStream hr = new PrintStream(heartrate);
59 |
60 | Scanner is = new Scanner(new File("src/test/resources/ecg.dat"));
61 |
62 | double max = 0;
63 | double t1=0,t2=0;
64 | int notDet = 0;
65 | double time = 0;
66 | int ignore = 100;
67 | int sampleno = 0;
68 |
69 | // let's do an impulse response
70 | while(is.hasNextLine()) {
71 | double v=0;
72 | time = time + 1.0/125.0;
73 | String data = is.nextLine();
74 | v = Double.parseDouble(data);
75 | v = butterworth.filter(v);
76 | v = v*v;
77 | bp.println(""+v);
78 | if (ignore>0) {
79 | ignore--;
80 | } else {
81 | if (v > max) {
82 | max = v;
83 | }
84 | }
85 | if (notDet>0) {
86 | notDet--;
87 | } else {
88 | if (v > 0.5*max) {
89 | t1 = time;
90 | notDet = 50;
91 | int r = (int)Math.round((t1-t2)*60);
92 | if (r>30) {
93 | hr.println(String.format("%d %d",sampleno,r));
94 | Assert.assertTrue((r>60)&&(r<160));
95 | }
96 | t2 = t1;
97 | }
98 | }
99 | sampleno++;
100 | }
101 |
102 | os.close();
103 | heartrate.close();
104 | is.close();
105 |
106 | }
107 |
108 |
109 | public void main(String args[]) {
110 | try {
111 | detTest();
112 | } catch (Exception e) {};
113 | }
114 |
115 | }
116 |
--------------------------------------------------------------------------------
/src/main/java/uk/me/berndporr/iirj/BandPassTransform.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | * Copyright (c) 2009 by Vinnie Falco
18 | * Copyright (c) 2016 by Bernd Porr
19 | */
20 |
21 |
22 | package uk.me.berndporr.iirj;
23 |
24 | import org.apache.commons.math3.complex.Complex;
25 |
26 | /**
27 | * Transforms from an analogue bandpass filter to a digital bandstop filter
28 | */
29 | public class BandPassTransform {
30 |
31 | private double wc2;
32 | private double wc;
33 | private double a, b;
34 | private double a2, b2;
35 | private double ab, ab_2;
36 |
37 | public BandPassTransform(double fc, double fw, LayoutBase digital,
38 | LayoutBase analog) {
39 |
40 | digital.reset();
41 |
42 | if (fc < 0) {
43 | throw new ArithmeticException("Cutoff frequency cannot be negative.");
44 | }
45 |
46 | if (!(fc < 0.5)) {
47 | throw new ArithmeticException("Cutoff frequency must be less than the Nyquist frequency.");
48 | }
49 |
50 | double ww = 2 * Math.PI * fw;
51 |
52 | // pre-calcs
53 | wc2 = 2 * Math.PI * fc - (ww / 2);
54 | wc = wc2 + ww;
55 |
56 | // what is this crap?
57 | if (wc2 < 1e-8)
58 | wc2 = 1e-8;
59 | if (wc > Math.PI - 1e-8)
60 | wc = Math.PI - 1e-8;
61 |
62 | a = Math.cos((wc + wc2) * 0.5) / Math.cos((wc - wc2) * 0.5);
63 | b = 1 / Math.tan((wc - wc2) * 0.5);
64 | a2 = a * a;
65 | b2 = b * b;
66 | ab = a * b;
67 | ab_2 = 2 * ab;
68 |
69 | int numPoles = analog.getNumPoles();
70 | int pairs = numPoles / 2;
71 | for (int i = 0; i < pairs; ++i) {
72 | PoleZeroPair pair = analog.getPair(i);
73 | ComplexPair p1 = transform(pair.poles.first);
74 | ComplexPair z1 = transform(pair.zeros.first);
75 |
76 | digital.addPoleZeroConjugatePairs(p1.first, z1.first);
77 | digital.addPoleZeroConjugatePairs(p1.second, z1.second);
78 | }
79 |
80 | if ((numPoles & 1) == 1) {
81 | ComplexPair poles = transform(analog.getPair(pairs).poles.first);
82 | ComplexPair zeros = transform(analog.getPair(pairs).zeros.first);
83 |
84 | digital.add(poles, zeros);
85 | }
86 |
87 | double wn = analog.getNormalW();
88 | digital.setNormal(
89 | 2 * Math.atan(Math.sqrt(Math.tan((wc + wn) * 0.5)
90 | * Math.tan((wc2 + wn) * 0.5))), analog.getNormalGain());
91 | }
92 |
93 | private ComplexPair transform(Complex c) {
94 | if (c.isInfinite()) {
95 | return new ComplexPair(new Complex(-1), new Complex(1));
96 | }
97 |
98 | c = ((new Complex(1)).add(c)).divide((new Complex(1)).subtract(c)); // bilinear
99 |
100 | Complex v = new Complex(0);
101 | v = MathSupplement.addmul(v, 4 * (b2 * (a2 - 1) + 1), c);
102 | v = v.add(8 * (b2 * (a2 - 1) - 1));
103 | v = v.multiply(c);
104 | v = v.add(4 * (b2 * (a2 - 1) + 1));
105 | v = v.sqrt();
106 |
107 | Complex u = v.multiply(-1);
108 | u = MathSupplement.addmul(u, ab_2, c);
109 | u = u.add(ab_2);
110 |
111 | v = MathSupplement.addmul(v, ab_2, c);
112 | v = v.add(ab_2);
113 |
114 | Complex d = new Complex(0);
115 | d = MathSupplement.addmul(d, 2 * (b - 1), c).add(2 * (1 + b));
116 |
117 | return new ComplexPair(u.divide(d), v.divide(d));
118 | }
119 |
120 | }
121 |
--------------------------------------------------------------------------------
/src/test/java/uk/me/berndporr/iirj/CustomTest.java:
--------------------------------------------------------------------------------
1 | package uk.me.berndporr.iirj;
2 | /*
3 | * Licensed to the Apache Software Foundation (ASF) under one or more
4 | * contributor license agreements. See the NOTICE file distributed with
5 | * this work for additional information regarding copyright ownership.
6 | * The ASF licenses this file to You under the Apache License, Version 2.0
7 | * (the "License"); you may not use this file except in compliance with
8 | * the License. You may obtain a copy of the License at
9 | *
10 | * http://www.apache.org/licenses/LICENSE-2.0
11 | *
12 | * Unless required by applicable law or agreed to in writing, software
13 | * distributed under the License is distributed on an "AS IS" BASIS,
14 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
15 | * See the License for the specific language governing permissions and
16 | * limitations under the License.
17 | */
18 |
19 |
20 | import java.io.PrintStream;
21 | import java.io.FileOutputStream;
22 | import java.io.File;
23 |
24 | import uk.me.berndporr.iirj.Butterworth;
25 |
26 | import org.junit.Assert;
27 | import org.junit.Test;
28 |
29 | // Tests if the Cascade works, the filter stages and
30 | // if the custom parameters are properly transmitted.
31 | public class CustomTest {
32 |
33 | static String prefix="target/surefire-reports/custom/";
34 |
35 | final double[][] coeff1 =
36 | {{ 0.02008337, 0.04016673, 0.02008337,
37 | 1, -1.56101808, 0.64135154}};
38 |
39 | final double[] input1 = {
40 | -1.0,
41 | 0.5,
42 | 1.0};
43 |
44 | final double[] result1 = {
45 | -2.00833656e-02,
46 | -6.14755450e-02,
47 | -6.30005740e-02};
48 |
49 | final double[][] coeff2 =
50 | {{1.78260999e-03, 3.56521998e-03, 1.78260999e-03,
51 | 1.00000000e+00, -1.25544047e+00, 4.09013783e-01},
52 | {1.00000000e+00, 2.00000000e+00, 1.00000000e+00,
53 | 1.00000000e+00, -1.51824184e+00, 7.03962657e-01}};
54 |
55 | final double[] input2 = {
56 | -1,0.5,-1,0.5,-0.3,3,-1E-5
57 | };
58 |
59 | final double[] result2 = {
60 | -0.00178261, -0.01118353, -0.03455084, -0.07277369, -0.11973872, -0.158864,
61 | -0.15873629
62 | };
63 |
64 | final double delta = 1E-5;
65 |
66 | @Test
67 | public void test1() throws Exception {
68 |
69 | SOSCascade cust = new SOSCascade();
70 | cust.setup(coeff1);
71 | int i = 0;
72 | for(double v:input1) {
73 | Assert.assertEquals(cust.filter(v),result1[i++],delta);
74 | }
75 |
76 | }
77 |
78 | @Test
79 | public void test2() throws Exception {
80 |
81 | SOSCascade cust = new SOSCascade();
82 | cust.setup(coeff1,DirectFormAbstract.DIRECT_FORM_I);
83 | int i = 0;
84 | for(double v:input1) {
85 | Assert.assertEquals(cust.filter(v),result1[i++],delta);
86 | }
87 |
88 | }
89 |
90 | @Test
91 | public void test3() throws Exception {
92 |
93 | SOSCascade cust = new SOSCascade();
94 | cust.setup(coeff2);
95 | int i = 0;
96 | for(double v:input2) {
97 | Assert.assertEquals(cust.filter(v),result2[i++],delta);
98 | }
99 |
100 | }
101 |
102 | @Test
103 | public void test4() throws Exception {
104 |
105 | SOSCascade cust = new SOSCascade();
106 | cust.setup(coeff2,DirectFormAbstract.DIRECT_FORM_I);
107 | int i = 0;
108 | for(double v:input2) {
109 | Assert.assertEquals(cust.filter(v),result2[i++],delta);
110 | }
111 |
112 | }
113 |
114 | @Test
115 | public void lowPassTest() throws Exception {
116 | SOSCascade cust = new SOSCascade();
117 | cust.setup(coeff2);
118 |
119 | File dir = new File(prefix);
120 | dir.mkdirs();
121 | FileOutputStream os = new FileOutputStream(prefix+"lp.txt");
122 | PrintStream bp = new PrintStream(os);
123 |
124 | // let's do an impulse response
125 | for (int i = 0; i < 500; i++) {
126 | double v = 0;
127 | if (i == 10)
128 | v = 1;
129 | v = cust.filter(v);
130 | bp.println("" + v);
131 | }
132 | Assert.assertTrue(Math.abs(cust.filter(0))<1E-30);
133 | Assert.assertTrue(Math.abs(cust.filter(0))!=0.0);
134 | Assert.assertTrue(Math.abs(cust.filter(0))!=Double.NaN);
135 |
136 | os.close();
137 | }
138 |
139 | }
140 |
--------------------------------------------------------------------------------
/src/main/java/uk/me/berndporr/iirj/BandStopTransform.java:
--------------------------------------------------------------------------------
1 | /*
2 | * Licensed to the Apache Software Foundation (ASF) under one or more
3 | * contributor license agreements. See the NOTICE file distributed with
4 | * this work for additional information regarding copyright ownership.
5 | * The ASF licenses this file to You under the Apache License, Version 2.0
6 | * (the "License"); you may not use this file except in compliance with
7 | * the License. You may obtain a copy of the License at
8 | *
9 | * http://www.apache.org/licenses/LICENSE-2.0
10 | *
11 | * Unless required by applicable law or agreed to in writing, software
12 | * distributed under the License is distributed on an "AS IS" BASIS,
13 | * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
14 | * See the License for the specific language governing permissions and
15 | * limitations under the License.
16 | *
17 | * Copyright (c) 2009 by Vinnie Falco
18 | * Copyright (c) 2016 by Bernd Porr
19 | */
20 |
21 | package uk.me.berndporr.iirj;
22 | import org.apache.commons.math3.complex.Complex;
23 |
24 | /**
25 | * Transforms from an analogue lowpass filter to a digital bandstop filter
26 | */
27 | public class BandStopTransform {
28 |
29 |
30 | private double wc;
31 | private double wc2;
32 | private double a;
33 | private double b;
34 | private double a2;
35 | private double b2;
36 |
37 |
38 | public BandStopTransform(double fc,
39 | double fw,
40 | LayoutBase digital,
41 | LayoutBase analog) {
42 | digital.reset();
43 |
44 | if (fc < 0) {
45 | throw new ArithmeticException("Cutoff frequency cannot be negative.");
46 | }
47 |
48 | if (!(fc < 0.5)) {
49 | throw new ArithmeticException("Cutoff frequency must be less than the Nyquist frequency.");
50 | }
51 |
52 | double ww = 2 * Math.PI * fw;
53 |
54 | wc2 = 2 * Math.PI * fc - (ww / 2);
55 | wc = wc2 + ww;
56 |
57 | // this is crap
58 | if (wc2 < 1e-8)
59 | wc2 = 1e-8;
60 | if (wc > Math.PI - 1e-8)
61 | wc = Math.PI - 1e-8;
62 |
63 | a = Math.cos((wc + wc2) * .5) /
64 | Math.cos((wc - wc2) * .5);
65 | b = Math.tan((wc - wc2) * .5);
66 | a2 = a * a;
67 | b2 = b * b;
68 |
69 | int numPoles = analog.getNumPoles();
70 | int pairs = numPoles / 2;
71 | for (int i = 0; i < pairs; i++) {
72 | PoleZeroPair pair = analog.getPair(i);
73 | ComplexPair p = transform(pair.poles.first);
74 | ComplexPair z = transform(pair.zeros.first);
75 | digital.addPoleZeroConjugatePairs(p.first, z.first);
76 | digital.addPoleZeroConjugatePairs(p.second, z.second);
77 | }
78 |
79 | if ((numPoles & 1) == 1) {
80 | ComplexPair poles = transform(analog.getPair(pairs).poles.first);
81 | ComplexPair zeros = transform(analog.getPair(pairs).zeros.first);
82 |
83 | digital.add(poles, zeros);
84 | }
85 |
86 | if (fc < 0.25)
87 | digital.setNormal(Math.PI, analog.getNormalGain());
88 | else
89 | digital.setNormal(0, analog.getNormalGain());
90 | }
91 |
92 | private ComplexPair transform(Complex c) {
93 | if (c.isInfinite())
94 | c = new Complex(-1);
95 | else
96 | c = ((new Complex(1)).add(c)).divide((new Complex(1)).subtract(c)); // bilinear
97 |
98 | Complex u = new Complex(0);
99 | u = MathSupplement.addmul(u, 4 * (b2 + a2 - 1), c);
100 | u = u.add(8 * (b2 - a2 + 1));
101 | u = u.multiply(c);
102 | u = u.add(4 * (a2 + b2 - 1));
103 | u = u.sqrt();
104 |
105 | Complex v = u.multiply(-.5);
106 | v = v.add(a);
107 | v = MathSupplement.addmul(v, -a, c);
108 |
109 | u = u.multiply(.5);
110 | u = u.add(a);
111 | u = MathSupplement.addmul(u, -a, c);
112 |
113 | Complex d = new Complex(b + 1);
114 | d = MathSupplement.addmul(d, b - 1, c);
115 |
116 | return new ComplexPair(u.divide(d), v.divide(d));
117 | }
118 |
119 | }
120 |
--------------------------------------------------------------------------------
/docs/uk/me/berndporr/iirj/class-use/BiquadPoleState.html:
--------------------------------------------------------------------------------
1 |
2 |
3 |
4 |
5 | Uses of Class uk.me.berndporr.iirj.BiquadPoleState (uk.me.berndporr:iirj 1.7 API)
6 |
7 |
8 |
9 |
10 |
11 |
12 |
13 |
14 |
15 |
16 |
17 |
18 |
19 |
21 |
24 |
25 |
26 |
47 |
48 |
49 |
50 |
51 |
Uses of Class uk.me.berndporr.iirj.BiquadPoleState
User facing class which contains two methods
91 | to create Custom SOS filters, in particular where
92 | the filter coefficients have been generated by
93 | Python's scipy signal library for example:
94 | sos = signal.butter(4, 0.1, output='sos').