function [y,u,t,y_e,t_e] = ppp_lin_run (Name,Simulate,ControlType,w,p_c,p_o)
## usage: [y,u,t,y_e,t_e] = ppp_lin_run (Name,Simulate,ControlType,w,p_c,p_o);
##
##
## Linear closed-loop PPP of lego system (and simulation)
##
## Name: Name of system (in mtt terms)
## Simulate = 0: real thing
## Simulate = 1: simulate
## Control = 0: step test
## Control = 1: PPP open-loop
## Control = 2: PPP closed-loop
## w is the (constant) setpoint
## par_control and par_observer are structures containing parameters
## for the observer and controller
##Defaults
if nargin<1 # Default name to dir name
names = split(pwd,"/");
[n_name,m_name] = size(names);
Name = deblank(names(n_name,:));
endif
if nargin<2
Simulate = 1;
endif
if nargin<3
ControlType = 2;
endif
if nargin<4
w = 1;
endif
if nargin<5
p_c.N = 10;
endif
if nargin<6
p_o.sigma = 0.001;
endif
if !struct_contains(p_c,"N")
p_c.N = 10; # Number of small samples per large sample
endif
if !struct_contains(p_c,"delta_ol")
p_c.delta_ol = 1.0; # OL sample interval
endif
if !struct_contains(p_c,"T")
p_c.T = 5.0; # Last time point.
endif
if !struct_contains(p_c,"A_w")
p_c.A_w = 0;
endif
if !struct_contains(p_c,"A_u")
p_c.N_u = 3;
a_u = 2.0;
p_c.A_u = ppp_aug(p_c.A_w,laguerre_matrix(p_c.N_u-1,a_u));
endif
[p_c.N_u,M_u] = size(p_c.A_u);
if (p_c.N_u<>M_u)
error("A_u must be square");
endif
## System
sys = mtt2sys(Name); # Create system
[A,B,C,D] = sys2ss(sys); # SS form
[n_x, n_u, n_y] = abcddim(A,B,C,D)
ol_poles = eig(A)
## Check w.
[n_w,m_w] = size(w);
if ( (n_w<>n_y) || (m_w<>1) )
error(sprintf("ppp_lin_run: w must a column vector with %i elements",n_y));
endif
## Initialise
x_0 = zeros(n_x,1);
x_est = x_0;
## Initilise simulation state
x = x_0;
##x(2) = 0.2;
# x(2) = y_0(1);
# x(4) = y_0(2);
if ControlType==0 # Step input
I = 1; # 1 large sample
p_c.delta_ol = p_c.T # I
K_w = zeros(p_c.N_u,n_y);
K_w(1,1) = 1;
K_w(2,1) = -1;
K_x = zeros(p_c.N_u,n_x);
U = K_w*w; # Initial control U
else # PPP control
I = ceil(p_c.T/p_c.delta_ol); # Number of large samples
tau = [10:0.1:11]*(2/a_u); # Time horizons
[k_x,k_w,K_x,K_w] = ppp_lin(A,B,C,D,p_c.A_u,p_c.A_w,tau); # Design
U = K_w*w # Initial control U
## Checks
cl_poles = eig(A - B*k_x)
endif
## Sample times
dt = 0.1;
delta = p_c.N*dt;
## Observer design
Ad = expm(A*delta); # Discrete-time transition matrix
if (ControlType==2)
G = eye(n_x); # State noise gain
sigma_x = eye(n_x); # State noise variance
Sigma = p_o.sigma*eye(n_y); # Measurement noise variance
L = dlqe(Ad,G,C,sigma_x,Sigma)
else
L = zeros(n_x,n_y);
endif
obs_poles = eig(Ad-L*C)
## Control loop
y = [];
u = [];
t = [];
y_e = [];
t_e = [];
for i=1:I
i
if Simulate
t_sim = [0:p_c.N]*dt;
[yi,ui,xsi] = ppp_ystar (A,B,C,D,x,p_c.A_u,U,t_sim);
x = xsi(:,p_c.N+1);
y_now = yi(:,p_c.N+1);
else # The real thing
to_rt(U'); # Send U
data = from_rt(p_c.N); # Receive data
[yi,ui] = convert_data(data);
y_now = yi(:,p_c.N); # Current output
endif
## Zero-gain (OL) observer with state resetting
[x_est y_est] = ppp_int_obs (x_est,y_now,U,A,B,C,D,p_c.A_u,delta,L);
# ## Reset states
# x_est(2) = y_now(1); # Position
# x_est(4) = y_now(2)/g_s; # Angle
##Control
U = K_w*w- K_x*x_est;
## Save
ti = [(i-1)*p_c.N:i*p_c.N-1]*dt;
t = [t;ti'];
y = [y;yi(:,1:p_c.N)'];
u = [u;ui(:,1:p_c.N)'];
y_e = [y_e; y_est'];
t_e = [t_e; (i*p_c.N)*dt];
endfor
## Put data on file (so can use for identification)
filename = sprintf("%s_ident_data.dat",Name);
eval(sprintf("save -ascii %s t y u",filename));
## Plot
gset nokey
title("");
boxed=0;
monochrome=1;
grid;
xlabel("t");
ylabel("y");
figure(1);plot(t,y, t_e,y_e,"+");
# figfig("OL_y","eps",boxed,monochrome);
ylabel("u");
figure(2);plot(t,u);
# figfig("OL_u","eps",boxed,monochrome);
endfunction