MATLAB: Effects of Zero Order Hold in Simulink linearization

continuous_to_discretedigital_controller_fir_continuos_plantdiscrete_to_continuoussimulinkSimulink Control Designsimulink_model_linearizerzero_order_hold_distortion

Hello, I am having some difficulties in finding out how to implement in Simulink a discrete time controller for an analog plant in a way that the frequency response of the "equivalent continuous-time controller" seen by the plant reflects the distortion produced by the zero-order-hold digital implementation.
From the theory it is known that if a digital controller Kd is implemented through a sample and hold mechanism, the "equivalent continuous-time controller" seen by the plant will have a distortion term equal to D(s) = (1-exp(-s*Ts)) / (s*Ts), where Ts is the sampling time.
To make my question clearer, consider the attached Simulink model ContVsDiscreteTime.slx
It has a continuous time noise source and a discrete-time LTI system (I will call it the controller) with transfer function K(z)=(631.3 z -578)/(z-0.3522) and sampling period Ts = 0.1 s. The transformations from the continuous-time source signal to the discrete-time controller input and from the discrete-time controller output back to continuous time at the outport are performed using two Rate Transition blocks as illustrated in the Fault-Tolerant Fuel Control System demo sldemo_fuelsys provided in the Simulink documentation.
To anayze the system, I use the Simulink Model Linearizer app. First I compute the Bode plot of the gain from B to C: as expected the Bode plot obtained matches the frequency response of the discrete-time block. Then I compute the Bode plot of the gain from A to D. My expectation is to obtain a continuous-time linear system whose frequency response is essentially equal to that of the discrete-time system modified by the distortion term D(s), which affects especially the phase. However, as shown in the attached screen shot, the Simulink Model Linearizer returns the same discrete-time system of the previous step, as if the conversions from and to continuous time were not present (the values stored in the To Workspace blocks clearly show.that the signals in A and D are not discrete-time with sampling time Ts)
This is particularly misleading when it's part of a feedback loop, because it characterizes closed-loop performance as if the deterioration D(s) due to the digital implementation was not present.
How should I modify the Simulink diagram to have the distortion term included in the analysis? Obviously, I can always explicitly add the block D(s) as an LTI system after converting back the controller output to continuous time. However, I have the feeling that it might not be the cleanest way to do it, as it is difficult to imagine that Simulink would overlook the necessity of directly implementing such an essential part of the conversion.
Thank you for any answers or comments.
Below are two JPG files with the block diagram and the relevant settings.

Best Answer

"My expectation is to obtain a continuous-time linear system whose frequency response is essentially equal to that of the discrete-time system modified by the distortion term D(s), which affects especially the phase."
The path from A to D contains a discrete element. AFAIK, there is no way to tell the linearizer to convert that to a continuous block. For sure, the default (and maybe only) behavior is to go the other way, i.e., in a sampled-data system all continuous poritions of the model are converted to discrete time in a prescribed manner, which is the textbook way of analyzing sampled-data systems. Here is a simple example to illustrate some concepts.
Consider the following block diagram.
The three transfer functions are:
Ts = 0.1;
G1 = tf([1 .5],[1 -.5],Ts);
G2 = tf(1,[1 1]);
G3 = tf(1,[1 2]);
First, we get the io points for the model.
io = getlinio('linexamp')
7x1 vector of Linearization IOs:
--------------------------
1. Linearization input perturbation located at the following signal:
- Block: linexamp/Gain
- Port: 1
- Signal Name: u2
2. Linearization input perturbation located at the following signal:
- Block: linexamp/Ground
- Port: 1
- Signal Name: u1
3. Linearization output measurement located at the following signal:
- Block: linexamp/sys1
- Port: 1
- Signal Name: y1
4. Linearization output measurement located at the following signal:
- Block: linexamp/sys2
- Port: 1
- Signal Name: y2
5. Linearization output measurement located at the following signal:
- Block: linexamp/sys3
- Port: 1
- Signal Name: y3
6. Linearization output measurement located at the following signal:
- Block: linexamp/sys4
- Port: 1
- Signal Name: y4
7. Linearization output measurement located at the following signal:
- Block: linexamp/sys5
- Port: 1
- Signal Name: y5
Linearize the model from input u1 to all outputs using all default options.
sys = linearize('linexamp',io(2:end));
The transfer functions from u1 to y1,y2,y3, and from u1 to y4 and y5 are:
tf(sys(1:3,1))
tf(sys(4:5,1))
ans =
From input "u1" to output...
z + 0.5
y1: -------
z - 0.5
0.09516 z + 0.04758
y2: ----------------------
z^2 - 1.405 z + 0.4524
0.004528 z^2 + 0.006361 z + 0.002049
y3: ------------------------------------
z^3 - 2.224 z^2 + 1.603 z - 0.3704
Sample time: 0.1 seconds
Discrete-time transfer function.
ans =
From input "u1" to output...
0.09516 z + 0.04758
y4: ----------------------
z^2 - 1.405 z + 0.4524
0.004528 z^2 + 0.006361 z + 0.002049
y5: ------------------------------------
z^3 - 2.224 z^2 + 1.603 z - 0.3704
Sample time: 0.1 seconds
Discrete-time transfer function.
We see that the tf Y1/U1 = G1, as expected. Furthermore, Y2/U1 = Y4/U1 and Y3/U1 = Y5/U1. These results show that that the linearizer does place a ZOH (default option) in front of G2, even though it is not exmplicitly included in the diagram. Also, these tf's are what we expect them to be:
Y2overU1 = G1*c2d(G2,Ts,'zoh')
Y3overU1 = G1*c2d(G3*G2,Ts,'zoh')
Y2overU1 =
0.09516 z + 0.04758
----------------------
z^2 - 1.405 z + 0.4524
Sample time: 0.1 seconds
Discrete-time transfer function.
Y3overU1 =
0.004528 z^2 + 0.006361 z + 0.002049
------------------------------------
z^3 - 2.224 z^2 + 1.603 z - 0.3704
Sample time: 0.1 seconds
Discrete-time transfer function.
Now look at what happens when we include the input u2 in the linearization. As expected the tf's from u1 don't change, but what about Y3/U2?
sys = linearize('linexamp',io);
Y2andY3overU1 = tf(sys(2:3,2))
Y3overU2 = tf(sys(3,1))
Y2andY3overU1 =
From input "u1" to output...
0.09516 z + 0.04758
y2: ----------------------
z^2 - 1.405 z + 0.4524
0.004528 z^2 + 0.006361 z + 0.002049
y3: ------------------------------------
z^3 - 2.224 z^2 + 1.603 z - 0.3704
Sample time: 0.1 seconds
Discrete-time transfer function.
Y3overU2 =
From input "u2" to output "y3":
0.09063
----------
z - 0.8187
Sample time: 0.1 seconds
Discrete-time transfer function.
The tf Y3/U2 is what we would expect if the the perturbuation input u2 is sampled and followed by a ZOH
c2d(G3,Ts,'zoh')
ans =
0.09063
----------
z - 0.8187
Sample time: 0.1 seconds
Discrete-time transfer function.
In this case, the system included a discrete element, G1, that it could not remove using the default linearization options (see response below from Marco for other options). So the linearization results in a discrete model of the sampled-data system. It (apparently) does this by isoloating the continuous portions of the model, discretizes assuming a ZOH on the inputs to that portion (unless specified otherwise) and then connects to the discrete part. If there are multiple sample times in the model, I'm pretty sure the default behavior is to use d2d to get all discrete blocks up to the largest sample time.
Let's look at what happens when we only specify only the input u2 and only the output y3:
sys = linearize('linexamp',io([1 5]))
sys =
A =
Internal
Internal -2
B =
u2
Internal 1
C =
Internal
y3 1
D =
u2
y3 0
Continuous-time state-space model.
We see that sys is now a continous model, with only one state, and the tf Y3/U2 is G2:
tf(sys)
ans =
From input "u2" to output "y3":
1
-----
s + 2
Continuous-time transfer function.
The reason for this behavior is that the default option for linearization is 'BlockReduction' = 'on'. With this setting, the linearizer first eliminates all blocks that are not in the linearizzation path(s), which in this case was specified by io([1 5]). If you turn BlockReduction off, you get back the discrete result (and you'll see that sys includes all of the states in the system):
sys=linearize('linexamp',io([1 5]),linearizeOptions('BlockReduction','off'));
tf(sys)
ans =
From input "u2" to output "y3":
0.09063
----------
z - 0.8187
Sample time: 0.1 seconds
Discrete-time transfer function.
More details and discussion at:
doc linearize
doc linearizeOptions