I have a problem when i use fsolve, the programm send me an error, but i don't know why. I should find for x(2) = 2.96e+13 and x(1)= 2.72e+22.
I tried this for solve my non linear equations : i have 2 equations and 2 unknows:
function y = f(x)
global x_rayon_droite
global z1
global r_droite
global x_rayon_gauche
global r_gauche
global y_rayon_droite
global y_rayon_gauche
x_rayon_droite=406
z1=2.72e+22
r_droite = 556.77
x_rayon_gauche=179
r_gauche = 241.42
y_rayon_droite=381
y_rayon_gauche=162
y(1)= x(1).*(x_rayon_droite./z1-x(2)./r_droite.*x_rayon_droite./r_droite)-x(1).*(x_rayon_gauche./z1-x(2)./r_gauche.*x_rayon_gauche./r_gauche)+x_rayon_droite-x_rayon_gauche;
y(2)= x(1).*(y_rayon_droite./z1-x(2)./r_droite.*y_rayon_droite./r_droite)-x(1).*(y_rayon_gauche./z1-x(2)./r_gauche.*y_rayon_gauche./r_gauche)+y_rayon_droite-y_rayon_gauche;
endfunction
[x,info]=fsolve("f",[1e+22;1e13])
Error after using fsolve:
Thx in advance
The first thing I'd do would be to change the call to
[x,val,info]=fsolve("f",[1e+22;1e13],options)
and experiment with options. In this example, it's easy to find the Jacobian of f analytically, so I'd provide that as the second output of f, and put options.Jacobian="on" Another potentially helpful option is AutoScaling = "on", to deal with variables of different scales.
But these don't help much in the specific example, because it's really badly scaled. Here's what the equations actually are:
0.0017615*x(1)*x(2) + (8.346e-21)*x(1) = -227
0.0015505*x(1)*x(2) + (8.051e-21)*x(1) = -219
This becomes a linear system if we introduce a new variable z = x(1)*x(2). But even as a linear system, it's so badly scaled than the solver is likely to give up. Instead, let's introduce z = (1e+15)*x(1)*x(2), which amounts to multiplying the first column by 1e-15. Then the linear solver returns
z = 96810.712
x(2) = -2.720e+22
and so x(1) = -3.559e-33
This is kind of insane scale disparity, which makes one wonder if the results are meaningful at all, given that you had 3-5 significant digits in your coefficients.
Related
I have a variable of a that is equal to (weight./(1360*pi)).^(1/3), where the weight ranges between 4 and 8kg.
I then have guess of the time taken ,which is 14400 seconds.
The function in question is attached, where infinity is replaced by k=22.
Function in question
This function should be equal to 57/80
r/a can be replaced by 0.464, meaning that the multiplication of the summation can be written as 2/(0.464*pi).
alpha will be equal to 0.7*10^-7
How would i be able to plot the times taken for the masses to cook in hours, for weight in the given range?
I have tried to code this function for a couple of days now but it wont seem to work, due to array size issues and the general function just not working.
Any help would be greatly appreciated :)
First, you need a master equation as a function of weight and t, which you want fsolve to find the zero of. Then for each weight, you can capture it in another function that you then solve for t:
alpha = 0.7e-7;
rbya = 0.464;
k = 1:22;
a = #(weight)(weight./(1360*pi)).^(1/3);
eqn = #(weight,t)2/pi/rbya*sum((-1).^(k-1)./k.*sin(k*pi*rbya).*exp(-1.*k.^2.*pi^2.*alpha.*t./(a(weight).^2)))-57/80;
weights = 4:8;
ts = zeros(size(weights));
for i = 1:numel(weights)
sub_eqn = #(t)eqn(weights(i),t);
ts(i)=fsolve(sub_eqn,14400);
end
plot(weights,ts/(60*60))
xlabel("Weight (kg)")
ylabel("Cooking Time (hrs)")
If you want to solve the entire set of equations at once, then you need to be careful of array sizes (as you have experienced, read more here). k should be a column vector so that sum will sum along each column, and weights should be a row vector so that element-wise operations will repeat the k’s for each weight. You also need your list of initial guesses to be the same size as weights so that fsolve can have a guess for each weight:
alpha = 0.7e-7;
rbya = 0.464;
k = (1:22)';
a = #(weight)(weight./(1360*pi)).^(1/3);
weights = 4:8;
eqn = #(t)2/pi/rbya*sum((-1).^(k-1)./k.*sin(k*pi*rbya).*exp(-1.*k.^2.*pi^2.*alpha.*t./(a(weights).^2)))-57/80;
ts=fsolve(eqn,repmat(14400,size(weights)));
plot(weights,ts/(60*60))
xlabel("Weight (kg)")
ylabel("Cooking Time (hrs)")
Note that you do get slightly different answers with the two 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:
I am trying to compute the maximum value of the solution of a system with two ODEs using Octave. I have firstly solved the system itself:
function xdot = f (x,t)
a1=0.00875;
a2=0.075;
b1=7.5;
b2=2.5;
d1=0.0001;
d2=0.0001;
g=4*10^(-8);
K1=5000;
K2=2500;
n=2;
m=2;
xdot = zeros(2,1);
xdot(1) = a1+b1*x(1)^n/(K1^n+x(1)^n)-g*x(1)*x(2)-d1*x(1);
xdot(2) = a2+b2*x(1)^m/(K2^m+x(1)^m)-d2*x(2);
endfunction
t = linspace(0, 5000, 200)';
x0 = [1000; 1000];
x = lsode ("f", x0, t);
set term dumb;
plot(t,x);
But now I do not know how to compute the maximum value of the two functions (numerical ones) obtained as solutions of the system. I have searched in the Internet but I haven't found what I want... I only have found the function fminbnd for the minimum of a function on an interval...
Is it possible to compute the maximum value of a numeric function with Octave?
Generally, if you know how to find the minimum of a function, you also know how to find its maximum: just look for the minimum of -f.
However, fminbnd is designed for functions that can be evaluated at any given point. What you have is just a vector of 200 points. In principle, you could use interpolation to get a function and then maximize that. But this is not really needed, because all the information you have is in that matrix x anyway, so it makes sense to just take the maximum value there. Like this:
[x1m, i1] = max(x(:,1));
[x2m, i2] = max(x(:,2));
disp(sprintf('Maximum of x1 is %f attained at t = %f', x1m, t(i1)));
disp(sprintf('Maximum of x1 is %f attained at t = %f', x2m, t(i2)));
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').
Within my daily work, I have got to maximize a particular function making use of fminsearch; the code is:
clc
clear all
close all
f = #(x,c,k) -(x(2)/c)^3*(((exp(-(x(1)/c)^k)-exp(-(x(2)/c)^k))/((x(2)/c)^k-(x(1)/c)^k))-exp(-(x(3)/c)^k))^2;
c = 10.1;
k = 2.3;
X = fminsearch(#(x) f(x,c,k),[4,10,20]);
It works fine, as I expect, but not the issue is coming up: I need to bound x within certain limits, as:
4 < x(1) < 5
10 < x(2) < 15
20 < x(3) < 30
To achieve the proper results, I should use the optimization toolbox, that I unfortunately cannot hand.
Is there any way to get the same analysis by making use of only fminsearch?
Well, not using fminsearch directly, but if you are willing to download fminsearchbnd from the file exchange, then yes. fminsearchbnd does a bound constrained minimization of a general objective function, as an overlay on fminsearch. It calls fminsearch for you, applying bounds to the problem.
Essentially the idea is to transform your problem for you, in a way that your objective function sees as if it is solving a constrained problem. It is totally transparent. You call fminsearchbnd with a function, a starting point in the parameter space, and a set of lower and upper bounds.
For example, minimizing the rosenbrock function returns a minimum at [1,1] by fminsearch. But if we apply purely lower bounds on the problem of 2 for each variable, then fminsearchbnd finds the bound constrained solution at [2,4].
rosen = #(x) (1-x(1)).^2 + 105*(x(2)-x(1).^2).^2;
fminsearch(rosen,[3 3]) % unconstrained
ans =
1.0000 1.0000
fminsearchbnd(rosen,[3 3],[2 2],[]) % constrained
ans =
2.0000 4.0000
If you have no constraints on a variable, then supply -inf or inf as the corresponding bound.
fminsearchbnd(rosen,[3 3],[-inf 2],[])
ans =
1.4137 2
Andrey has the right idea, and the smoother way of providing a penalty isn't hard: just add the distance to the equation.
To keep using the anonymous function:
f = #(x,c,k, Xmin, Xmax) -(x(2)/c)^3*(((exp(-(x(1)/c)^k)-exp(-(x(2)/c)^k))/((x(2)/c)^k-(x(1)/c)^k))-exp(-(x(3)/c)^k))^2 ...
+ (x< Xmin)*(Xmin' - x' + 10000) + (x>Xmax)*(x' - Xmax' + 10000) ;
The most naive way to bound x, would be giving a huge penalty for any x that is not in the range.
For example:
function res = f(x,c,k)
if x(1)>5 || x(1)<4
penalty = 1000000000000;
else
penalty = 0;
end
res = penalty - (x(2)/c)^3*(((exp(-(x(1)/c)^k)-exp(-(x(2)/c)^k))/((x(2)/c)^k-(x(1)/c)^k))-exp(-(x(3)/c)^k))^2;
end
You can improve this approach, by giving the penalty in a smoother way.