Defining windows to find multiple slopes - matlab

I need to define several windows for an experimental plot for which slopes can be found. For example, x runs from 0 to 400. I want to find the derivative of each 50x (i.e. 0 to 50, 50 to 100 & so on), and then average all derivatives (8 derivatives in this example). Thanks for any helps!

Assuming you have a vector y of measurements and want to compute the derivative by taking the difference between entry 1 and 50, 51 and 100, and so on, you could do the following:
% generate a signal
x=1:400;
y = x.^2;
nSamples = length(y);
% define number of segments and window size
N = 8;
Winsize = ceil(nSamples/N);
% preallocate the vector of slopes and compute the slopes
slopes = zeros(1,N);
for ii=1:N
slopes(ii) = (y(min(nSamples,Winsize*ii))-y(1+Winsize*(ii-1)))/(x(min(nSamples,Winsize*ii))-x(1+Winsize*(ii-1)));
end
% take the average slope value
Averageslope = mean(slopes);
However, since you are using matlab anyway you could also just take the average derivative of the vector, which should yield a much more accurate average when dealing with noisy data:
% generate a signal
x=1:400;
y = x.^2;
slope = mean(diff(y)/diff(x));

Related

Vectors must be the same length error in Curve Fitting in Matlab

I'm having problems in curve fitting my randomized data for the function
Here is my code
N = 100;
mu = 5; stdev = 2;
x = mu+stdev*randn(N,1);
bin=mu-6*stdev:0.5:mu+6*stdev;
f=hist(x,bin);
plot(bin,f,'bo'); hold on;
x_ = x(1):0.1:x(end);
y_ = (1./sqrt(8.*pi)).*exp(-((x_-mu).^2)./8);
plot(x_,y_,'b-'); hold on;
It seems like I'm having vector size problems since it is giving me the error
Error using plot
Vectors must be the same length.
Note that I simplified y_ since mu and the standard deviation is known.
Plot:
Well first of all some adjustments to your question:
You are not trying to do curve fitting. What you are trying to do (in my opinion) is to overlay a probability density function on an histogram obtained by taking random points from the same distribution (A normal distribution with parameters (mu,sigma)). These two curve should indeed overlay, as they represent the same thing, only one is analytical and the other one is obtained numerically.
As seen in the hist documentation, hist is not recommended and you should use histogram instead
First step: Generating your random data
Knowing the distribution is the Normal distribution, we can use MATLAB's random function to do that :
N = 150;
rng('default') % For reproducibility
mu = 5;
sigma = 2;
r = random('Normal',mu,sigma,N,1);
Second step: Plot the histogram
Because we don't just want a count of the elements in each bin, but a feel of the probability density function, we can use the 'Normalization' 'pdf' arguments
Nbins = 25;
f=histogram(r,Nbins,'Normalization','pdf');
hold on
Here I'd rather specify a number of bins than specifying the bins themselves, because you never know in advance how far from the mean your data is going to be.
Last step: overlay the probability density function over the histogram
The histogram being already consistent with a probability density function, it is sufficient to just overlay the density function:
x_ = linspace(min(r),max(r),100);
y_ = (1./sqrt(2*sigma^2*pi)).*exp(-((x_-mu).^2)./(2*sigma^2));
plot(x_,y_,'b-');
With N = 150
With N = 1500
With N = 150.000 and Nbins = 50
If for some obscure reason you want to use old hist() function
The old hist() function can't handle normalization, so you'll have to do it by hand, by normalizing your density function to fit your histogram:
N = 1500;
% rng('default') % For reproducibility
mu = 5;
sigma = 2;
r = random('Normal',mu,sigma,1,N);
Nbins = 50;
[~,centers]=hist(r,Nbins);
hist(r,Nbins); hold on
% Width of bins
Widths = diff(centers);
x_ = linspace(min(r),max(r),100);
y_ = N*mean(Widths)*(1./sqrt(2*sigma^2*pi)).*exp(-((x_-mu).^2)./(2*sigma^2));
plot(x_,y_,'r-');

Interpolation using chebyshev points

Interpolate the Runge function of Example 10.6 at Chebyshev points for n from 10 to 170
in increments of 10. Calculate the maximum interpolation error on the uniform evaluation
mesh x = -1:.001:1 and plot the error vs. polynomial degree as in Figure 10.8 using
semilogy. Observe spectral accuracy.
The runge function is given by: f(x) = 1 / (1 + 25x^2)
My code so far:
x = -1:0.001:1;
n = 170;
i = 10:10:170;
cx = cos(((2*i + 1)/(2*(n+1)))*pi); %chebyshev pts
y = 1 ./ (1 + 25*x.^2); %true fct
%chebyshev polynomial, don't know how to construct using matlab
yc = polyval(c, x); %graph of approx polynomial fct
plot(x, yc);
mErr = (1 / ((2.^n).*(n+1)!))*%n+1 derivative of f evaluated at max x in [-1,1], not sure how to do this
%plotting stuff
I know very little matlab, so I am struggling on creating the interpolating polynomial. I did some google work, but I was confused with the current functions as I didn't find one that just simply took in points and the polynomial to be interpolated. I am also a bit confused in this case of whether I should be doing i = 0:1:n and n=10:10:170 or if n is fixed here. Any help is appreciated, thank you
Since you know very little about MATLAB, I will try explain everything step by step:
First, to visualize the Runge function, you can type:
f = #(x) 1./(1+25*x.^2); % Runge function
% plot Runge function over [-1,1];
x = -1:1e-3:1;
y = f(x);
figure;
plot(x,y); title('Runge function)'); xlabel('x');ylabel('y');
The #(x) part of the code is a function handle, a very useful feature of MATLAB. Notice the function is properly vecotrized, so it can receive as an argument a variable or an array. The plot function is straightforward.
To understand the Runge phenomenon, consider a linearly spaced vector of [-1,1] of 10 elements and use these points to obtain the interpolating (Lagrange) polynomial. You get the following:
% 10 linearly spaced points
xc = linspace(-1,1,10);
yc = f(xc);
p = polyfit(xc,yc,9); % gives the coefficients of the polynomial of degree 10
hold on; plot(xc,yc,'o',x,polyval(p,x));
The polyfit function does a polynomial curve fitting - it obtains the coefficients of the interpolating polynomial, given the poins x,y and the degree of the polynomial n. You can easily evaluate the polynomial at other points with the polyval function.
Obseve that, close to the end domains, you get an oscilatting polynomial and the interpolation is not a good approximation of the function. As a matter of fact, you can plot the absolute error, comparing the value of the function f(x) and the interpolating polynomial p(x):
plot(x,abs(y-polyval(p,x))); xlabel('x');ylabel('|f(x)-p(x)|');title('Error');
This error can be reduced if, instead of using a linearly space vector, you use other points to do the interpolation. A good choice is to use the Chebyshev nodes, which should reduce the error. As a matter of fact, notice that:
% find 10 Chebyshev nodes and mark them on the plot
n = 10;
k = 1:10; % iterator
xc = cos((2*k-1)/2/n*pi); % Chebyshev nodes
yc = f(xc); % function evaluated at Chebyshev nodes
hold on;
plot(xc,yc,'o')
% find polynomial to interpolate data using the Chebyshev nodes
p = polyfit(xc,yc,n-1); % gives the coefficients of the polynomial of degree 10
plot(x,polyval(p,x),'--'); % plot polynomial
legend('Runge function','Chebyshev nodes','interpolating polynomial','location','best')
Notice how the error is reduced close to the end domains. You don't get now that high oscillatory behaviour of the interpolating polynomial. If you plot the error, you will observe:
plot(x,abs(y-polyval(p,x))); xlabel('x');ylabel('|f(x)-p(x)|');title('Error');
If, now, you change the number of Chebyshev nodes, you will get an even better approximation. A little modification on the code lets you run it again for different numbers of nodes. You can store the maximum error and plot it as a function of the number of nodes:
n=1:20; % number of nodes
% pre-allocation for speed
e_ln = zeros(1,length(n)); % error for the linearly spaced interpolation
e_cn = zeros(1,length(n)); % error for the chebyshev nodes interpolation
for ii=1:length(n)
% linearly spaced vector
x_ln = linspace(-1,1,n(ii)); y_ln = f(x_ln);
p_ln = polyfit(x_ln,y_ln,n(ii)-1);
e_ln(ii) = max( abs( y-polyval(p_ln,x) ) );
% Chebyshev nodes
k = 1:n(ii); x_cn = cos((2*k-1)/2/n(ii)*pi); y_cn = f(x_cn);
p_cn = polyfit(x_cn,y_cn,n(ii)-1);
e_cn(ii) = max( abs( y-polyval(p_cn,x) ) );
end
figure
plot(n,e_ln,n,e_cn);
xlabel('no of points'); ylabel('maximum absolute error');
legend('linearly space','chebyshev nodes','location','best')

Creating histograms of distance from the origin for 2D Random Walkers

Let's say you can show the distribution in space of the the positions of a large number of random walkers at three different time points. This was provided an answer to my previous question and with some tweaks is beautiful.
clc;
close all;
M = 1000; % The amount of random walks.
steps = [100,200,300]; % here we analyse the step 10,200 and 1000
cc = hsv(length(steps)); % manage the color of the plot
%generation of each random walk
x = sign(randn(max(steps),M));
y = sign(randn(max(steps),M));
xs = cumsum(x);
xval = xs(steps,:);
ys = cumsum(y);
yval = ys(steps,:);
hold on
for n=1:length(steps)
plot(xval(n,:),yval(n,:),'o','markersize',1,'color',cc(n,:),'MarkerFaceColor',cc(n,:));
end
legend('100','200','300')
axis square
grid on;
Now to the question, could I in some way use the hist() and subplot() functions to show the distance from the origin of the random walkers at three separate time points, or more I guess, but three for simplicity.
I'm not sure how to go about this beyond producing distributions of random walkers at the three time points themselves so far.
I hope that I've understand your question, I think that you want to use the bar plot with the stack option.
I've used the answer of #LuisMendo to my question to increase the code efficiency.
steps = [10,200,1000]; % the steps
M = 5000; % Number of random walk
DV = [-1 1]; % Discrete value
p = .5; % probability of DV(2)
% Using the #LuisMendo binomial solution:
for ii = 1:length(steps)
xval(ii,:) = (DV(2)-DV(1))*binornd(steps(ii), p, M, 1)+DV(1)*steps(ii);
yval(ii,:) = (DV(2)-DV(1))*binornd(steps(ii), p, M, 1)+DV(1)*steps(ii);
end
[x, cen] = hist(sqrt(xval.^2+yval.^2).'); %where `sqrt(xval.^2+yval.^2)` is the euclidian distance
bar(cen,x,'stacked');
legend('10','200','1000')
axis square
grid on;
Increase the # of bins in the histogram function to increase the plot precision.
Results:

How to generate data with a specific trend in MATLAB

I want to test the Akaike criterion (it is a criterion that gives where do you get a significant change in a time series), but to do that I need to generate data that for example follow a sinusoidal trend, a linear trend with positive or negative slope, a constant trend, etc. So far I have done this but with random numbers, this is:
%Implementation of the Akaike method for Earth sciences.
N=100;
data=zeros(N,1);
for i=1:N
data(i,1)=unifrnd(1,N);
end
%AIC=zeros(N-1,1);
data=rand(1,N);
for k=1:N
%y=datasample(data,k);
AIC(k,1)=k*log(var(data(1:k),1))+(N-k-1)*log(var(data(k+1:N),1));
end
AIC(1)=NaN;
%AIC(N-1)=[];AIC(N)=[];
%disp(AIC)
%plot(AIC)
subplot(2,1,1)
plot(data,'Marker','.')
subplot(2,1,2)
plot(AIC,'Marker','.')
So, How can I generate different data with different trend in MATLAB?
Thanks a lot in advance.
What you can do is first start off with a known curve, then add some noise or random values so that the signal does follow a trend but it is noisy. Given a set of independent values, use these to generate values for your sinusoidal curves, a line with a positive or negative slope and a constant value.
Something like this comes to mind:
X = 1 : N; % N is defined in your code
Y1 = sin(X) + rand(1, N); % Sinusoidal
slope1 = 2; intercept = 3;
Y2 = slope1*X + intercept + rand(1, N); % Line with a positive slope
slope2 = -1; intercept2 = 0.5;
Y3 = slope2*X + intercept2 + rand(1, N); % Line with a negative slope
B = 2;
Y4 = B*ones(1, N) + rand(1, N); % Constant line
rand is a function in MATLAB that uniformly generates floating-point values between [0,1]. Y1, Y2, Y3 and Y4 are the trends you desire where they follow the curve defined but they add a bit of random values so that you don't completely get the trend you want and the noise is designed to decrease how similarity those curves are to the curve you defined. Increase the magnitude of the random values to decrease the similarity.

Integration of normal probability distribution function with random numbers

function Y=normpdf(X)
syms X
Y = normpdf(X);
int(Y,X,1,inf)
end
I need to integrate normal pdf function from 1 to infinity for the case of N=100 where N is the total numbers generated.I know i need to use randn() for generating random numbers but i dont know how to use it in this situation.
You could have N = 100 random numbers from t = randn(N, 1);. First, we sort with t = sort(t), then the integrated PDF, i.e. cumulative density function is approximated by your samples with p = (1 : N) / N for t as you can see with plot(t, p). It will overlap well with hold on, plot(t, normcdf(t), 'r').
A perhaps more intuitive approach is to partition the x axis into bins in order to estimate the CDF:
N = 100; % number of samples
t = randn(N, 1); % random data
x = linspace(-10,10,200); % define bins
estim_cdf = mean(bsxfun(#le, t, x)); % estimate CDF
plot(x, estim_cdf);
hold on
plot(x, normcdf(x), 'r')
Note that #s.bandara's solution can be interpreted as the limiting case of this as the number of bins tends to infinity, and therefore it probably gives more accurate results.