I want to model a simple elastic pendulum in Modelica;
But i did not get a proper result - could anyone help?
Mass, nominal pendulum length and gravitational constant are taken to be one.
model SP
parameter Real k = 1; "spring constant"
Real y1(start=1), y2(start=0),y3,y4;
Real ld;
equation
ld= k* (sqrt(y1^2+y2^2)-1)/sqrt(y1^2+y2^2);
der(y1) = y3;
der(y2) = y4;
der(y3) = -y1*ld;
der(y4)= -y2*ld;
end SP;
First there is a small syntax error. Move the comma after the k = 1 to after "spring constant":
parameter Real k = 1 "spring constant";
Second, give y3 and y4 initial conditions. Either by using start or initial equation. Here's a plot of the solution for ld in Wolfram SystemModeler:
Related
Task:
I have a variable y1 whose derivative is driven by some law
e.g. y1 = sin(time)
and for which I set the starting value
e.g. y1 = 3.0
I have a second variable y2
that is defined by y2 = y1 + offset
Now, I want this offset to be a Parameter (thus constant during the simulation) and to be evaluated based on starting/initial values of y1 and y2
like offset = y2.start - y1.start
Code
Conceptually I want to achieve:
model SetParametersFromInitialValues
Real y1(start = 3.0, fixed = true);
Real y2(start = 3.0, fixed = true);
parameter Real offset(fixed = false);
initial equation
offset = y2.start - y1.start;
equation
der(y1) = sin(time);
y2 = y1 + offset;
end SetParametersFromInitialValues;
and I thought it could work since start should be a parameter attribute of the built-in type Real, but it is not usable in this way.
I thought also of using a discrete instead of parameter, but I don't know if this will affect the performance.
However, even in this case, I get some dangerous warning (because of an algebraic loop), namely "It was not possible to check the given initialization system for consistency symbolically, because the relevant equations are part of an algebraic loop. This is not supported yet."
model SetParametersFromInitialValues
Real y1(start = 3.0, fixed = true);
discrete Real offset(fixed = false);
Real y2(start = 5.0, fixed = true);
equation
when initial() then
offset = y2 - y1;
end when;
der(y1) = sin(time);
y2 = y1 + offset;
end SetParametersFromInitialValues;
Questions:
is there a way to achieve what I want with Parameter? Am I forced to use some more 'variable' variable?
are fixed attributes required? What if y1 and y2 values are fixed from other components? and what if they are not?
(please mind that I thinks it's different from Define Model Parameter as Variable since I need to evaluate parameters based specifically on initial values)
Initial values of variables are accessed using their names in an initial equation section.
With some smaller modifications, your code works with Dymola an OpenModlica:
model SetParametersFromInitialValues
Real y1(start=3.0, fixed=true);
Real y2(start=2.0, fixed=true);
final parameter Real offset(fixed=false);
equation
der(y1) = sin(time);
y2 = y1 + offset;
end SetParametersFromInitialValues;
Note that no initial equation section is needed here, as equations are also valid during initialization. See the details below for further description.
Details about the removed initial equation
The Modelica Specification 3.40 writes in chapter 8.6 Initialization, initial equation, and initial algorithm:
The initialization uses all equations and algorithms that are utilized in the intended operation [such as simulation or linearization].
Since we specified y2 = y1 + offset in the equation section already, this equation must not be declared again in the initial equation section (offset = y2 - y1 is the same equation, just written in another way).
In fact, this example demonstrates very nicely, how Modelica enables you to describe models with equations instead of simple assignments.
During initialization the equation
y2 = y1 + offset
is solved as
offset := y2 - y1
by using the start values of y1 and y2.
During simulation the same equation is used to compute
y2 := y1 + offset.
Details about the fixed attribute
Modelica by Example gives a very nice explanation for the fixed attribute:
The fixed attribute changes the way the start attribute is used when
the start attribute is used as an initial condition. Normally, the
start attribute is considered a “fallback” initial condition and only
used if there are insufficient initial conditions explicitly specified
in the initial equation sections. However, if the fixed attribute is
set to true, then the start attribute is treated as if it was used as
an explicit initial equation (i.e., it is no longer used as a
fallback, but instead treated as a strict initial condition).
So without using fixed=true we can reformulate the code above as follows:
model SetParametersFromInitialValues2
Real y1;
Real y2;
final parameter Real offset(fixed=false);
initial equation
y1 = 3;
y2 = 1;
equation
der(y1) = sin(time) + 1;
y2 = y1 + offset;
end SetParametersFromInitialValues2;
You could introduce parameters for setting the start values, might look less elegant, then calculating the offset is easy, and it introduces the possibility to set start values from the parameter dialog.
model SetParametersFromInitialValues
parameter Real y1_start = 3.0;
parameter Real y2_start = 3.1;
final parameter Real offset= y2_start - y1_start;
Real y1(start = y1_start, fixed = true);
Real y2(start = y2_start, fixed = true);
equation
der(y1) = sin(time);
y2 = y1 + offset;
end SetParametersFromInitialValues;
I ran through the algebra which I had previously done for the Verlet method without the force - this lead to the same code as you see below, but the "+(2*F/D)" term was missing when I ignored the external force. The algorithm worked accurately, as expected, however for the following parameters:
m = 7 ; k = 8 ; b = 0.1 ;
params = [m,k,b];
(and step size h = 0.001)
a force far above something like 0.00001 is much too big. I suspect I've missed a trick with the algebra.
My question is whether someone can spot the flaw in my addition of a force term in my Verlet method
% verlet.m
% uses the verlet step algorithm to integrate the simple harmonic
% oscillator.
% stepsize h, for a second-order ODE
function vout = verlet(vinverletx,h,params,F)
% vin is the particle vector (xn,yn)
x0 = vinverletx(1);
x1 = vinverletx(2);
% find the verlet coefficients
D = (2*params(1))+(params(3)*h);
A = (2/D)*((2*params(1))-(params(2)*h^2));
B=(1/D)*((params(3)*h)-(2*params(1)));
x2 = (A*x1)+(B*x0)+(2*F/D);
vout = x2;
% vout is the particle vector (xn+1,yn+1)
end
As written in the answer to the previous question, the moment friction enters the equation, the system is no longer conservative and the name "Verlet" does no longer apply. It is still a valid discretization of
m*x''+b*x'+k*x = F
(with some slight error with large consequences).
The discretization employs the central difference quotients of first and second order
x'[k] = (x[k+1]-x[k-1])/(2*h) + O(h^2)
x''[k] = (x[k+1]-2*x[k]+x[k-1])/(h^2) + O(h^2)
resulting in
(2*m+b*h)*x[k+1] - 2*(2*m+h^2*k) * x[k] + (2*m-b*h)*x[k-1] = 2*h^2 * F[k] + O(h^4)
Error: As you can see, you are missing a factor h^2 in the term with F.
In the optimal control tracking problem, there is a Riccati equation of the gain matrix K(t) which is:
\dot{K}(t) = -K(t) A - A^{T} K(t) - Q + K(t) B R^{-1} B^{T} K(t)
At the final time of Tf, the terminal boundary condition K(Tf) is given.
Edit: After consideration, I think the question is how to numerically backward integrate the gain matrix with the given terminal boundary condition and save the results in a lookup table to obtain the solution over the interval [t0,Tf] for further computations in Simulink ?
The numerical solution to this equation is found in the book Optimal Control Systems
For example, the following is an excerpt of the technique:
E=B*inv(R)*B'; % the matrix E = BR^{-1}B'
%
% solve matrix difference Riccati equation backwards
% starting from kf to kO
% use the form P(k) = A'P(k+1)[I + EP(k+1)]^{-1}A + Q
% first fix the final condition P(k_f) = F
Pkplus1=F;
p11(N)=F(1);
p12(N)=F(2);
p21(N)=F(3);
p22(N)=F(4);
for k=N-1:-1:1,
Pk = A' *Pkplus1*inv(I+E*Pkplus1)*A+Q;
p11 (k) = Pk(1);
p12(k) = Pk(2);
p21(k) = Pk(3);
p22(k) = Pk(4);
Pkplus1 = Pk;
end
For further information, you may check this book. It's great and informative.
I was wondering if there are established robust libraries or FEX-like packages to deal with scalar conservation laws (say 1D) in matlab.
I am currently dealing with 1D non-linear, non-local, conservation laws and the diffusive error of first order schemes is killing me, moreover a lot of physics is missed. Thus, I am wondering if there is some robust tool already there so to avoid cooking some code myself (ideally, something like boost::odeint for scheme agnostic high order ODE integration in C++).
Any help appreciated.
EDIT: Apologies for the lack of clarity. Here for conservation laws I mean general hyberbolic partial derivative equations in the form
u_t(t,x) + F_x(t,x) = 0
where u=u(t,x) is an intensive conserved variable (say scalar, 1D, e.g. mass density, energy density,...) and F = F(t,x) is its flux. Therefore, I am not interested in the kind of conservation properties Hamiltonian systems feature (energy, currents...) (thanks to #headmyshoulder for his comment).
I cited boost::odeint for a conceptual reference of a robust and generic library addressing a mathematical issue (integration of ODEs). Therefore I am looking for some package implementing Godunov-type methods and so on.
I am currently working on new methods for shock-turbulence simulations and doing lots of code testing/validation in MATLAB. Unfortunately, I haven't found a general library that does what you're hoping, but a basic Godunov or MUSCL code is relatively straightforward to implement. This paper has a good overview of some useful methods:
[1] Kurganov, Alexander and Eitan Tadmor (2000), New High-Resolution Central Schemes for Nonlinear Conservation Laws and Convection-Diffusion Equations, J. Comp. Phys., 160, 214–282. PDF
Here are a few examples from that paper for a 1D equally spaced grid on a periodic domain for solving inviscid Burgers equation. The methods easily generalize to systems of equations, dissipative (viscous) systems, and higher dimension as outlined in [1]. These methods rely on the following functions:
Flux term:
function f = flux(u)
%flux term for Burgers equation: F(u) = u^2/2;
f = u.^2/2;
Minmod function:
function m = minmod(a,b)
%minmod function:
m = (sign(a)+sign(b))/2.*min(abs(a),abs(b));
Methods
Nessyahu-Tadmor scheme:
A 2nd order scheme
function unew = step_u(dx,dt,u)
%%% Nessyahu-Tadmor scheme
ux = minmod((u-circshift(u,[0 1]))/dx,(circshift(u,[0 -1])-u)/dx);
f = flux(u);
fx = minmod((f-circshift(f,[0 1]))/dx,(circshift(f,[0 -1])-f)/dx);
umid = u-dt/2*fx;
fmid = flux(umid);
unew = (u + circshift(u,[0 -1]))/2 + (dx)/8*(ux-circshift(ux,[0 -1])) ...
-dt/dx*( circshift(fmid,[0 -1])-fmid );
This method computes a new u value at xj+1/2 grid points so it also requires a grid shift at each step. The main function should be something like:
clear all
% Set up grid
nx = 256;
xmin=0; xmax=2*pi;
x=linspace(xmin,xmax,nx);
dx = x(2)-x(1);
%initialize
u = exp(-4*(x-pi*1/2).^2)-exp(-4*(x-pi*3/2).^2);
%CFL number:
CFL = 0.25;
t = 0;
dt = CFL*dx/max(abs(u(:)));
while (t<2)
u = step_u(dx,dt,u);
x=x+dx/2;
% handle grid shifts
if x(end)>=xmax+dx
x(end)=0;
x=circshift(x,[0 1]);
u=circshift(u,[0 1]);
end
t = t+dt;
%plot
figure(1)
clf
plot(x,u,'k')
title(sprintf('time, t = %1.2f',t))
if ~exist('YY','var')
YY=ylim;
end
axis([xmin xmax YY])
drawnow
end
Kurganov-Tadmor scheme
The Kurganov-Tadmor scheme of [1] has several advantages over the NT scheme including lower numerical dissipation and a semi-discrete form that allows the use of any time integration method you choose. Using the same spatial discretization as above, it can be formulated as an ODE for du/dt = (stuff). The right hand side of this ODE can be computed by the function:
function RHS = KTrhs(dx,u)
%%% Kurganov-Tadmor scheme
ux = minmod((u-circshift(u,[0 1]))/dx,(circshift(u,[0 -1])-u)/dx);
uplus = u-dx/2*ux;
uminus = circshift(u+dx/2*ux,[0 1]);
a = max(abs(rhodF(uminus)),abs(rhodF(uplus)));
RHS = -( flux(circshift(uplus,[0 -1]))+flux(circshift(uminus,[0 -1])) ...
-flux(uplus)-flux(uminus) )/(2*dx) ...
+( circshift(a,[0 -1]).*(circshift(uplus,[0 -1])-circshift(uminus,[0 -1])) ...
-a.*(uplus-uminus) )/(2*dx);
This function also relies on knowing the spectral radius of the Jacobian of F(u) (rhodF in the code above). For inviscid Burgers this is just
function rho = rhodF(u)
dFdu=abs(u);
The main program of the KT scheme could be something like:
clear all
nx = 256;
xmin=0; xmax=2*pi;
x=linspace(xmin,xmax,nx);
dx = x(2)-x(1);
%initialize
u = exp(-4*(x-pi*1/2).^2)-exp(-4*(x-pi*3/2).^2);
%CFL number:
CFL = 0.25;
t = 0;
dt = CFL*dx/max(abs(u(:)));
while (t<3)
% 4th order Runge-Kutta time stepping
k1 = KTrhs(dx,u);
k2 = KTrhs(dx,u+dt/2*k1);
k3 = KTrhs(dx,u+dt/2*k2);
k4 = KTrhs(dx,u+dt*k3);
u = u+dt/6*(k1+2*k2+2*k3+k4);
t = t+dt;
%plot
figure(1)
clf
plot(x,u,'k')
title(sprintf('time, t = %1.2f',t))
if ~exist('YY','var')
YY=ylim;
end
axis([xmin xmax YY])
drawnow
end
I'm experimenting with ode45 in Matlab. I've learned how to pass parameters to the ode function but I still have a question. Let's suppose that I want to compute the trajectory (speed profile) of a Car and I have a function, e.g. getAcceleration, that gives me the acceleration of the car but also the right gear: [acceleration, gear] = getAcceleration(speed,modelStructure) where modelStructure represents the model of the car.
The ode function would be:
function [dy] = car(t,y,modelStructure)
dy = zeros(2,1);
dy(1) = y(2);
[dy(2),gear] = getAcceleration(y(1),modelStructure);
Then I call the Ode45 integrator in this way:
tInit = 0;
tEnd = 5,
[t,y] = ode45(#car,[tInit tEnd], [speedInitial,accelerationInitial],options,modelStructure);
The problem is: how do I get the vector storing gears? Should I have something like [t,y,gear]=ode45(....) or should gear be within the y vector?
I've been working on my code and using the events function I'm now able to get the car 'gears' changes (as events).
Now I have a new problem related to the same code.
Imagine that when I evaluate de 'dy' vector I'm able to get a further value Z which let me to have a massive speed up calling the acceleration computation (getAcceleration):
function [dy] = car(t,y,modelStructure)
dy = zeros(2,1);
dy(1) = y(2);
[dy(2),Z(t)] = getAcceleration(y(1),modelStructure,Z(t-1));
and suppose that I'm also able to compute Z at the initial condition. The problem is that I'm not able to compute the Z derivative.
Is there a way to pass Z value throw the stepping without integrating it?
Thanks guys.
First off: why are the initial values to the differential equation the initial speed (speedInitial) and the initial acceleration (accelerationInitial)? That means that the differential equation car will be computing the acceleration (y(1)) and the jerk (y(2)), the time-derivative of the acceleration, at each time t. That seems incorrect...I would say the initial values should be the initial position (positionInitial) and the initial speed (speedInitial). But, I don't know your model, I could be wrong.
Now, getting the gear in the solution directlty: you can't, not without hacking ode45. This is also logical; you also cannot get dy at all times directly, can you? That's just not how ode45 is set up.
There's two ways out I see here:
Global variable
DISCLAIMER: don't use this method. It's only here to show what most people would do as a first attempt.
You can store gear in a global variable. It's probably the least amount of coding, but also the least convenient outcome:
global ts gear ii
ii = 1;
tInit = 0;
tEnd = 5,
[t,y] = ode45(...
#(t,y) car(t,y,modelStructure), ...
[tInit tEnd], ...
[speedInitial, accelerationInitial], options);
...
function [dy] = car(t,y,modelStructure)
global ts gear ii
dy = zeros(2,1);
dy(1) = y(2);
[dy(2),gear(ii)] = getAcceleration(y(1),modelStructure);
ts(ii) = t;
ii = ii + 1;
But, due to the nature of ode45, this will get you an array of times ts and associated gear which contains intermediate points and/or points that got rejected by ode45. So, you'll have to filter for those afterwards:
ts( ~ismember(ts, t) ) = [];
I'll say it again: this is NOT the method I'd recommend. Only use global variables when testing or doing some quick-n-dirty stuff, but always very quickly shift towards other solutions. Also, the global variables grow at each (sub-)iteration of ode45, which is an unacceptable performance penalty.
It's better to use the next method:
Post-solve call
This is also not too hard for your case, and the way I'd recommend you to go. First, modify the differential equation as below, and solve as normal:
tInit = 0;
tEnd = 5,
[t,y] = ode45(...
#(t,y) car(t,y,modelStructure), ...
[tInit tEnd], ...
[speedInitial, accelerationInitial], options);
...
function [dy, gear] = car(t,y,modelStructure)
dy = [0;0];
dy(1) = y(2);
[dy(2),gear] = getAcceleration(y(1),modelStructure);
and then after ode45 completes, do this:
gear = zeros(size(t));
for ii = 1:numel(t)
[~, gear(ii)] = car(t(ii), y(ii,:).', modelStructure);
end
That will get you all the gears the car would have at times t.
The only drawback that I can see here is that you'll have many more function evaluations of car than ode45 would use by itself. But this is only a real problem if each evaluation of car takes in the order of seconds or longer, which I suspect is not the case in your setup.