Project Task 2

import numpy as np
 
import matplotlib.pyplot as plt
 
import control as ct
 
from control.matlab import *
 
  
 
class SystemModel:
 
def __init__(self, z0=[]):
 
self.dt = 0.001
 
self.d = 10.0
 
if z0 == []:
 
self.z = np.array([0.0, 0.0, 0.0, 0.0])
 
else:
 
self.z = z0
 
  
 
def step(self, u):
 
self.z = self.z + 0.1665834 * np.array([
 
(self.z[2]) * self.dt + 2.0 * ((self.z[2] + (-self.d * self.z[2]**3 + u[0]) * self.dt / 2.0) * self.dt + (self.z[2] + (-self.d * (self.z[2] + (-self.d * self.z[2]**3 + u[0]) * self.dt / 2.0)**3 + u[0]) * self.dt / 2.0) * self.dt) + (self.z[2] + (-self.d * (self.z[2] + (-self.d * (self.z[2] + (-self.d * self.z[2]**3 + u[0]) * self.dt / 2.0)**3 + u[0]) * self.dt / 2.0)**3 + u[0]) * self.dt) * self.dt,
 
(self.z[3]) * self.dt + 2.0 * ((self.z[3] + (-self.d * self.z[3]**3 + u[1]) * self.dt / 2.0) * self.dt + (self.z[3] + (-self.d * (self.z[3] + (-self.d * self.z[3]**3 + u[1]) * self.dt / 2.0)**3 + u[1]) * self.dt / 2.0) * self.dt) + (self.z[3] + (-self.d * (self.z[3] + (-self.d * (self.z[3] + (-self.d * self.z[3]**3 + u[1]) * self.dt / 2.0)**3 + u[1]) * self.dt / 2.0)**3 + u[1]) * self.dt) * self.dt,
 
(-self.d * self.z[2]**3 + u[0]) * self.dt + 2.0 * ((-self.d * (self.z[2] + (-self.d * self.z[2]**3 + u[0]) * self.dt / 2.0)**3 + u[0]) * self.dt + (-self.d * (self.z[2] + (-self.d * (self.z[2] + (-self.d * self.z[2]**3 + u[0]) * self.dt / 2.0)**3 + u[0]) * self.dt / 2.0)**3 + u[0]) * self.dt) + (-self.d * (self.z[2] + (-self.d * (self.z[2] + (-self.d * (self.z[2] + (-self.d * self.z[2]**3 + u[0]) * self.dt / 2.0)**3 + u[0]) * self.dt / 2.0)**3 + u[0]) * self.dt)**3 + u[0]) * self.dt,
 
(-self.d * self.z[3]**3 + u[1]) * self.dt + 2.0 * ((-self.d * (self.z[3] + (-self.d * self.z[3]**3 + u[1]) * self.dt / 2.0)**3 + u[1]) * self.dt + (-self.d * (self.z[3] + (-self.d * (self.z[3] + (-self.d * self.z[3]**3 + u[1]) * self.dt / 2.0)**3 + u[1]) * self.dt / 2.0)**3 + u[1]) * self.dt) + (-self.d * (self.z[3] + (-self.d * (self.z[3] + (-self.d * (self.z[3] + (-self.d * self.z[3]**3 + u[1]) * self.dt / 2.0)**3 + u[1]) * self.dt / 2.0)**3 + u[1]) * self.dt)**3 + u[1]) * self.dt
 
])
 
z_noisy = self.z + 0.01 * np.random.normal(0.0, 0.1, size=self.z.shape)
 
return z_noisy[:2]
 
  
 
def sim(self, input_signal):
 
N = input_signal.shape[0]
 
y = np.zeros((N, 2))
 
for n in range(N):
 
y_t = self.step(input_signal[n, :])
 
y[n, :] = y_t
 
return y
 
  
  
 
##############
 
### TASK 1 ###
 
##############
 
  
 
# Calculate y_11, y_12, y_21, y_22 #
 
  
 
# sim parameters
 
T = 15
 
dt = 0.001
 
steps = int(T / dt)
 
  
 
# calculate y_11 and y_21
 
sm = SystemModel()
 
  
 
# inputs
 
u_11 = np.ones(steps)
 
u_21 = np.zeros(steps)
 
  
 
#combine inputs
 
u = np.vstack((u_11, u_21)).T
 
  
 
#simulate output
 
y = sm.sim(u)
 
  
 
y_11 = y[:, 0] # first component of y for each time step : output for the first eq
 
y_21 = y[:, 1] # second component of y for each time step : output for the second eq
 
  
 
# calculate y_12 and y_22
 
sm = SystemModel()
 
  
 
# inputs
 
u_12 = np.zeros(steps)
 
u_22 = np.ones(steps)
 
  
 
#combine inputs
 
u = np.vstack((u_12, u_22)).T
 
  
 
#simulate output
 
y = sm.sim(u)
 
  
 
# extract outputs
 
y_12 = y[:, 0]
 
y_22 = y[:, 1]
 
  
  
 
##############
 
### TASK 2 ###
 
##############
 
  
 
# Design and apply a low-pass filter #
 
  
 
# choose filter frequency and create transfer function for it
 
w_c = 100
 
tau = 1 / w_c # time constant
 
  
 
s = ct.tf('s') # laplace variable
 
t = np.linspace(0, (steps - 1) * dt, steps)
 
  
  
 
G_s = 1 / ((1 + tau * s) ** 3) # transfer function (3rd order low-pass filter)
 
  
 
# filter application: simulate affect of filter on y_11, y_12, y21, y22
 
y_11_filtered = lsim(G_s, y_11, t)[0]
 
y_12_filtered = lsim(G_s, y_12, t)[0]
 
y_21_filtered = lsim(G_s, y_21, t)[0]
 
y_22_filtered = lsim(G_s, y_22, t)[0]
 
  
  
 
##############
 
### TASK 3 ###
 
##############
 
  
 
# calculate the first and second derivatives of y_11, y_12, y21, y22
 
# and the first derivative of u_11, u_12, u_21, u_22
 
  
 
# calulate first derivative of y_11, y_12, y21, y22
 
y_11_filtered_1 = np.diff(y_11_filtered).T/dt
 
y_12_filtered_1 = np.diff(y_12_filtered).T/dt
 
y_21_filtered_1 = np.diff(y_21_filtered).T/dt
 
y_22_filtered_1 = np.diff(y_22_filtered).T/dt
 
  
 
# calculate second derivative of y_11, y_12, y21, y22
 
y_11_filtered_2 = np.diff(y_11_filtered_1).T/dt
 
y_12_filtered_2 = np.diff(y_12_filtered_1).T/dt
 
y_21_filtered_2 = np.diff(y_21_filtered_1).T/dt
 
y_22_filtered_2 = np.diff(y_22_filtered_1).T/dt
 
  
 
# calulate first derivate of u_11, u_12, u_21, u_22
 
u_11_1 = np.diff(u_11).T/dt
 
u_12_1 = np.diff(u_12).T/dt
 
u_21_1 = np.diff(u_21).T/dt
 
u_22_1 = np.diff(u_22).T/dt
 
  
  
 
##############
 
### TASK 4 ###
 
##############
 
  
 
fig = plt.figure(figsize = (24, 12))
 
ax1 = fig.add_subplot(221)
 
ax2 = fig.add_subplot(222)
 
ax3 = fig.add_subplot(223)
 
ax4 = fig.add_subplot(224)
 
ax1.plot(t, y_11)
 
ax1.title.set_text('y_11')
 
ax2.plot(t, y_12)
 
ax2.title.set_text('y_12')
 
ax3.plot(t, y_21)
 
ax3.title.set_text('y_21')
 
ax4.plot(t, y_22)
 
ax4.title.set_text('y_22')
 
  
 
fig = plt.figure(figsize = (24, 12))
 
ax1 = fig.add_subplot(221)
 
ax2 = fig.add_subplot(222)
 
ax3 = fig.add_subplot(223)
 
ax4 = fig.add_subplot(224)
 
ax1.plot(t, y_11_filtered)
 
ax1.title.set_text('y_11 filtered')
 
ax2.plot(t, y_12_filtered)
 
ax2.title.set_text('y_12 filtered')
 
ax3.plot(t, y_21_filtered)
 
ax3.title.set_text('y_21 filtered')
 
ax4.plot(t, y_22_filtered)
 
ax4.title.set_text('y_22 filtered')
 
  
 
fig = plt.figure(figsize = (24, 12))
 
ax1 = fig.add_subplot(221)
 
ax2 = fig.add_subplot(222)
 
ax3 = fig.add_subplot(223)
 
ax4 = fig.add_subplot(224)
 
ax1.plot(np.arange(0, T-dt, dt), y_11_filtered_1)
 
ax1.title.set_text('y_11 filtered first derivative')
 
ax2.plot(np.arange(0, T-dt, dt), y_12_filtered_1)
 
ax2.title.set_text('y_12 filtered first derivative')
 
ax3.plot(np.arange(0, T-dt, dt), y_21_filtered_1)
 
ax3.title.set_text('y_21 filtered first derivative')
 
ax4.plot(np.arange(0, T-dt, dt), y_22_filtered_1)
 
ax4.title.set_text('y_22 filtered first derivative')
 
  
 
fig = plt.figure(figsize = (24, 12))
 
ax1 = fig.add_subplot(221)
 
ax2 = fig.add_subplot(222)
 
ax3 = fig.add_subplot(223)
 
ax4 = fig.add_subplot(224)
 
ax1.plot(np.arange(0, T-2*dt, dt), y_11_filtered_2)
 
ax1.title.set_text('y_11 filtered second derivative')
 
ax2.plot(np.arange(0, T-2*dt, dt), y_12_filtered_2)
 
ax2.title.set_text('y_12 filtered second derivative')
 
ax3.plot(np.arange(0, T-2*dt, dt), y_21_filtered_2)
 
ax3.title.set_text('y_21 filtered second derivative')
 
ax4.plot(np.arange(0, T-2*dt, dt), y_22_filtered_2)
 
ax4.title.set_text('y_22 filtered second derivative')
 
  
  
 
##############
 
### TASK 5 ###
 
##############
 
  
 
# function to compute d_t
 
def d_t(step_index, u, u_1, y, y_1):
 
return np.vstack((u[step_index], u_1[step_index], -y[step_index], -y_1[step_index])).T
 
  
  
 
# function to compute theta
 
def theta(time_steps, u, u_1, y, y_1, y_2):
 
y_bar = np.zeros(time_steps)
 
D_bar = np.zeros((time_steps, 4))
 
for i in range(0, time_steps-2):
 
y_bar[i] = y_2[i]
 
D_bar[i] = d_t(i, u, u_1, y, y_1)
 
return np.linalg.lstsq(D_bar, y_bar)[0]
 
  
  
 
#calulate thetas
 
theta_11 = theta(steps, u_11, u_11_1, y_11_filtered, y_11_filtered_1, y_11_filtered_2)
 
theta_12 = theta(steps, u_12, u_12_1, y_12_filtered, y_12_filtered_1, y_12_filtered_2)
 
theta_21 = theta(steps, u_21, u_21_1, y_21_filtered, y_21_filtered_1, y_21_filtered_2)
 
theta_22 = theta(steps, u_22, u_22_1, y_22_filtered, y_22_filtered_1, y_22_filtered_2)
 
  
  
 
# function to get transfer function from theta
 
def theta_to_g(theta):
 
return (theta[1]*s + theta[0])/(s**2 + theta[3]*s + theta[2])
 
  
  
 
# compute transfer functions
 
g_11 = theta_to_g(theta_11)
 
g_12 = theta_to_g(theta_12)
 
g_21 = theta_to_g(theta_21)
 
g_22 = theta_to_g(theta_22)
 
  
 
# print out transfer functions
 
print(g_11)
 
print(g_12)
 
print(g_21)
 
print(g_22)
 
  
  
 
##############
 
### TASK 6 ###
 
##############
 
  
 
# compute simulated output of transfer function on unit step
 
y_11_id = lsim(g_11, np.ones(steps), t)[0]
 
y_12_id = lsim(g_12, np.ones(steps), t)[0]
 
y_21_id = lsim(g_21, np.ones(steps), t)[0]
 
y_22_id = lsim(g_22, np.ones(steps), t)[0]
 
  
 
fig = plt.figure(figsize = (24, 12))
 
ax1 = fig.add_subplot(221)
 
ax2 = fig.add_subplot(222)
 
ax3 = fig.add_subplot(223)
 
ax4 = fig.add_subplot(224)
 
ax1.plot(t, y_11)
 
ax1.plot(t, y_11_id)
 
ax1.title.set_text('y_11 identified vs real')
 
ax2.plot(t, y_12)
 
ax2.plot(t, y_12_id)
 
ax2.title.set_text('y_12 identified vs real')
 
ax3.plot(t, y_21)
 
ax3.plot(t, y_21_id)
 
ax3.title.set_text('y_21 identified vs real')
 
ax4.plot(t, y_22)
 
ax4.plot(t, y_22_id)
 
ax4.title.set_text('y_22 identified vs real')
 
  
  
 
##############
 
### TASK 7 ###
 
##############
 
  
 
# calculate y_11 and y_21 response to sin input
 
sm = SystemModel()
 
  
 
u_11_sin = np.sin(t)
 
u_21_sin = np.zeros(steps)
 
u = np.vstack((u_11_sin, u_21_sin)).T
 
y = sm.sim(u)
 
  
 
y_11_sin = y[:, 0]
 
y_21_sin = y[:, 1]
 
  
  
 
# calculate y_12 and y_22 response to sin input
 
sm = SystemModel()
 
  
 
u_12_sin = np.zeros(steps)
 
u_22_sin = np.sin(t)
 
u = np.vstack((u_12_sin, u_22_sin)).T
 
y = sm.sim(u)
 
  
 
y_12_sin = y[:, 0]
 
y_22_sin = y[:, 1]
 
  
  
 
# compute simulated output of transfer function on sin
 
y_11_sin_id = lsim(g_11, np.sin(t), t)[0]
 
y_12_sin_id = lsim(g_12, np.sin(t), t)[0]
 
y_21_sin_id = lsim(g_21, np.sin(t), t)[0]
 
y_22_sin_id = lsim(g_22, np.sin(t), t)[0]
 
  
 
fig = plt.figure(figsize = (24, 12))
 
ax1 = fig.add_subplot(221)
 
ax2 = fig.add_subplot(222)
 
ax3 = fig.add_subplot(223)
 
ax4 = fig.add_subplot(224)
 
ax1.plot(t, y_11_sin)
 
ax1.plot(t, y_11_sin_id)
 
ax1.title.set_text('y_11 sin input identified vs real')
 
ax2.plot(t, y_12_sin)
 
ax2.plot(t, y_12_sin_id)
 
ax2.title.set_text('y_12 sin input identified vs real')
 
ax3.plot(t, y_21_sin)
 
ax3.plot(t, y_21_sin_id)
 
ax3.title.set_text('y_21 sin input identified vs real')
 
ax4.plot(t, y_22_sin)
 
ax4.plot(t, y_22_sin_id)
 
ax4.title.set_text('y_22 sin input identified vs real')
 
  
  
 
plt.show()