Get integrated vector values - matlab

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);

Related

Generating iterative sequence without using for-loop

I want to generate a random series x with length N through the following rule related to non-central chi-square distribution:
xn+1~χν2(λxn)
where ν is a given constant representing degrees of freedom, λ is also pre-specified and the multiplication of λ and xn is the non-centrality parameter, x1 is supposed to be given.
I wrote the following code to generate such sequence and time the running with x1=0.04, ν=0.005, λ=100 and N=1e5:
tic;
N = 1e5;
x = zeros(1,N);
x(1) = 0.04;
nu = 0.005;
lambda = 100;
for i = 1:N-1
x(i+1) = ncx2rnd(nu,lambda*x(i));
end
toc;
To illustrate my question, I have tested another example, which is different from above. Here I considered generating N=1e5 samples from the distribution χν2(λ) with ν=0.005 and λ=100:
tic;
N = 1e5;
x = zeros(1,N);
nu = 0.005;
lambda = 100;
for i = 1:N
x(i) = ncx2rnd(nu,lambda);
end
toc;
tic;
N = 1e5;
nu = 0.005;
lambda = 100;
x = ncx2rnd(nu,lambda*ones(1,N));
toc;
These two approaches work equivalently. However, it turns out that the second approach which does not use for-loop is much faster than the first one. The difference between both examples is, in the second example, the rule to generate some sample does not require the information of previous samples, which is not the case in the first, therefore all samples can be generated simultaneously without using for-loop. Based on this I wonder whether avoiding for-loop would accelerate the code execution. So would there be any MATLAB built-in function to generate random series shown in the first example without using for-loop when the rule of dependence on previous samples is explicit? If the rule is linear I know the function filter would be a possible choice, what about cases like the first example?
Logically it's impossible to calculate something iterative without doing the iterations. If x(n+1) is dependent on x(n) then you must calculate x(n) first, there is no "clever trick" here.
That just leaves us to optimise the calculation within the loop, specifically ncx2rnd. As with most MATLAB in-built functions, it is already fairly concise and performant, but there are some things to consider. Note that what I'm about to suggest involves using edit ncx2nrd to look inside this in-built function which contains code under MathWorks copyright, I'm simply noting observations about how it works.
There are some input checks to handle incorrectly sized inputs and/or inputs with negative values. If you can take the burden of validation on yourself (i.e. you know your inputs are valid) then you can reduce the function to its single mathematical operation:
% function r = ncx2rnd(v,delta)
r = 2.*randg(poissrnd(delta./2, sizeOut)) + 2.*randg(v./2,sizeOut);
Running this standalone saves around 20% of the processing time, which was for input validation (with a nominal N=1e5).
In the MathWorks syntax, delta is equal to your lambda*x(i), the other term including v is independent of your x, so you could compute it outside of the loop, i.e. vectorising one of the calls to randg. Again using N=1e5 this brings the total time saving to around 25%.
The result would mean this change to your example:
% Common inputs
N = 1e5;
nu = 0.1;
lambda = 0.1;
% Baseline example
x = zeros(1,N);
x(1) = 0.04;
for i = 1:N-1
x(i+1) = ncx2rnd(nu,lambda*x(i));
end
% ~25% faster alternative, with no input validation and partially vectorised
x = zeros(1,N);
x(1) = 0.04;
vTerm = 2.*randg(nu./2, [1,N]);
for i = 1:N-1
x(i+1) = 2.*randg(poissrnd(lambda*x(i)./2, [1,1])) + vTerm(i);
end

find the line which best fits to the data

I'm trying to find the line which best fits to the data. I use the following code below but now I want to have the data placed into an array sorted so it has the data which is closest to the line first how can I do this? Also is polyfit the correct function to use for this?
x=[1,2,2.5,4,5];
y=[1,-1,-.9,-2,1.5];
n=1;
p = polyfit(x,y,n)
f = polyval(p,x);
plot(x,y,'o',x,f,'-')
PS: I'm using Octave 4.0 which is similar to Matlab
You can first compute the error between the real value y and the predicted value f
err = abs(y-f);
Then sort the error vector
[val, idx] = sort(err);
And use the sorted indexes to have your y values sorted
y2 = y(idx);
Now y2 has the same values as y but the ones closer to the fitting value first.
Do the same for x to compute x2 so you have a correspondence between x2 and y2
x2 = x(idx);
Sembei Norimaki did a good job of explaining your primary question, so I will look at your secondary question = is polyfit the right function?
The best fit line is defined as the line that has a mean error of zero.
If it must be a "line" we could use polyfit, which will fit a polynomial. Of course, a "line" can be defined as first degree polynomial, but first degree polynomials have some properties that make it easy to deal with. The first order polynomial (or linear) equation you are looking for should come in this form:
y = mx + b
where y is your dependent variable and X is your independent variable. So the challenge is this: find the m and b such that the modeled y is as close to the actual y as possible. As it turns out, the error associated with a linear fit is convex, meaning it has one minimum value. In order to calculate this minimum value, it is simplest to combine the bias and the x vectors as follows:
Xcombined = [x.' ones(length(x),1)];
then utilized the normal equation, derived from the minimization of error
beta = inv(Xcombined.'*Xcombined)*(Xcombined.')*(y.')
great, now our line is defined as Y = Xcombined*beta. to draw a line, simply sample from some range of x and add the b term
Xplot = [[0:.1:5].' ones(length([0:.1:5].'),1)];
Yplot = Xplot*beta;
plot(Xplot, Yplot);
So why does polyfit work so poorly? well, I cant say for sure, but my hypothesis is that you need to transpose your x and y matrixies. I would guess that that would give you a much more reasonable line.
x = x.';
y = y.';
then try
p = polyfit(x,y,n)
I hope this helps. A wise man once told me (and as I learn every day), don't trust an algorithm you do not understand!
Here's some test code that may help someone else dealing with linear regression and least squares
%https://youtu.be/m8FDX1nALSE matlab code
%https://youtu.be/1C3olrs1CUw good video to work out by hand if you want to test
function [a0 a1] = rtlinreg(x,y)
x=x(:);
y=y(:);
n=length(x);
a1 = (n*sum(x.*y) - sum(x)*sum(y))/(n*sum(x.^2) - (sum(x))^2); %a1 this is the slope of linear model
a0 = mean(y) - a1*mean(x); %a0 is the y-intercept
end
x=[65,65,62,67,69,65,61,67]'
y=[105,125,110,120,140,135,95,130]'
[a0 a1] = rtlinreg(x,y); %a1 is the slope of linear model, a0 is the y-intercept
x_model =min(x):.001:max(x);
y_model = a0 + a1.*x_model; %y=-186.47 +4.70x
plot(x,y,'x',x_model,y_model)

How to perform indefinite integration of this function in MATLAB?

I need to perform the following operations as shown in the image. I need to calculate the value of function H for different inputs(x) using MATLAB.
I am giving the following command from Symbolic Math Toolbox
syms y t x;
f1=(1-exp(-y))/y;
f2=-t+3*int(f1,[0,t]);
f3=exp(f2);
H=int(f3,[0,x]);
but the value of 2nd integral i.e. integral in the function H can't be calculated and my output is of the form of
H =
int(exp(3*eulergamma - t - 3*ei(-t) + 3*log(t)), t, 0, x)
If any of you guys know how to evaluate this or have a different idea about this, please share it with me.
Directly Finding the Numerical Solution using integral:
Since you want to calculate H for different values of x, so instead of analytical solution, you can go for numerical solution.
Code:
syms y t;
f1=(1-exp(-y))/y; f2=-t+3*int(f1,[0,t]); f3=exp(f2);
H=integral(matlabFunction(f3),0,100) % Result of integration when x=100
Output:
H =
37.9044
Finding the Approximate Analytical Solution using Monte-Carlo Integration:
It probably is an "Elliptic Integral" and cannot be expressed in terms of elementary functions. However, you can find an approximate analytical solution using "Monte-Carlo Integration" according to which:
where f(c) = 1/n Σ f(xᵢ)
Code:
syms x y t;
f1=(1-exp(-y))/y; f2=-t+3*int(f1,[0,t]); f3=exp(f2);
f3a= matlabFunction(f3); % Converting to function handle
n = 1000;
t = x*rand(n,1); % Generating random numbers within the limits (0,x)
MCint(x) = x * mean(f3a(t)); % Integration
H= double(MCint(100)) % Result of integration when x=100
Output:
H =
35.2900
% Output will be different each time you execute it since it is based
% on generation of random numbers
Drawbacks of this approach:
Solution is not exact but approximated.
Greater the value of n, better the result and slower the code execution speed.
Read the documentation of matlabFunction, integral, Random Numbers Within a Specific Range, mean and double for further understanding of the code(s).

Fourier Transforms in MatLab

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');

Can someone explain how to graph this sum in MATLAB using contourf?

I'm going to start off by stating that, yes, this is homework (my first homework question on stackoverflow!). But I don't want you to solve it for me, I just want some guidance!
The equation in question is this:
I'm told to take N = 50, phi1 = 300, phi2 = 400, 0<=x<=1, and 0<=y<=1, and to let x and y be vectors of 100 equally spaced points, including the end points.
So the first thing I did was set those variables, and used x = linspace(0,1) and y = linspace(0,1) to make the correct vectors.
The question is Write a MATLAB script file called potential.m which calculates phi(x,y) and makes a filled contour plot versus x and y using the built-in function contourf (see the help command in MATLAB for examples). Make sure the figure is labeled properly. (Hint: the top and bottom portions of your domain should be hotter at about 400 degrees versus the left and right sides which should be at 300 degrees).
However, previously, I've calculated phi using either x or y as a constant. How am I supposed to calculate it where both are variables? Do I hold x steady, while running through every number in the vector of y, assigning that to a matrix, incrementing x to the next number in its vector after running through every value of y again and again? And then doing the same process, but slowly incrementing y instead?
If so, I've been using a loop that increments to the next row every time it loops through all 100 values. If I did it that way, I would end up with a massive matrix that has 200 rows and 100 columns. How would I use that in the linspace function?
If that's correct, this is how I'm finding my matrix:
clear
clc
format compact
x = linspace(0,1);
y = linspace(0,1);
N = 50;
phi1 = 300;
phi2 = 400;
phi = 0;
sum = 0;
for j = 1:100
for i = 1:100
for n = 1:N
sum = sum + ((2/(n*pi))*(((phi2-phi1)*(cos(n*pi)-1))/((exp(n*pi))-(exp(-n*pi))))*((1-(exp(-n*pi)))*(exp(n*pi*y(i)))+((exp(n*pi))-1)*(exp(-n*pi*y(i))))*sin(n*pi*x(j)));
end
phi(j,i) = phi1 - sum;
end
end
for j = 1:100
for i = 1:100
for n = 1:N
sum = sum + ((2/(n*pi))*(((phi2-phi1)*(cos(n*pi)-1))/((exp(n*pi))-(exp(-n*pi))))*((1-(exp(-n*pi)))*(exp(n*pi*y(j)))+((exp(n*pi))-1)*(exp(-n*pi*y(j))))*sin(n*pi*x(i)));
end
phi(j+100,i) = phi1 - sum;
end
end
This is the definition of contourf. I think I have to use contourf(X,Y,Z):
contourf(X,Y,Z), contourf(X,Y,Z,n), and contourf(X,Y,Z,v) draw filled contour plots of Z using X and Y to determine the x- and y-axis limits. When X and Y are matrices, they must be the same size as Z and must be monotonically increasing.
Here is the new code:
N = 50;
phi1 = 300;
phi2 = 400;
[x, y, n] = meshgrid(linspace(0,1),linspace(0,1),1:N)
f = phi1-((2./(n.*pi)).*(((phi2-phi1).*(cos(n.*pi)-1))./((exp(n.*pi))-(exp(-n.*pi)))).*((1-(exp(-1.*n.*pi))).*(exp(n.*pi.*y))+((exp(n.*pi))-1).*(exp(-1.*n.*pi.*y))).*sin(n.*pi.*x));
g = sum(f,3);
[x1,y1] = meshgrid(linspace(0,1),linspace(0,1));
contourf(x1,y1,g)
Vectorize the code. For example you can write f(x,y,n) with:
[x y n] = meshgrid(-1:0.1:1,-1:0.1:1,1:10);
f=exp(x.^2-y.^2).*n ;
f is a 3D matrix now just sum over the right dimension...
g=sum(f,3);
in order to use contourf, we'll take only the 2D part of x,y:
[x1 y1] = meshgrid(-1:0.1:1,-1:0.1:1);
contourf(x1,y1,g)
The reason your code takes so long to calculate the phi matrix is that you didn't pre-allocate the array. The error about size happens because phi is not 100x100. But instead of fixing those things, there's an even better way...
MATLAB is a MATrix LABoratory so this type of equation is pretty easy to compute using matrix operations. Hints:
Instead of looping over the values, rows, or columns of x and y, construct matrices to represent all the possible input combinations. Check out meshgrid for this.
You're still going to need a loop to sum over n = 1:N. But for each value of n, you can evaluate your equation for all x's and y's at once (using the matrices from hint 1). The key to making this work is using element-by-element operators, such as .* and ./.
Using matrix operations like this is The Matlab Way. Learn it and love it. (And get frustrated when using most other languages that don't have them.)
Good luck with your homework!