I've created a simple simpson_adaptive method that uses my own simpson method.
My simpson method is correct, but my adaptive method does not seem to work for
integral( sin(2*pi*x)² ) ranging from -1 to 1
The following code represents the adaptive simpson method.
The parameters stand for the function, [a,b] being the interval for the integral and e being the precision.
function I = simpson_adaptief(f,a,b,e)
I1 = simpson(f,a,b,2);
I2 = simpson(f,a,b,4);
if (abs(I1-I2)<e)
I = I2;
else
I = simpson_adaptief(f,a,(a+b)/2,e) + simpson_adaptief(f,(a+b)/2,b,e);
end
end
n here being the amount of parts the function is being split into.
function I = simpson(f,a,b,n)
h = (b-a)/(n);
p=0;
q=0;
for k=1:2:(n-1)
x=a+h*k;
p=p+f(x);
end
for k=2:2:(n-1)
x=a+h*k;
q=q+f(x);
end
I = h/3*(f(a)+f(b)+4*p+2*q);
end
Do you guys have any suggestions on what the possible cause of the problem could be?
Other functions seem to work.
EDIT: I think it has something to do with my if abs(I1-I2)<e. When I change it to abs(I1-I2)>e, it works, as my program then does the recursion step first.
Thanks in advance!
I'm pretty new to matlab, but is it possible to call for the function you are creating inside that same function file? That is what I see in your simpson_adaptief function
Related
To solve one dimensional advection equation denoted by
u_t+u_x = 0, u=u(x,t), and i.c. u(x,0)= 1+H(x+1)+H(x-1)
using Lax Wanderoff method,
I need to write a Heaviside step function H(x) and it needs to be zero when x <= 0, 1 when x>0 . The problem is I also need to use that function writing H(x-t+1), H(x-t-1) as I will compare what I find by the exact solution:
u(x,t) =1 + H(x-t+1) -H(x-t-1)
Here, the "x" and "t" are vectors such that;
x=-5:0.05:5
t=0:0.05:1
I wrote the Heaviside step function as the following; however, I need it without the for loop.
L=length(x)
function H_X= heavisidefunc(x,L)
H_X=zeros(1,L);
for i= 1:L
if x(i)<= 0
H_X(i)=0;
else
H_X(i)=1;
end
end
end
I get "Dimensions must agree." error if I write
H_X3 = heavisidefunc(x-t+1,L);
H_X4 = heavisidefunc(x-t-1,L);
The Heavyside function is really easy to program in Matlab
Heavyside=#(x) x>= 0;
The easiest way to get rid of the dimensions must agree error is to transpose one of the vectors. This will cause Matlab to construct a matrix of length(x1) by length(x2)
Heavyside(x-t'+1);
I came up with a solution. My new Heaviside function is;
function H_X= heavisidefunc(x)
if x<= 0
H_X=0;
else
H_X=1;
end
end
The problem I had was because I was storing the output as a vector and it just complicated things.
Now,writing H(x-t+1), H(x-t-1) is easier. Just put "heavisidefunc(x(i)-t(j)-1)" and loop from 1 to the length of x and l in two loops. Thanks to everyone!
I have something similar to the following block diagram on Simulink, which looks rather messy especially with an increasing number of blocks.
I want to replace a 3-point summing block with a function block, while keeping the same output.
First I started by placing the code inside the function block:
function y = fcn(u)
sys1 = tf(0.5,[1 0 0 4]);
sys2 = tf([3 0.5],[1 0 15]);
sys3 = tf(1,[1 1]);
y = sys1 + sys2 + sys3;
However I was greeted with an error saying that Simulink does not support code generation.
"The 'tf' class does not support code generation."
I then came across a similar problem here: https://nl.mathworks.com/matlabcentral/answers/74770-is-there-any-way-to-disable-code-generation-in-simulink
I am trying to implement an extrinsic function or 'wrapper function' with some difficulty. I created a new script called myWrapper.m, containing the same code:
function y = myWrapper(u)
sys1 = tf(0.5,[1 0 0 0 4]);
sys2 = tf([3 5],[1 0 15]);
sys3 = tf(1,[1 1]);
y = sys1 + sys2 + sys3;
and the MATLAB Function edited to:
function y1 = fcn(u1)
y1 = myWrapper(u1);
The error persists.
I somehow want to access myWrapper.m file from the MATLAB Function block. Any pointers on how this should be done? Following the previous link given and the official docs I am ending up with something like this in my MATLAB Function block:
function y1 = fcn(u1)coder.extrinsic('myWrapper')
y1 = myWrapper(u1);
The last code above is syntactically incorrect and I am at a loss on how it should be done. MATLAB automaticaly corrects the above code to:
function y1 = fcn(u1,coder,extrinsic, myWrapper )
y1 = myWrapper(u1);
which is not what I want.
Any tips and/or suggestions on how this could be done would be appreciated.
A similar question was asked on the MathWorks forum here, two years ago, with no response.
I was going about tackling this problem completely wrong. Thanks to several helpful comments I realized that in order to replace the summing block, one must NOT remove the Transfer Function blocks which feed into the summing block.
A MATLAB Function does not support code generation (and rightly so) such that a transfer function may be implemented inside it. That is why the blocks simply feed into the MATLAB Function as follows.
The script would very simply be:
function y1 = fcn(u1, u2, u3)
x = (u1 + u2 +u3);
y1 = x;
end
Is there a function that can repeat a segment of code for a given number of times?
for example:
t= 0;
while (t< 10)
if x==2
x=1
else
x=3;
end
end
How can i rewrite this function using another function ?
A recursive function can do this for you (assuming you can't use: for,while,repeat).
http://www.matrixlab-examples.com/recursion.html
Or, if the code executed in one iteration is independent on the results of other iterations, you can use arrayfun or cellfun.
For instance
fun = #(x) disp(['hello ' , num2str(x)]);
arrayfun(fun,1:5);
returns
hello 1
hello 2
hello 3
hello 4
hello 5
Personally I do like these constructs because I find them very expressive just as std::for_each in C++.
Nonetheless, they have proven to be slower than their naive-loop counterparts which get JITed away by Matlab (there are several Q/A about this issue here on SO).
Matlab automatically 'repeats' the code for you if you put it in a vector format:
x_vector = round(2*rand(10,1)) %Your x input
idx = (x_vector==2)
x_vector(idx) = 1;
x_vector(~idx) = 3;
The code in question is here:
function k = whileloop(odefun,args)
...
while (sign(costheta) == originalsign)
y=y(:) + odefun(0,y(:),vars,param)*(dt); % Line 4
costheta = dot(y-normpt,normvec);
k = k + 1;
end
...
end
and to clarify, odefun is F1.m, an m-file of mine. I pass it into the function that contains this while-loop. It's something like whileloop(#F1,args). Line 4 in the code-block above is the Euler method.
The reason I'm using a while-loop is because I want to trigger upon the vector "y" crossing a plane defined by a point, "normpt", and the vector normal to the plane, "normvec".
Is there an easy change to this code that will speed it up dramatically? Should I attempt learning how to make mex files instead (for a speed increase)?
Edit:
Here is a rushed attempt at an example of what one could try to test with. I have not debugged this. It is to give you an idea:
%Save the following 3 lines in an m-file named "F1.m"
function ydot = F1(placeholder1,y,placeholder2,placeholder3)
ydot = y/10;
end
%Run the following:
dt = 1.5e-12 %I do not know about this. You will have to experiment.
y0 = [.1,.1,.1];
normpt = [3,3,3];
normvec = [1,1,1];
originalsign = sign(dot(y0-normpt,normvec));
costheta = originalsign;
y = y0;
k = 0;
while (sign(costheta) == originalsign)
y=y(:) + F1(0,y(:),0,0)*(dt); % Line 4
costheta = dot(y-normpt,normvec);
k = k + 1;
end
disp(k);
dt should be sufficiently small that it takes hundreds of thousands of iterations to trigger.
Assume I must use the Euler method. I have a stochastic differential equation with state-dependent noise if you are curious as to why I tell you to take such an assumption.
I would focus on your actual ODE integration. The fewer steps you have to take, the faster the loop will run. I would only worry about the speed of the sign check after you've optimized the actual integration method.
It looks like you're using the first-order explicit Euler method. Have you tried a higher-order integrator or an implicit method? Often you can increase the time step significantly.
Let's say I want to take the sin of 1 through 100 (in degrees).
I come from a C background so my instinct is to loop 1 through 100 in a for loop (something I can do in Matlab). In a matrix/vector/array I would store sin(x) where x is the counter of the for loop.
I cannot figure out how to do this in Matlab. Do I create a array like
x = [1 .. 100];
And then do
x[offset] = numberHere;
I know the "correct" way. For operations like addition you use .+ instead of + and with a function like sin I'm pretty sure you just do
resultArray = sin(x);
I just want to know that I could do it the C way in case that ever came up, thus my question here on SO. :)
% vectorized
x = sin((1:100)*pi/180);
or
% nonvectorized
x=[];
for i = 1:100
x(i) = sin(i*pi/180);
end
I beleive this can actually be done as a one liner in MatLab:
x = sind(1:100);
Note that you use sind() instead of sin(). Sin() takes radians as arguments.
As others have already pointed out there are for-loops in MATLAB as well.
help for
should give you everything you need about how it works. The difference from C is that the loop can go over objects and not only an integer:
objects = struct('Name', {'obj1', 'obj2'}, 'Field1', {'Value1','Value2'});
for x = objects
disp(sprintf('Object %s Field1 = %d', x.Name, x.Field1))
end
That example will output:
Object obj1 Field1 = Value1
Object obj2 field1 = Value2
This could have been done as
for i=1:length(objects)
x = objects(i);
disp(sprintf('Object %s Field1 = %d', x.Name, x.Field1))
end
And now to what I really wanted to say: If you ever write a for loop in MATLAB, stop and think!. For most tasks you can vectorize the code so that it uses matrix operations and builtin functions instead of looping over the data. This usually gives a huge speed gain. It is not uncommon that vectorized code executes 100x faster than looping code. Recent versions of MATLAB has JIT compilation which makes it less dramatic than before, but still: Always vectorize if you can.
#Daniel Fath
I think you'll need the final line to read
resultArray(i) = sin(x(i)) (rather than x(1))
I think you can also do:
for i = x
...
though that will behave differently if x is not a simple 1-100 vector
Hmm, if understand correctly you want a loop like structure
resultArray = zeros(1,length(x)) %% initialization aint necessary I just forgot how you dynamically add members :x
for i = 1:length(x) %% starts with 1 instead of zero
resultArray(i) = sin(x(i))
end
Warning I didn't test this but it should be about right.