Complex angle calculation with no reset of argument: continuous unbounded angle - matlab

Consider the following example Simulink (Download example) system:
Input is a magnitude and an ever increasing angle, which will return two sine, the real and imaginary part as expected:
Calculating the Magntitude from real and imaginary part is no issue. Getting the angle in the domain between -pi and pi neither:
But I'm really struggling in calculating the original angle from the imaginary and real part. Do you have any ideas how to get rid of the discontinuity (yellow line, last picture)?

How about this example?
function [ub_ang,ang] = phase_unwrap(re, im, theta)
%#codegen
ang = atan2(im,re);
tmp = [theta ang];
uang = unwrap(tmp);
ub_ang = uang(2);
Scope1 plot is below
Scope plot is below.

Daniel's Solution was exact what I was looking for, but in case the DSP System Toolbox is not available, like in case of my project partners, I came up with the following solution:
with
function [y, corr] = phase_unwrap(zz,z,v)
%#codegen
d = diff([v,z,zz]);
if abs(d(1)) > pi
y = sign(d(1));
corr = -3/2*d(2);
else
y = 0;
corr = -3/2*d(1);
end
end
The discrete time integrator has the same sampling time as the zero-order-hold and a gain of 2*pi.
The example output is satisfying, but I still need to test it for the real case.

Use the block called unwrap. In case the toolbox is not available, this discrete implementation in simulink could be used:

Related

Is there any method that can get solution more accurate than integral3 by MATLAB (except using "for" loop)?

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.

Matlab cart2pol function

Does the Matlab's cart2pol() function calculate the value of theta differently? Here's an example i worked out when converting to polar coordinates using cart2pol.
First, i implement it with cart2pol.
N = 8;
x = 1:N; y = x;
[X,Y] = meshgrid(x,y);
[theta,rho] = cart2pol(X-floor(N/2),-(Y-floor(N/2)))
which gives
Now, if i use the equation which is:
Note in Matlab, -1 and +1 is not required
theta = atan2((N-2.*Y),(2.*X-N))
i get:
Why is it that the value 3.1416 is negative for the cart2pol function and positive based on the equation?
As beaker said, the angle is the same. But regarding your comment: You can always use edit <functionname> to see how the Matlab function is implemented. This usually works for .m files, but not for P and MEX files, since these are binary and therefore can't be edited directly. So
edit cart2pol
in this case and you'll see that all cart2poldoes, is just atan2(y,x) to get theta. So this means that the different results are just due to the fact that you call the function using different inputs than the inputs you use in your "formula".
atan2(-(Y-floor(N/2)),X-floor(N/2))
gives exactly the same result as your call of cart2pol.

Fourier transform of normal density function

I am using the following MATLAB code to perform a Fourier transformation of a normal density function:
N=100;
j=0:(N-1);
a=-5;
b=5;
dx = (b-a)/N;
x = a+j*dx;
dt = 2*pi/(N*dx);
f1 = -N/2*dt;
f2 = N/2*dt;
t= f1+ j*dt;
GX = normpdf(x,0,1);
fft_GX = real(fft(GX))';
However, I do not get the expected bell shaped curve when I try to plot fft_GX.
The Fourier transformation of a normal density has the form of e^(-t^2/2). Can someone please help as to what I am doing incorrect?
Trying using abs instead of real.
Another helpful function to recenter the frequency domain is fftshift. Otherwise you will see the plot from 0 to 2*pi I believe, instead of the more recognizable view from -pi to pi.
fft_GX = abs(fftshift((fft(GX))');
plot(fft_GX);
You may need to do some further normalization based on the number of samples you have, but it looks more like the expected bell curve than what you were seeing originally.

Does MATLAB support double integration on single variable numerically?

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.

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