I have a continuous S-Function that solves the derivatives for various state properties within a ICE cylinder. As such, the output of the function is set to output the integral of those derivatives for each time step which is a 7 element vector (1 for each of the properties being calculated)
block.OutputPort(1).Data = block.ContStates.Data;
At some point in the cycle I would like to change the value of this output to an explicit value (i.e. not the integral of the derivative) such as below (in this case the explicit value being x):
block.OutputPort(1).Data = block.ContStates.Data;
block.OutputPort(1).Data(3) = x;
I'm using a if statement to switch into this alternative output. Through debugging, I think I've verified that Simulink is entering this block of code at the right point - however the output of the S-Function remains as the integral of the derivatives which gives me a non-finite error.
Any help or suggestions that would allow me to explicitly set the output of a continuous S-Function would be much appreciated.
Related
I would like to drive a transfer function block with a pulse signal in Simulink. This can for example be done with a Pulse Generator block. The only thing I am missing is an external input where I can specify the pulse width or duty cycle of the signal. Signal parameters can only be entered through the Pulse Generator's Block parameters. Is there a way to go around this?
Simulink model 1
Pulse generator block parameters
Alternatively, I tried to use a Matlab function block inside Simulink with the Matlab function "square", which takes a few constants as well as the current simulation time as inputs. I used the following function:
% Output data value for specific time instant
function DataValue = pulsegen(PulseWidth,Frequency,TimeInput)
PulseDutyCycle = PulseWidth*Frequency*100;
% Generate signal
t = 0:0.0001:60;
y = square(2*pi*Frequency*t,PulseDutyCycle);
y = max(y,0); % Set nonzero elements to zero
DataValue = y(find(t==TimeInput)); % find data value at specific time instance
end
And the following model:
Simulink model 2
But with no luck either. I get the following error message:
Simulink error messages
Which does not makes sense to me. When I test this function stand-alone in Matlab, the function output is just a 1x1 constant value, not an array. Does anyone know a solution to this?
I need to use resample() function to take a variable argument of Q downsampling factor in Simulink. Basically a Simulink fcn block containing this code:
function y = resample(data,Q)
y=resample(data,1000,Q);
On desktop simulation I can get variable Q to work as argument by specifying it as input to a MATLAB interpreted function, but since I need to generate a C code,my only option is to use the fcn block, obviously it won't compile due to above limitation.
error: the downsample factor Q must be constant
I understand this is a documented limitation of the resample function:
resample: The upsampling and downsampling factors must be specified as
constants. Expressions or variables are allowed if their values do not
change.
Any workaround or different approach to address this? Perhaps other block which is capable of doing the same job? ofc it has to be compatible with Simulink coder.
Thanks!
resample function would need to design filters and decide output sizes based on the sample factors. After code generation this cannot be changed, which is why this function needs the sampling factors to be constant.
But if the different downsampling factor values you need to support are limited you could use conditional branching with calls to resample in each branch with constant values. For example,
% Declare out as a var-size with max decided by the minimum downsampling factor
% Assuming data is [1000, 1]
coder.varsize('out', [500 1]);
out = zeros(500,1);
if Q == 2
out = resample(data,1000,2);
elseif Q == 4
out = resample(data,1000,4);
elseif ...
...
end
You also need to deal with variable sized data "out" in the rest of your MATLAB code and Simulink model if this is an output variable from MATLAB Function block.
How do I convert a continuous PID (in s form) to discrete form (in z form)? Let's say I have the tuned gain of the PID (in s form) :
Kp=2266.76751174231;
Ki=3461.10112077832;
Kd=360.96017761997;
Now, I would like to apply the same gain to the PID in z form. However I couldn't get the same responses in discrete compared to continuous. Below is the z block diagram:
And this is the responses in z form:
Block diagram in s form:
this is the responses in continuous form:
Any suggestion what's my mistake?
thanks!
I tried running the model in continuous time with the PID parameters that you specified and the default N=100 for the derivative gain filter coefficient. I used ode45 solver with default parameters, but I limited the maximum time step to 0.01. Unfortunately, I found the system to be unstable.
I tuned the gains using a heuristic manual approach (I believe that the values of the gains are not relevant from the perspective of answering your question). I settled on the following set of gains:
Kp = 6
Ki = 12
Kd = 1
The models that I used are shown below. As you can see from the Simulink diagram, I constructed two models. They are (almost) equivalent. However, the first model (the topmost model) uses the standard Simulink PID(s) block and the second one (the lowermost model) uses a custom transfer function block instead of the Simulink PID(s) block. The custom transfer function should produce the output that is equivalent to the Simulink PID(s) block, as they only differ in their implementation. The second model was created to assist in the explanation of the method that I used for the conversion of the models from z-domain to s-domain. I also used it as a "sanity check" to ensure that the implementation of the Simulink PID is not different from the way I thought it was implemented.
The PID parameters for the continuous time simulation.
The parameters of the transfer function block associated with the plant.
The result of the continuous time simulation.
In order to convert the plant model from s-domain to z-domain I used the Tustin transformation. I used the symbolic toolbox in MATLAB to perform the conversion. This is my preferred approach, as it enables for a more general solution in comparison with the in-built toolboxes for control systems. I also constructed the PID function in s-domain and converted it to z-domain using the same approach. The script that does the conversion is shown below. Please note that I used 0.1 as the simulation time step for the discrete time simulation. This value should also be set in the solver configuration in Simulink.
The following variables are important from the perspective of the construction of the Simulink model in z-domain:
NPlantCoeffs - contains the coefficients of the numerator of the transfer function associated with the plant in z-domain. For a reference, the following value was obtained: [45 135 135 45].
DPlantCoeffs- contains the coefficients of the denominator of the transfer function associated with the plant in z-domain. For a reference, the following value was obtained: [406502 -1104494 1035506 -333498].
NPIDFiltCoeffs - contains the coefficients of the numerator of the transfer function associated with the PID in z-domain. For a reference, the following value was obtained: [-349 515 -196].
DPIDFiltCoeffs - contains the coefficients of the denominator of the transfer function associated with the PID in z-domain. For a reference, the following value was obtained: [-15 5 10].
Tval - the value of the time step. For a reference, the following value was used: 0.1.
The script for the definition of the parameters for the discrete-time simulation.
% Initialisation.
clear;
clc;
% Define the symbolic variables of interest.
% T is the time step for discrete simulation.
syms s z T;
% Define the controller parameters.
% The parameters should correspond to the parameters obtained from tuning
% the continuous system.
Kp = 6;
Ki = 12;
Kd = 1;
N = 100;
% Define the plant and the controller in the s-domain.
TFPlant = 0.09/(0.09*s^3 + 0.18*s^2 + s + 1.004);
TFPIDFilt = Kp + Ki/s + Kd*N/(1 + N/s);
% Obtain the numerator and the denominator of the transfer functions in the
% s-domain.
[NPIDCont, DPIDCont] = numden(collect(TFPIDFilt));
NPIDCont = sym2poly(NPIDCont);
DPIDCont = sym2poly(DPIDCont);
% Convert to z-domain using Tustin substitution (referred to as Trapezoidal
% method in Simulink block PID(s)).
TFPlant = collect(subs(TFPlant, s, (2/T)*(z - 1)/(z + 1)));
TFPIDFilt = collect(subs(TFPIDFilt, s, (2/T)*(z - 1)/(z + 1)));
% Define time step for discrete simulation.
Tval = 0.1;
% Perform substitution for the time step T.
TFPlant = subs(TFPlant, T, Tval);
TFPIDFilt = subs(TFPIDFilt, T, Tval);
% Decompose into the numerator and denominator.
[NPlant, DPlant] = numden(TFPlant);
[NPIDFilt, DPIDFilt] = numden(TFPIDFilt);
% Obtain the polynomial coefficients associated with the numerator and
% denominator.
NPlantCoeffs = sym2poly(NPlant);
DPlantCoeffs = sym2poly(DPlant);
NPIDFiltCoeffs = sym2poly(NPIDFilt);
DPIDFiltCoeffs = sym2poly(DPIDFilt);
For the discrete time simulation, it is important to select the fixed time step solver and set the time step to the value that is equivalent to the value that was used for the conversion of the plant model from s-domain to z-domain. As you can see below, I used the z-domain version of the continuous time PID controller block for the discrete time simulation. Given the calculated plant parameters for the discrete-time simulation, the result of the simulation is very close to the result of the simulation of the continuous time system.
Solver configuration for the discrete time simulation.
Models for the discrete time simulation.
Discrete time plant model parameters.
Parametrisation of the Simulink PID(s) block for discrete time simulation.
The result of the discrete time simulation.
To answer your original question, I am not sure where your mistake is exactly. However, I provide several assumptions below:
There is something strange with the PID gains that you obtained for continuous time simulation. The system that was specified in your screenshot is unstable when these gains are used, unless I misread the plant parameters in the screenshot.
I am not sure what process you followed for the conversion of the plant model from s-domain to z-domain. The conversion process that I presented in the answer should provide a valid methodology for the conversion. It is also important to use a fixed time step solver for the discrete time domain simulation. Moreover, it is important to use the time step that is equivalent to the time step used for the conversion of your plant model from s-domain to z-domain.
How can I introduce a continuos signal to a MATLAB Function block so I can get a continuos output.
My MATLAB Function block will be this:
function y = fcn(u)
y = 2*exp(-u);
So I can get a negative exponential, this because I need a control voltage source with a negative exponential signal. I need to introduce a controlled voltage source a exponential signal, is there other way?
Thanks
First of all, you don't need a MATLAB function to do that: take your input signal, multiply it by -1 with a Gain block, then use a Math Function block set to exp, and finally another Gain block to multiply it by 2.
Second, your input signal can be whatever you want. For example, you can use a Sine Wave block, or choose whatever block you want from the Sources library. If you leave the Sample Time parameter to 0, you will have a "continuous" signal (in the Simulink sense of the word), see Specify Sample Time in the documentation for more details. You can also use your own data from the MATLAB workspace using a From Workspace block.
I have an ODE model in Matlab coded as a function. I integrate the ODE's over time using ode15s. After the solver has finished, I calculate algebraically, a new variable that's a fraction of the sum of the other variables output by the model.
For example:
dA/dt = xxxxx
dB/dt = xxxxx
dC/dt = xxxxx
this gets integrated and returns an array of columns for dA,dB,dC. From the output I calculate:
model_result = A/(A+B+C).
for the whole time course), and plot this vector of values vs time.
However, I also need to perform sensitivity analysis on the model, for which I've used the modified ODE15s on the Mathworks repository. I need to be able to set "model_result" above as the objective function for the sensitivity calculations.
I attempted to calculate model_result inside the function, and have it returned as another variable, but obviously this doesn't work as the integrator returns the integrated value, rather than the algebraically calculated value.
Is it possible to have algebraic values returned by an ODE solver in Matlab?
If not, does anybody have any idea how to perform this kind of sensitivity analysis?
thanks for any help. I'm quite new to modelling so apologies if I'm using all the wrong terms!