Trapezoidal numerical integration in Modelica - modelica

I have two arrays "x" and "fy". I have to do the trapezoidal integration of array "fy" w.r.t array "x". I could not find a function in Modelica library. I have found a function in Buildings library but it does not help me exactly. Could you please suggest, if there is other function for this type of integration.

I thought it was worth posting an alternative way to get the integral of an input relying on what Modelica does well. I found this nice example here that uses time and der().
I'm not sure if the trapezoidal rule integration is done in the MSL but below is a simple function that implements the trapezoidal rule. Here is a pdf with a nice summary and example.
In the future, you will likely have to write many of your own functions/models. There is still a lot of functionality Modelica needs such as a more complete verified and validated set of math functions like SciPy or GNU Standard Library which would have all sorts of integral, interpolation, etc. things that may be useful.
function integral_TrapezoidalRule "Integral of array y(x) using the trapezoidal rule"
extends Modelica.Icons.Function;
input Integer n(min=2) "length of array";
input Real[n] x "dependent array";
input Real[n] y "independent array";
output Real integral "Resulting integral";
protected
Real[n-1] dx;
algorithm
integral := 0;
for i in 1:n-1 loop
dx[i] := x[i+1] - x[i];
integral := integral + 0.5*dx[i]*(y[i+1]+y[i]);
end for;
end integral_TrapezoidalRule;
Using the example from the pdf, calling the function with:
n = 6;
x = {2.1,2.4,2.7,3.0,3.3,3.6};
y = {3.2,2.7,2.9,3.5,4.1,5.2};
Yields:
integral = 5.22;

Related

Minimizing Function with vector valued input in MATLAB

I want to minimize a function like below:
Here, n can be 5,10,50 etc. I want to use Matlab and want to use Gradient Descent and Quasi-Newton Method with BFGS update to solve this problem along with backtracking line search. I am a novice in Matlab. Can anyone help, please? I can find a solution for a similar problem in that link: https://www.mathworks.com/help/optim/ug/unconstrained-nonlinear-optimization-algorithms.html .
But, I really don't know how to create a vector-valued function in Matlab (in my case input x can be an n-dimensional vector).
You will have to make quite a leap to get where you want to be -- may I suggest to go through some basic tutorial first in order to digest basic MATLAB syntax and concepts? Another useful read is the very basic example to unconstrained optimization in the documentation. However, the answer to your question touches only basic syntax, so we can go through it quickly nevertheless.
The absolute minimum to invoke the unconstraint nonlinear optimization algorithms of the Optimization Toolbox is the formulation of an objective function. That function is supposed to return the function value f of your function at any given point x, and in your case it reads
function f = objfun(x)
f = sum(100 * (x(2:end) - x(1:end-1).^2).^2 + (1 - x(1:end-1)).^2);
end
Notice that
we select the indiviual components of the x vector by matrix indexing, and that
the .^ notation effects that the operand is to be squared elementwise.
For simplicity, save this function to a file objfun.m in your current working directory, so that you have it available from the command window.
Now all you have to do is to call the appropriate optimization algorithm, say, the quasi Newton method, from the command window:
n = 10; % Use n variables
options = optimoptions(#fminunc,'Algorithm','quasi-newton'); % Use QM method
x0 = rand(n,1); % Random starting guess
[x,fval,exitflag] = fminunc(#objfun, x0, options); % Solve!
fprintf('Final objval=%.2e, exitflag=%d\n', fval, exitflag);
On my machine I see that the algorithm converges:
Local minimum found.
Optimization completed because the size of the gradient is less than
the default value of the optimality tolerance.
Final objval=5.57e-11, exitflag=1

For loop equation into Octave / Matlab code

I'm using octave 3.8.1 which works like matlab.
I have an array of thousands of values I've only included three groupings as an example below:
(amp1=0.2; freq1=3; phase1=1; is an example of one grouping)
t=0;
amp1=0.2; freq1=3; phase1=1; %1st grouping
amp2=1.4; freq2=2; phase2=1.7; %2nd grouping
amp3=0.8; freq3=5; phase3=1.5; %3rd grouping
The Octave / Matlab code below solves for Y so I can plug it back into the equation to check values along with calculating values not located in the array.
clear all
t=0;
Y=0;
a1=[.2,3,1;1.4,2,1.7;.8,5,1.5]
for kk=1:1:length(a1)
Y=Y+a1(kk,1)*cos ((a1(kk,2))*t+a1(kk,3))
kk
end
Y
PS: I'm not trying to solve for Y since it's already solved for I'm trying to solve for Phase
The formulas located below are used to calculate Phase but I'm not sure how to put it into a for loop that will work in an array of n groupings:
How would I write the equation / for loop for finding the phase if I want to find freq=2.5 and amp=.23 and the phase is unknown I've looked online and it may require writing non linear equations which I'm not sure how to convert what I'm trying to do into such an equation.
phase1_test=acos(Y/amp1-amp3*cos(2*freq3*pi*t+phase3)/amp1-amp2*cos(2*freq2*pi*t+phase2)/amp1)-2*freq1*pi*t
phase2_test=acos(Y/amp2-amp3*cos(2*freq3*pi*t+phase3)/amp2-amp1*cos(2*freq1*pi*t+phase1)/amp2)-2*freq2*pi*t
phase3_test=acos(Y/amp3-amp2*cos(2*freq2*pi*t+phase2)/amp3-amp1*cos(2*freq1*pi*t+phase1)/amp3)-2*freq2*pi*t
Image of formula below:
I would like to do a check / calculate phases if given a freq and amp values.
I know I have to do a for loop but how do I convert the phase equation into a for loop so it will work on n groupings in an array and calculate different values not found in the array?
Basically I would be given an array of n groupings and freq=2.5 and amp=.23 and use the formula to calculate phase. Note: freq will not always be in the array hence why I'm trying to calculate the phase using a formula.
Ok, I think I finally understand your question:
you are trying to find a set of phase1, phase2,..., phaseN, such that equations like the ones you describe are satisfied
You know how to find y, and you supply values for freq and amp.
In Matlab, such a problem would be solved using, for example fsolve, but let's look at your problem step by step.
For simplicity, let me re-write your equations for phase1, phase2, and phase3. For example, your first equation, the one for phase1, would read
amp1*cos(phase1 + 2 freq1 pi t) + amp2*cos(2 freq2 pi t + phase2) + amp3*cos(2 freq3 pi t + phase3) - y = 0
Note that ampX (X is a placeholder for 1, 2, 3) are given, pi is a constant, t is given via Y (I think), freqX are given.
Hence, you are, in fact, dealing with a non-linear vector equation of the form
F(phase) = 0
where F is a multi-dimensional (vector) function taking a multi-dimensional (vector) input variable phase (comprised of phase1, phase2,..., phaseN). And you are looking for the set of phaseX, where all of the components of your vector function F are zero. N.B. F is a shorthand for your functions. Therefore, the first component of F, called f1, for example, is
f1 = amp1*cos(phase1+...) + amp2*cos(phase2+...) + amp3*cos(phase3+...) - y = 0.
Hence, f1 is a one-dimensional function of phase1, phase2, and phase3.
The technical term for what you are trying to do is find a zero of a non-linear vector function, or find a solution of a non-linear vector function. In Matlab, there are different approaches.
For a one-dimensional function, you can use fzero, which is explained at http://www.mathworks.com/help/matlab/ref/fzero.html?refresh=true
For a multi-dimensional (vector) function as yours, I would look into using fsolve, which is part of Matlab's optimization toolbox (which means I don't know how to do this in Octave). The function fsolve is explained at http://www.mathworks.com/help/optim/ug/fsolve.html
If you know an approximate solution for your phases, you may also look into iterative, local methods.
In particular, I would recommend you look into the Newton's Method, which allows you to find a solution to your system of equations F. Wikipedia has a good explanation of Newton's Method at https://en.wikipedia.org/wiki/Newton%27s_method . Newton iterations are very simple to implement and you should find a lot of resources online. You will have to compute the derivative of your function F with respect to each of your variables phaseX, which is very simple to compute since you're only dealing with cos() functions. For starters, have a look at the one-dimensional Newton iteration method in Matlab at http://www.math.colostate.edu/~gerhard/classes/331/lab/newton.html .
Finally, if you want to dig deeper, I found a textbook on this topic from the society for industrial and applied math: https://www.siam.org/books/textbooks/fr16_book.pdf .
As you can see, this is a very large field; Newton's method should be able to help you out, though.
Good luck!

How to solve an equation with piecewise defined function in Matlab?

I have been working on solving some equation in a more complicated context. However, I want to illustrate my question through the following simple example.
Consider the following two functions:
function y=f1(x)
y=1-x;
end
function y=f2(x)
if x<0
y=0;
else
y=x;
end
end
I want to solve the following equation: f1(x)=f2(x). The code I used is:
syms x;
x=solve(f1(x)-f2(x));
And I got the following error:
??? Error using ==> sym.sym>notimplemented at 2621
Function 'lt' is not implemented for MuPAD symbolic objects.
Error in ==> sym.sym>sym.lt at 812
notimplemented('lt');
Error in ==> f2 at 3
if x<0
I know the error is because x is a symbolic variable and therefore I could not compare x with 0 in the piecewise function f2(x).
Is there a way to fix this and solve the equation?
First, make sure symbolic math is even the appropriate solution method for your problem. In many cases it isn't. Look at fzero and fsolve amongst many others. A symbolic method is only needed if, for example, you want a formula or if you need to ensure precision.
In such an old version of Matlab, you may want to break up your piecewise function into separate continuous functions and solve them separately:
syms x;
s1 = solve(1-x^2,x) % For x >= 0
s2 = solve(1-x,x) % For x < 0
Then you can either manually examine or numerically compare the outputs to determine if any or all of the solutions are valid for the chosen regime – something like this:
s = [s1(double(s1) >= 0);s2(double(s2) < 0)]
You can also take advantage of the heaviside function, which is available in much older versions.
syms x;
f1 = 1-x;
f2 = x*heaviside(x);
s = solve(f1-f2,x)
Yes, the Heaviside function is 0.5 at zero – this gives it the appropriate mathematical properties. You can shift it to compare values other than zero. This is a standard technique.
In Matlab R2012a+, you can take advantage of assumptions in addition to the normal relational operators. To add to #AlexB's comment, you should convert the output of any logical comparison to symbolic before using isAlways:
isAlways(sym(x<0))
In your case, x is obviously not "always" on one side or the other of zero, but you may still find this useful in other cases.
If you want to get deep into Matlab's symbolic math, you can create piecewise functions using MuPAD, which are accessible from Matlab – e.g., see my example here.

find all zeros of a polynomal function

Im working with Dymola Version 2013. I try to solve a simple mathematical problem, like:
f= x^2 -4 ;
y=1;
f=y;
f and x are defined as Real. The solution is 2.36. but I need to calculate with both solutions. So 2.36 and -2.36!
In my problem f is a polynomial like ax^3 + bx^2 +cx +d
and y is linear. y = ax +b
How can I get all solutions of this problem? x has no explicit value. x often has at least two solutions. Should x be a vector? in this case I got problems with the dimension of the equation...
Can someone help me?
If I understand you correctly, your goal is to use Modelica to find all the roots of a (higher than second order) polynomial. I'm afraid that just isn't what Modelica is intended for. For a given non-linear equations, the simulation of a Modelica model will use (at most) one root of the non-linear equation. If you want to find all the roots, you'll have to find a way to factor the polynomial yourself. In your case, you are only dealing with a cubic polynomial so you should research algorithms for factoring cubic polynomials. You could then write such an algorithm as a Modelica function.
As I understood your question you have two polynomials and want to find all points where they are equal.
Here is a function that does that using Modelica.Math.Vectors.Utilities.roots:
First, you give the two polynomials poly1 and poly2. Finding poly1=poly2is identical to finding poly1-poly2=0, so I define a third polynomial polyDiff = polyLong-polyShort and then hand over that polynomial to Modelica.Math.Vectors.Utilities.roots. It will return all roots, even complex ones.
function polyIntersect
input Real[:] poly1={3,2,1,0};
input Real[:] poly2={8,7};
output Real[:,2] intersect;
protected
Integer nPoly1 = size(poly1,1);
Integer nPoly2 = size(poly2,1);
Integer nPolyShort = min(nPoly1, nPoly2);
Integer nPolyLong = max(nPoly1, nPoly2);
Real[nPolyShort] polyShort;
Real[nPolyLong] polyLong;
Real[nPolyLong] polyDiff;
algorithm
if (nPoly1<nPoly2) then
polyShort := poly1;
polyLong := poly2;
else
polyShort := poly2;
polyLong := poly1;
end if;
polyDiff := polyLong;
for i in 0:nPolyShort-1 loop
polyDiff[nPolyLong-i] := polyLong[nPolyLong-i] - polyShort[nPolyShort-i];
end for;
intersect := Modelica.Math.Vectors.Utilities.roots(polyDiff);
end polyIntersect;
The above code is also available here: https://gist.github.com/thorade/5388205

Multiplication of large number with small number

I'm trying to compute a rather ugly integral using MATLAB. What I'm having problem with though is a part where I multiply a very big number (>10^300) with a very small number (<10^-300). MATLAB returns 'inf' for this even though it should be in the range of 0-0.0005. This is what I have
besselFunction = #(u)besseli(qb,2*sqrt(lambda*(theta + mu)).*u);
exponentFuncion = #(u)exp(-u.*(lambda + theta + mu));
where qb = 5, lambda = 12, theta = 10, mu = 3. And what I want to find is
besselFunction(u)*exponentFunction(u)
for all real values of u. The problem is that whenever u>28 it will be evaluated as 'inf'. I've heared, and tried, to use MATLAB function 'vpa' but it doesn't seem to work well when I want to use functions...
Any tips will be appreciated at this point!
I'd use logarithms.
Let x = Bessel function of u and y = x*exp(-u) (simpler than your equation, but similar).
Since log(v*w) = log(v) + log(w), then log(y) = log(x) + log(exp(-u))
This simplifies to
log(y) = log(x) - u
This will be better behaved numerically.
The other key will be to not evaluate that Bessel function that turns into a large number and passing it to a math function to get the log. Better to write your own that returns the logarithm of the Bessel function directly. Look at a reference like Abramowitz and Stegun to try and find one.
If you are doing an integration, consider using Gauss–Laguerre quadrature instead. The basic idea is that for equations of the form exp(-x)*f(x), the integral from 0 to inf can be approximated as sum(w(X).*f(X)) where the values of X are the zeros of a Laguerre polynomial and W(X) are specific weights (see the Wikipedia article). Sort of like a very advanced Simpson's rule. Since your equation already has an exp(-x) part, it is particularly suited.
To find the roots of the polynomial, there is a function on MATLAB Central called LaguerrePoly, and from there it is pretty straightforward to compute the weights.