Completed
Push — master ( 084255...8f04c7 )
by Rafael S.
02:42
created

ButterworthLPF.runStage_   A

Complexity

Conditions 1

Size

Total Lines 11
Code Lines 10

Duplication

Lines 0
Ratio 0 %

Importance

Changes 0
Metric Value
cc 1
eloc 10
dl 0
loc 11
rs 9.9
c 0
b 0
f 0
1
/*
2
 * Copyright (c) 2019 Rafael da Silva Rocha.
3
 * Copyright (c) 2014 Florian Markert
4
 *
5
 * Permission is hereby granted, free of charge, to any person obtaining
6
 * a copy of this software and associated documentation files (the
7
 * "Software"), to deal in the Software without restriction, including
8
 * without limitation the rights to use, copy, modify, merge, publish,
9
 * distribute, sublicense, and/or sell copies of the Software, and to
10
 * permit persons to whom the Software is furnished to do so, subject to
11
 * the following conditions:
12
 *
13
 * The above copyright notice and this permission notice shall be
14
 * included in all copies or substantial portions of the Software.
15
 *
16
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
17
 * EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
18
 * MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
19
 * NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
20
 * LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
21
 * OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
22
 * WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
23
 *
24
 */
25
26
/**
27
 * @fileoverview Butterworth LPF. Based on the Butterworth LPF from Fili.js.
28
 * @see https://github.com/rochars/wavefile
29
 * @see https://github.com/markert/fili.js
30
 */
31
32
/**
33
 * Butterworth LPF.
34
 */
35
export class ButterworthLPF {
36
  
37
  /**
38
   * @param {number} order The order of the filter.
39
   * @param {number} sampleRate The sample rate.
40
   * @param {number} cutOff The cut off frequency.
41
   */
42
  constructor(order, sampleRate, cutOff) {
43
    let filters = [];
44
    for (let i = 0; i < order; i++) {
45
      filters.push(this.getCoeffs_({
46
        Fs: sampleRate,
47
        Fc: cutOff,
48
        Q: 0.5 / (Math.sin((Math.PI / (order * 2)) * (i + 0.5)))
49
      }));
50
    }
51
    this.stages = [];
52
    for (let i = 0; i < filters.length; i++) {
53
      this.stages[i] = {
54
        b0 : filters[i].b[0],
55
        b1 : filters[i].b[1],
56
        b2 : filters[i].b[2],
57
        a1 : filters[i].a[0],
58
        a2 : filters[i].a[1],
59
        k : filters[i].k,
60
        z : [0, 0]
61
      };
62
    }
63
  }
64
65
  /**
66
   * @param {number} sample A sample of a sequence.
67
   * @return {number}
68
   */
69
  filter(sample) {
70
    let out = sample;
71
    for (let i = 0, len = this.stages.length; i < len; i++) {
72
      out = this.runStage_(i, out);
73
    }
74
    return out;
75
  }
76
77
  getCoeffs_(params) {
78
    let coeffs = {};
79
    coeffs.z = [0, 0];
80
    coeffs.a = [];
81
    coeffs.b = [];
82
    let p = this.preCalc_(params, coeffs);
83
    coeffs.k = 1;
84
    coeffs.b.push((1 - p.cw) / (2 * p.a0));
85
    coeffs.b.push(2 * coeffs.b[0]);
86
    coeffs.b.push(coeffs.b[0]);
87
    return coeffs;
88
  }
89
90
  preCalc_(params, coeffs) {
91
    let pre = {};
92
    let w = 2 * Math.PI * params.Fc / params.Fs;
93
    pre.alpha = Math.sin(w) / (2 * params.Q);
94
    pre.cw = Math.cos(w);
95
    pre.a0 = 1 + pre.alpha;
96
    coeffs.a0 = pre.a0;
97
    coeffs.a.push((-2 * pre.cw) / pre.a0);
98
    coeffs.k = 1;
99
    coeffs.a.push((1 - pre.alpha) / pre.a0);
100
    return pre;
101
  }
102
  
103
  runStage_(i, input) {
104
    let temp =
105
      input * this.stages[i].k - this.stages[i].a1 * this.stages[i].z[0] -
106
      this.stages[i].a2 * this.stages[i].z[1];
107
    let out =
108
      this.stages[i].b0 * temp + this.stages[i].b1 * this.stages[i].z[0] +
109
      this.stages[i].b2 * this.stages[i].z[1];
110
    this.stages[i].z[1] = this.stages[i].z[0];
111
    this.stages[i].z[0] = temp;
112
    return out;
113
  }
114
115
  /**
116
   * Reset the filter.
117
   */
118
  reset() {
119
    for (let i = 0; i < this.stages.length; i++) {
120
      this.stages[i].z = [0, 0];
121
    }
122
  }
123
}
124