Design of a robust digital controller with PPR toolbox

by

 

07 Oct 2008 (Updated )

This script shows the basic steps for the "digital two degrees of freedom controller" (2DOF) design

A robust digital two degrees of freedom controller, a polynomial approach.

A robust digital two degrees of freedom controller, a polynomial approach.

This script shows the basic steps for the "digital two degrees of freedom controller" (2DOF) design with the PPR toolbox.

The illustration of our methodology is based on a difficult plant control. To get a 2DOF controller, only 2 "high level" parameters that have deterministic action on the closed-loop performances are required.

Taking account in the modelisation of the external signals that act on the plant lead to a controller with better performances than a classical PID regulator.

The action on 2 high-level parameters give the user a powerfull tool to deal clearly with the performance/robustness dilemma : the more closed-loop performances (in a disturbance rejection meaning) the more sensitivity to uncertainties on the plant's model that can lead to unstability.

Required installation :

  • the PPR directories must be set in the Matlab path.
  • the Matlab CONTROL toolbox is required.

Required background :

  • frequential analysis ;
  • discrete time controller ;
  • SISO (single input single output) continuous time control theory.

Not required but ...

  • SISO space state controllers ;
  • SISO dynamic state observers ;
  • polynomial controllers and their resolution with Bezout equation solver.

References :

  • Computer controlled systems, theory and design - K.J. Astrom and B. Wittenmark - 3rd edition 1997, Prentice Hall.
  • Automatique - P. de Larminat - 2nd edition 1996, Hermès.

Author :

  • Gilles Bailly, LCAR UMR5589 CNRS, 118 route de Narbonne, Toulouse, France

Last revision :

  • 2008/09/17

Contents

Standard modelisation : purpose

The purpose of the standard modelisation is to give a complete linear description of the plant and the external signals that disturb its behavior. These descriptions are used by the controller solver.

  reference : wr -->[WR]--r------------[+]---> z
                                        |-
      noise : wn -->[WN]--n----------+  |
                                     |  |
disturbance : wd -->[WD]--d--+       |  |
                             |-      |  |
    command : u --->[P]-----[+]--y--[+]------> ym

Transfers

  • WR : reference signal predictor
  • WD : disturbance signal predictor
  • WN : noise measurement signal predictor
  • P : plant model

Signals

  • u : command signal
  • y : plant output signal
  • r : reference signal
  • n : noise measurement
  • d : disturbance signal
  • ym : noisy plant measured output
  • z : error signal
close all, clear all, clc;
% simulink model
model_name = 'sample1_SIM';

Standard modelisation : plant

First order model with delay. The dominant time constant, the delay and the gain are set respectively to 1s, 0.5s and 1.

              -0.5s
           exp
G(s) = 1 x --------
          1 + 1s
plant_num = [1];
plant_den = [1 1];
plant_tf = tf(plant_num, plant_den);
plant_tf.iodelay = 0.5;

Standard modelisation : reference

Choose a predictor for the reference exo-signal.

The usual predictors are :

  1. constant => WR(s) = s
  2. ramp => WR(s) = s^2
  3. sine => WR(s) = s^2 + s(w0/q0) + w0^2
reference_num = [1];
% step predictor
reference_den = [1 0];
reference_tf = tf(reference_num, reference_den);

Standard modelisation : disturbance

Choose a predictor for the disturbance exo-signal.

The usual predictors are :

  1. constant => WD(s) = s
  2. ramp => WD(s) = s^2
  3. sine => WD(s) = s^2 + s(w0/q) + w0^2

WARNING : polynoms WN[s], WD[s] must satisfy PGCD(WN[s], WD[s]) = 1 this mathematical constraint is simple to understand : the closed-loop can not reject a signal and be insensitive to this signal in a same time !

disturbance_num = [1];
% step predictor
disturbance_den = [1 0 0];
disturbance_tf = tf(disturbance_num, disturbance_den);

% sine  predictor
%[disturbance_num, disturbance_den] = ord2(2*pi*0.2, 0.001);
%disturbance_gain = sum(disturbance_num)/sum(disturbance_den);
%disturbance_tf = tf(disturbance_num/disturbance_gain, disturbance_den);

% step + sine predictor
%[disturbance_num, disturbance_den] = ord2(2*pi*0.2, 0.001);
%disturbance_gain = sum(disturbance_num)/sum(disturbance_den);
%disturbance_tf = tf(disturbance_num/disturbance_gain, disturbance_den)*tf(1, [1 0]);

% ramp predictor
%disturbance_tf = tf(1, [1 0 0]);

Standard modelisation : noise

Choose a predictor for the noise exo-signal.

The usual predictors are :

  1. none => WN(s) = 1
  2. sine => WN(s) = s^2 + s(w0/q) + w0^2

WARNING : polynoms WN[s], WD[s] must satisfy PGCD(WN[s], WD[s]) = 1 this mathematical constraint is simple to understand : the closed-loop can not reject a signal and be insensitive to this signal in a same time !

% impulse noise predictor
noise_tf = tf(1,1);

% sine noise predictor
% [noise_num, noise_den] = ord2(2*pi*1, 0.003);
% noise_gain = sum(noise_num)/sum(noise_den);
% noise_tf = tf(noise_num/noise_gain, noise_den);

Standard modelisation : impulse responses

Display the open-loop responses of the standard model.

figure;
[y,t]=step(plant_tf);
subplot(411);
plot(t,y);
title('Plant : step response from u to y');
subplot(412);
impulse(disturbance_tf, t);
title('Disturbance : impulse response from wd to d');
subplot(413);
impulse(noise_tf, t);
title('Noise : impulse response from wn to n');
subplot(414);
impulse(reference_tf, t);
title('Reference : impulse response from wr to yr');

Controller : initialization

Initialize the required structures for the controller solver.

% 1st tuning trial (to = 0.3s) : data1
% 2nd tuning trial (to = 1s)   : data2
data1.model.plant = plant_tf;
data1.model.reference = reference_tf;
data1.model.noise = noise_tf;
data1.model.disturbance = disturbance_tf;
data1.preference = ppr_preference('init');
data1.control.current_controller = 1;
data1.controller = ppr_controller('init');
data1.controller.specification.sampling_period = 0.1;

data2 = data1;

Controller : command poles placement

The command poles proceed from the plant's poles and they are computed according to the horizon time.

% collect open-loop poles and zeros
transfert = data1.model.plant;

% init placement structure with plant poles and zeros
command_placement = ppr_placement('init', transfert);

% specify horizon time
% There is one open-loop pole due to the plant : po1 = -1.
% Set the placement horizon to 1/3 to place po1 from -1 to -3.
% This makes the closed-loop 3 times faster in tracking reference mode.
command_placement.horizon = 1/3;

% make placement
command_placement = ppr_placement('place', command_placement);
data1.controller.specification.command_placement = command_placement;

% make same pole placement for 2nd trial
data2.controller.specification.command_placement = command_placement;

Controller: observer poles placement

The observer poles proceed from the plant augmented poles and they are computed according to the horizon time.

% collect observer open-loop poles
plant = data1.model.plant;
noise = data1.model.noise;
disturbance = data1.model.disturbance;
s_loopshaping_filter = data1.controller.specification.s_loopshaping_filter;
t_loopshaping_filter = data1.controller.specification.t_loopshaping_filter;
transfert = plant *  noise * disturbance * s_loopshaping_filter * t_loopshaping_filter;

% init placement structure
observer_placement = ppr_placement('init', transfert);

% specify horizon time
% There is 3 open-loop poles , one from the plant (po1 = -1) and 2 from
% the disturbance (po2 = po3 = 0)

% 1 )try the placement horizon set to 1/3 and place po1 to po3 at -3
observer_placement.horizon = 1/3;
observer_placement = ppr_placement('place', observer_placement);
data1.controller.specification.observer_placement = observer_placement;

% 2 )now, try the placement horizon set to 1/1 and place po2 and po3 at -1
% when po1 remains at -1 location.
observer_placement.horizon = 1/1;
observer_placement = ppr_placement('place', observer_placement);
data2.controller.specification.observer_placement = observer_placement;

Controller : reference observer poles placement

The reference observer poles proceed from the plant's poles and they are computed according to the horizon time. This horizon has no effect on stability.

% collect open-loop poles
transfert = data1.model.reference;

% init placement structure
reference_observer_placement = ppr_placement('init', transfert);

% specify horizon time
% There is one open-loop pole due to the reference : pro1 = 0.
% Set the placement horizon equal to the command horizon (1/3) to place
% po1 from 0 to -3.
% This controls the smoothing of the applied reference signal. The smaller
% reference horizon, the stronger command applied to the plant.
% Note that the reference placement has not effect on the closed-loop
% robustness.
reference_observer_placement.horizon = 1/3;

% make placement
reference_observer_placement = ppr_placement('place', reference_observer_placement);
data1.controller.specification.reference_observer_placement = reference_observer_placement;

% make same placement for 2nd controller
data2.controller.specification.reference_observer_placement = reference_observer_placement;

Controller : poles placement map

Display the three poles placements.

figure;
subplot(311);
pzmap(plant_tf, 'r',...
    tf(1,poly(data1.controller.specification.command_placement.closed_loop_pole)), 'g');
hor = data1.controller.specification.command_placement.horizon;
line([ -1/hor -1/hor], get(gca,'YLim'), 'LineStyle', ':');
title('Command pole placement for t_c = 0.3s');
subplot(312);
pzmap(reference_tf, 'r',...
    tf(1,poly(data1.controller.specification.reference_observer_placement.closed_loop_pole)),...
    'g');
h1c = data1.controller.specification.reference_observer_placement.horizon;
line([ -1/h1c -1/h1c], get(gca,'YLim'), 'LineStyle', ':');
title('Reference observer pole placement for t_{ro} = 0.3s');
subplot(313);
pzmap(plant_tf*disturbance_tf*noise_tf, 'r',...
    tf(1,poly(data1.controller.specification.observer_placement.closed_loop_pole)),...
    'g',...
    tf(1,poly(data2.controller.specification.observer_placement.closed_loop_pole)),...
    'c');
h1o = data1.controller.specification.observer_placement.horizon;
line([ -1/h1o -1/h1o], get(gca,'YLim'), 'LineStyle', ':');
title('Observer pole placement for t_o = 0.3s and t_o = 1s');

Controller : resolution

Solve the Bezout equations and return the controller

data1.controller = ppr_controller('get', data1);
data2.controller = ppr_controller('get', data2);

Controller : internal connections

Make internal connection between augmented plant and controller's transfers.

data1.controller = ppr_connect( data1.model, data1.controller );
data2.controller = ppr_connect( data2.model, data2.controller );

Controller : digital implementation

The resolution of controller's equations lead to the to 3 polynoms (R,S,T). The practical implementation follows the scheme below which is an antiwindup form useful when the actuator presents some nonlinearities like saturation.

         wr -->[ Dr ]---r----------+
                                   |
+-v----------->[ P  ]---ym-------+ |
|                                | |
|                                | |
+-v--[ NL ]<-u-[ + ]<---[ yu ]<--+ |
|                |-                |
|                |                 |
+-v->[ vu ]--->[ + ]<---[ ru ]<----+

Closed-loop : impulse responses

Display the closed-loop responses for the two controllers designed with (tc, to, tro) horizons set to (0.3,0.3,0.3) and (0.3,1,0.3)

figure;
nsample = 100;
ts = data1.controller.specification.sampling_period;
data1.controller.closed_loop.system.outputnames = {'yr','d', 'n', 'u', 'ym', 'z'};
data1.controller.closed_loop.system.inputnames = {'wr','wd', 'wn'};
data2.controller.closed_loop.system.outputnames = {'yr','d', 'n', 'u', 'ym', 'z'};
data2.controller.closed_loop.system.inputnames = {'wr','wd', 'wn'};
impulse(data1.controller.closed_loop.system,...
    data2.controller.closed_loop.system, 0:ts:nsample*ts);
title('Closed-loop responses for t_o = 0.3s and t_o = 1s');

Closed-loop : robustness, stability margins

Compute the stability margins for the two closed-loops.

% get limit margins
margin_reference =  data1.preference.margin;

% compute margins from closed-loop
data1.controller = ppr_margin( 'compute_margin',...
    data1.controller, margin_reference);
data2.controller = ppr_margin( 'compute_margin',...
    data2.controller, margin_reference);

Closed-loop : robustness and performances, S, T & L Bode plots

Plot bode diagrams and evaluate robustness and performances with each controller.

figure;
data1.controller.closed_loop.loop_transfert.name = 'L1';
data1.controller.closed_loop.s_function.name = 'S1';
data1.controller.closed_loop.t_function.name = 'T1';
data2.controller.closed_loop.loop_transfert.name = 'L2';
data2.controller.closed_loop.s_function.name = 'S2';
data2.controller.closed_loop.t_function.name = 'T2';
hb=bodeplot(data1.controller.closed_loop.loop_transfert,...
    data1.controller.closed_loop.s_function,...
    data1.controller.closed_loop.t_function,...
    data2.controller.closed_loop.loop_transfert,...
    data2.controller.closed_loop.s_function,...
    data2.controller.closed_loop.t_function);
setoptions(hb,'FreqUnits','Hz','PhaseVisible','off');
grid on;
% title('L transfer and sensitivity functions S & T for t_o = 0.3s and t_o = 1s');
% legend('L t_o = 0.3s', 'S t_o = 0.3s', 'T t_o = 0.3s',...
%     'L t_o = 1s', 'S t_o = 1s', 'T t_o = 1s');

Closed-loop: robustness Nichols plot

Nichols plot of the open-loop transfers.

figure;
nichols(data1.controller.closed_loop.loop_transfert,...
    data2.controller.closed_loop.loop_transfert);
grid on;
title(' open-loop L for t_o = 0.3s and t_o = 1s');
legend('t_o = 0.3s', 't_o = 1s');

Closed-loop : Simulink modelisation

Create the Simulink model of the more robust controller

% get num & den controller blocks, in dsp form
[transfert_dsp_vu_num, transfert_dsp_vu_den] = ...
    tfdata(data2.controller.implementation.transfert_dsp_vu, 'v');
[transfert_dsp_ru_num, transfert_dsp_ru_den] = ...
    tfdata(data2.controller.implementation.transfert_dsp_ru, 'v');
[transfert_dsp_yu_num, transfert_dsp_yu_den] = ...
    tfdata(data2.controller.implementation.transfert_dsp_yu, 'v');

% convert num & den into strings
transfert_dsp_vu_num = mat2str(transfert_dsp_vu_num, 10);
transfert_dsp_vu_den = mat2str(transfert_dsp_vu_den, 10);
transfert_dsp_ru_num = mat2str(transfert_dsp_ru_num, 10);
transfert_dsp_ru_den = mat2str(transfert_dsp_ru_den, 10);
transfert_dsp_yu_num = mat2str(transfert_dsp_yu_num, 10);
transfert_dsp_yu_den = mat2str(transfert_dsp_yu_den, 10);

% get plant poles, zeros and gain
[plant_z, plant_p, plant_k] = zpkdata( data2.model.plant, 'v' );

% get disturbance poles, zeros and gain
[disturbance_num, disturbance_den] = tfdata( data2.model.disturbance, 'v' );

% get noise poles, zeros and gain
[noise_num, noise_den] = tfdata( data2.model.noise, 'v' );

% get reference poles, zeros and gain
[reference_num, reference_den] = tfdata( data2.model.reference, 'v' );

% get plant delay
plant_delay = data2.model.plant.iodelay;

% convert data into strings
plant_z = mat2str( plant_z );
plant_p = mat2str( plant_p );
plant_k = mat2str( plant_k );
plant_delay = mat2str( plant_delay );
disturbance_num = mat2str( disturbance_num );
disturbance_den = mat2str( disturbance_den );
noise_num = mat2str( noise_num );
noise_den = mat2str( noise_den );
reference_num = mat2str( reference_num );
reference_den = mat2str( reference_den );

% get sampling period
sampling_period = mat2str(data2.controller.specification.sampling_period);

% close model if it's already open
try
    close_system(model_name, 1);
catch
end
% set pathfile for simulink model
path_model = cd;
path = [path_model,'/', model_name];

% make and save a copy of the template
cd(path_model);
load_system('ppr_sim_session');
save_system( 'ppr_sim_session', path );
close_system(model_name);
close_system('ppr_sim_session');

% load the Simulink model
load_system(model_name);

% update plant model parameters
set_param( [model_name,'/plant_pole_zero'], 'Poles',plant_p,...
        'Zeros',plant_z, 'Gain', '1');
set_param( [model_name,'/plant_gain'], 'Gain',plant_k);
set_param( [model_name,'/plant_delay'], 'DelayTime',plant_delay);

% update reference model parameters
set_param( [model_name,'/reference_predictor'], 'Numerator',reference_num,...
        'Denominator', reference_den);

% update disturbance model parameters
set_param( [model_name,'/disturbance_predictor'], 'Numerator',disturbance_num,...
        'Denominator', disturbance_den);

% update noise model parameters
 set_param( [model_name,'/noise_predictor'], 'Numerator',noise_num,...
        'Denominator', noise_den);

% update zoh parameters
 set_param( [model_name,'/v_zoh'], 'SampleTime',  sampling_period);
    set_param( [model_name,'/yr_zoh'], 'SampleTime',  sampling_period);
    set_param( [model_name,'/ym_zoh'], 'SampleTime',  sampling_period);

% update controller parameters
    set_param( [model_name,'/transfert_dsp_vu'], 'Numerator',transfert_dsp_vu_num,...
        'Denominator',transfert_dsp_vu_den, 'SampleTime', sampling_period);
    set_param( [model_name,'/transfert_dsp_ru'], 'Numerator',transfert_dsp_ru_num,...
        'Denominator',transfert_dsp_ru_den, 'SampleTime', sampling_period);
    set_param( [model_name,'/transfert_dsp_yu'], 'Numerator',transfert_dsp_yu_num,...
        'Denominator',transfert_dsp_yu_den, 'SampleTime', sampling_period);

% update model for reference predictor
set_param( [model_name,'/reference_impulse'],'PulseType', 'Sample based',...
         'TimeSource', 'Use simulation time','Amplitude', '1',...
         'Period', '500','PulseWidth', '1',...
         'PhaseDelay', '10','SampleTime', sampling_period );

% update model for disturbance predictor
set_param( [model_name,'/disturbance_impulse'],'PulseType', 'Sample based',...
         'TimeSource', 'Use simulation time','Amplitude', '1',...
         'Period', '500','PulseWidth', '1',...
         'PhaseDelay', '100','SampleTime', sampling_period );

% update model for noise predictor
set_param( [model_name,'/noise_impulse'],'PulseType', 'Sample based',...
         'TimeSource', 'Use simulation time','Amplitude', '1',...
         'Period', '500','PulseWidth', '1',...
         'PhaseDelay', '200','SampleTime', sampling_period );

% save updates and open model
save_system(gcs);
open_system(gcs);

Discussion

The plant includes a 0.5s time delay which is about the dominant time constant (1s). This delay complicates the design of the controller, because the delay makes large phase rotation at low frequencies that reduces the stability margins.

The exo-signals are the reference and disturbance, respectively described by a step and a ramp signal. The process is sampled at 0.1s.

This standard model (step reference, ramp disturbance, and delayed first order plant) is not easily controllable with a pid controller. Of course, a pid can stabilize this augmented plant and reduce the sensitivity to the exo-signals, but it can not reject the disturbance without a constant error. The 0.5s delay-time constant ratio yields to a low proportionnal gain to preserve stability and the final closed-loop presents poor dynamic performances either in tracking or regulating mode.

The 2DOF controller includes a simulation of the model without any approximation of the delay. The 8th order controller indicates that a simulation of the augmented plant is included in the controller structure : 5 orders for the plant delay (0.5/0.1), 1 for the first order plant and 2 for the ramp disturbance predictor. This makes 2DOF equivalent to the predictive command and explains its capacity to control delayed system when pid fails.

Controller tuning : 1st trial

From localisation of the open loop poles, we propose Tc=1/3s, To=1/3s and Tr = Tc. The resulting command placement projects the unique pole (-1) on the vertical horizon line at -3. A simple rule consists to move no more than 2 or 3 poles with Tc = kc/|pmin| where pmin is the slower open-loop pole and kc varies between 2 to 10. Tc controls the performance in tracking mode and the robustness.

With To = 1/3, we move the 3 open-loop poles (-1,0,0) at -3 location. The To horizon controls the performance of the disturbance rejection and the robustness. The higher To, the more time required to reject disturbance and noise.

The proposed methodology is :

  1. set Tc to meet the desired tracking performance;
  2. set To to have sufficient stability margins and disturbance rejection;
  3. set Tr to smooth command signal;

figure 1 shows the response of the standard model. Note the presence of the delay on the plant step response.

Figure 2 displays the 3 poles placement according to the selected horizon time.

Figure 3 shows the closed-loop responses. After a right click to normalize amplitude, we can analyze the behavior of the closed-loop for the reference and disturbance excitations.

The tracking of the reference is done after 3.7s. The delay is not compensated, but the overshoot on the command is merely 30% of its final value.

The disturbance signal is completely removed after 7s. Note that in real world applications, because the command deviates linearly, the error remains at zero until the saturation level is not reached.

Figure 4 displays the frequency responses of the L, T and S transfers for an evaluation of the robustness properties of the closed-loop controlled system. The corresponding stability margins are displayed in Matlab workspace. Even if the responses of figure 3 seem to be acceptable, the resulting margins are not sufficient for a robust controller.

Controller tuning : 2nd trial

If we set To = 1s, we just move 2 poles during the observer placement. Reduce the number of shifted poles always augment margins. Unfortunately, this leads to a performance degradation visible on disturbance rejection.

With To=1s, all margins are acceptable now. The tracking performance is not modified, only Tc affects it. But it's clear that the time to reject disturbance is about 10s now.

Conclusion

With the manipulation of the Tc and To parameters, we have shown that we can deal with the closed-loop performances/robustness dilemma.

These horizons are initialized from the open-loop poles locations and their actions on closed-loop performance are predictible.

An antiwindup implementation for the digital controller is automatically computed for futher precise simulations like non-linearity modelisation.

The recommended methodology linked to the pole placement strategy give the control designer the powerfull tools required to get high performance and robust digital regulators.

The more difficult in this design phase is probably to get a "valid" linear model of the plant !

Ouputs in command window

disp(' ');
disp('************** STANDARD MODELISATION *****************');

disp(' ');
disp('Plant ');
disp(' ');
plant_tf

disp(' ');
disp('Reference predictor');
disp(' ');
reference_tf

disp(' ');
disp('Disturbance predictor ');
disp(' ');
disturbance_tf

disp(' ');
disp('Noise predictor');
disp(' ');
noise_tf
disp(' ');

disp('*****************************************************');
disp('************** 1st POLES PLACEMENTS *****************');
disp('*****************************************************');
disp(' ');
disp('Command pole placement');
disp(' ');
disp(['open-loop poles: p_ol = ',...
    num2str(data1.controller.specification.command_placement.open_loop_pole')]);
disp(['horizon: h_c = ',...
    num2str(data1.controller.specification.command_placement.horizon)]);
disp(['closed-loop poles: p_cl = ',...
    num2str(data1.controller.specification.command_placement.closed_loop_pole')]);
disp(' placement infos: ');
disp(data1.controller.specification.command_placement.info);

disp(' ');
disp('Observer pole placement');
disp(' ');
disp(['open-loop poles: p_ol = ',...
    num2str(data1.controller.specification.observer_placement.open_loop_pole')]);
disp(['horizon: h_o = ',...
    num2str(data1.controller.specification.observer_placement.horizon)]);
disp(['closed-loop poles: p_cl = ',...
    num2str(data1.controller.specification.observer_placement.closed_loop_pole')]);
disp(' placement infos: ');
disp(data1.controller.specification.observer_placement.info);

disp(' ');
disp('Reference observer pole placement');
disp(' ');
disp(['open-loop poles: p_ol = ',...
    num2str(data1.controller.specification.reference_observer_placement.open_loop_pole')]);
disp(['horizon: h_r = ',...
    num2str(data1.controller.specification.reference_observer_placement.horizon)]);
disp(['closed-loop poles: p_cl = ',...
    num2str(data1.controller.specification.reference_observer_placement.closed_loop_pole')]);
disp(' placement infos: ');
disp(data1.controller.specification.reference_observer_placement.info);

disp(' ');
disp('Stability margins');
disp(' ');
disp(data1.controller.margin.info);

disp(' ');
disp('*****************************************************');
disp('************** 2nd POLES PLACEMENTS *****************');
disp('*****************************************************');
disp(' ');
disp('Command pole placement');
disp(' ');
disp(['open-loop poles: p_ol = ',...
    num2str(data2.controller.specification.command_placement.open_loop_pole')]);
disp(['horizon: h_c = ',...
    num2str(data2.controller.specification.command_placement.horizon)]);
disp(['closed-loop poles: p_cl = ',...
    num2str(data2.controller.specification.command_placement.closed_loop_pole')]);
disp(' placement infos: ');
disp(data2.controller.specification.command_placement.info);

disp(' ');
disp('Observer pole placement');
disp(' ');
disp(['open-loop poles: p_ol = ',...
    num2str(data2.controller.specification.observer_placement.open_loop_pole')]);
disp(['horizon: h_o = ',...
    num2str(data2.controller.specification.observer_placement.horizon)]);
disp(['closed-loop poles: p_cl = ',...
    num2str(data2.controller.specification.observer_placement.closed_loop_pole')]);
disp(' placement infos: ');
disp(data2.controller.specification.observer_placement.info);

disp(' ');
disp('Reference observer pole placement');
disp(' ');
disp(['open-loop poles: p_ol = ',...
    num2str(data2.controller.specification.reference_observer_placement.open_loop_pole')]);
disp(['horizon: h_r = ',...
    num2str(data2.controller.specification.reference_observer_placement.horizon)]);
disp(['closed-loop poles: p_cl = ',...
    num2str(data2.controller.specification.reference_observer_placement.closed_loop_pole')]);
disp(' placement infos: ');
disp(data2.controller.specification.reference_observer_placement.info);

disp(' ');
disp('Stability margins');
disp(' ');
disp(data2.controller.margin.info);

disp(' ');
disp('*****************************************************');
disp('********* CONTROLLER IMPLEMENTATION *****************');
disp('*****************************************************');
disp(' ');
% r->u transfer
disp('r->u transfer');
data2.controller.implementation.transfert_ru
disp(' ');
% y->u transfer
disp('y->u transfer ');
data2.controller.implementation.transfert_yu
disp(' ');
% v->u transfer
disp('v->u transfer ');
data2.controller.implementation.transfert_vu
 
************** STANDARD MODELISATION *****************
 
Plant 
 
 
Transfer function:
                1
exp(-0.5*s) * -----
              s + 1
 
 
Reference predictor
 
 
Transfer function:
1
-
s
 
 
Disturbance predictor 
 
 
Transfer function:
 1
---
s^2
 
 
Noise predictor
 
 
Transfer function:
1
 
 
*****************************************************
************** 1st POLES PLACEMENTS *****************
*****************************************************
 
Command pole placement
 
open-loop poles: p_ol = -1
horizon: h_c = 0.33333
closed-loop poles: p_cl = -3
 placement infos: 
    'horizon = 0.33333s'
    'damping_factor = 0.01'
    '0 zeros and 1 poles total.'
    '0 not commandables poles are unchanged.'
    '0 unstable poles have been symetrised.'
    '1 slow poles have been shifted , where 0 have been damped.'
    '0 fast poles have been damped.'
    '0 fast poles unchanged.'
 
Observer pole placement
 
open-loop poles: p_ol = 0  0 -1
horizon: h_o = 0.33333
closed-loop poles: p_cl = -3 -3 -3
 placement infos: 
    'horizon = 0.33333s'
    'damping_factor = 0.01'
    '0 zeros and 3 poles total.'
    '0 not commandables poles are unchanged.'
    '0 unstable poles have been symetrised.'
    '3 slow poles have been shifted , where 0 have been damped.'
    '0 fast poles have been damped.'
    '0 fast poles unchanged.'
 
Reference observer pole placement
 
open-loop poles: p_ol = 0
horizon: h_r = 0.33333
closed-loop poles: p_cl = -3
 placement infos: 
    'horizon = 0.33333s'
    'damping_factor = 0.01'
    '0 zeros and 1 poles total.'
    '0 not commandables poles are unchanged.'
    '0 unstable poles have been symetrised.'
    '1 slow poles have been shifted , where 0 have been damped.'
    '0 fast poles have been damped.'
    '0 fast poles unchanged.'
 
Stability margins
 
    ' gain margin   : +3.0 dB  at 0.588 Hz (min. 6 dB)'
    ' phase margin  : +23.5° at 0.328 Hz (min. 30°)'
    ' module margin : -10.8 dB at 0.514 Hz (min. -6 dB)'
    ' delay margin : +0.2 s at 0.328 Hz (min.  0.1 s)'
    ' static margin : 38 % at 0.41 Hz (min. 50 %)'
    ' dynamic margin : +0.1 s at 0.845 Hz (min. 0.1 s)'
 
*****************************************************
************** 2nd POLES PLACEMENTS *****************
*****************************************************
 
Command pole placement
 
open-loop poles: p_ol = -1
horizon: h_c = 0.33333
closed-loop poles: p_cl = -3
 placement infos: 
    'horizon = 0.33333s'
    'damping_factor = 0.01'
    '0 zeros and 1 poles total.'
    '0 not commandables poles are unchanged.'
    '0 unstable poles have been symetrised.'
    '1 slow poles have been shifted , where 0 have been damped.'
    '0 fast poles have been damped.'
    '0 fast poles unchanged.'
 
Observer pole placement
 
open-loop poles: p_ol = 0  0 -1
horizon: h_o = 1
closed-loop poles: p_cl = -1 -1 -1
 placement infos: 
    'horizon = 1s'
    'damping_factor = 0.01'
    '0 zeros and 3 poles total.'
    '0 not commandables poles are unchanged.'
    '0 unstable poles have been symetrised.'
    '2 slow poles have been shifted , where 0 have been damped.'
    '0 fast poles have been damped.'
    '1 fast poles unchanged.'
 
Reference observer pole placement
 
open-loop poles: p_ol = 0
horizon: h_r = 0.33333
closed-loop poles: p_cl = -3
 placement infos: 
    'horizon = 0.33333s'
    'damping_factor = 0.01'
    '0 zeros and 1 poles total.'
    '0 not commandables poles are unchanged.'
    '0 unstable poles have been symetrised.'
    '1 slow poles have been shifted , where 0 have been damped.'
    '0 fast poles have been damped.'
    '0 fast poles unchanged.'
 
Stability margins
 
    ' gain margin   : +7.1 dB  at 0.397 Hz (min. 6 dB)'
    ' phase margin  : +39.5° at 0.157 Hz (min. 30°)'
    ' module margin : -5.6 dB at 0.331 Hz (min. -6 dB)'
    ' delay margin : +0.7 s at 0.157 Hz (min.  0.1 s)'
    ' static margin : 66 % at 0.123 Hz (min. 50 %)'
    ' dynamic margin : +0.5 s at 0.361 Hz (min. 0.1 s)'
 
*****************************************************
********* CONTROLLER IMPLEMENTATION *****************
*****************************************************
 
r->u transfer
 
Transfer function from input "yr" to output "u1":
  0.7105
----------
z - 0.7408
 
Sampling time: 0.1
 
y->u transfer 
 
Transfer function from input "ym" to output "u2":
   0.7422 z^2 - 1.389 z + 0.649
----------------------------------
z^3 - 2.714 z^2 + 2.456 z - 0.7406
 
Sampling time: 0.1
 
v->u transfer 
 
Transfer function from input "v" to output "u3":
 
0.1657 z^7 - 0.2998 z^6 + 0.1356 z^5 + 7.122e-014 z^4 + 6.442e          
                                                                        
                         -014 z^3 + 5.826e-014 z^2 - 0.07063 z + 0.06826
                                                                        
------------------------------------------------------------------------
                z^8 - 2.714 z^7 + 2.456 z^6 - 0.7406 z^5
 
Sampling time: 0.1

Contact us