forked from alchemyst/Skogestad-Python
-
Notifications
You must be signed in to change notification settings - Fork 0
/
Uncertain_MIMO.py
187 lines (143 loc) · 5.66 KB
/
Uncertain_MIMO.py
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
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
from __future__ import division
from __future__ import print_function
from builtins import range
import numpy as np
import matplotlib as ml
import scipy.optimize as op
ml.rcParams['font.family'] = 'serif'
ml.rcParams['font.serif'] = ['Cambria'] + ml.rcParams['font.serif']
# Calculates plant perturbations
# Currently for SISO only
# Give the minimum and maximum values of a specific variable in a matrix form
# For example a matrix of the minimum and maximum values of
# a certain set of parameters
# Create a matrix of all possibilities of the umin and umax vectors
# The first entry of the matrix corresponds to the first entry
# in the minimum and maximum matrices
def bound_SISO_wi(w_start, w_end, vec, G, Gp, steps):
w = np.logspace(w_start, w_end, steps)
# Gp_i = np.zeros((vec.shape[0], len(w), 1))
Gp_i_max = np.zeros((len(w)))
# Plotting the multiplicative relative uncertianty as a function of w
# Plotting the multiplicative relative uncertainty as a function of w
# Calculate sequences to plot all perturbations
# for i in range(vec.shape[0]):
# Gp_i = [(Gp(w_i * 1j, vec, i) - G(w_i * 1j)) / (G(w_i * 1j))
# for w_i in w]
# plt.loglog(w, np.abs(Gp_i), 'b+')
# plt.ylabel('Deviation due to uncertainty')
# plt.xlabel('Frequency (rad/min)')
#
# Calculate the vales by frequency and store the highest
# value at each frequency
# Plotting only the maximum value evaluated at each frequency
for k in range(len(w)):
w_i = w[k]
Gp_i = [(Gp(w_i * 1j, vec, i) - G(w_i * 1j)) / (G(w_i * 1j))
for i in range(vec.shape[0])]
Gp_i_max[k] = np.max(np.abs(Gp_i))
# plt.loglog(w, Gp_i_max, 'b+')
return Gp_i_max
def bound_MIMO_wi(w_start, w_end, vec, G, Gp, steps):
w = np.logspace(w_start, w_end, steps)
# Gp_i = np.zeros((vec.shape[0], len(w), 1))
Gp_i_max = np.zeros((len(w)))
# Plotting the multiplicative output relative uncertianty
# Plotting the multiplicative output relative uncertainty
# as a function of w
# Calculate the vales by frequency and store the highest
# value at each frequency
# Plotting only the maximum value evaluated at each frequency
for k in range(len(w)):
w_i = w[k]
# Calculate all perturbations at a specific frequency
Gp_i = [np.linalg.svd((Gp(w_i * 1j, vec, i) - G(w_i * 1j))
* np.linalg.pinv(G(w_i * 1j)), compute_uv=False)[0]
for i in range(vec.shape[0])]
# Calculate the maximum of the maximum singular values
# at each frequency
Gp_i_max[k] = np.max(Gp_i)
# plt.loglog(w, Gp_i_max, 'b+')
return Gp_i_max
def weight_calc(w_start, w_end, li, weight_i, steps):
"""Calculates a simple third-order weight
Accommodates situations were the weight increases with frequency
"""
w = np.logspace(w_start, w_end, steps)
# Search for the first index where the next value is lower
# than the previous
# Only works if no peaks are present and a low order
# weight is to be fitted
init_old = 0
found = False
safety_fac = 10 # amount of initial indexes to ignore
for k in range(steps - safety_fac):
init = li[k + safety_fac]
if init < init_old:
index = k + safety_fac
found = True
print(index)
break
else:
init_old = init
l_org = np.copy(li)
l_mod = li
if found:
max_val = np.max(li[index:-1])
# Write the maximum value over the rest of the range
z = 0 # margin on turn
for k in range(steps - index - z):
i = k + z + index
l_mod[i] = max_val
# Must change a, b, and c in weight to fit to l_mod
popt, pcov = op.curve_fit(weight_i, w * 1j, l_mod, [0.5, 0.5, 0.5])
return popt, l_mod, l_org, w
def weight_calc_dec(w_start, w_end, li, weight_i, steps):
"""Calculates a simple third-order weight
Accommodates situations were the weight decreases with frequency
"""
w = np.logspace(w_start, w_end, steps)
# Search for the first index where the next value is lower
# than the previous
# Only works if no peaks are present and a low order
# weight is to be fitted
# init_old = 0
# found = False
# safety_fac = 10 # amount of initial indexes to ignore
# for k in range(steps - safety_fac):
# init = li[k + safety_fac]
# if init > init_old:
# index = k + safety_fac
# found = True
# print index
# break
# else:
# init_old = init
l_org = np.copy(li)
l_mod = li
# if found:
# max_val = np.max(li[index:-1])
# # Write the maximum value over the rest of the range
# z = 0 # margin on turn
# for k in range(steps - index - z):
# i = k + z + index
# l_mod[i] = max_val
# Must change a, b, and c in weight to fit to l_mod
popt, pcov = op.curve_fit(weight_i, w * 1j, l_mod, [0.5, 0.5, 0.5])
return popt, l_mod, l_org, w
# TODO: The following is a list of possible expansions
# Calculate upper bounds on S'
# eq 6-88 pg 248
# Check input and output condition number along with RGA elements
# Nuquist plot with perturbed plant models generating all
# possible plants Nuquist plots using method outlined in 7.4.3
# pg 268-271 Skogestad
#################
# Use of state space descriptions
# Easier to discribe uncertainty and is numerically easier
# Easier to describe uncertainty and is numerically easier
#################
####
# Higher frequency uncertainty (higher order weights)
# For example see eq 7-36 and 7-37
####