Auto-covariance and Cross Covariance Function in Matlab without using imbuilt functions - matlab

x and y are 1x100000 vectors.
I have calculated the mean and variance of x and y. When I want to calculate the autocovariance and cross covariance function the simulation lasts maybe 5 minutes because of my loops. It is not allowed to use xcorr, xcov, mean, cov, var etc.
Please help me.
Thanks in advance.
%%Mean of Vector x
Nx=length(x);
mx= sum(x)/Nx;
%%Mean of Vector y
Ny=length(y);
my=sum(y)/Ny;
%%Variance of x
varx=0;
for i=1:Nx
varx=varx+(abs(x(i)-mx)^(2));
end
varx=varx/Nx;
%%Variance of y
vary=0;
for j=1:Ny
vary=vary+(abs(y(j)-my)^(2));
end
vary=vary/Ny;
%%Auto-Covariance function of x
for k=1:Nx
Cxx(k)=0;
for i=1:(Nx-k+1)
Cxx(k)=Cxx(k)+(x(i+k-1)-mx)*conj((x(i)-my));
end
end
%%Auto-Covariance function of y
for s=1:Ny
Cyy(s)=0;
for j=1:(Ny-s+1)
Cyy(s)=Cyy(s)+(y(j+s-1)-my)*conj((y(j)-mx));
end
end

Use the fact that FFT(corr(x, y)) = FFT(x) * conj(FFTy)):
corrxy = ifft(fft(x) .* conj(fft(y)));
corrxy = [corrxy(end - length(x) + 2:end); corrxy(1:length(x))];
To get the cross-covariance just multiply the correlation by the standard deviations:
covarxy = corrxy * sqrt(varx) * sqrt(vary);
To get the autocovariance, compute the cross covariance between x and itself.

Doing a re-write of this code:
%%Auto-Covariance function of x
for k=1:Nx
Cxx(k)=0;
for i=1:(Nx-k+1)
Cxx(k)=Cxx(k)+(x(i+k-1)-mx)*conj((x(i)-my));
end
end
The following code takes out the inner for-loop:
% x is a [Nx x 1] vector (lets say Nx = 50)
Cxx = zeros(Nx,1); % [Nx x 1] vector of zeros
for k = 1:Nx,
a = (x(k:Nx) -mx); % If k=3, then x(3:50) and a is [Nx-k+1 x 1]
b = (x(1:Nx-k+1)-my); % If k=3, then x(1:48) and b is [Nx-k+1 x 1]
Cxx(k) = a'*conj(b); % Cxx(k) is always 1x1. (*) is a matrix multiply
end
Since x is a really large vector, and the way to take out the the last for-loop for k=1:Nx is to make a [Nx x Nx] matrix, I'm going to leave it at the above answer for now. Plus, if you have the parfor function in the Parallel Computing Toolbox then you can parallelize it to make it run even faster.

Related

Matlab: 2D Discrete Fourier Transform and Inverse

I'm trying to run a program in matlab to obtain the direct and inverse DFT for a grey scale image, but I'm not able to recover the original image after applying the inverse. I'm getting complex numbers as my inverse output. Is like i'm losing information. Any ideas on this? Here is my code:
%2D discrete Fourier transform
%Image Dimension
M=3;
N=3;
f=zeros(M,N);
f(2,1:3)=1;
f(3,1:3)=0.5;
f(1,2)=0.5;
f(3,2)=1;
f(2,2)=0;
figure;imshow(f,[0 1],'InitialMagnification','fit')
%Direct transform
for u=0:1:M-1
for v=0:1:N-1
for x=1:1:M
for y=1:1:N
F(u+1,v+1)=f(x,y)*exp(-2*pi*(1i)*((u*(x-1)/M)+(v*(y-1)/N)));
end
end
end
end
Fab=abs(F);
figure;imshow(Fab,[0 1],'InitialMagnification','fit')
%Inverse Transform
for x=0:1:M-1
for y=0:1:N-1
for u=1:1:M
for v=1:1:N
z(x+1,y+1)=(1/M*N)*F(u,v)*exp(2*pi*(1i)*(((u-1)*x/M)+((v-1)*y/N)));
end
end
end
end
figure;imshow(real(z),[0 1],'InitialMagnification','fit')
There are a couple of issues with your code:
You are not applying the definition of the DFT (or IDFT) correctly: you need to sum over the original variable(s) to obtain the transform. See the formula here; notice the sum.
In the IDFT the normalization constant should be 1/(M*N) (not 1/M*N).
Note also that the code could be made mucho more compact by vectorization, avoiding the loops; or just using the fft2 and ifft2 functions. I assume you want to compute it manually and "low-level" to verify the results.
The code, with the two corrections, is as follows. The modifications are marked with comments.
M=3;
N=3;
f=zeros(M,N);
f(2,1:3)=1;
f(3,1:3)=0.5;
f(1,2)=0.5;
f(3,2)=1;
f(2,2)=0;
figure;imshow(f,[0 1],'InitialMagnification','fit')
%Direct transform
F = zeros(M,N); % initiallize to 0
for u=0:1:M-1
for v=0:1:N-1
for x=1:1:M
for y=1:1:N
F(u+1,v+1) = F(u+1,v+1) + ...
f(x,y)*exp(-2*pi*(1i)*((u*(x-1)/M)+(v*(y-1)/N))); % add term
end
end
end
end
Fab=abs(F);
figure;imshow(Fab,[0 1],'InitialMagnification','fit')
%Inverse Transform
z = zeros(M,N);
for x=0:1:M-1
for y=0:1:N-1
for u=1:1:M
for v=1:1:N
z(x+1,y+1) = z(x+1,y+1) + (1/(M*N)) * ... % corrected scale factor
F(u,v)*exp(2*pi*(1i)*(((u-1)*x/M)+((v-1)*y/N))); % add term
end
end
end
end
figure;imshow(real(z),[0 1],'InitialMagnification','fit')
Now the original and recovered image differ only by very small values, of the order of eps, due to the usual floating-point inaccuacies:
>> f-z
ans =
1.0e-15 *
Columns 1 through 2
0.180411241501588 + 0.666133814775094i -0.111022302462516 - 0.027755575615629i
0.000000000000000 + 0.027755575615629i 0.277555756156289 + 0.212603775716506i
0.000000000000000 - 0.194289029309402i 0.000000000000000 + 0.027755575615629i
Column 3
-0.194289029309402 - 0.027755575615629i
-0.222044604925031 - 0.055511151231258i
0.111022302462516 - 0.111022302462516i
Firstly, the biggest error is that you are computing the Fourier transform incorrectly. When computing F, you need to be summing over x and y, which you are not doing. Here's how to rectify that:
F = zeros(M, N);
for u=0:1:M-1
for v=0:1:N-1
for x=1:1:M
for y=1:1:N
F(u+1,v+1)=F(u+1,v+1) + f(x,y)*exp(-2*pi*(1i)*((u*(x-1)/M)+(v*(y-1)/N)));
end
end
end
end
Secondly, in the inverse transform, your bracketing is incorrect. It should be 1/(M*N) not (1/M*N).
As an aside, at the cost of a bit more memory, you can speed up the computation by not nesting so many loops. Namely, when computing the FFT, do the following instead
x = (1:1:M)'; % x is a column vector
y = (1:1:N) ; % y is a row vector
for u = 0:1:M-1
for v = 0:1:N-1
F2(u+1,v+1) = sum(f .* exp(-2i * pi * (u*(x-1)/M + v*(y-1)/N)), 'all');
end
end
To take this method to the extreme, i.e. not using any loops at all, you would do the following (though this is not recommended, since you would lose code readability and the memory cost would increase exponentially)
x = (1:1:M)'; % x is in dimension 1
y = (1:1:N) ; % y is in dimension 2
u = permute(0:1:M-1, [1, 3, 2]); % x-freqs in dimension 3
v = permute(0:1:N-1, [1, 4, 3, 2]); % y-freqs in dimension 4
% sum the exponential terms in x and y, which are in dimensions 1 and 2.
% If you are using r2018a or older, the below summation should be
% sum(sum(..., 1), 2)
% instead of
% sum(..., [1,2])
F3 = sum(f .* exp(-2i * pi * (u.*(x-1)/M + v.*(y-1)/N)), [1, 2]);
% The resulting array F3 is 1 x 1 x M x N, to make it M x N, simply shiftdim or squeeze
F3 = squeeze(F3);

Create arrays based on a different array

% create variable x with array of all necessary values
x=linspace(0.1,13,50);
for i=x
% create equation to determine y
y=(sqrt(2.*i)*4*i.^3)/(4.*i+7.^(i/10));
%create equation to determine z
z=log10(2.*i+5)+(4.*i+exp(i))/(2./3+4.*i.^2);
end
Using Matlab and im trying to use values from my x array to create two arrays, y and z, im pretty new to matlab and im struggling, thanks.
The problem in you code is that you did not use for loop properly. You can run through the index of x, then assign x(i) to a new variable k in each iteration, i.e.,
x=linspace(0.1,13,50);
for k = 1:length(x)
i = x(k);
% create equation to determine y
y(k) =(sqrt(2.*i)*4*i.^3)/(4.*i+7.^(i/10));
%create equation to determine z
z(k) =log10(2.*i+5)+(4.*i+exp(i))/(2./3+4.*i.^2);
end
Since MATLAB is able to vectorize the operations, so you are recommended to do it like below to speed up (for loop in MATLAB is expensive)
x = linspace(0.1,13,50);
y = (sqrt(2*x).*4.*x.^3)./(4*x+7^(x/10));
z = log10(2*x+5)+(4*x+exp(x))./(2/3 + 4*x.^2);
Remarks: you should be careful about the difference between .* and *, or ./ and /, where * and / are not element-wise operations.
Method 1:
you can initialize y and z into empty arrays and just append the corresponding result at the end:
% create variable x with array of all necessary values
x=linspace(0.1,13,50);
y=[];
z=[];
for i=x
% create equation to determine y
y(end+1)=(sqrt(2.*i)*4*i.^3)/(4.*i+7.^(i/10));
%create equation to determine z
z(end+1)=log10(2.*i+5)+(4.*i+exp(i))/(2./3+4.*i.^2);
end
This approach can prove to be poor in terms of efficiency, since the size of y and z changes dynamically.
Method 2:
If you still want to use a for loop, it is better to preallocate memory for y and z and iterate the indices of x, something like:
% create variable x with array of all necessary values
x=linspace(0.1,13,50);
% Memory allocation
y = zeros(1, length(x));
z = zeros(1, length(x));
for i = 1 : length(x)
% create equation to determine y
y(i)=(sqrt(2.*x(i)*4*x(i).^3)/(4.*x(i)+7.^(x(i)/10));
%create equation to determine z
z(i)=log10(2.*x(i)+5)+(4.*x(i)+exp(x(i)))/(2./3+4.*x(i).^2);
end
Method 3 (preferred one):
It is generally more efficient to vectorize your implementations. In your case you could use something like:
x = linspace(0.1,13,50);
y = (sqrt(2.*x)*4*.*x.^3) ./ (4*x + 7.^(x./10));
z = log10(2*x+5) + (4*x + exp(x)) ./ (2/3 + 4*x.^2);

Matlab: work with 2NxN matrix

I have a matrix 2NxN.
And I want get some parametrs by this matrix. For example it:
How, I can do it?
You may want to break your 12x6 matrix, into two 6x6 matrix; let's say: Z and Zb (last one for z bar). Odd rows are Z and evens are Zb.
Considering M to be the combined matrices:
Z = M(1:2:end,:)
Zb = M(2:2:end,:)
read about the colon(:) operator and end to see what 1:2:end means.
Hope it helps.
From what I understand here are the first three:
% Random Matrix
% Needs to be defined before the functions since the functions look for
% the m variable
m = rand(12,6);
% Function 1
p = #(i,j) sign(m(i,j)+m(i+1,j)) * max(abs(m(i,j)),abs(m(i+1,j)));
p(2,2)
% Function 2 - Avg of row
pavg = #(i) mean(m(i,:));
pavg(2)
% Function 3
c = #(i,j) abs(m(i,j)+m(i+1,j)) / (abs(m(i,j)) + abs(m(i+1,j)));
c(2,2)

Making a function in terms of a sum from 1 to n in Matlab

I'm trying to get Matlab to take this as a function of x_1 through x_n and y_1 through y_n, where k_i and r_i are all constants.
So far my idea was to take n from the user and make two 1×n vectors called x and y, and for the x_i just pull out x(i). But I don't know how to make an arbitrary sum in MATLAB.
I also need to get the gradient of this function, which I don't know how to do either. I was thinking maybe I could make a loop and add that to the function each time, but MATLAB doesn't like that.
I don't believe a loop is necessary for this calculation. MATLAB excels at vectorized operations, so would something like this work for you?
l = 10; % how large these vectors are
k = rand(l,1); % random junk values to work with
r = rand(l,1);
x = rand(l,1);
y = rand(l,1);
vals = k(1:end-1) .* (sqrt(diff(x).^2 + diff(y).^2) - r(1:end-1)).^2;
sum(vals)
EDIT: Thanks to #Amro for correcting the formula and simplifying it with diff.
You can solve for the gradient symbolically with:
n = 10;
k = sym('k',[1 n]); % Create n variables k1, k2, ..., kn
x = sym('x',[1 n]); % Create n variables x1, x2, ..., xn
y = sym('y',[1 n]); % Create n variables y1, y2, ..., yn
r = sym('r',[1 n]); % Create n variables r1, r2, ..., rn
% Symbolically sum equation
s = sum((k(1:end-1).*sqrt((x(2:end)-x(1:end-1)).^2+(y(2:end)-y(1:end-1)).^2)-r(1:end-1)).^2)
grad_x = gradient(s,x) % Gradient with respect to x vector
grad_y = gradient(s,y) % Gradient with respect to y vector
The symbolic sum and gradients can be evaluated and converted to floating point with:
% n random data values for k, x, y, and r
K = rand(1,n);
X = rand(1,n);
Y = rand(1,n);
R = rand(1,n);
% Substitute in data for symbolic variables
S = double(subs(s,{[k,x,y,r]},{[K,X,Y,R]}))
GRAD_X = double(subs(grad_x,{[k,x,y,r]},{[K,X,Y,R]}))
GRAD_Y = double(subs(grad_y,{[k,x,y,r]},{[K,X,Y,R]}))
The gradient function is the one overloaded for symbolic variables (type help sym/gradient) or see the more detailed documentation online).
Yes, you could indeed do this with a loop, considering that x, y, k, and r are already defined.
n = length(x);
s = 0;
for j = 2 : n
s = s + k(j-1) * (sqrt((x(j) - x(j-1)).^2 + (y(j) - y(j-1)).^2) - r(j-1)).^2
end
You should derive the gradient analytically and then plug in numbers. It should not be too hard to expand these terms and then find derivatives of the resulting polynomial.
Vectorized solution is something like (I wonder why do you use sqrt().^2):
is = 2:n;
result = sum( k(is - 1) .* abs((x(is) - x(is-1)).^2 + (y(is) - y(is-1)).^2 - r(is-1)));
You can either compute gradient symbolically or rewrite this code as a function and make a standard +-eps calculation. If you need a gradient to run optimization (you code looks like a fitness function) you could use algorithms that calculate them themselves, for example, fminsearch can do this

How to generate a function of two variables without using any loop?

Suppose I have a function y(t,x) = exp(-t)*sin(x)
In Matlab, I define
t = [0: 0.5: 5];
x = [0: 0.1: 10*2*pi];
y = zeros(length(t), length(x)); % empty matrix init
Now, how do I define matrix y without using any loop, such that each element y(i,j) contains the value of desired function y at (t(i), x(j))? Below is how I did it using a for loop.
for i = 1:length(t)
y(i,:) = exp(-t(i)) .* sin(x);
end
Your input vectors x is 1xN and t is 1xM, output matrix y is MxN. To vectorize the code both x and t must have the same dimension as y.
[x_,t_] = meshgrid(x,t);
y_ = exp(-t_) .* sin(x_);
Your example is a simple 2D case. Function meshgrid() works also 3D. Sometimes you can not avoid the loop, in such cases, when your loop can go either 1:N or 1:M, choose the shortest one. Another function I use to prepare vector for vectorized equation (vector x matrix multiplication) is diag().
there is no need for meshgrid; simply use:
y = exp(-t(:)) * sin(x(:)'); %multiplies a column vector times a row vector.
Those might be helpful:
http://www.mathworks.com/access/helpdesk/help/techdoc/ref/meshgrid.html
http://www.mathworks.com/company/newsletters/digest/sept00/meshgrid.html
Good Luck.