State Feedback and Observer
English translation
Learning objectives
Estimate velocity to control a system that measures only position, and compare estimated velocity and noise sensitivity.
Can measurements distinguish states?
Starting conditions
With position [m] and velocity [m/s] as states, use , . Use , , .
Procedure
- Form the controllability matrix [B,AB] and observability matrix [C;CA], and find their ranks.
- Compare the case where B is a zero vector with the case .
- Explain the distinction between an ineffective input and an unavailable measurement.
Results to retain
- A comparison table of both ranks and feasible designs for the three conditions.
import numpy as np
A=np.array([[0.,1.],[-2.,-3.]])
B=np.array([[0.],[1.]])
C=np.array([[1.,0.]])
for label,b,c in [('base',B,C),('no input',0*B,C),('no sensor',B,0*C)]:
ctrb=np.column_stack([b,A@b]);obsv=np.vstack([c,c@A])
print(label,np.linalg.matrix_rank(ctrb),np.linalg.matrix_rank(obsv))
# TODO: State what can and cannot be designed under each condition.
Record results and self-check
Condition:
Controllability rank:
Observability rank:
Design feasibility:
Points to check
- Are both ranks of the baseline model 2?
- Did you avoid applying pole placement directly to a rank-deficient model?
Connecting state feedback and observer
Starting conditions
, . Control poles: −2,−4; observer poles: −8,−10. Use , .
Procedure
- Calculate K and L, and compare the eigenvalues of and .
- Integrate actual and estimated states simultaneously, and plot position, velocity, and estimation errors over 0–4 s.
- Distinguish the reduction in estimation error from the output approaching its reference.
Results to retain
- Two plots of actual and estimated position and actual and estimated velocity, and the final estimation errors.
from scipy.signal import place_poles,StateSpace,lsim
import matplotlib.pyplot as plt
K=place_poles(A,B,[-2.,-4.]).gain_matrix
L=place_poles(A.T,C.T,[-8.,-10.]).gain_matrix.T
a_aug=np.block([[A,-B@K],[L@C,A-B@K-L@C]])
b_aug=np.vstack([8*B,8*B])
t=np.linspace(0,4,801)
_,z,_=lsim(StateSpace(a_aug,b_aug,np.eye(4),np.zeros((4,1))),np.ones(len(t)),t,X0=[1,0,0,0])
fig,axes=plt.subplots(2,1,sharex=True)
for j,ax in enumerate(axes):
ax.plot(t,z[:,j],label='state');ax.plot(t,z[:,j+2],'--',label='estimate');ax.legend();ax.grid()
axes[0].set_ylabel('Position [m]');axes[1].set_ylabel('Velocity [m/s]');axes[-1].set_xlabel('Time [s]')
print('final estimation error:',np.linalg.norm(z[-1,:2]-z[-1,2:]))
# TODO: Print and compare the control poles and observer poles.
Record results and self-check
K:
L:
Control poles:
Observer Pole:
Final error:
Points to check
- Do the eigenvalues of and , after substituting the calculated and , match the specified control and observer poles, respectively?
- At s, are the position and velocity estimation errors below 1e-6 m and 1e-6 m/s, respectively?
Is a faster observer always better?
Starting conditions
Add n(t)=0.02sin(40t) to the measurement. Compare observer poles (−8,−10) and (−20,−25), keeping controller K fixed.
Procedure
- Use both observer settings in the practice notebook's function, and compare the control input u on the same time axis.
- Calculate position-error RMS, velocity-error RMS, and control-input RMS separately after 1 s.
- Interpret initial estimation-error convergence separately from the response to measurement noise.
Results to retain
- Control-input curves, a comparison table of the three RMS values, and justification for the selected setting.
def noisy_observer(poles):
L=place_poles(A.T,C.T,poles).gain_matrix.T
aa=np.block([[A,-B@K],[L@C,A-B@K-L@C]])
bb=np.block([[8*B,np.zeros((2,1))],[8*B,L]])
inputs=np.column_stack([np.ones(len(t)),.02*np.sin(40*t)])
_,z,_=lsim(StateSpace(aa,bb,np.eye(4),np.zeros((4,2))),inputs,t,X0=[1,0,0,0])
u=8-(z[:,2:]@K.T).ravel();keep=t>=1
return u,np.sqrt(np.mean((z[keep,:2]-z[keep,2:])**2,axis=0)),np.sqrt(np.mean(u[keep]**2))
for poles in [(-8,-10),(-20,-25)]:
u,err,rms=noisy_observer(poles);plt.plot(t,u,label=str(poles));print(poles,err,rms)
plt.xlabel('Time [s]');plt.ylabel('u [N]');plt.legend();plt.grid()
# TODO: Explain which of the two settings you would choose, based on the metrics.
Record results and self-check
Observer Pole:
Position error RMS [m]:
Velocity error RMS [m/s]:
Input RMS [N]:
Reason for your choice:
Points to check
- Are noise, initial conditions, and time steps the same for both settings?
- Did you avoid conflating error and input in a single metric?