-
Notifications
You must be signed in to change notification settings - Fork 214
/
Copy pathqf_legendre.cpp
157 lines (116 loc) · 2.97 KB
/
qf_legendre.cpp
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
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
149
150
151
152
153
154
155
156
157
// Legendre filters (or Papoulis)
// This class of filters is montonic, but possess the sharpest fall off
// while being polynomial (no transmission zeros)
// This function returns successive Legendre's polynoms in increasing
// order
#include "qf_common.h"
#include "qf_poly.h"
#include "qf_comp.h"
#include "qf_filter.h"
#include "qf_capacity.h"
#include "qf_legendre.h"
#define _QF_LGNDR_DEBUG
// Computes the characteristic polynomial, which is derived from
// Legendre polynomials
qf_poly qf_lgndr::legendre (void) {
qf_poly L0 (0.0, 0.0, 1.0), L1 (0.0, 1.0, 0.0), L2 (1.5, 0.0, -0.5);
qf_poly W (2.0, 0.0, -1.0);
qf_poly S (0.0, 0.0, 0.0);
unsigned k;
qf_double_t c;
if (Pspec -> ord % 2) { // Odd case
k = (Pspec -> ord - 1) / 2;
c = one_over_sqrt2 / (k + 1);
S = L0 * c;
for (unsigned i = 1; i < k + 1; i ++) {
if (i == 1) {S += L1 * (3 * c); continue;}
if (i == 2) {S += L2 * (5 * c); continue;}
// Recurrence to compute L(i)
L0 = L1;
L1 = L2;
L2 = (L2 >> 1) * (2 * i - 1);
L2 -= L0 * (i - 1);
L2 *= (1.0 / i);
// Add to Sum polynom
S += L2 * ((2 * i + 1) * c);
}
}
else { // Even case
k = Pspec -> ord / 2 - 1;
c = 1 / sqrt ((k + 1) * (k + 2));
if (k % 2) {
S = L1 * (3 * c);
for (unsigned i = 3; i < k + 1; i ++) {
// Recurrence to compute L(i)
L0 = L1;
L1 = L2;
L2 = (L2 >> 1) * (2 * i - 1);
L2 -= L0 * (i - 1);
L2 *= (1.0 / i);
if (i % 2) S += L2 * ((2 * i + 1) * c);
}
}
else {
S = L0 * c;
if (k >= 2) S += L2 * (5 * c);
for (unsigned i = 3; i < k + 1; i ++) {
// Recurrence to compute L(i)
L0 = L1;
L1 = L2;
L2 = (L2 >> 1) * (2 * i - 1);
L2 -= L0 * (i - 1);
L2 *= (1.0 / i);
if ((i % 2) == 0) S += L2 * ((2 * i + 1) * c);
}
}
}
qf_poly S2 (S * S);
// If n is even, multiply S^2 by (x + 1)
if ((Pspec -> ord % 2) == 0) S2 *= qf_poly (0.0, 1.0, 1.0);
// Integrate S2
qf_poly IS2 (S2. intgrt ());
// Form attenuation function
qf_poly L (IS2. rond (W));
L -= IS2. eval (-1.0);
// Some form of normalization
if (Pspec -> ord % 2) L. nrm (2);
else { // x^2 factor is null
qf_poly Lr (L << 2);
Lr -= Lr.eval (0);
L = Lr >> 2;
L. nrm (4);
}
return L;
}
// Constructor
qf_lgndr::qf_lgndr (qf_spec* Pspec): qf_filter (Pspec) {
qf_poly L (legendre ());
#ifdef _QF_LGNDR_DEBUG
L. disp ("L0");
#endif
// Computes the normalization frequency ws
L -= 1.0;
L.rroot (ws);
L += 1.0;
qf_poly MP2 (-1.0, 0.0, 0.0);
// F(p)F(-p)
F = (L. sqr ()). rond (MP2);
#ifdef _QF_LGNDR_DEBUG
L.disp ("L");
cout << "Normalization ws: " << ws << endl;
F.disp ("F");
#endif
// Since P(p) = 1, E(p)E(-p) = F(p)F(-p) + 1
E = F;
E += 1.0;
E. hurw ();
F. hurw ();
}
bool qf_lgndr::synth (void) {
scptX2 (E, F, BN, BD);
#ifdef _QF_LGNDR_DEBUG
BN.disp ("BN");
BD.disp ("BD");
#endif
return synth_ladder (1.0 / ws);
}