from control.matlab import *
import matplotlib.pyplot as plt
import numpy as np
#plt.rcParams['font.family'] ='sans-serif' #使用するフォント
plt.rcParams['font.family'] = 'Times New Roman' # font familyの設定
plt.rcParams['mathtext.fontset'] = 'cm' # math fontの設定
plt.rcParams['xtick.direction'] = 'in' #x軸の目盛線が内向き('in')か外向き('out')か双方向か('inout')
plt.rcParams['ytick.direction'] = 'in' #y軸の目盛線が内向き('in')か外向き('out')か双方向か('inout')
plt.rcParams['xtick.major.width'] = 1.0 #x軸主目盛り線の線幅
plt.rcParams['ytick.major.width'] = 1.0 #y軸主目盛り線の線幅
plt.rcParams['font.size'] = 11 #フォントの大きさ
plt.rcParams['axes.linewidth'] = 0.5 # 軸の線幅edge linewidth。囲みの太さ
plt.rcParams['mathtext.default'] = 'it'#'regular'
plt.rcParams['axes.xmargin'] = '0'
plt.rcParams['axes.ymargin'] = '0.05'
plt.rcParams['savefig.facecolor'] = 'None'
plt.rcParams['savefig.edgecolor'] = 'None'
plt.rcParams["legend.fancybox"] = True # 丸角
# plt.rcParams["legend.framealpha"] = 1 # 透明度の指定、0で塗りつぶしなし
# plt.rcParams["legend.edgecolor"] = 'gray' # edgeの色を変更
plt.rcParams["legend.handlelength"] = 1.8 # 凡例の線の長さを調節
plt.rcParams["legend.labelspacing"] = 0.4 # 垂直方向(縦)の距離の各凡例の距離
plt.rcParams["legend.handletextpad"] = 0.7 # 凡例の線と文字の距離の長さ
plt.rcParams["legend.markerscale"] = 1.0 # 点がある場合のmarker scale
def linestyle_generator():
linestyle = ['-', '--', '-.', ':']
lineID = 0
while True:
yield linestyle[lineID]
lineID = (lineID + 1) % len(linestyle)
def plot_set(fig_ax, *args):
fig_ax.set_xlabel(args[0])
fig_ax.set_ylabel(args[1])
fig_ax.grid(ls=':', lw=0.5)
if len(args)==3:
fig_ax.legend(loc=args[2])
def bodeplot_set(fig_ax, *args):
fig_ax[0].grid(which="both", ls=':', lw=0.5)
fig_ax[0].set_ylabel('Gain [dB]')
fig_ax[1].grid(which="both", ls=':', lw=0.5)
fig_ax[1].set_xlabel('$\omega$ [rad/s]')
fig_ax[1].set_ylabel('Phase [deg]')
if len(args) > 0:
fig_ax[1].legend(loc=args[0])
if len(args) > 1:
fig_ax[0].legend(loc=args[1])
# 図を保存するかどうか
is_savefig = False
# 図の保存パス
figpath="./notebook_output/"
# 数式処理のためにsympyをインポート
import sympy as sp
from sympy.matrices import *
状態方程式を定義
A = np.matrix([[4,3],[-6,-5]])
B = np.matrix([[0],[1]])
C1 = np.matrix([1,0])
C2 = np.matrix([1,1])
D = np.matrix([0])
ss1 = ss(A, B, C1, D)
ss2 = ss(A, B, C2, D)
ss1
ss2
Aの固有値を調べてみると1と-2で,正のものを一つ含むので不安定である.
l, _ = np.linalg.eig(A)
l
array([ 1., -2.])
一方,伝達関数を調べてみると,G1の極はAの固有値を二つとも保存しているが,G2の極は安定な固有値の方しか含まない.Aの不安定極は,出力行列C2によって隠されてしまっている.
G1 = ss2tf(ss1)
G1
pole(G1)
array([-2., 1.])
G2 = ss2tf(ss2)
G2
pole(G2)
array([-2.])
積分器を含むシステム=原点に極を持つ場合の挙動
G1=tf([1],[1,1,0])
G1
pole(G1)
array([-1., 0.])
ss1 = tf2ss(G1)
ss1
s, v = np.linalg.eig(ss1.A)
s
array([ 0., -1.])
fig, ax = plt.subplots(figsize=(6, 6))
w = 1.5
Y, X = np.mgrid[-w:w:5j, -w:w:5j]
U = ss1.A[0,0]*X + ss1.A[0,1]*Y
V = ss1.A[1,0]*X + ss1.A[1,1]*Y
# 固有空間のプロット
vv = v * w * np.sqrt(2)
if s.imag[0] == 0 and s.imag[1] == 0: #固有値が複素数の場合はプロットできない
ax.plot([-vv[0,0],vv[0,0]], [-vv[1,0],vv[1,0]], c='k', ls='-.', lw=2)
ax.plot([-vv[0,1],vv[0,1]], [-vv[1,1],vv[1,1]], c='k', ls='--', lw=2)
ax.streamplot(X, Y, U, V, density=0.7, color='k', linewidth=0.5)
ax.set_xlim(-1.5,1.5)
ax.set_ylim(-1.5,1.5)
ax.set_xticks(np.arange(-1.5, 1.51, step=0.5))
ax.set_yticks(np.arange(-1.5, 1.51, step=0.5))
ax.grid(ls = ':')
plot_set(ax, '$x_1$', '$x_2$')
_, _, x = initial(ss1, X0=[1,-0.5], return_x=True)
ax.plot(x[:,0], x[:,1], lw=2, color='r',)
[<matplotlib.lines.Line2D at 0x7f9b204cd220>]
fig, ax = plt.subplots(figsize=(6, 4.6))
x0 = [1,-0.5]
_, trange, x = initial(ss1, X0=x0, return_x=True) # シミュレーション
ax.plot(trange, x[:,0], lw=2, color='r', label='$x_1$')
ax.plot(trange, x[:,1], lw=2, color='b', label='$x_2$')
ax.axhline(0, color="k", linewidth=0.5)
ax.grid(ls = ':')
plot_set(ax,'t','x','best')
A = np.matrix([[1, 2],[-3, -4]])
B = np.matrix([[0],[1]])
C = np.matrix([1, 0])
D = np.matrix([0])
sys = ss(A, B, C, D)
print(sys)
A = [[ 1. 2.] [-3. -4.]] B = [[0.] [1.]] C = [[1. 0.]] D = [[0.]]
Q = np.eye(A.shape[0])*12
Q
array([[12., 0.], [ 0., 12.]])
#関数の仕様上,A^Tを代入していることに注意
P = lyap(np.transpose(A),Q)
print(P)
[[27. 11.] [11. 7.]]
P*A + np.transpose(A)*P
matrix([[-1.20000000e+01, -3.55271368e-15], [-3.55271368e-15, -1.20000000e+01]])
固有値の確認
l, v = np.linalg.eig(A)
l
array([-1., -2.])
※数式処理による理論解
import sympy
sympy.init_printing()
sympy.var('p11, p12, p22')
Asym=sympy.Matrix(A)
Psym=sympy.Matrix([[p11, p12],[p12, p22]])
Qsym=sympy.Matrix(Q)
Lyap = Psym*Asym + Asym.transpose()*Psym + Qsym
Lyap
eq1 = sympy.Eq(Lyap[0,0], 0)
eq2 = sympy.Eq(Lyap[0,1], 0)
eq3 = sympy.Eq(Lyap[1,1], 0)
sympy.solve([eq1, eq2, eq3], [p11, p12, p22])
章末問題【2】も参照のこと.
数式処理による理論解析
s=sp.symbols('s')
K=(s-1)/(s+1)
P=1/(s-1)
K,P
Gyr=sp.factor(P*K/(1+P*K))
Gyr
Gyd=sp.factor(P/(1+P*K))
Gyd #不安定!
Gur=sp.factor(K/(1+P*K))
Gur
章末問題【3】も参照のこと.
L=tf([1],[1,0]) * tf([1],[1,1])**3
# 全体図(左),拡大図(右)
fig, ax = plt.subplots(1,2,figsize=(12, 6))
x, y, _ = nyquist(L, logspace(-3,3,1000), plot=False)
for i in [0,1]:
ax[i].plot(x, y, c='k', ls='-', lw=2)
ax[i].plot(x, -y, c='k', ls=':', lw=2)
ax[i].grid(ls=':', lw=0.5)
ax[i].set_xlabel('Re')
ax[i].set_ylabel('Im')
ax[0].set_xlim(-5,15)
ax[0].set_ylim(-10, 10)
ax[1].set_xlim(-3,1)
ax[1].set_ylim(-2,2)
ax[1].scatter(0, 0, color='k')
ax[1].annotate('$O$', xy=(0.2, 0), size=10)
Text(0.2, 0, '$O$')
# Bode線図(参考)
fig, ax = plt.subplots(2, 1, figsize=(8,7))
gain, phase, w = bode(L, logspace(-3,3), plot=False)
ax[0].semilogx(w, 20*np.log10(gain), color='k', lw=1)
ax[1].semilogx(w, phase*180/np.pi, color='k', lw=1)
bodeplot_set(ax)
ax[1].set_yticks([-360,-270,-180,-90,0])
fig.tight_layout()
omega = 10.0
L=tf([omega],[1,0,omega**2]) * tf([1],[1,1])
# 全体図(左),拡大図(右)
fig, ax = plt.subplots(1,2,figsize=(12, 6))
log_eps = 0.1
x, y, _ = nyquist(L, logspace(-3, 1-log_eps,1000), plot=False)
x2, y2, _ = nyquist(L, logspace(1+log_eps,3,1000), plot=False)
for i in [0,1]:
ax[i].plot(x, y, c='k', ls='-', lw=2)
ax[i].plot(x, -y, c='k', ls=':', lw=2)
ax[i].plot(x2, y2, c='k', ls='-', lw=2)
ax[i].plot(x2, -y2, c='k', ls=':', lw=2)
ax[i].grid(ls=':', lw=0.5)
ax[i].set_xlabel('Re')
ax[i].set_ylabel('Im')
# ax[0].set_xlim(-5,15)
# ax[0].set_ylim(-10, 10)
# ax[1].set_xlim(-3,1)
# ax[1].set_ylim(-2,2)
# Bode線図(参考)
fig, ax = plt.subplots(2, 1, figsize=(8,7))
gain, phase, w = bode(L, logspace(-3,3,1000), plot=False)
ax[0].semilogx(w, 20*np.log10(gain), color='k', lw=1)
ax[1].semilogx(w, phase*180/np.pi, color='k', lw=1)
bodeplot_set(ax)
ax[1].set_yticks([-90,-45,0])
fig.tight_layout()
/Users/minami/opt/anaconda3/lib/python3.8/site-packages/control/xferfcn.py:317: RuntimeWarning: divide by zero encountered in true_divide out[i][j] = (polyval(self.num[i][j], x_arr) / /Users/minami/opt/anaconda3/lib/python3.8/site-packages/control/xferfcn.py:317: RuntimeWarning: invalid value encountered in true_divide out[i][j] = (polyval(self.num[i][j], x_arr) /
import sympy as sp
s = sp.symbols('s')
a3,a2,a1,a0 = sp.symbols('a_3, a_2, a_1, a_0')
# b3,b2,b1 = sp.symbols('b_3, b_2, b_1')
# c3,c2,c1 = sp.symbols('c_3, c_2, c_1')
# d3,d2,d1 = sp.symbols('d_3, d_2, d_1')
sp.init_printing()
b1 = (a3*a2 - 1*a1) / a3
b2 = (a3*a0 - 1*0) / a3 # 係数がないところは0を埋める
b3 = (a3* 0 - 1*0) / a3 # 係数がないところは0を埋める
b1,b2,b3
c1 = (b1*a1 - a3*b2) / b1
c2 = (b1*0 - a3*b3) / b1
c3 = (b1*0 - a3*0 ) / b1
c1, c2, c3
c1 = sp.factor(sp.expand(c1))
c1
d1 = (c1*b2 - b1*c2) / c1
d2 = (c1*b3 - b1*c3) / c1
d1,d2
再評価
Routh = sp.Matrix([
[1, a2, a0],
[a3, a1, 0],
[b1, b2, b3],
[c1, c2, 0],
[d1, d2, 0]
])
Routh
係数を代入して確認
values=[(a3,2), (a2,3), (a1,4), (a0, 5)]
Routh.subs(values)
最左列をみると,2回符号が変わっているので,不安定(不安定極を二つもつ)ことがわかる.
H4 = sp.Matrix([[a1, a3, 0, 0],[a0, a2, 1, 0],[0, a1, a3, 0], [0, a0, a2, 1]])
H3 = H4[:3,:3]
H2 = H4[:2,:2]
H1 = H4[:1,:1]
H1, H2, H3, H4
sp.det(H1), sp.det(H2), sp.det(H3), sp.det(H4)
sp.Matrix([sp.det(H1), sp.det(H2), sp.det(H3), sp.det(H4)]).subs(values)
P = tf([1],[1,2,3,4,5])
P
pole(P)
array([-1.28781548+0.85789676j, -1.28781548-0.85789676j, 0.28781548+1.41609308j, 0.28781548-1.41609308j])
A = np.matrix([[-2, 1],[2, -3]])
B = np.matrix([[0],[1]])
C = np.matrix([1, 0])
D = np.matrix([0])
sys = ss(A, B, C, D)
print(sys)
A = [[-2. 1.] [ 2. -3.]] B = [[0.] [1.]] C = [[1. 0.]] D = [[0.]]
Q = np.eye(A.shape[0])
Q
array([[1., 0.], [0., 1.]])
#関数の仕様上,A^Tを代入していることに注意
P = lyap(np.transpose(A),Q)
P*40
matrix([[17., 7.], [ 7., 9.]])
P*A + np.transpose(A)*P
matrix([[-1.00000000e+00, 5.55111512e-17], [ 5.55111512e-17, -1.00000000e+00]])
l, v = np.linalg.eig(A)
l
array([-1., -4.])
※数式処理による理論解
import sympy
sympy.init_printing()
sympy.var('p, q, r')
Asym=sympy.Matrix(A)
Psym=sympy.Matrix([[p, q],[q, r]])
Qsym=sympy.Matrix(Q)
Lyap = Psym*Asym + Asym.transpose()*Psym + Qsym
Lyap
eq1 = sympy.Eq(Lyap[0,0], 0)
eq2 = sympy.Eq(Lyap[0,1], 0)
eq3 = sympy.Eq(Lyap[1,1], 0)
sympy.solve([eq1, eq2, eq3], [p, q, r])
数式処理による理論解析
s=sp.symbols('s')
K=(s**2-3*s+2)/(s**2+2*s+1)
P=(s+1)/(s**2-4)
K,P
K=sp.factor(K)
P=sp.factor(P)
K,P
Gyr=sp.factor(P*K/(1+P*K))
Gyr
Gyd=sp.factor(P/(1+P*K))
Gyd
Gur=sp.factor(K/(1+P*K))
Gur
phi_FB=sp.factor(sp.denom(P)*sp.denom(K) + sp.numer(P)*sp.numer(K))
phi_FB
import sympy as sp
sp.init_printing()
s=sp.Symbol('s')
Psym= sp.expand( 1 / ((s+1)**2 * (0.1*s+1)) )
Psym
Ksym=sp.Symbol('k')
Ksym
Gsym = sp.simplify( Psym * Ksym / (1 + Psym * Ksym) )
Gsym
P = tf([1],[1,1])**2 * tf(1,[0.1, 1])
fig, ax = plt.subplots(2, 1, figsize=(4, 3.5))
k=1
gain, phase, w = bode(P*k, logspace(-2,3), plot=False)
ax[0].semilogx(w, 20*np.log10(gain), color='k', lw=1)
ax[1].semilogx(w, phase*180/np.pi, color='k', lw=1)
bodeplot_set(ax)
ax[0].semilogx(w, 0*w, c='c', ls='-', lw=1)
ax[1].semilogx(w, -180*np.ones_like(w), c='c', ls='-', lw=1)
ax[1].set_yticks([-270,-180,-90,0])
# ゲイン余裕,位相余裕,位相交差周波数,ゲイン交差周波数
gm, pm, wpc, wgc = margin(P*k)
GM = 20*np.log10(gm) #デシベル値に変換
ax[0].plot([wpc,wpc],[-GM,0], c='r', ls='-', lw=2)
ax[0].scatter(wpc,-GM, alpha=0.5, c='k')
ax[1].scatter(wpc,-180, alpha=0.5, c='k')
fig.tight_layout()
if (is_savefig):
fig.savefig(figpath+"ans/ch5_4_bode.pdf", transparent=True, bbox_inches="tight", pad_inches=0.0)