How to solve a second order differential equation on Scilab? - numerical-methods

I need to solve this differential equation using Runge-Kytta 4(5) on Scilab:
The initial conditions are above. The interval and the h-step are:
I don't need to implement Runge-Kutta. I just need to solve this and plot the result on the plane:
I tried to follow these instructions on the official "Scilab Help":
https://x-engineer.org/graduate-engineering/programming-languages/scilab/solve-second-order-ordinary-differential-equation-ode-scilab/
The suggested code is:
// Import the diagram and set the ending time
loadScicos();
loadXcosLibs();
importXcosDiagram("SCI/modules/xcos/examples/solvers/ODE_Example.zcos");
scs_m.props.tf = 5000;
// Select the solver Runge-Kutta and set the precision
scs_m.props.tol(6) = 6;
scs_m.props.tol(7) = 10^-2;
// Start the timer, launch the simulation and display time
tic();
try xcos_simulate(scs_m, 4); catch disp(lasterror()); end
t = toc();
disp(t, "Time for Runge-Kutta:");
However, it is not clear for me how I can change this for the specific differential equation that I showed above. I have a very basic knowledge of Scilab.
The final plot should be something like the picture bellow, an ellipse:
Just to provide some mathematical context, this is the differential equation that describes the pendulum problem.
Could someone help me, please?
=========
UPDATE
Based on #luizpauloml comments, I am updating this post.
I need to convert the second-order ODE into a system of first-order ODEs and then I need to write a function to represent such system.
So, I know how to do this on pen and paper. Hence, using z as a variable:
OK, but how do I write a normal script?
The Xcos is quite disposable. I only kept it because I was trying to mimic the example on the official Scilab page.

To solve this, you need to use ode(), which can employ many methods, Runge-Kutta included. First, you need to define a function to represent the system of ODEs, and Step 1 in the link you provided shows you what to do:
function z = f(t,y)
//f(t,z) represents the sysmte of ODEs:
// -the first argument should always be the independe variable
// -the second argument should always be the dependent variables
// -it may have more than two arguments
// -y is a vector 2x1: y(1) = theta, y(2) = theta'
// -z is a vector 2x1: z(1) = z , z(2) = z'
z(1) = y(2) //first equation: z = theta'
z(2) = 10*sin(y(1)) //second equation: z' = 10*sin(theta)
endfunction
Notice that even if t (the independent variable) does not explicitly appear in your system of ODEs, it still needs to be an argument of f(). Now you just use ode(), setting the flag 'rk' or 'rkf' to use either one of the available Runge-Kutta methods:
ts = linspace(0,3,200);
theta0 = %pi/4;
dtheta0 = 0;
y0 = [theta0; dtheta0];
t0 = 0;
thetas = ode('rk',y0, t0, ts, f); //the output have the same order
//as the argument `y` of f()
scf(1); clf();
plot2d(thetas(2,:),thetas(1,:),-5);
xtitle('Phase portrait', 'theta''(t)','theta(t)');
xgrid();
The output:

Related

Octave keeps giving results from function although not asked

I created a function in Octave for which I, at this moment, only want one of the possible outputs displayed. The code:
function [pi, time, numiter] = PageRank(pi0,H,v,n,alpha,epsilon);
rowsumvector=ones(1,n)*H';
nonzerorows=find(rowsumvector);
zerorows=setdiff(1:n,nonzerorows); l=length(zerorows);
a=sparse(zerorows,ones(l,1),ones(l,1),n,1);
k=0;
residual=1;
pi=pi0;
tic;
while (residual >= epsilon)
prevpi=pi;
k=k+1;
pi=alpha*pi*H + (alpha*(pi*a)+1-alpha)*v;
residual = norm(pi-prevpi,1);
end
pi;
numiter=k
time=toc;
endfunction
Now I only want numiter returned, but it keeps giving me back pi as well, no matter whether I delete pi;, or not.
It returns it in the following format:
>> PageRank(pi0,H,v,length(H),0.9,epsilon)
numiter = 32
ans =
0.026867 0.157753 0.026867 0.133573 0.315385
To me it seems strange that the pi is not given with its variable, but merely as an ans.
Any suggestions?
I know the Octave documentation for this is not very extensive, but perhaps it gives enough hints to understand that how you think about output variables is wrong.
The call
PageRank(pi0,H,v,length(H),0.9,epsilon)
returns a single output argument, it is equivalent to
ans = PageRank(pi0,H,v,length(H),0.9,epsilon)
ans is always the implied output argument if none is explicitly given. ans will be assigned the value of pi, the first output argument of your function. The variable pi (nor time, nor numiter) in your workspace will be modified or assigned to. These are the names of local variables inside your function.
To obtain other output variables, do this:
[out1,out2,out3] = PageRank(pi0,H,v,length(H),0.9,epsilon)
Now, the variable out1 will be assigned the value that pi had inside your function. out2 will contain the value of time, and out3 the value of numiter,
If you don't want the first two output arguments, and only want the third one, do this:
[~,~,out3] = PageRank(pi0,H,v,length(H),0.9,epsilon)
The ~ indicates to Octave that you want to ignore that output argument.

Piecewise functions in the Octave symbolic package?

Unlike Matlab, Octave Symbolic has no piecewise function. Is there a work around? I would like to do something like this:
syms x
y = piecewise(x0, 1)
Relatedly, how does one get pieces of a piecewise function? I ran the following:
>> int (exp(-a*x), x, 0, t)
And got the following correct answer displayed and stored in a variable:
t for a = 0
-a*t
1 e
- - ----- otherwise
a a
But now I would like to access the "otherwise" part of the answer so I can factor it. How do I do that?
(Yes, I can factor it in my head, but I am practicing for when more complicated expressions come along. I am also only really looking for an approach using symbolic expressions -- even though in any single case numerics may work fine, I want to understand the symbolic approach.)
Thanks!
Matlab's piecewise function seems to be fairly new (introduced in 2016b), but it basically just looks like a glorified ternary operator. Unfortunately I don't have 2016 to check if it performs any checks on the inputs or not, but in general you can recreate a 'ternary' operator in octave by indexing into a cell using logical indexing. E.g.
{#() return_A(), #() return_B(), #() return_default()}([test1, test2, true]){1}()
Explanation:
Step 1: You put all the values of interest in a cell array. Wrap them in function handles if you want to prevent them being evaluated at the time of parsing (e.g. if you wanted the output of the ternary operator to be to produce an error)
Step 2: Index this cell array using logical indexing, where at each index you perform a logical test
Step 3: If you need a 'default' case, use a 'true' test for the last element.
Step 4: From the cell (sub)array that results from above, select the first element and 'run' the resulting function handle. Selecting the first element has the effect that if more than one tests succeed, you only pick the first result; given the 'default' test will always succeed, this also makes sure that this is not picked unless it's the first and only test that succeeds (which it does so by default).
Here are the above steps implemented into a function (appropriate sanity checks omitted here for brevity), following the same syntax as matlab's piecewise:
function Out = piecewise (varargin)
Conditions = varargin(1:2:end); % Select all 'odd' inputs
Values = varargin(2:2:end); % Select all 'even' inputs
N = length (Conditions);
if length (Values) ~= N % 'default' case has been provided
Values{end+1} = Conditions{end}; % move default return-value to 'Values'
Conditions{end} = true; % replace final (ie. default) test with true
end
% Wrap return-values into function-handles
ValFuncs = cell (1, N);
for n = 1 : N; ValFuncs{n} = #() Values{n}; end
% Grab funhandle for first successful test and call it to return its value
Out = ValFuncs([Conditions{:}]){1}();
end
Example use:
>> syms x t;
>> F = #(a) piecewise(a == 0, t, (1/a)*exp(-a*t)/a);
>> F(0)
ans = (sym) t
>> F(3)
ans = (sym)
-3⋅t
ℯ
─────
9

How to compute Fourier coefficients with MATLAB

I'm trying to compute the Fourier coefficients for a waveform using MATLAB. The coefficients can be computed using the following formulas:
T is chosen to be 1 which gives omega = 2pi.
However I'm having issues performing the integrals. The functions are are triangle wave (Which can be generated using sawtooth(t,0.5) if I'm not mistaking) as well as a square wave.
I've tried with the following code (For the triangle wave):
function [ a0,am,bm ] = test( numTerms )
b_m = zeros(1,numTerms);
w=2*pi;
for i = 1:numTerms
f1 = #(t) sawtooth(t,0.5).*cos(i*w*t);
f2 = #(t) sawtooth(t,0.5).*sin(i*w*t);
am(i) = 2*quad(f1,0,1);
bm(i) = 2*quad(f2,0,1);
end
end
However it's not getting anywhere near the values I need. The b_m coefficients are given for a
triangle wave and are supposed to be 1/m^2 and -1/m^2 when m is odd alternating beginning with the positive term.
The major issue for me is that I don't quite understand how integrals work in MATLAB and I'm not sure whether or not the approach I've chosen works.
Edit:
To clairify, this is the form that I'm looking to write the function on when the coefficients have been determined:
Here's an attempt using fft:
function [ a0,am,bm ] = test( numTerms )
T=2*pi;
w=1;
t = [0:0.1:2];
f = fft(sawtooth(t,0.5));
am = real(f);
bm = imag(f);
func = num2str(f(1));
for i = 1:numTerms
func = strcat(func,'+',num2str(am(i)),'*cos(',num2str(i*w),'*t)','+',num2str(bm(i)),'*sin(',num2str(i*w),'*t)');
end
y = inline(func);
plot(t,y(t));
end
Looks to me that your problem is what sawtooth returns the mathworks documentation says that:
sawtooth(t,width) generates a modified triangle wave where width, a scalar parameter between 0 and 1, determines the point between 0 and 2π at which the maximum occurs. The function increases from -1 to 1 on the interval 0 to 2πwidth, then decreases linearly from 1 to -1 on the interval 2πwidth to 2π. Thus a parameter of 0.5 specifies a standard triangle wave, symmetric about time instant π with peak-to-peak amplitude of 1. sawtooth(t,1) is equivalent to sawtooth(t).
So I'm guessing that's part of your problem.
After you responded I looked into it some more. Looks to me like it's the quad function; not very accurate! I recast the problem like this:
function [ a0,am,bm ] = sotest( t, numTerms )
bm = zeros(1,numTerms);
am = zeros(1,numTerms);
% 2L = 1
L = 0.5;
for ii = 1:numTerms
am(ii) = (1/L)*quadl(#(x) aCos(x,ii,L),0,2*L);
bm(ii) = (1/L)*quadl(#(x) aSin(x,ii,L),0,2*L);
end
ii = 0;
a0 = (1/L)*trapz( t, t.*cos((ii*pi*t)/L) );
% now let's test it
y = ones(size(t))*(a0/2);
for ii=1:numTerms
y = y + am(ii)*cos(ii*2*pi*t);
y = y + bm(ii)*sin(ii*2*pi*t);
end
figure; plot( t, y);
end
function a = aCos(t,n,L)
a = t.*cos((n*pi*t)/L);
end
function b = aSin(t,n,L)
b = t.*sin((n*pi*t)/L);
end
And then I called it like:
[ a0,am,bm ] = sotest( t, 100 );
and I got:
Sweetness!!!
All I really changed was from quad to quadl. I figured that out by using trapz which worked great until the time vector I was using didn't have enough resolution, which led me to believe it was a numerical issue rather than something fundamental. Hope this helps!
To troubleshoot your code I would plot the functions you are using and investigate, how the quad function samples them. You might be undersampling them, so make sure your minimum step size is smaller than the period of the function by at least factor 10.
I would suggest using the FFTs that are built-in to Matlab. Not only is the FFT the most efficient method to compute a spectrum (it is n*log(n) dependent on the length n of the array, whereas the integral in n^2 dependent), it will also give you automatically the frequency points that are supported by your (equally spaced) time data. If you compute the integral yourself (might be needed if datapoints are not equally spaced), you might calculate frequency data that are not resolved (closer spacing than 1/over the spacing in time, i.e. beyond the 'Fourier limit').

Adding an arbitrary number of functions into a function handle MATLAB

I'm trying to generate .bmp graphics in MATLAB and I'm having trouble summing functions together. I'm designing my function such that given an arbitrary set of inputs, my function will add an arbitrary number of functions together and output a function handle. The inputs are coefficients to my general function so I can specify any number of functions (that only differ due to their coefficients) and then add them together into a function handle. What I've tried to do is create each function as a string and then concatenate them and then write them as a function handle. The main problem is that because x and y aren't defined (because I'm trying to create a function handle) MATLAB can't add them regularly. My current attempt:
function HGHG = anyHGadd(multi) %my array of inputs
m=length(multi);
for k=3:3:m;
m1=multi(k-2); %these three are the coefficients that I'd like to specify
n1=multi(k-1);
w1=multi(k);
HGarrm1=hermite(m1); %these generate arrays
HGarrn1=hermite(n1);
arrm1=[length(HGarrm1)-1:-1:0];%these generate arrays with the same length
arrn1=[length(HGarrn1)-1:-1:0];%the function below is the general form of my equation
t{k/3}=num2str(((sum(((sqrt(2)*x/w1).^arrm1).*HGarrm1))*(sum(((sqrt(2)*y/w1).^arrn1).*HGarrn1))*exp(-(x^2+y^2)/(w1^2))));
end
a=cell2mat(t(1:length(t)));
str2func(x,y)(a);
Any help would be much appreciated. I haven't seen much on here about this, and I'm not even sure this is entirely possible. If my question isn't clear, please say so and I'll try again.
Edit: The fourth from last line shouldn't produce a number because x and y aren't defined. They can't be because I need them to be preserved as a part of my function handle. As for a stripped down version of my code, hopefully this gets the point across:
function HGHG = anyHGadd(multi) %my array of inputs
m=length(multi);
for k=3:3:m;
m1=multi(k-2); %these three are the coefficients that I'd like to specify
n1=multi(k-1);
w1=multi(k);
t{k/3}=num2str(genericfunction(x,y,n1,m1,n1,w1); %where x and y are unspecified
end
a=cell2mat(t(1:length(t)));
str2func(x,y)(a);
Edit I am expecting this to output a single function handle that is the sum of an arbitrary number of my functions. However, I'm not sure if using strings would be the best method or not.
Your question is not very clear to me, but I think you are trying to create a function that generate output functions parametrized by some input.
One way is to use closures (nested function that access its parent function workspace). Let me illustrate with an example:
function fh = combineFunctions(funcHandles)
%# return a function handle
fh = #myGeneralFunction;
%# nested function. Implements the formula:
%# f(x) = cos( f1(x) + f2(x) + ... + fN(x) )
%# where f1,..,fN are the passed function handles
function y = myGeneralFunction(x)
%# evaluate all functions on the input x
y = cellfun(#(fcn) fcn(x), funcHandles);
%# apply cos(.) to the sum of all the previous results
%# (you can make this any formula you want)
y = cos( sum(y) );
end
end
Now say we wanted to create the function #(x) cos(sin(x)+sin(2x)+sin(5x)), we would call the above generator function, and give it three function handles as follows:
f = combineFunctions({#(x) sin(x), #(x) sin(2*x), #(x) sin(5*x)});
Now we can evaluate this created function given any input:
>> f(2*pi/5) %# evaluate f(x) at x=2*pi/5
ans =
0.031949
Note: The function returned will work on scalars and return a scalar value. If you want it vectorized (so that you can apply it on whole vector at once f(1:100)), you'll have to set UniformOutput to false in cellfun, then combine the vectors into a matrix, sum them along the correct dimension, and apply your formula to get a vector result.
If your goal is to create a function handle that sums the output of an arbitrary number functions, you can do the following:
n = 3; %# number of function handles
parameters = [1 2 4];
store = cell(2,3);
for i=1:n
store{1,i} = sprintf('sin(t/%i)',parameters(i));
store{2,i} = '+'; %# operator
end
%# combine such that we get
%# sin(t)+sin(t/2)+sin(t/4)
funStr = ['#(t)',store{1:end-1}]; %# ignore last operator
functionHandle = str2func(funStr)
functionHandle =
#(t)sin(t/1)+sin(t/2)+sin(t/4)

Restrict variable in Matlab

Is there a way in matlab to restrict variables in a function
For example i have a function
function S0 = S0Func(obj, c, delta, xT, sigma)
beta = obj.betaFunc(sigma);
xb = obj.xbFunc(c, delta, sigma);
S0 = (1-obj.tau).*(obj.x0./(obj.r-obj.mu)-c./obj.r-(xb./(obj.r-obj.mu)-c./obj.r).*((obj.x0./xb).^beta)-((delta-1).*c./obj.r).*((obj.x0./xT).^beta-((obj.x0./xb).^beta)));
end
where I would like to have the restrictions (obj is an object of a class)
0<xb<xT<1
0<c
1<delta
What I would like to do is to draw a 3d graph of the following with the restrictions mentioned above
S0Func(2.7, 1, 1, 0.3)-S0Func(c,delta,xT,0.2)<0;
EDIT
I have tried using the isosurface
optimalStraightCoupon = fminbnd(#(c) -(S0Function(c,1,1)+D0Function(c,1,1)), 0, 4);
[xT, delta, c] = meshgrid(0.8:.01:1, 1:.1:3, 0:.1:4);
values = S0Function(optimalStraightCoupon,1, 1)- S0Function(c,delta, xT);
patch(isosurface(xT, c, delta, values, 1), 'FaceColor', 'red');
view(3);
I get some output, but it is not correct as the restriction on xT is violated.
Any help is appreciated. Thank you.
It's a little unclear what you are trying to achieve. I expect that you know that you can write statements such as (pseudocode):
if c>=0 exit
which, in a sense, restricts your function to operate only on values which meet the defined constraints.
The foregoing is so simple that I am sure that I have misunderstood your question.
No, it appears you wish MORE than a just 3-d graph. It appears you wish to see this function as a FUNCTION of three variables: c, delta, xT. So a 4-d graph. In that event, you will need to simply evaluate the function over a 3-d mesh (using meshgrid or ndgrid to generate the points.)
Then use isosurface to visualize the result, as essentially a higher dimensional contour plot. Do several such plots, at different iso-levels.
I would just return NaN when your constraints are violated.
Just add following lines to your function (preferable before the calculation to save time)
if delta <= 1 || c <= 0 || ... % I assume you can write them yourself
S0 = NaN;
return
end
Plot will not draw NaNs.
Though as you input c,delta,xT it's the question why they are set to invalid values in the first place. You could save some checks and therefore time if you assure that beforehand.