<jupyter_start><jupyter_text>DC motor with observer<jupyter_code>import numpy as np
import sympy as sy
sy.init_printing()
s = sy.symbols('s', real=False)
J, gr, b, k, kv, tau, tauc = sy.symbols('J, gr, b, k, k_v, tau, tau_c', real=True, positive=True)
l1, l2, k1, k2 = sy.symbols('l_1, l_2, k_1, k_2', real=True)
# Using physical states x = [omega, theta]
A = sy.Matrix([[-1/tau, 0], [1, 0]])
B = sy.Matrix([[k/tau], [0]])
Bv = sy.Matrix([[1/J], [0]])
C = sy.Matrix([[0, 1]])
            
# Charact polynomial
L = sy.Matrix([[l1, l2]])
M = s*sy.eye(2) - (A-B*L)
char_pol = sy.poly(sy.det(M), s)
char_pol

# Desired closed-loop poles
wc = 1/tauc
p1 = wc/sy.sqrt(2)*(-1 + sy.I)
p2 = wc/sy.sqrt(2)*(-1 - sy.I)
char_pol_des = sy.poly((s-p1)*(s-p2), s)
char_pol_des
eqns = [c_ - cd_ for c_, cd_ in zip(char_pol.coeffs(), char_pol_des.coeffs())]
sol = sy.solve(eqns, [l1, l2])
sol<jupyter_output><empty_output><jupyter_text>Observer design<jupyter_code>d = sy.symbols('d', real=True, positive=True)
po1 = d*p1
po2 = d*p2
char_pol_des_o = sy.poly((s-po1)*(s-po2), s)
char_pol_des_o
K = sy.Matrix([[k1], [k2]])
char_pol_o = sy.Poly(sy.det(s*sy.eye(2)-(A-K*C)), s)
char_pol_o
eqns = [c_ - cd_ for c_, cd_ in zip(char_pol_o.coeffs(), char_pol_des_o.coeffs())]
sol_o = sy.solve(eqns, [k1, k2])
sol_o
K*C
A-K*C
s*sy.eye(2)-(A-K*C)<jupyter_output><empty_output><jupyter_text>Observer gains to eliminate constant input disturbance Plant dynamics, reference signal $r=0$$$ \dot{x} = Ax - BL\hat{x} + Bv $$ Observer dynamics$$ \dot{\hat{x}} = A\hat{x} - BL\hat{x} + KCx - KC\hat{x} + Bv = (A-KC)\hat{x} + KCx + Bv $$ Error dynamics, $\tilde{x} = x-\hat{x}$$$ \dot{\tilde{x}} = (A-KC)\tilde{x} + Bv $$ Steady-state estimation error$$ \tilde{x}_{ss} = -(A-KC)^{-1}Bv. $$Steady-state state$$0 = Ax_{ss} - BL\hat{x}_{ss} + Bv$$Steady-state output\begin{align}y_{ss} = Cx_{ss} = C\hat{x}_{ss} + C\tilde{x}_ss\end{align}<jupyter_code>kv = Bv[0,0]/B[0,0]
kv

AminKC = A-K*C
AminKCinv = AminKC.inv()
AminKC, AminKCinv
lhs = L*AminKC.inv()*B
lhs
sol = sy.solve(lhs[0,0]+1,k1)
sol
sol = sy.solve(lhs[0,0].subs([(k2, tau*k1)])+1,k1)
sol
a, b = sy.symbols('a, b')
sol = sy.solve(lhs[0,0].subs([(k2, tau*k1), (k, b*tau),(tau, 1/a)])+1,k1)
sol[0]

Kk = sy.Matrix([sol[0], 1/a*sol[0]])
Kk
AA = A.subs([(k, b*tau),(tau, 1/a)])
BB = B.subs([(k, b*tau),(tau, 1/a)])
BB 
AminKkC = AA-Kk*C
AminKkCinv = AminKkC.inv()
AA, AminKkC, AminKkCinv
sy.simplify(L*AminKkCinv*BB)
L<jupyter_output><empty_output>
{'fraction_non_alphanumeric': 0.236105476673428, 'fraction_numerical': 0.029614604462474645, 'mean_word_length': 4.748251748251748, 'pattern_counts': {'":': 0, '<': 13, '<?xml version=': 0, '>': 13, 'https://': 0, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'chain_length': '3', 'dir': 'jupyter-structured-clean-dedup', 'id': '521518', 'license': 'MIT', 'n_tokens_mistral': 1283, 'n_tokens_neox': 1238, 'n_words': 235, 'path': 'modern-control/notebooks/DC motor with observer.ipynb', 'repo_name': 'kjartan-at-tec/mr2025', 'size': '2465'}