Skip to content

Commit 23eb133

Browse files
committed
add deconvolve test; refactor code part 1
1 parent 0c0f15b commit 23eb133

File tree

6 files changed

+130
-93
lines changed

6 files changed

+130
-93
lines changed

examples/1_example.py

Lines changed: 12 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -4,14 +4,14 @@
44
from vrft import *
55

66
def generateNoise(t):
7-
omega = 2*np.pi*100
8-
xi = 0.9
9-
dt = t[1] - t[0]
10-
noise = np.random.normal(0,0.1,t.size)
11-
tf = scipysig.TransferFunction([10*omega**2], [1, 2*xi*omega, omega**2])
12-
# Second order system
13-
_, yn, _ = scipysig.lsim(tf, noise, t)
14-
return yn
7+
omega = 2*np.pi*100
8+
xi = 0.9
9+
dt = t[1] - t[0]
10+
noise = np.random.normal(0,0.1,t.size)
11+
tf = scipysig.TransferFunction([10*omega**2], [1, 2*xi*omega, omega**2])
12+
# Second order system
13+
_, yn, _ = scipysig.lsim(tf, noise, t)
14+
return yn
1515

1616
#Generate time and u(t) signals
1717
t_start = 0
@@ -28,7 +28,7 @@ def generateNoise(t):
2828
sys = ExtendedTF(num, den, dt=t_step)
2929
t, y = scipysig.dlsim(sys, u, t)
3030
y = y[:, 0]
31-
y += generateNoise(t)
31+
#y += generateNoise(t)
3232
data = iddata(y, u, t_step, [0])
3333

3434

@@ -37,7 +37,7 @@ def generateNoise(t):
3737

3838
#PI Controller
3939
base = [ExtendedTF([1], [1, -1], dt=t_step),
40-
ExtendedTF([1, 0], [1, -1], dt=t_step)]
40+
ExtendedTF([1, 0], [1, -1], dt=t_step)]
4141

4242
#Experiment filter
4343
L = refModel * (1 - refModel)
@@ -47,10 +47,10 @@ def generateNoise(t):
4747
#Obtained controller
4848
print("Controller: {}".format(C))
4949

50-
L = C * sys
51-
L = feedback(L)
50+
L = (C * sys).feedback()
5251

5352
print("Theta: {}".format(theta))
53+
print(scipysig.ZerosPolesGain(L))
5454

5555
#Analysis
5656
t = t[:len(r)]

test/test_tf.py renamed to test/test_utils.py

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,25 @@
11
from unittest import TestCase
22
from vrft.utilities.utils import *
3+
from vrft.vrft.vrft_algo import virtualReference
34
import numpy as np
5+
import scipy.signal as scipysig
6+
7+
class TestUtils(TestCase):
8+
def test_deconvolve(self):
9+
t_start = 0
10+
t_end = 10
11+
t_step = 1e-2
12+
t = np.arange(t_start, t_end, t_step)
13+
sys = ExtendedTF([0.5], [1, -0.9], dt=t_step)
14+
u = np.random.normal(size=t.size)
15+
_, y = scipysig.dlsim(sys, u, t)
16+
y = y[:, 0]
17+
data = iddata(y, u, t_step, [0])
18+
r1, _ = virtualReference(data, sys.num, sys.den)
19+
r2 = deconvolve_signal(sys, data.y, data.ts)
20+
self.assertTrue(np.linalg.norm(r2-r1[:r2.size], np.infty) < 1e-3)
21+
422

5-
class TestTF(TestCase):
623
def test_checkSystem(self):
724
a = [1, 0, 1]
825
b = [1, 0, 2]

vrft/utilities/utils.py renamed to vrft/extended_tf.py

Lines changed: 8 additions & 77 deletions
Original file line numberDiff line numberDiff line change
@@ -2,83 +2,11 @@
22

33
import numpy as np
44
import scipy.signal as scipysig
5-
from .iddata import iddata
65

76
from scipy.signal.ltisys import TransferFunction as TransFun
87
from numpy import polymul, polyadd
98

10-
def Doperator(p: int, q: int, x: float) -> np.ndarray:
11-
D = np.zeros((p * q, q))
12-
for i in range(q):
13-
D[i * p:(i + 1) * p, i] = x
14-
return D
159

16-
def checkSystem(num: np.ndarray, den: np.ndarray) -> bool:
17-
try:
18-
M, N = systemOrder(num, den)
19-
except ValueError:
20-
raise
21-
22-
if (N < M):
23-
raise ValueError("The system is not causal.")
24-
25-
return True
26-
27-
def systemOrder(num: np.ndarray, den: np.ndarray) -> tuple:
28-
den = den if isinstance(den, np.ndarray) else np.array([den]).flatten()
29-
num = num if isinstance(num, np.ndarray) else np.array([num]).flatten()
30-
31-
if num.ndim == 0:
32-
num = np.expand_dims(num, axis=0)
33-
34-
if den.ndim == 0:
35-
den = np.expand_dims(den, axis=0)
36-
37-
N = den.size
38-
M = num.size
39-
40-
denOrder = -1
41-
numOrder = -1
42-
43-
for i, d in enumerate(den):
44-
if not np.isclose(d, 0):
45-
denOrder = N - i - 1
46-
break
47-
48-
for i, n in enumerate(num):
49-
if not np.isclose(n, 0):
50-
numOrder = M - i - 1
51-
break
52-
53-
if (denOrder == -1):
54-
raise ValueError("Denominator can not be zero.")
55-
56-
if (numOrder == -1):
57-
raise ValueError("Numerator can not be zero.")
58-
59-
return (numOrder, denOrder)
60-
61-
62-
def filter_iddata(data: iddata, L: scipysig.dlti) -> iddata:
63-
t_start = 0
64-
t_step = data.ts
65-
t_end = len(data.y) * t_step
66-
67-
t = np.arange(t_start, t_end, t_step)
68-
69-
if (L != None):
70-
t, y = scipysig.dlsim(L, data.y, t)
71-
t, u = scipysig.dlsim(L, data.u, t)
72-
return iddata(y[:, 0], u[:, 0], data.ts, data.y0)
73-
return data
74-
75-
def deconvolve_signal(T: scipysig.dlti, x: np.ndarray, dt: float) -> np.ndarray:
76-
impulse = scipysig.dimpulse(T)[1][0].flatten()
77-
idx1 = np.argwhere(impulse != 0)[0].item()
78-
idx2 = np.argwhere(np.isclose(impulse[idx1:], 0.) == True)
79-
idx2 = -1 if not idx2 else idx2[0].item()
80-
recovered, _ = scipysig.deconvolve(x, impulse[idx1:idx2])
81-
return recovered[np.argwhere(impulse != 0)[0].item():]
8210

8311
class ExtendedTF(scipysig.ltisys.TransferFunctionDiscrete):
8412
def __init__(self, num, den, dt):
@@ -152,12 +80,15 @@ def __rsub__(self,other):
15280
denom = polymul(self.den,other.den)
15381
return ExtendedTF(numer,denom, dt=self._dt)
15482

83+
def feedback(self):
84+
num = self.num
85+
den = self.den
86+
den = polyadd(num, den)
87+
self = ExtendedTF(num, den, dt=self.dt)
88+
return self
89+
15590
# sheer laziness: symmetric behaviour for commutative operators
15691
__rmul__ = __mul__
15792
__radd__ = __add__
15893

159-
def feedback(L):
160-
num = L.num
161-
den = L.den
162-
den = polyadd(num, den)
163-
return ExtendedTF(num, den, dt=L.dt)
94+
File renamed without changes.

vrft/utils.py

Lines changed: 81 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,81 @@
1+
from __future__ import division
2+
3+
import numpy as np
4+
import scipy.signal as scipysig
5+
from .iddata import iddata
6+
7+
from scipy.signal.ltisys import TransferFunction as TransFun
8+
from numpy import polymul, polyadd
9+
10+
def Doperator(p: int, q: int, x: float) -> np.ndarray:
11+
D = np.zeros((p * q, q))
12+
for i in range(q):
13+
D[i * p:(i + 1) * p, i] = x
14+
return D
15+
16+
def checkSystem(num: np.ndarray, den: np.ndarray) -> bool:
17+
try:
18+
M, N = systemOrder(num, den)
19+
except ValueError:
20+
raise
21+
22+
if (N < M):
23+
raise ValueError("The system is not causal.")
24+
25+
return True
26+
27+
def systemOrder(num: np.ndarray, den: np.ndarray) -> tuple:
28+
den = den if isinstance(den, np.ndarray) else np.array([den]).flatten()
29+
num = num if isinstance(num, np.ndarray) else np.array([num]).flatten()
30+
31+
if num.ndim == 0:
32+
num = np.expand_dims(num, axis=0)
33+
34+
if den.ndim == 0:
35+
den = np.expand_dims(den, axis=0)
36+
37+
N = den.size
38+
M = num.size
39+
40+
denOrder = -1
41+
numOrder = -1
42+
43+
for i, d in enumerate(den):
44+
if not np.isclose(d, 0):
45+
denOrder = N - i - 1
46+
break
47+
48+
for i, n in enumerate(num):
49+
if not np.isclose(n, 0):
50+
numOrder = M - i - 1
51+
break
52+
53+
if (denOrder == -1):
54+
raise ValueError("Denominator can not be zero.")
55+
56+
if (numOrder == -1):
57+
raise ValueError("Numerator can not be zero.")
58+
59+
return (numOrder, denOrder)
60+
61+
62+
def filter_iddata(data: iddata, L: scipysig.dlti) -> iddata:
63+
t_start = 0
64+
t_step = data.ts
65+
t_end = len(data.y) * t_step
66+
67+
t = np.arange(t_start, t_end, t_step)
68+
69+
if (L != None):
70+
t, y = scipysig.dlsim(L, data.y, t)
71+
t, u = scipysig.dlsim(L, data.u, t)
72+
return iddata(y[:, 0], u[:, 0], data.ts, data.y0)
73+
return data
74+
75+
def deconvolve_signal(T: scipysig.dlti, x: np.ndarray, dt: float) -> np.ndarray:
76+
impulse = scipysig.dimpulse(T)[1][0].flatten()
77+
idx1 = np.argwhere(impulse != 0)[0].item()
78+
idx2 = np.argwhere(np.isclose(impulse[idx1:], 0.) == True)
79+
idx2 = -1 if idx2.size == 0 else idx2[0].item()
80+
recovered, _ = scipysig.deconvolve(x, impulse[idx1:idx2])
81+
return recovered[np.argwhere(impulse != 0)[0].item():]

vrft/vrft/vrft_algo.py renamed to vrft/vrft_algo.py

Lines changed: 11 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,5 +1,5 @@
11
from vrft.utilities.iddata import iddata
2-
from vrft.utilities.utils import systemOrder, checkSystem, filter_iddata
2+
from vrft.utilities.utils import systemOrder, checkSystem, filter_iddata, deconvolve_signal
33
import numpy as np
44
import scipy.signal as scipysig
55

@@ -94,14 +94,22 @@ def control_response(data: iddata, error: np.ndarray, control: list):
9494
return phi
9595

9696
def compute_vrft(data: iddata, refModel: scipysig.dlti, control: list, L: scipysig.dlti):
97+
# import pdb
98+
# import matplotlib.pyplot as plt
99+
# pdb.set_trace()
97100
data = filter_iddata(data, L)
98101
r, n = virtualReference(data,
99102
refModel.num,
100103
refModel.den)
104+
# r2=deconvolve_signal(refModel, data.y, data.ts)
105+
# plt.plot(r)
106+
# plt.plot(r2)
107+
# plt.show()
101108

102-
phi = control_response(data, np.subtract(r, data.y[:-n]), control)
109+
phi = control_response(data, np.subtract(r, data.y[:n]), control)
103110
theta, phi = calc_minimum(data, phi)
104111
loss = compute_vrft_loss(data, phi, theta)
105-
112+
print(phi)
113+
#theta[0] = -theta[0]
106114
final_control = np.dot(theta, control)
107115
return theta, r, phi, loss, final_control

0 commit comments

Comments
 (0)