Skip to content

Commit 06e98a9

Browse files
committed
autotune: Change id interface to work with SIPPY
SIPPY support will be added in the near future remove state vector plot as not really useful and won't be available later, when using SIPPY
1 parent 38345ac commit 06e98a9

3 files changed

Lines changed: 27 additions & 47 deletions

File tree

File renamed without changes.

autotune/autotune.py

Lines changed: 10 additions & 38 deletions
Original file line numberDiff line numberDiff line change
@@ -452,55 +452,27 @@ def runIdentification(self):
452452
n = self.sys_id_n_poles # order of the denominator (a_1,...,a_n)
453453
m = self.sys_id_n_zeros # order of the numerator (b_0,...,b_m)
454454
d = self.sys_id_delays # number of delays
455-
tau = 60.0 # forgetting period
456-
lbda = 1.0 - self.dt/tau
457-
self.sysid = SystemIdentification(n, m, d)
458-
self.sysid.lbda = lbda
455+
id = SystemIdentification(n, m, d, self.dt)
459456

460-
(theta_hat, a_coeffs, b_coeffs) = self.sysid.run(self.t, self.u, self.y)
457+
est = id.fit(self.u.reshape(-1, 1), self.y.reshape(-1, 1))
461458

462-
self.plotStateVector(a_coeffs, b_coeffs)
459+
self.num = est.G_.num_list[0][0]
460+
self.den = est.G_.den_list[0][0][0:n+1]
461+
self.Gz = ctrl.TransferFunction(self.num, self.den, self.dt)
462+
463+
num_coeffs = self.num
464+
den_coeffs = self.den[1:n+1]
463465
self.is_system_identified = True
464466
self.btn_run_sys_id.setEnabled(False)
465-
dt = self.dt
466-
# num = self.sysid.getNum()
467-
# den = self.sysid.getDen()
468-
# self.Gz_dot = ctrl.TransferFunction(num, den, dt)
469467

470-
# Uncomment below to add integrator
471-
# self.sysid.addIntegrator()
472-
self.num = self.sysid.getNum()
473-
474-
self.den = self.sysid.getDen()
475-
476-
self.Gz = ctrl.TransferFunction(self.num, self.den, dt)
477-
self.updateTfDisplay(a_coeffs[:, -1], b_coeffs[:, -1])
468+
self.updateTfDisplay(den_coeffs, num_coeffs)
478469
self.plotPolesZeros()
479470
self.replayInputData()
480471

481-
def plotStateVector(self, a_coeffs, b_coeffs):
482-
t = self.t
483-
ax = self.figure.add_subplot(3,3,(4,5))
484-
legend = []
485-
486-
for i in range(len(a_coeffs)):
487-
ax.plot(t, a_coeffs[i])
488-
legend.append("a{}".format(i+1))
489-
490-
for i in range(len(b_coeffs)):
491-
ax.plot(t, b_coeffs[i])
492-
legend.append("b{}".format(i))
493-
494-
ax.set_title("Parameter identification")
495-
ax.set_xlabel("Time (s)")
496-
ax.legend(legend, loc='lower left')
497-
498-
self.canvas.draw()
499-
500472
def replayInputData(self):
501473
if not self.is_system_identified:
502474
return
503-
d = self.sysid.d
475+
d = self.sys_id_delays
504476
u_detrended = detrend(self.u)
505477
u_delayed = np.concatenate(([0 for k in range(d)], u_detrended[0:(len(u_detrended)-d)]))
506478
self.t_est, self.y_est = ctrl.forced_response(self.Gz, T=self.t, U=u_delayed)

autotune/system_identification.py

Lines changed: 17 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -44,23 +44,30 @@
4444
from arx_rls import ArxRls
4545
from scipy.optimize import lsq_linear, minimize
4646

47+
class SysIdResult(object):
48+
def __init__(self, num, den, dt):
49+
self.G_ = ctrl.TransferFunction(num, den, dt)
50+
4751
class SystemIdentification(object):
48-
def __init__(self, n=2, m=2, d=1):
52+
def __init__(self, n=2, m=2, d=1, dt = 0.0):
4953
self.n = n # order of the denominator (a_1,...,a_n)
5054
self.m = m # order of the numerator (b_0,...,b_m)
5155
self.d = d # number of delays
5256
self.forgetting_tc = 60.0 # forgetting factor for weighted RLS in seconds
5357
self.f_hp = 0.5 # high-pass filter cutoff frequency
5458
self.f_lp = 30.0 # low-pass filter cutoff frequency
59+
self.dt = dt
60+
61+
tau = 60.0 # forgetting period
62+
self.lbda = 1.0 - self.dt/tau
5563

56-
def run(self, t, u, y):
57-
n_steps = len(t)
58-
dt = t[1] - t[0]
64+
def fit(self, u, y):
65+
n_steps = len(u)
5966

6067
# High-pass filter parameters
6168
if self.f_hp > 0.0:
6269
tau_hp = 1/(2*np.pi*self.f_hp)
63-
alpha_hp = tau_hp/(tau_hp+dt)
70+
alpha_hp = tau_hp/(tau_hp+self.dt)
6471
else:
6572
alpha_hp = 0.0
6673

@@ -71,7 +78,7 @@ def run(self, t, u, y):
7178

7279
# Low-pass filter parameters
7380
tau_lp = 1/(2*np.pi*self.f_lp)
74-
alpha_lp = tau_lp/(tau_lp+dt)
81+
alpha_lp = tau_lp/(tau_lp+self.dt)
7582
u_lp = np.zeros(n_steps)
7683
y_lp = np.zeros(n_steps)
7784
u_lp[0] = u[0]
@@ -97,7 +104,7 @@ def run(self, t, u, y):
97104
use_rls = True
98105
if use_rls:
99106
# Identification
100-
rls = ArxRls(self.n, self.m, self.d, lbda=(1 - dt / self.forgetting_tc))
107+
rls = ArxRls(self.n, self.m, self.d, lbda=(1 - self.dt / self.forgetting_tc))
101108

102109
for k in range(n_steps):
103110
# Update model
@@ -126,7 +133,7 @@ def run(self, t, u, y):
126133
theta_hat = res.x
127134

128135
# Refine model using output-error optimization
129-
J = lambda x: np.sum(np.power(abs(np.array(B)-self.simulateModel(x, u_lp, dt)), 2.0)) # cost function
136+
J = lambda x: np.sum(np.power(abs(np.array(B)-self.simulateModel(x, u_lp, self.dt)), 2.0)) # cost function
130137
x0 = np.append(res.x, 0) # initial conditions
131138
res = minimize(J, x0, method='nelder-mead', options={'disp': True})
132139
theta_hat = res.x
@@ -138,7 +145,8 @@ def run(self, t, u, y):
138145

139146
self.theta_hat = theta_hat
140147

141-
return (theta_hat, a_coeffs, b_coeffs)
148+
estimate = SysIdResult(self.getNum(), self.getDen(), self.dt)
149+
return estimate
142150

143151
def simulateModel(self, x, u, dt):
144152
a_coeffs = np.ones(self.n+1)

0 commit comments

Comments
 (0)