summaryrefslogtreecommitdiff
path: root/src/biquad.cxx
blob: 372b89e231e11125173c33f3754b1525aca20d3b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
#include <iostream>
#include "biquad.h"
#include "bad_thing.h"
using namespace std;

// gory-detail constructor
biquad::biquad(vector<double> const _c, vector<double> const _d,
                vector<C> _zeros, vector<C> _poles)
: c(_c), d(_d), zeros(_zeros), poles(_poles),
  ws1(0), ws2(0)
{
    if (d[0] != 1.) throw bad_thing("biquad: d0 must be 1.");
}

// constructor in terms of zero and pole position,
// assuming conjugate pairs:
biquad::biquad(C const zero, C const pole)
///// nume = (z-zero)(z-zerobar)
/////      = z^2 - 2 zero.real + |zero|^2
: biquad({1., -2.*zero.real(), norm(zero)},
         {1., -2.*pole.real(), norm(pole)},
         {zero, conj(zero)},
         {pole, conj(pole)})
{}

C constexpr biquad::C0;
C constexpr biquad::C1;

vector<C> solve(vector<double> const poly) {
    double disc(1 - 4. * poly[0] * poly[2] / poly[1] / poly[1]);
    C inner(biquad::C1 + sqrt(C(disc, 0)));
    C root1 = C(-poly[1]/2/poly[0], 0) * inner;
    return { root1,
             C(poly[2]/poly[0], 0) / root1 };
}

// constructor in terms of coefficients:
biquad::biquad(vector<double> const _c, vector<double> const _d)
: biquad(_c, _d,
       {C0, C0}, {C0, C0})
{
  zeros = solve(c);
  poles = solve(d);
}

double biquad::step(double const Vin){
    double q1(ws1);
    double q2(ws2);
    double Vout = c[0]*Vin + q1;
    ws1 = c[1]*Vin - d[1]*Vout + q2;
    ws2 = c[2]*Vin - d[2]*Vout;
    return Vout;
}

// transfer function
C biquad::xfunc(C const z) const {
    C nume = (c[0]*z + c[1])*z + c[2];
    C denom =     (z + d[1])*z + d[2];
    return nume / denom;
}

void biquad::please_normalize(C const z) {
    double denom(abs(xfunc(z)));
//    cout << "denom: " << denom << endl;
//    cout << "c2: " << c[2] << endl;
//    cout << "z: " << z << endl;
    for (auto &coeff : c) {
      coeff /= denom;
    }
}

// same as above, but with some error checking:

void biquad::normalize(C const z) {
  if (abs(abs(z) - 1.) > 1e-10) {
//
    throw bad_thing("normalizing to z not on unit circle");
  }
  please_normalize(z);
}