I have a long vector
acceleration=[6.45, 6.50, 6.52, 6.32, .... , 4.75]
Already obtained from a simulink (takes a very long time to run the simulink model again). And assume the step time is constant dt=0.1
Is there any way to find the final position numerically?
I know there is a trapz function an I know that MATLAB supports 2D integration and I know that integration inside simulink is an option. However, is there any way to take double integration:
final_position= integrate integrate acceleration dt^2
Numerically, with a precision not worse than trapezoidal method?
I prefer to avoid loop based solution.
Using the trapezoidal rule:
vinit = 0; % initial velocity
pinit = 0; % initial position
velocity = zeros(size(acceleration)) + vinit; % velocity vector
position = zeros(size(acceleration)) + pinit; % position vector
velocity(2:end) = velocity(2:end) + 0.5 * dt * cumsum(acceleration(2:end)+acceleration(1:end-1));
position(2:end) = position(2:end) + 0.5 * dt * cumsum( velocity(2:end)+ velocity(1:end-1));
I'm using cumsum() (cumulative sum) to calculate the integral at each point, not just the overall sum; this means that the velocity can be integrated again to get the position. The final position is obviously position(end).
I'm not aware of a built in function that does what you want. My suggestion would be to build your own. The function trapz is taking the integral along the entire domain and hence gives you one value. Since you want to take the second integral you first need to produce a vector of values that correspond to the first integral. This is accomplished by integrating increasingly large steps of the original vector.
acceleration = [6.45, 6.50, 6.52, 6.32, .... , 4.75];
velocity = zeros(size(acceleration));
for i = 1:length(acceleration),
velocity(i) = trapz(acceleration(1:i))*dt;
end
p = trapz(velocity)*dt;
I know this uses a loop but maybe it can help you get started. Good luck.
Another approach is to turn your second order differential equation into a first order one.
Your equation is
X''(t) = a(t);
X(0) = x_0;
X'(0) = x_p_0;
Now if you define u1(t) = X(t); u2(t) = X'(t), you will get
U'(t) = A*U(t) + a(t)
where
U(t) = [u1(t);u2(t)]
A = [0 1
0 0]
Then you can use any solver (say ode45) to solve this U(t) vector. The second component of the vector is the position. It's error bounds is much smaller than trapz like functions. Also matlab has many optimizations inside the solvers they implemented.
Related
I am trying to calculate the torque an ellipsoid gets in a gravity field. In theory, the torque the ellipsoid gets should become zero as alpha goes to zero. However, MATLAB returned a nonzero value for the following integral:
e = 1/1737100/10^2;
D = 384399000;
G = 6.6743*10^(-11);
R = 1737100;
M = 5.97237*10^24;
alpha = 0;
dT = #(r,theta,phi) ((1+e).*sin(theta).*sin(phi).*sin(alpha)+cos(theta).*cos(alpha)).*r.^3.*sin(theta)./(r.^2+D.^2-2.*r.*D.*((1+e).*sin(theta).*sin(phi).*cos(alpha)-cos(theta)*sin(alpha))).^(3./2);
Torque = G.*M.*D.*(1+e).*integral3(dT,0,R,0,pi,0,2*pi)
I guess this is because that integral3 just inputs a matrix into the equation to get the numerical solution. So I am wondering, is there any numerical method which we can use to get a more accurate solution than integral3? Ideally computational time shouldn't be too high and of course, if an analytical solution exists, I'd be happy to hear about that.
I wish to create a limit cycle in Matlab. A limit cycle looks something like this:
I have no idea how to do it though, I've never done anything like this in Matlab.
The equations to describe the limit cycle are the following:
x_1d=x_2
x_2d=-x_1+x_2-2*(x_1+2*x_2)x_2^2
It is to be centered around the equilibrium which is (0,0)
Can any of you help me?
If you use the partial derivatives of your function to make a vector field, you can then use streamlines to visualize the cycle that you are describing.
For example, the function f = x^2+y^2
Gives me partial derivatives dx = 2x, dy=2y For the visualization, I sample from the partial derivatives over a grid.
[x,y] = meshgrid(0:0.1:1,0:0.1:1);
dx = 2*x;
dy = 2*y;
To visualize the vector field, I use quiver;
figure;
quiver(x, y, dx, dy);
Using streamline, I can visualize the path a particle injected into the vector field would take. In my example, I inject the particle at (0.1, 0.1)
streamline(x,y, dx, dy, 0.1, 0.1);
This produces the following visualization
In your case, you can omit the quiver step to remove the hedgehog arrows at every grid point.
Here's another example that shows the particle converging to an orbit.
Edit: Your function specifically.
So as knedlsepp points out, the function you are interested in is a bit ambiguously stated. In Matlab, * represents the matrix product while .* represents the element-wise multiplication between matrices. Similarly, '^2' represents MM for a matrix M, while .^2 represents taking the element-wise power.
So,
[x_1,x_2] = meshgrid(-4:0.1:4,-4:0.1:4);
dx_1 = x_2;
dx_2 = -x_1+x_2-2*(x_1+2*x_2)*(x_2)^2;
figure; streamline(x_1,x_2, dx_1, dx_2, 0:0.1:4, 0:0.1:4);
Looks like
This function will not show convergence because it doesn't converge.
knedlsepp suggests that the function you are actually interested in is
dx_1 = -1 * x_2;
dx_2 = -1 * -x_1+x_2-2*(x_1+2*x_2).*(x_2).^2;
His post has a nice description of the rest.
This post shows the code to produce the integral lines of your vector field defined by:
dx/dt = y
dy/dt = -x+y-2*(x+2*y)*y^2.
It is important to properly vectorize this function. (i.e. Introducing dots at all the important places)
dxdt = #(x,y) y;
dydt = #(x,y) -x+y-2*(x+2*y).*y.^2;
[X,Y] = meshgrid(linspace(-4,4,100));
[sx,sy] = meshgrid(linspace(-3,3,20));
streamline(stream2(X, Y, ... % Points
dxdt(X,Y), dydt(X,Y),... % Derivatives
sx, sy)); % Starting points
axis equal tight
To get a picture more similar to yours, change the grid size and starting points:
[X,Y] = meshgrid(linspace(-1,1,100));
[sx,sy] = meshgrid(linspace(0,0.75,20),0.2);
I am trying to integrate the sine-function. My goal is to get not just the value of the area inbetween a certain distance but the specific values of the integrated course.
One way to achieve this is by using cumtrapz. I want to get the same result using integral or quad. So I am wondering if there is something like cumquad?
I tried to write something for myself but it works very slow and seems to be even worse than cumtrapz. Later on I want to integrate measured data. So it won't be as simple as a sine.
Here is my current code:
a = 0; b = 10;
x = a:0.1:b;
y = 2*sin(3*x);
pp = spline(x,y);
y2=zeros(1,length(y));
y3=zeros(1,length(y));
y2(1)=integral(#(x)ppval(pp,x),x(1),x(2));
y3(1)=integral(#(x)ppval(pp,x),x(1),x(2));
for a=2:(length(y)-1)
y2(a) = y2(a-1)+integral(#(x)ppval(pp,x),x(a-1),x(a));
y3(a) = y3(a-1)+quad(#(x)ppval(pp,x),x(a-1),x(a));
end
y4=cumtrapz(x,y);
% y5=cumsum(y);
plot(x,y)
hold on
plot(x,y2,'-ro')
plot(x,y3,'-kx')
plot(x,y4,'g')
syms x % compare with analytical result
ya=2*sin(3*x);
ya5=int(ya)+(2/3);
ezplot(x,ya5)
Using integral
I don't think there is a way to have MATLAB return the integral along the path, so you are correct in performing the integration one Δx at a time.
The slowness comes from the loop and subsequent restart of every integral call.
You can avoid the loop by posing the integral over every interval as a vector-valued function.
The Math
Suppose we divide x into N-1 intervals with N total boundaries and denote an interval boundary as xn where n ∈{1,2,3...,N} such that x1 ≤ x2 ≤ x3 ... ≤ xN.
Then any integral over the interval would be
Using the u-substitution:
The integral becomes:
where Δxn = xn - xn-1
The Code
So now, we can pose the interval integration of any function by specifying the lower bound xn-1, specifying the interval width Δx, and integrating from 0 to 1.
The best part is that if the lower bound and interval widths are vectors, we can create a vector-valued function in terms of u and have integral integrate with the option 'ArrayValued' = true.
x = a:0.1:b;
xnm1 = x(1:end-1);
dx = x(2:end) - xnm1;
fx = #(x) 2*sin(3*x);
f = #(u) dx .* fx(dx*u+xnm1);
y = cumsum([0,integral(#(u)f(u),0,1,'ArrayValued',true)]);
The cumsum accounts for the fact that each integral over a given interval needs to have the value of the previous interval added to it.
On my machine, this is at least order of magnitude faster than the loop version and gets better as the interval count increases.
Using ode45
Use can also use ode45 to perform the integration.
It is not nearly as efficient as the integral method, but it may be easier conceptually and look cleaner.
In fact, ode45 is about 10 times slower than the integral method above when required to return an absolute error on par with that of integral.
a = 0;
b = 10;
% These options are necessary to approach the accuracy of integral
opt = odeset('RelTol',100*eps(),'AbsTol',eps());
sol = ode45(#(x,y) 2*sin(3*x),[a,b],0,opt);
x = a:0.01:b;
yint = deval(sol,x);
I am working on a problem involves my using the Euler Method to approximate the differential equation df/dt= af(t)−b[f(t)]^2, both when b=0 and when b is not zero; and I am to compare the analytic solution to the approximate solution when b=0.
f(1) = 1000;
t(1)= 0;
a = 10;
b = 0 ;
dt = 0.01;
Nsteps = 10/dt;
for i = 2:Nsteps
t(i) = dt + t(i-1);
%f(i) = f(i-1)*(1 + dt*(a - b*f(i-1)));
f(i) = f(i-1)*(1 + a*dt);
end
plot(t,f,'r-')
hold on
fa= a*exp(a*t)
plot(t,fa,'bo')
When b=0, the solution to the differential equation is f(t)=c*exp(at). When I apply the initial condition, that f(0) = 1000, then the differential equation becomes f(t)=1000*exp(at). Now, my professor said that a differential equation has an analytic solution, no matter what time step you use, the graph of analytic solution and the approximation (Euler's Method) will coincide. So, I expected the two graphs to overlap. I attached a picture of what I got.
Why did this occur? In order to get the graphs to overlap, I changed 1000 to 10, which is a=10, just for the heck of it. When I did this, the two overlapped. I don't understand. What am I doing incorrectly?
Why should the numerical solution give the same answer as the analytical one? Looking at pixels overlapping on the screen is not a very precise way to discern anything. You should examine the error between the two (absolute and/or relative). You might also want to examine what happens when you change the step size. And you might want to play with a linear system as well. You don't need to integrate out so far to see these effects – just setting t equal 0.1 or 1 suffices. Here is some better-formatted code to work with:
t0 = 0;
dt = 0.01;
tf = 0.1;
t = t0:dt:tf; % No need to integrate t in for loop for fixed time step
lt = length(t);
f = zeros(1,lt); % Pre-allocate f
f0 = 1000; % Initial condition
f(1) = f0;
a = 10;
for i = 1:lt-1
f(i+1) = f(i) + a*f(i)*dt;
%f(i+1) = f(i) + a*dt; % Alternative linear system to try
end
% Analytic solution
fa = f0*exp(a*t);
%fa = f0+a*t; % Alternative linear system to try
figure;
plot(t,f,'r-',t,fa,'bo')
% Plot absolute error
figure;
plot(t,abs(f-fa))
% Plot relative error
figure;
plot(t,abs(f-fa)./fa)
You're also not preallocating any of your arrays which makes you code very inefficient. My code does. Read about that here.
Much more beyond this is really off-topic for this site, which is focussed on programming rather than mathematics. If you really have questions about the numerical details that aren't answered by reading your text book (or the Wikipedia page for the Euler method) then you should ask them at Math.StackExchange.
Numerical methods are not precise and there is always an error between numerical and analytical solution. As Euler's method is first order method, global truncation error is proportional to step of integration step.
So I have had a few posts the last few days about using MatLab to perform a convolution (see here). But I am having issues and just want to try and use the convolution property of Fourier Transforms. I have the code below:
width = 83.66;
x = linspace(-400,400,1000);
a2 = 1.205e+004 ;
al = 1.778e+005 ;
b1 = 94.88 ;
c1 = 224.3 ;
d = 4.077 ;
measured = al*exp(-((abs((x-b1)./c1).^d)))+a2;
%slit
rect = #(x) 0.5*(sign(x+0.5) - sign(x-0.5));
rt = rect(x/width);
subplot(5,1,1);plot(x,measured);title('imported data-super gaussian')
subplot(5,1,2);plot(x,(real(fftshift(fft(rt)))));title('transformed slit')
subplot(5,1,3);plot(x,rt);title('slit')
u = (fftshift(fft(measured)));
l = u./(real(fftshift(fft(rt))));
response = (fftshift(ifft(l)));
subplot(5,1,4);plot(x,real(response));title('response')
%Data Check
check = conv(rt,response,'full');
z = linspace(min(x),max(x),length(check));
subplot(5,1,5);plot(z,real(check));title('check')
My goal is to take my case, which is $measured = rt \ast signal$ and find signal. Once I find my signal, I convolve it with the rectangle and should get back measured, but I do not get that.
I have very little matlab experience, and pretty much 0 signal processing experience (working with DFTs). So any advice on how to do this would be greatly appreciated!
After considering the problem statement and woodchips' advice, I think we can get closer to a solution.
Input: u(t)
Output: y(t)
If we assume the system is causal and linear we would need to shift the rect function to occur before the response, like so:
rt = rect(((x+270+(83.66/2))/83.66));
figure; plot( x, measured, x, max(measured)*rt )
Next, consider the response to the input. It looks to me to be first order. If we assume as such, we will have a system transfer function in the frequency domain of the form:
H(s) = (b1*s + b0)/(s + a0)
You had been trying to use convolution to and FFT's to find the impulse response, "transfer function" in the time domain. However, the FFT of the rect, being a sinc has a zero crossing periodically. These zero points make using the FFT to identify the system extremely difficult. Due to:
Y(s)/U(s) = H(s)
So we have U(s) = A*sinc(a*s), with zeros, which makes the division go to infinity, which doesn't make sense for a real system.
Instead, let's attempt to fit coefficients to the frequency domain linear transfer function that we postulate is of order 1 since there are no overshoots, etc, 1st order is a reasonable place to start.
EDIT
I realized my first answer here had a unstable system description, sorry! The solution to the ODE is very stiff due to the rect function, so we need to crank down the maximum time step and use a stiff solver. However, this is still a tough problem to solve this way, a more analytical approach may be more tractable.
We use fminsearch to find the continuous time transfer function coefficients like:
function x = findTf(c0,u,y,t)
% minimize the error for the estimated
% parameters of the transfer function
% use a scaled version without an offset for the response, the
% scalars can be added back later without breaking the solution.
yo = (y - min(y))/max(y);
x = fminsearch(#(c) simSystem(c,u,y,t),c0);
end
% calculate the derivatives of the transfer function
% inputs and outputs using the estimated coefficient
% vector c
function out = simSystem(c,u,y,t)
% estimate the derivative of the input
du = diff([0; u])./diff([0; t]);
% estimate the second derivative of the input
d2u = diff([0; du])./diff([0; t]);
% find the output of the system, corresponds to measured
opt = odeset('MaxStep',mean(diff(t))/100);
[~,yp] = ode15s(#(tt,yy) odeFun(tt,yy,c,du,d2u,t),t,[y(1) u(1) 0],opt);
% find the error between the actual measured output and the output
% from the system with the estimated coefficients
out = sum((yp(:,1) - y).^2);
end
function dy = odeFun(t,y,c,du,d2u,tx)
dy = [c(1)*y(3)+c(2)*y(2)-c(3)*y(1);
interp1(tx,du,t);
interp1(tx,d2u,t)];
end
Something like that anyway should get you going.
x = findTf([1 1 1]',rt',measured',x');