Why use the complex conjugate for Fourier spectra division? - matlab

I saw several codes written where Fourier spectra are divided with the complex conjugate like this:
af = fftn(double(img1));
bf = fftn(double(img2));
cp = af .* conj(bf) ./ abs(af .* conj(bf));
in this script among others.
Is this related to handling complex division? Reading the documentation about the ./ operator, it is stated that it handles complex numbers. So is this wrong?:
af./bf

The expressions af./bf and af.*conj(bf)./abs(bf).^2 are completely equivalent in MATLAB, if that's what you're asking. There is no clear connection, however, between that question and the example you've shown. abs(bf).^2 does not appear in the denominator in your example.
The only reason conj() is being used in the code you've shown is because it is the Fourier dual of time inversion
I.e., f(t)<-->F(k) implies f(-t)<--->conj(F(k)), for real-valued time signals f(t).
This has a specific application to time delay analysis using phase correlation.

You could rewrite this expression avoiding the conjugation as
(af./bf)./abs(af./bf).
However, the given form of the expression has the advantage that you can desingularize the division by adding a small epsilon to the denominator,
(af.*conj(bf))./(1e-40+abs(af.*conj(bf)))

Consider the following equivalent (within about 1e-15) code:
cpX = exp(1i*(angle(af)-angle(bf)));
You can compute the normalized cross power spectrum as you have shown with the complex conjugate (cp = af .* conj(bf) ./ abs(af .* conj(bf))) or by explicitly subtracting the phase as above.
Considering that the FFT of a shifted impulse is a complex exponential, the cpX equation should give some insight into how "phase correlation" allows you to find a translation between two images. The location of the peak in the inverse FFT gives the translation.

Related

Speed up calculation in Physics simulation in Matlab

I am working on a MR-physic simulation written in Matlab which simulates bloch's equations on an defined object. The magnetisation in the object is updated every time-step with the following functions.
function Mt = evolveMtrans(gamma, delta_B, G, T2, Mt0, delta_t)
% this function calculates precession and relaxation of the
% transversal component, Mt, of M
delta_phi = gamma*(delta_B + G)*delta_t;
Mt = Mt0 .* exp(-delta_t*1./T2 - 1i*delta_phi);
end
This function is a very small part of the entire code but is called upon up to 250.000 times and thus slows down the code and the performance of the entire simulation. I have thought about how I can speed up the calculation but haven't come up with a good solution. There is one line that is VERY time consuming and stands for approximately 50% - 60% of the overall simulation time. This is the line,
Mt = Mt0 .* exp(-delta_t*1./T2 - 1i*delta_phi);
where
Mt0 = 512x512 matrix
delta_t = a scalar
T2 = 512x512 matrix
delta_phi = 512x512 matrix
I would be very grateful for any suggestion to speed up this calculation.
More info below,
The function evovleMtrans is called every timestep during the simulation.
The parameters that are used for calling the function are,
gamma = a constant. (gyramagnetic constant)
delta_B = the magnetic field value
G = gradientstrength
T2 = a 512x512 matrix with T2-values for the object
Mstart.r = a 512x512 matrix with the values M.r had the last timestep
delta_t = a scalar with the difference in time since the last calculated M.r
The only parameters of these that changed during the simulation are,
G, Mstart.r and delta_t. The rest do not change their values during the simulation.
The part below is the part in the main code that calls the function.
% update phase and relaxation to calcTime
delta_t = calcTime - Mstart_t;
delta_B = (d-d0)*B0;
G = Sq.Gx*Sq.xGxref + Sq.Gz*Sq.zGzref;
% Precession around B0 (z-axis) and B1 (+-x-axis or +-y-axis)
% is defined clock-wise in a right hand system x, y, z and
% x', y', z (see the Bloch equation, Bloch 1946 and Levitt
% 1997). The x-axis has angle zero and the y-axis has angle 90.
% For flipping/precession around B1 in the xy-plane, z-axis has
% angle zero.
% For testing of precession direction:
% delta_phi = gamma*((ones(size(d)))*1e-6*B0)*delta_t;
M.r = evolveMtrans(gamma, delta_B, G, T2, Mstart.r, delta_t);
M.l = evolveMlong(T1, M0.l, Mstart.l, delta_t);
This is not a surprise.
That "single line" is a matrix equation. It's really 1,024 simultaneous equations.
Per Jannick, that first term means element-wise division, so "delta_t/T[i,j]". Multiplying a matrix by a scalar is O(N^2). Matrix addition is O(N^2). Evaluating exponential of a matrix will be O(N^2).
I'm not sure if I saw a complex argument in there as well. Does that mean complex matricies with real and imaginary entries? Does your equation simplify to real and imaginary parts? That means twice the number of computations.
Your best hope is to exploit symmetry as much as possible. If all your matricies are symmetric, you cut your calculations roughly in half.
Use parallelization if you can.
Algorithm choice can make a big difference, too. If you're using explicit Euler integration, you may have time step limitations due to stability concerns. Is that why you have 250,000 steps? Maybe a larger time step is possible with a more stable integration schema. Think about a higher order adaptive scheme with error correction, like 5th order Runge Kutta.
There are several possibilities to improve the speed of the code but all that I see come with a caveat.
Numerical ode integration
The first possibility would be to change your analytical solution by numerical differential equation solver. This has several advantages
The analytical solution includes the complex exponential function, which is costly to calculate, while the differential equation contains only multiplication and addition. (d/dt u = -a u => u=exp(-at))
There are plenty of built-in solvers for matlab available and they are typically pretty fast (e.g. ode45). The built-ins however all use a variable step size. This improves speed and accuracy but would be a problem if you really need a fixed equally spaced grid of time points. Here are unofficial fixed step solvers.
As a start you could also try to use just an euler step by replacing
M.r = evolveMtrans(gamma, delta_B, G, T2, Mstart.r, delta_t);
by
delta_phi = gamma*(delta_B + G)*t_step;
M.r += M.r .* (1-t_step*1./T2 - 1i*delta_phi);
You can then further improve that by precalculating all constant values, e.g. one_over_T1=1/T1, moving delta_phi out of the loop.
Caveat:
You are bound to a minimum step size or the accuracy suffers. Therefore this is only a good idea if you time-spacing is quite fine.
Less points in time
You should carfully analyze whether you really need so many points in time. It seems somewhat puzzling to me that you need so many points. As you know the full analytical solution you can freely choose how to sample the time and maybe use this to your advantage.
Going fortran
This might seem like a grand step but in my experience basic (simple loops, matrix operations etc.) matlab code can be relatively easily translated to fortran line-by-line. This would be especially helpful in addition to my first point. If you still want to use the full analytical solution probably there is not much to gain here because exp is already pretty fast in matlab.

How to compute inverse of a matrix accurately?

I'm trying to compute an inverse of a matrix P, but if I multiply inv(P)*P, the MATLAB does not return the identity matrix. It's almost the identity (non diagonal values in the order of 10^(-12)). However, in my application I need more precision.
What can I do in this situation?
Only if you explicitly need the inverse of a matrix you use inv(), otherwise you just use the backslash operator \.
The documentation on inv() explicitly states:
x = A\b is computed differently than x = inv(A)*b and is recommended for solving systems of linear equations.
This is because the backslash operator, or mldivide() uses whatever method is most suited for your specific matrix:
x = A\B solves the system of linear equations A*x = B. The matrices A and B must have the same number of rows. MATLAB® displays a warning message if A is badly scaled or nearly singular, but performs the calculation regardless.
Just so you know what algorithm MATLAB chooses depending on your input matrices, here's the full algorithm flowchart as provided in their documentation
The versatility of mldivide in solving linear systems stems from its ability to take advantage of symmetries in the problem by dispatching to an appropriate solver. This approach aims to minimize computation time. The first distinction the function makes is between full (also called "dense") and sparse input arrays.
As a side-note about error of order of magnitude 10^(-12), besides the above mentioned inaccuracy of the inv() function, there's floating point accuracy. This post on MATLAB issues on it is rather insightful, with a more general computer science post on it here. Basically, if you are computing numerics, don't worry (too much at least) about errors 12 orders of magnitude smaller.
You have what's called an ill-conditioned matrix. It's risky to try to take the inverse of such a matrix. In general, taking the inverse of anything but the smallest matrices (such as those you see in an introduction to linear algebra textbook) is risky. If you must, you could try taking the Moore-Penrose pseudoinverse (see Wikipedia), but even that is not foolproof.

Cross-correlation in matlab without using the inbuilt function?

can someone tell how to do the cross-correlation of two speech signals (each of 40,000 samples) in MATLAB without using the built-in function xcorr and the correlation coefficient?
Thanks in advance.
You can do cross-correlations using fft. The cross-correlation of two vectors is simply the product of their respective Fourier transforms, with one of the transforms conjugated.
Example:
a=rand(5,1);
b=rand(5,1);
corrLength=length(a)+length(b)-1;
c=fftshift(ifft(fft(a,corrLength).*conj(fft(b,corrLength))));
Compare results:
c =
0.3311
0.5992
1.1320
1.5853
1.5848
1.1745
0.8500
0.4727
0.0915
>> xcorr(a,b)
ans =
0.3311
0.5992
1.1320
1.5853
1.5848
1.1745
0.8500
0.4727
0.0915
If there some good reason why you can't use the inbuilt, you can use a convolution instead. Cross-correlation is simply a convolution without the reversing, so to 'undo' the reversing of the correlation integral you can first apply an additional reverse to one of your signals (which will cancel out in the convolution).
Well yoda gave a good answer but I thought I mention this anyway just in case. Coming back to the definition of the discrete cross correlation you can compute it without using (too much) builtin Matlab functions (which should be what Matlab do with xcorr). Of course there is still room for improvment as I did not try to vectorize this:
n=1000;
x1=rand(n,1);
x2=rand(n,1);
xc=zeros(2*n-1,1);
for i=1:2*n-1
if(i>n)
j1=1;
k1=2*n-i;
j2=i-n+1;
k2=n;
else
j1=n-i+1;
k1=n;
j2=1;
k2=i;
end
xc(i)=sum(conj(x1(j1:k1)).*x2(j2:k2));
end
xc=flipud(xc);
Which match the result of the xcorr function.
UPDATE: forgot to mention that in my opinion Matlab is not the appropriate tool for doing real time cross correlation of large data sets, I would rather try it in C or other compiled languages.

How to add white noise process term for a couple of ODEs, assuming the Gaussian distribution?

This question has already confused me several days. While I referred to senior students, they also cannot give a reply.
We have ten ODEs, into which each a noise term should be added. The noise is defined as follows. since I always find that I cannot upload a picture, the formula below maybe not very clear. In order to understand, you can either read my explanation or go the this address: Plos one. You could find the description of the equations directly above the Support Information in this address
The white noise term epislon_i(t) is assumed with Gaussian distribution. epislon_i(t) means that for equation i, and at t timepoint, the value of the noise.
the auto-correlation of noise are given:
(EQ.1)
where delta(t) is the Dirac delta function and the diffusion matrix D is defined by
(EQ.2)
Our problem focuses on how to explain the Dirac delta function in the diffusion matrix. Since the property of Dirac delta function is delta(0) = Inf and delta(t) = 0 if t neq 0, we don't know how to calculate the epislonif we try to sqrt of 2D(x, t)delta(t-t'). So we simply assume that delta(0) = 1 and delta(t) = 0 if t neq 0; But we don't know whether or not this is right. Could you please tell me how to use Delta function of diffusion equation in MATLAB?
This question associates with the stochastic process in MATLAB. So we review different stochastic process to inspire our ideas. In MATLAB, the Wienner process is often defined as a = sqrt(dt) * rand(1, N). N is the number of steps, dt is the length of the steps. Correspondingly, the Brownian motion can be defined as: b = cumsum(a); All of these associate with stochastic process. However, they doesn't related to the white noise process which has a constraints on the matrix of auto-correlation, noted by D.
Then we consider that, we may simply use randn(1, 10) to generate a vector representing the noise. However, since the definition of the noise must satisfy the equation (2), this cannot enable noise term in different equation have the predefined partial correlation (D_ij). Then we try to use mvnrnd to generate a multiple variable normal distribution at each time step. Unfortunately, the function mvnrnd in MATLAB return a matrix. But we need to return a vector of length 10.
We are rather confused, so could you please give me just a light? Thanks so much!
NOTE: I see two hazy questions in here: 1) how to deal with a stochastic term in a DE and 2) how to deal with a delta function in a DE. Both of these are math related questions and http://www.math.stackexchange.com will be a better place for this. If you had a question pertaining to MATLAB, I haven't been able to pin it down, and you should perhaps add code examples to better illustrate your point. That said, I'll answer the two questions briefly, just to put you on the right track.
What you have here are not ODEs, but Stochastic differential equations (SDE). I'm not sure how you're using MATLAB to work with this, but routines like ode45 or ode23 will not be of any help. For SDEs, your usual mathematical tools of separation of variables/method of characteristics etc don't work and you'll need to use Itô calculus and Itô integrals to work with them. The solutions, as you might have guessed, will be stochastic. To learn more about SDEs and working with them, you can consider Stochastic Differential Equations: An Introduction with Applications by Bernt Øksendal and for numerical solutions, Numerical Solution of Stochastic Differential Equations by Peter E. Kloeden and Eckhard Platen.
Coming to the delta function part, you can easily deal with it by taking the Fourier transform of the ODE. Recall that the Fourier transform of a delta function is 1. This greatly simplifies the DE and you can take an inverse transform in the very end to return to the original domain.

Least squares optimal scaling

I have two waveforms which are linked by a numerical factor. I need to use optimal scaling (least squares) between the two waveforms to calculate this factor in Matlab. Unfortunately I have no idea how to do this. The two wave forms are seismic signals related by the velocity of the seismic waves, which I'm trying to calculate. Any ideas? need more info?
Call W1 and W2 the two vectors. For this to work, they must be column vectors. Transpose them if they are rows instead of columns. Then if we wish to find the value of k such that W1 = k*W2, just use backslash.
k = W2\W1;
Backslash here gives you a linear regression (least squares) estimator, as requested. This does not handle the unknown phase shift case of course.
one cheesy way to estimate the linear factor without having to deal with phase shift is to compute the ratio of the estimated scales of the waves. the cheesiest way is to use standard deviation:
k = std(W1) / std(W2);
if you care about robustness, I would substitute in the MAD or the IQR; the MAD is the median absolute deviation, which you can (somewhat inefficiently) 'inline' as so:
MAD = #(x)(median(abs(bsxfun(#minus,x,median(x)))));
k = MAD(W1) / MAD(W2);
the IQR is the interquartile range, which requires a proper quantile computation. you can implement this inefficiently using sort. I leave this as an exercise to the reader.