Variables interdependency terminates Dymola simulation and produces nonlinear system of equations - modelica

I’m developing a model to describe the behavior of a two-pipe network. The network is connected to a tank where heat is injected or extracted from the system depending on external mass flow rates. The mass flow rates for both heating and cooling are arbitrarily assumed to vary over time.
The initial value of PipeTemp is associated with the parameter StartTemp. However, at different time points PipeTemp is computed from a max function.
The problem is that because the variable PipeTemp depends on other time varying variables that are computed using the value of PipeTemp, Dymola terminates the simulation and produces the following error: Failed to solve nonlinear system using Newton solver.
This simple model can be easily simulated in Excel because it’s capable of handling interdependency between cell variables. What could be the workaround for this model in Dymola in order to avoid the nonlinear system of equations?
model FullyMixedTemperature
parameter Real StartTemp = 20; //Assumed mixed temperature in the pipes
parameter Real dTpipe = 10; //Temperature difference between the two pipes
parameter Real TankVol = 150; //Total volume
Real DecreasingTemp; //Mixed temperature in the pipe due to additional cooling mass flow rate
Real IncreasingTemp; //Mixed temperature in the pipe due to additional heating mass flow rate
Real PipeTemp(start=StartTemp); //Mixed temperature in the pipe
Real CoolFlowRate; //Additional cooling flow rate from external sources
Real HeatFlowRate; //Additional heating flow rate from external sources
equation
CoolFlowRate=0.5*time;
HeatFlowRate=2*time;
PipeTemp = max(DecreasingTemp, IncreasingTemp);
DecreasingTemp= PipeTemp-(dTpipe*CoolFlowRate/TankVol);
IncreasingTemp= PipeTemp+(dTpipe*HeatFlowRate/TankVol);
end FullyMixedTemperature;

The model as written doesn't make sense.
Since dTPipe, HeatFlowRate, CoolFlowRate and TankVol are all non-negative IncreasingTemp is greater than DecreasingTemp, and thus the equation collapses to:
PipeTemp=PipeTemp+dTPipe*HeatFlowRate/TankVol;
and you cannot compute PipeTemp from that.
The closest variant would be that in each sampling point we compute a new PipeTemp, and that would be:
model FullyMixedTemperature
parameter Real StartTemp = 20; //Assumed mixed temperature in the pipes
parameter Real dTpipe = 10; //Temperature difference between the two pipes
parameter Real TankVol = 150; //Total volume
Real DecreasingTemp; //Mixed temperature in the pipe due to additional cooling mass flow rate
Real IncreasingTemp; //Mixed temperature in the pipe due to additional heating mass flow rate
Real PipeTemp(start=StartTemp); //Mixed temperature in the pipe
Real CoolFlowRate; //Additional cooling flow rate from external sources
Real HeatFlowRate; //Additional heating flow rate from external sources
equation
CoolFlowRate=0.5*time;
HeatFlowRate=2*time;
when sample(1,1) then
PipeTemp = max(pre(DecreasingTemp), pre(IncreasingTemp));
end when;
DecreasingTemp= PipeTemp-(dTpipe*CoolFlowRate/TankVol);
IncreasingTemp= PipeTemp+(dTpipe*HeatFlowRate/TankVol);
end FullyMixedTemperature;
But to me it seems more likely you want a differential equation where both flows contribute:
model FullyMixedTemperature
parameter Real StartTemp = 20; //Assumed mixed temperature in the pipes
parameter Real dTpipe = 10; //Temperature difference between the two pipes
parameter Real TankVol = 150; //Total volume
Real PipeTemp(start=StartTemp); //Mixed temperature in the pipe
Real CoolFlowRate; //Additional cooling flow rate from external sources
Real HeatFlowRate; //Additional heating flow rate from external sources
equation
CoolFlowRate=0.5*time;
HeatFlowRate=2*time;
der(PipeTemp) =(dTpipe*HeatFlowRate/TankVol)-(dTpipe*CoolFlowRate/TankVol);
end FullyMixedTemperature;

Related

matlab simulink convert PID continuous to discrete

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.

Energy from Power

I am working in MATLAB and I have 2 arrays. Current and Voltage flowing in a capacitance when I connect and disconnect it from the voltage. Of course I have a time_stamp vector in which there are all the samples of time at which I made the measurements.
I want to plot the power and energy associated to those arrays.
For the power I just need to do:
z1 = plot(time_stamp_ms,measured_voltage.*current,'-b','LineWidth',1);
Right?
Instead, how can I do to plot the energy?
Thanks for your time.
I think your power looks right. For energy, it's just power multiplied by time right so:
dt = diff(time_stamp_ms);
power = measured_voltage.*current;
energy = dt.*power(2:end);
well this gives the energy used between each time step. If you wanted the cumulative energy then:
energy_cum = cumsum(energy)

Scipy periodogram terminology confusion

I am confused about the terminology used in scipy.signal.periodogram, namely:
scaling : { 'density', 'spectrum' }, optional
Selects between computing the power spectral density ('density')
where Pxx has units of V*2/Hz if x is measured in V and computing
the power spectrum ('spectrum') where Pxx has units of V*2 if x is
measured in V. Defaults to 'density'
(see: http://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.periodogram.html)
1) a few tests show that result for option 'density' is dependent on signal and window length and sampling frequency (grows when signal length increases). How come? I would say that it is exactly density that should be not dependent on these things. If I take a longer signal I should just get more accurate estimation, not different result. Not to mention that dependence on window length is also very surprising.
Result diverges in the limit of infinite signal, which could be a feature of energy, but not power. Shouldn't the periodogram converge to real theoretical PSD when length increases? If, so, am I supposed to perform another normalisation outside of the signal.periodogram method?
2) to the contrary I see that alternative option 'spectrum' gives what I would previously call Power Spectrum Density, that is, it gives a resuls independent on window segment and window length and consistent with theoretical calculation. For instance for Asin(2PIft) a two sided solution yields two peaks at -f and f, each of height 0.25*A^2.
There is a lot of literature on this subject, but I get an impression that also there is a lot of incompatibile terminology, so I will be thankful for any clarification. The straightforward question is how to interpret these options and their units. (I am used to seeing V^2/Hz which are labeled "Power Spectrum Density").
Let's take a real array called data, of length N, and with sampling frequency fs. Let's call the time bin dt=1/fs, and T = N * dt. In frequency domain, the frequency bin df = 1/T = fs/N.
The power spectrum PS (scaling='spectrum' in scipy.periodogram) is calculated as follow:
import numpy as np
import scipy.fft as fft
dft = fft.fft(data)
PS = np.abs(dft)**2 / N ** 2
It has the units of V^2. It can be understood as follow. By analogy to the continuous Fourier transform, the energy E of the signal is:
E := np.sum(data**2) * dt = 1/N * np.sum(np.abs(dft)**2) * dt
(by Parseval's theorem). The power P of the signal is the total energy E divided by the duration of the signal T:
P := E/T = 1/N**2 * np.sum(np.abs(dft)**2)
The power P only depends on the Discrete Fourier Transform (DFT) and the number of samples N. Not directly on the sampling frequency fs or signal duration T. And the power per frequency channel, i.e., power spectrum SP, is thus given by the formula above:
PS = np.abs(dft)**2 / N ** 2
For the power spectrum density PSD (scaling='density' in scipy.periodogram), one needs to divide the PS by the frequency bin of the DFT, df:
PSD := PS/df = PS * N * dt = PS * N / fs
and thus:
PSD = np.abs(dft)**2 / N * dt
This has the units of V^2/Hz = V^2 * s, and now depends on the sampling frequency. That way, integrating the PSD over the frequency range gives the same result as summing the individual values of the PS.
This should explain the relations that you see when changing the window, sampling frequency, duration.
scipy.signal.peridogram uses the scipy.signal.welch function with 0 overlap. Therefore, the scaling is similar to the one provided by the welch function, density or spectrum.
In case of the density scaling, the amplitude will vary with window length, as the longer the window the higher the frequency resolution e.g. the \Delta_f is smaller. Since the estimated density is the average one, the smaller the \Delta_f the less zero energy is considered in the averaging.
As you have mentioned spectrum scaling is an integration of the energy density over the spectrum to produce the energy. Therefore, the integration over zero values does not affect the final value.
Fourier transform actually requires finite energy in an infinite duration of time series (like a decay). So, If you just make your time series sample longer by "duplicating", the energy will be infinite with an infinite duration.
My main confusion was on the "spectrum" option for scipy.signal.periodogram, which seems to create a constant energy spectrum even when the time series become longer.
Normally, 0.5*A^2=S(f)*delta_f, where S(f) is the power density spectrum. S(f)*delta_f, representing energy is constant if A is constant. But when using a longer duration of time series, delta_f (i.e. incremental frequency) is reduced accordingly, based on FFT procedure. For example, 100s time series will lead to a delta_f=0.01Hz, while 1000s time series will have a delta_f=0.001Hz. S(f) representing density will accordingly change.

Freqeuncy content of a signal inside a simulink model using embedded matlab function block?

I am trying to acquire the frequency information about a displacement signal(e.g., Vx) while the simulation is running.
My idea was to make use of the fft command supported by Embedded Matlab Function block.
The first thing which i performed was to store the values of displacement signal 'Vx' in a buffer of length 'L'.
The second thing is to compute the fft of those values stored in the buffer and calculate the index value corresponding to the maximum amplitude.
The third thing is to acquire the frequency from index value, sampling frequency and length of the buffer.
Embedded Matlab code is the following:-
Function[freq_Vx,buffero_Vx] = fcn(Vx,bufferi_Vx)
% This block supports the Embedded MATLAB subset.
% See the help menu for details.
buffo_Vx = [Vx;buffi_Vx(1:end-1)]; % buffer which stores the values of signal 'Vx'
Fs = 2000;
nfft = 2^nextpow2(length(buffo_Vx));
[max_Vx,index_Vx] = max(abs(fft(buffo_Vx,nfft)));
freq_Vx = index_Vx*Fs/length(buffo_Vx);
end
Is this the right way of acquiring the frequency content of a signal while the simulation is running?
I believe your approach to processing the data "real time" in the model is reasonable, however I believe the index_Vx*Fs/length(buffo_Vx) is not going to give the desired results and buffo_Vx = [Vx;buffi_Vx(1:end-1)]; will likely need to be buffo_Vx = [Vx;bufferi_Vx(1:end-1)];` Checkout this link for your frequency conversion.
For diagnostic purposes, check out the Simulink Extras -> Additional Sinks blocks on the Simulink library browser.
The Spectral densities should be helpful.

i am trying to write a code to cross correlate a transmitted signal with a received signal to determine the number of samples delay

Cross correlation is to be used to measure distance to an aircraft by transmitting a
known wide-band signal and correlating the transmitted signal with incoming signals
received via the radar reception dish
The transmitted signal x(n) is of length N=512 while the received signal y(n) is of length N=2048.
y(n)=kx(n-d)+w(n); where 'kx(n-d)' is x(n) delayed by d samples and attenuated by a factor k, and w(n) is reception noise.
i am trying to write a MATLAB program to cross correlate x(n) with the y(n) to determine the value of d, the number of samples delay.
And also Determine a suitable sampling frequency if the distance to the aircraft is to be
determined within 50 km to an accuracy of 50 m, given that the transmitted
and received data is travelling at the speed of light.
The easiest way to do this is with the "xcorr" function. This is part of the Signal Processing toolbox for matlab, but should be available for GNU Octave here. I have not checked if the octave script is completely MATLAB compatible.
You can use the xcorr function as:
[correlation,lags] = xcorr(x,y);
The lag value can be found using
delay = lags(find(correlation==max(correlation)))
At the speed of light, the signal will be travelling at 3 x 10^8 m/s, so to have a resolution of 50m, you should be sampling at at least (3e8/50m) = 6MHz. At this sampling rate, each lag will be 1/6000000 second. If you multiply your delay by this value, you get your total time intervel between transmission and reception of the signal. Multiply this time intervel by the speed of light to get your distance.
You can use generalized Cross correlation -Phase transform GCC PHAT
The following is the MATLAB code for it
function time=GCCPHAT_testmode(b1,b2)
b1f=fft(b1);
b2f=fft(b2);
b2fc=conj(b2f);
neuma=(b1f).*(b2fc);
deno=abs((b1f).*(b2fc));
GPHAT=neuma./deno;
GPHATi=ifft(GPHAT);
[maxval ind]= max(GPHATi);
samp=ind
end
we can ignore the 'find' function in matlab, the command could be changed to
delay = lags(correlation==max(correlation))
'xcorr' suits for vectors with long length;
'gcc' prefer frame by frame.
Aj463's comment above is good, indeed GCC-PHAT is better than unweighted correlation for estimating delay of wide-band signals.
I would suggest a small improvement to the code posted above: to add a small value epsilon to the denominator, epsilon -> 0, in order to avoid eventual division by zero.
Thus, I would change the line
deno=abs((b1f).*(b2fc));
to
deno=abs((b1f).*(b2fc)) + epsilon;