1
1
"""Chapter 4 modeling algorithm implementations."""
2
2
3
+ import logging
3
4
from typing import NoReturn
4
5
5
6
import numpy as np
6
- import scipy as sp
7
7
from numpy .typing import ArrayLike
8
+ from scipy import signal
8
9
9
10
from .state import convm
10
11
12
+ logger = logging .getLogger (__name__ )
13
+
11
14
12
15
def pade (x : ArrayLike , p : int , q : int ) -> tuple [ArrayLike , ArrayLike ]:
13
16
"""Reference Page 138, Table 4.1.
14
17
15
18
The Pade approximation models a signal as the unis sample response
16
19
of linear shift invariant system have p poles and q zeros.
17
20
"""
18
- _x = np .array (x )
21
+ _x = np .array (x ). reshape ( - 1 )
19
22
if p + q > len (_x ):
20
23
raise ValueError (f"Model order { p + q } is too large." )
21
24
22
25
X = convm (_x , p + 1 )
23
26
24
27
# Linear difference matrix spanning the number of zeros
25
28
Xq = X [q + 1 :q + p + 1 , 1 :p + 1 ].copy ()
26
- print (Xq .shape )
27
29
a = np .linalg .solve (- Xq , X [q + 1 : q + p + 1 , 0 ])
28
30
# a(0) normalized to 1
29
31
a = np .concatenate ((np .ones (1 ), a )).reshape (- 1 , 1 )
30
32
b = X [:q + 1 , :p + 1 ] @ a
31
33
32
- return ( a , b )
34
+ return a . ravel () , b . ravel ( )
33
35
34
36
35
- def prony (x : ArrayLike , p : int , q : int ) -> tuple [ArrayLike , ArrayLike , ArrayLike ]:
37
+ def prony (x : ArrayLike , p : int , q : int ) -> tuple [ArrayLike , ArrayLike , float ]:
36
38
"""Least square minimization of poles to get denominator coefficients.
37
39
38
40
Solves directly (Pade method) to get numerator coefficients.
39
41
Also calculates minimum error achieved.
40
42
41
43
Condition to energy_match is on page 575
42
44
"""
43
- x = np .array (x )
44
- if p + q > len (x ):
45
+ _x = np .array (x ).reshape (- 1 , 1 )
46
+ N = len (_x )
47
+ if p + q > N :
45
48
raise ValueError (f"Model order { p + q } is too large." )
46
49
47
- # copy and make given signal column array
48
50
X = convm (x , p + 1 )
49
- print (X .shape )
50
- # M = p + q
51
- N = len (x )
52
- print (f"{ N = } " )
53
- xc = x .copy ().reshape (- 1 , 1 )
54
-
55
- # Xq = X[q + 1:q + p + 1, 1:p + 1].copy()
56
- # a = np.linalg.solve(-Xq, X[q + 1: q + p + 1, 0])
57
- # a = np.concatenate((np.ones(1), a)).reshape(-1, 1)
58
- # b = X[:q + 1, :p + 1] @ a
59
51
60
52
# the factorization does not guarantee nonsingularity!
61
53
# resulting matrix is positive *semi*-definite: all zeros are
@@ -66,76 +58,62 @@ def prony(x: ArrayLike, p: int, q: int) -> tuple[ArrayLike, ArrayLike, ArrayLike
66
58
rx = Xq_H @ Xq1
67
59
Xinv = np .linalg .inv (Xq_H @ Xq )
68
60
a = - Xinv @ rx
69
- print (a .shape )
70
61
# a(0) normalized to 1
71
62
a = np .concatenate ((np .ones (1 ), a )).reshape (- 1 , 1 )
72
63
# same as Pade method
73
64
b = X [:q + 1 , :p + 1 ] @ a
74
65
75
66
# the minimum squared error
76
- err = np .transpose (xc [q + 1 :N ]) @ X [q + 1 :N , :p + 1 ] @ a
67
+ err = np .transpose (_x [q + 1 :N ]) @ X [q + 1 :N , :p + 1 ] @ a
77
68
78
- return a , b , err
69
+ return a . ravel () , b . ravel () , err . ravel ()[ 0 ]
79
70
80
71
81
72
def shanks (x : ArrayLike , p : int , q : int ) -> tuple [ArrayLike , ArrayLike , float ]:
82
73
"""Shank's method."""
83
- x = np .array (x )
84
- N = len (x )
74
+ _x = np .array (x ). ravel (). reshape ( - 1 , 1 )
75
+ N = len (_x )
85
76
if p + q >= N :
86
77
raise ValueError (f"Model order { p + q } is too large." )
87
78
88
79
a , _ , _ = prony (x , p , q )
89
- a = np .array (a )
90
- print (f"{ a .transpose ().ravel ()= } " )
80
+ logger .info (f"{ a = } " )
91
81
u = np .concatenate ((np .ones (1 ), np .zeros (N - 1 )))
92
- res = sp .signal .tf2zpk ([1 ], a .ravel ())
93
- res = sp .signal .zpk2sos (* res )
94
- res = sp .signal .sosfilt (res , x = u )
95
- G = convm (res .ravel (), q + 1 )
96
- G0 = G [:N ,].copy ()
97
- print (f"{ G0 .shape = } " )
98
- G0_H = np .transpose ((G0 .copy ()).conjugate ())
99
- x0 = (x .copy ()).reshape (- 1 , 1 )
100
- gx = G0_H @ x0
101
- # the factorization does not guarantee nonsingularity!
102
- # resulting matrix is positive *semi*-definite
103
- Ginv = np .linalg .inv (G0_H @ G0 )
104
- print (f"{ x .shape = } " )
105
- print (f"{ Ginv .shape = } " )
106
- b = Ginv @ gx
107
- err = 1
82
+ sos = signal .tf2sos ([1 ], a )
83
+ g = signal .sosfilt (sos , x = u )
84
+ logger .info (f"{ g = } " )
85
+ G = convm (g , q + 1 )
86
+ G0 = G [:N ].copy ()
87
+ logger .info (f"{ G0 = } " )
88
+ b = np .linalg .lstsq (G0 , _x , rcond = None )[0 ]
89
+ err = _x .T @ _x - _x .T @ G [:N , :q + 1 ] @ b
108
90
109
- return a , b , err
91
+ return a , b . ravel () , err . ravel ()[ 0 ]
110
92
111
93
112
- def spike (g : ArrayLike , n0 : int , n : int ) -> ArrayLike :
94
+ def spike (g : ArrayLike , n0 : int , n : int ) -> tuple [ ArrayLike , float ] :
113
95
"""Leaset Squares Inverse Filter."""
114
- g = np .array (g ).reshape (- 1 , 1 )
115
- m = len (g )
96
+ _g = np .array (g ).reshape (- 1 , 1 )
97
+ m = len (_g )
116
98
117
99
if m + n - 1 <= n0 :
118
100
raise ValueError (f"m + n - 1 must be less than { n0 = } " )
119
101
120
102
G = convm (g , n )
121
103
d = np .zeros ((m + n - 1 , 1 ))
122
104
d [n0 ] = 1
123
- print ( f" { d . shape = } , { G . shape = } " )
124
- G_H = np . transpose ( G . conjugate ())
105
+ h = np . linalg . lstsq ( G , d , rcond = None )[ 0 ]
106
+ err = 1 - G [ n0 ,] @ h
125
107
126
- print (f"{ G_H .shape = } , { G .shape = } " )
127
- Ginv = np .linalg .inv (G_H @ G )
128
- h = Ginv @ G_H @ d
129
-
130
- return h
108
+ return h .ravel (), err .ravel ()[0 ]
131
109
132
110
133
111
def ipf (x : ArrayLike , p : int , q : int , n : None , a : ArrayLike ) -> NoReturn :
134
112
"""Iterative Pre-Filtering."""
135
113
raise NotImplementedError ()
136
114
137
115
138
- def acm (x : ArrayLike , p : int ) -> tuple [np .ndarray , np . ndarray ]:
116
+ def acm (x : ArrayLike , p : int ) -> tuple [np .ndarray , float ]:
139
117
"""The auto-correlation method."""
140
118
x0 = np .array (x ).ravel ().reshape (- 1 , 1 )
141
119
N = len (x0 )
@@ -151,36 +129,49 @@ def acm(x: ArrayLike, p: int) -> tuple[np.ndarray, np.ndarray]:
151
129
a = np .concatenate ((np .ones (1 ), a1 )).reshape (- 1 , 1 )
152
130
err = np .abs (X [:N + p , 0 ].T @ X @ a )
153
131
154
- return a , err
132
+ return a , err . ravel ()[ 0 ]
155
133
156
134
157
135
def covm (x : ArrayLike , p : int )-> tuple [ArrayLike , float ]:
158
136
"""Solve the complete Prony normal equations."""
159
- x0 = np .array (x ).ravel ().reshape (- 1 , 1 )
160
- N = len (x0 )
161
- if p >= len ( x0 ) :
137
+ _x = np .array (x ).ravel ().reshape (- 1 , 1 )
138
+ N = len (_x )
139
+ if p >= N :
162
140
raise ValueError (f"{ p = } all-pole model too large" )
163
141
164
- X = convm (x0 , p + 1 )
142
+ X = convm (_x , p + 1 )
165
143
Xq = X [p - 1 :N - 1 , :p ].copy ()
166
- cx = X [p :N , 0 ].copy ()
167
- Xq_H = Xq .copy ().conjugate ().transpose ()
168
- print (f"{ Xq = } " )
169
- Xinv = np .linalg .inv (Xq_H @ Xq )
170
- a1 = - Xinv @ Xq_H @ cx
171
- a = np .concatenate ((np .ones (1 ), a1 )).reshape (- 1 , 1 )
172
- err = np .abs (cx .transpose () @ X [p :N ,] @ a )
173
- return a , err
144
+ Xsol = np .linalg .lstsq (- Xq , X [p :N , 0 ], rcond = None )[0 ]
145
+ logger .warning (f"{ Xsol = } " )
146
+ a = np .hstack (([1 ], Xsol ))
147
+ err = np .abs (X [p :N ,0 ] @ X [p :N ,] @ a )
148
+ return a , err .ravel ()[0 ]
174
149
175
150
176
151
def durbin (x : ArrayLike , p : int , q : int ) -> tuple [ArrayLike , ArrayLike ]:
177
152
"""The durbin method."""
178
- x0 = np .array (x ).ravel ().reshape (- 1 , 1 )
179
- # N = len(x0 )
180
- if p >= len ( x0 ) :
153
+ _x = np .array (x ).ravel ().reshape (- 1 , 1 )
154
+ N = len (_x )
155
+ if p >= N :
181
156
raise ValueError ("p (all-pole model) too large" )
182
157
183
- a , eps = acm (x , p )
158
+ a , eps = acm (_x , p )
184
159
b , eps = acm (a / np .sqrt (eps ), q )
185
- b /= np .sqrt (eps )
160
+ b = b / np .sqrt (eps )
186
161
return a , b
162
+
163
+
164
+ def mywe (x : ArrayLike , p : int , q : int ) -> NoReturn :
165
+ """Modified Yuler-Walker Systems of Equations.
166
+
167
+ Page 190.
168
+ """
169
+ raise NotImplementedError ()
170
+
171
+
172
+ def eywe (x : ArrayLike , p : int , q : int ) -> NoReturn :
173
+ """Extended Yuler-Walker Systems of Equations.
174
+
175
+ Page 193.
176
+ """
177
+ raise NotImplementedError ()
0 commit comments