Find areas in discrete data, which can be approximated by lines - matlab

I have a discrete function y(n), n=1..8000 with two areas, which can be approximated by almost horizontal straight lines as shown in image.
I'd like to find coordinates x1, x2 of points where these areas meet the rapidly growing part of function. In Matlab, y(n) is a one-dimensional vector.

If data set is very smooth, you can use simple derivative magnitude detector.
If some noise peaks and small false fronts are possible, you'd better to use more robust method, for example
Choose some initial value for x1 (for example, 600)
Calculate linear regression parameters y = a*x + b for range 1..x1
If slope parameter a is small enough, increase x1 and repeat calculation
if slope is larger than some reasonable threshold, decrease x1 and repeat.
Binary search algorithm is rather quick way to reach needed x1 value.
Do the same for x2..N range.

As mentioned by #PatronBernard, you could look at the derivative of your trace, knowing that the derivative deviates from zero once you are no longer in the flat bit. This would involve manually picking a threshold which might have to be done for each new trace, and would be sensitive to noise in your trace. Here is an implementation, also showing the issues you might get with a noisy trace:
threshold = 0.2;
y1 = diff(y)/(x(2) - x(1));
y2 = diff(y1)/(x(2) - x(1));
figure;
hold on
plot(x,y, 'b')
xi = find(y1>threshold,1);
line([x(xi) x(xi)], ylim, 'Color', 'r')
xi = find(flipud(y1)>threshold,1);
line([x(length(x) - xi + 1) x(length(x) - xi + 1)], ylim, 'Color', 'r')
Alternatively, if you have genuinely noisy data I would recommend looking at IEC standard 60469:2013 "Transitions, Pulses and Related Waveforms - Terms, Definitions and Algorithms".

Related

MATLAB Wigner plot for Matching Pursuit atoms

Using MATLAB I apply Matching Pursuit to approximate a signal. My problem is that I struggle to visualize the time-frequency representation of the selected atoms. I'm trying to produce a Wigner plot similar to the following image (source).
I have looked into the Wavelet Toolbox, Signal Processing Toolbox as well as the open source Time-Frequency Toolbox, but I'm possibly just using the wrong parameters, since my experience with signal processing is quite limited.
Example
Using this data my goal is to reproduce the plot from above.
% fit the signal using MP
itermax = 50;
signal = load('signal.txt');
dict = wmpdictionary(length(signal));
[signal_fit, r, coeff, iopt, qual, X] = wmpalg('OMP', signal, dict, ...
'itermax', itermax);
% wigner plot of the simulated signal
tfrwv(signal_fit) % wigner-ville function from time-frequency toolbox
% wigner plot of each atom
atoms = full(dict(:, iopt)) % selected atoms
for i = 1:itermax
tfrwv(atoms(:, i))
end
Unfortunately, none of the resulting plots comes close to the target visualization. Note, that in the example I use tfrwv with standard parameters which I tweak with the GUI that it opens.
I'd greatly appreciate your help.
Update
I think I have now understood that one needs to use Gabor atoms to get blobs with shapes resembling stretched gaussians. Unfortunately, there are no Gabor functions in the predefined dicts of the Signal Processing Toolbox. However, this question helped me in implementing the needed dictionaries, such that I get atoms which look quite similar to the example:
Since my plots come close but are not perfect, there are still two questions open:
Can all of the blobs that we see in the first example be modeled by Gabor atoms alone, or do I need another dictionary of functions?
How can I combine the indidividual imagesc plots into a single visualization?
To answer your second question 'How can I combine the indidividual imagesc plots into a single visualization?'
If you have multiple 2d matrices that you want to superimpose and display using imagesc, I would suggest taking the element-wise maximum.
For example, I generate two 31x31 grids with gaussians with different mean and variance.
function F = generate2dGauss(mu, Sigma)
x1 = -3:.2:3; x2 = -3:.2:3;
[X1,X2] = meshgrid(x1,x2);
F = mvnpdf([X1(:) X2(:)],mu,Sigma);
F = reshape(F,length(x2),length(x1));
end
F1 = generate2dGauss([1 1], [.25 .3; .3 1]);
F2 = generate2dGauss([-1 -1], [.1 .1; .1 1]);
I can plot them with subplots as in your example,
figure;
subplot(1,2,1);
title('Atom 1');
imagesc(F1);
subplot(1,2,2);
title('Atom 2');
imagesc(F2);
Or I can plot the per element maximum of the two grids.
figure;
title('Both Atoms');
imagesc(max(F1, F2));
You can also experiment with element-wise means, sums, etc, but based on the example you give, I think maximum will give you the cleanest looking result.
Possible pros and cons of different functions:
Maximum will work best if your atoms always have zero-valued backgrounds and no negative values. If the background is zero-valued, but the atoms also contain negative values, the negative values may be covered up by the background of other atoms. If your atom's overlap, the higher value will of course dominate.
Mean will make your peaks less high, but may be more intuitive where you have overlap between atoms.
Sum will make overlapping areas larger valued.
If you have non-zero backgrounds, you could also try using logical indexing. You would have to make some decisions about what to do in overlapping areas, but it would make it easy to filter out backgrounds.
Q. How can I combine the indidividual imagesc plots into a single visualization?
A. Use subplot to draw multiple plots, find below sample with 2 by 2 plots in a figure. Change your equations in code
x = linspace(-5,5);
y1 = sin(x);
subplot(2,2,1)
plot(x,y1)
title('First subplot')
y2 = sin(2*x);
subplot(2,2,2)
plot(x,y2)
title('Second subplot')
y3 = sin(4*x);
subplot(2,2,3)
plot(x,y3)
title('Third subplot')
y4 = sin(6*x);
subplot(2,2,4)
plot(x,y4)
title('Fourth subplot')

How to analyze and visualize a 3D velocity field?

I am trying to use the best practice techniques in the Computational fluid dynamics area to analyze and visualize a velocity field.
Given 6 arrays of moving particles' positions and velocities: x,y,z and vx,vy,vz respectively.
I want to visualize and calculate the induced velocity field and its properties such as: curl, divergence, isosurfaces etc.
Here is a modest script of the volume visualization functions I was able to use without calling meshgrid (to avoid interpolation and more noise).
Ultimately, one of the things that I am not sure about is how to wisely create a mesh grid from my 50 points in space, the second is how to use CFD approaches to visualize the velocity field regardless the small amount of data points.
close all
rng default
t=0.1:0.1:10;
x = sin(t)';
y = cos(t)';
z = t.^0.2';
vx=y;vy=x;vz=z;
figure
subplot(2,3,1);
quiver3(x,y,z,vx,vy,vz);
hold on
streamribbon({ [x y z] }, {vx},{vy},{vz});
subplot(2,3,2);
[curl_val, cav] = curl([x,y,z],[vx,vy,vz]);
surfc([x,y,z],cav);
subplot(2,3,3);
surfc([x,y,z],curl_val);
w = sqrt( vx.^2 + vy.^2 + vz.^2 );
subplot(2,3,4);
quiver3(x,y,z,vx,vy,vz);
streamtube({ [x y z] }, {w});
subplot(2,3,5);
quiver3(x,y,z,vx,vy,vz);
subplot(2,3,6);
surfc([x,y,z],[vx,vy,vz]);
When I run the above script (excluding the data generation) on a real data, I get the following plots which aren't very informative:
I strongly suspect that the problem here is with the data, not the visualization technique. But in general, the problem is one or more of the following:
1) You do not have enough data to capture the underlying dynamics (the dynamics in space operate at a higher spatial frequency than you sampled)
2) The data is too noisy for the number of datapoints your collected.
3) The flow is fundamentally turbulent, and hence hoping for a nice laminar-like plot is not going to happen.
When you have problems visualizing data, the first rule of thumb is always to throw away any visualization that attempts to approximate a derivative (or gradient) in any way. The reason is that when you try to approximate a derivative with real data, noise almost always makes that estimate nonsense. For example, let's suppose we have a cosine that gets corrupted by some noise, and we try to numerically estimate the derivative from the data
figure
% Create a signal
dt = .1;
t = 0:.1:10;
x = cos(t);
% Add some noise
y = x + .5 * randn(size(x));
% Compute the first order approximation of the derivatives of the signals
dx = diff(x)/dt;
dy = diff(y)/dt;
% Plot everything
subplot(2,1,1)
plot(t,x,t,y)
axis tight
subplot(2,1,2)
plot(t(2:end),dx,t(2:end),dy)
axis tight
In the first plot, which shows the raw data, the noise doesn't look to bad, but when we look at the derivative estimate! Ouch... The noise is really amplified. So forget about higher order properties of a flow, such as the curl and vorticity, which require gradients of the data.
So what can we do in cases like these? Well essentially, just look at the raw data. If there is a pattern, it will reveal itself. For instance, let's look at your raw velocity vectors from 3 different perspectives:
data = dlmread('data.csv','\s')
x = data(:,1);
y = data(:,2);
z = data(:,3);
vx = data(:,4);
vy = data(:,5);
vz = data(:,6);
close all
figure
subplot(1,3,1);
quiver3(x,y,z,vx,vy,vz);
view([1,0,0])
subplot(1,3,2);
quiver3(x,y,z,vx,vy,vz);
view([0,1,0])
subplot(1,3,3);
quiver3(x,y,z,vx,vy,vz);
view([0,0,1])
The only thing that looks even slightly structured is that last plot. However, that plot tells us that we probably also have turbulence (in addition to noise) to contend with.
Specifically, from view 3, it definitely seems like you are taking velocity measurements in a flow that is tightly hugging an object. In this case, your measurements are probably too tight though... and probably in the boundary layer. If that is the case (that the measurements are in the boundary layer), then you can get time-varying effects in the flow, meaning that it doesn't make sense to look at anything without also having a time component. The "nice" plots that you have in your answer are only really helpful when the flow is laminar, where we get to see these nice, consistent stream lines. If it is turbulent, then there is no discernable pattern in the flow, no matter how hard you look.
So in conclusion, I don't think you will be able to find a nice visualization for your data because either the sensors you used were too noisy, or the flow was too turbulent.
As an aside... consider what happens when we look at the raw velocity vectors from your "nice" dataset:
That, my friend, is a well-trained house pet. You have a wild mountain lion on your hands.

How can I define the period before fitting a Fourier series to discrete data using MATLAB?

I'm using MATLAB's fit function:
fourier_series=(x,y,'fourier8');
to fit an 8th order Fourier series to a set of discrete data (x,y). I need the period of the Fourier series to be 2*pi. However I can't work out how to fix this so that when I call the function it fits the series to my required period. Any suggestions would be greatly appreciated. Thanks.
Background to problem:
I am analysing video capture data of cyclist's pedalling which outputs as a cloud of joint positions in 3D space over time. The joint positions change slightly every pedal stroke. I am therefore wishing to fit Fourier series' to these joint positions and joint angles as a function of crank arm angle to find the cyclist's "average" position. The period of the Fourier series' therefore need to be constrained to be 2*pi as the "average" positions must return to the same location when the crank arm angle is zero (i.e. top dead centre, TDC) and the crank arm angle is 2*pi (i.e. TDC after one crank arm rotation).
Currently MATLAB is selecting the period to be slightly greater than 2*pi which means that when I use the Fourier series' to calculate the cyclist's position, the cyclist's position changes for the same crank arm angle on consecutive pedal strokes.
The best way to force the fit function on a certain period is to resort to a custom equation model, via fittype. Another option (that will throw a warning) is to fix the lower and upper bounds of the parameter w to the same value, and select as solution method LinearLeastSquares.
A cleaner solution is obtained by observing that, since you already know the period the fitting problem is linear in the parameters, and so you can resort to the linear least-squares method. I'll show hereafter an example of this approach.
%// Build a simple time series with period 2*pi.
t = (0:0.01:4*2*pi)';
y = sawtooth(t);
T = 2*pi;
%// Compute the angular speed and the azimuth.
Omega = 2*pi/T;
alpha = Omega*t;
%// Build the regressor matrix, with n harmonics.
n = 8;
A = ones(length(t), 2*n+1);
for i = 1:n
A(:,[2*i 2*i+1]) = [cos(i*alpha) sin(i*alpha)];
end
%// Solve the linear system.
%// The parameters are sorted as:
%// p = [y0 a1 b1 a2 b2 ...]'
%// being y0 the average of y, a_i the terms multiplying the sines
%// and b_i the terms multiplying the cosines.
p = A\y;
%// Evaluate the Fourier series.
yApprox = A*p;
%// Compare the solution with the data.
figure();
hold on;
plot(t, y, 'b');
plot(t, yApprox, 'r');

Pi phase shift b/w adjacent pixels while using fft2

I have a 2D Gaussian beam at its waist (where the phase is zero throughout the transverse plane). When I use fft2 to find the 2D spatial Fourier transform and plot the phase, I observe that there is a pi phase shift between any 2 adjacent data points. However, I don't observe this when I use for loops to calculate the Fourier transform instead of using fft2.
Is this due to phase wrapping? How do I overcome this?
Thanks.
Edit: I'm posting the code for the fft of a circular aperture, since the same results are observed, and because it is much simpler.
Nx = 200; Ny = Nx;
%creating coordinate grids
x = -Nx/2:Nx/2 - 1; y = -Ny/2:Ny/2 - 1;
[X,Y] = meshgrid(x,y);
r = 15; %radius of aperture
Eip = ((X.^2 + Y.^2 ) <= r^2); %aperture
figure;pcolor(abs(Eip));axis square; shading flat; colorbar;
figure;pcolor(angle(Eip));axis square; shading flat; colorbar;
Cip = fftshift(fft2(Eip)); %FFT
figure;pcolor(abs(Cip));axis square; shading flat; colorbar;
figure;pcolor(angle(Cip));axis square; shading flat; colorbar;
Short answer
Cip turns out to be real. You're just seeing sign changes between contiguous points.
Long answer
Eip is obviously real. Besides, it exhibits the following symmetry along the x and y axes. Let's take the x axis first. For any fixed y, consider Eip as a finite signal defined at x values 0,1,...,Nx-1. If that finite signal is extended into a periodic sequence, then this periodic sequence turns out to be even. This is true for your specific definition of Eip. Together with the fact that the values are real, this implies1 that the DFT along x is also real and has the same type of symmetry. Now, regarding the y axis, the same holds. The final result is that the 2D-DFT Cip is real and has the mentioned x and y symmetries.
(As a side note, Cip as obtained in your code is not real but complex. However, the imaginary part is of the order of eps, and thus negligible. You can check:
>> max(real(Cip(:)))
ans =
709
>> max(imag(Cip(:)))
ans =
4.6262e-014
So the imaginary part is only an artifact of finite numerical precision. We can do
Cip = real(Cip);
to remove that spurious imaginary part.)
Now that we know that Cip is real (up to numerical precision), it's natural that all its values have phase either 0 or pi (or equivalently -pi). That is, what you are seeing is just changes of sign between consecutive values in the DFT. To illustrate, see the following graph, which shows the variation of Cip along a line parallel to the y axis (corresponding to x equal to 120; just as an example):
stem(1:Nx, Cip(120,:))
1
See Discrete-time signal processing, Oppenheim et al., 2nd ed., pp. 568--570.
To avoid this, you need an additional ifftshift.
This is due to the algorithm Matlab uses and the results you expect.
To avoid the pi phase jumps use this instead:
fftshift(fft2(ifftshift(Eip)));

How can I find equation of a plot connecting data points in Matlab?

I have various plots (with hold on) as show in the following figure:
I would like to know how to find equations of these six curves in Matlab. Thanks.
I found interactive fitting tool in Matlab simple and helpful, though somewhat limited in scope:
The graph above seems to be linear interpolation. Given vectors X and Y of data, where X contains the arguments and Y the function points, you could do
f = interp1(X, Y, x)
to get the linearly interpolated value f(x). For example if the data is
X = [0 1 2 3 4 5];
Y = [0 1 4 9 16 25];
then
y = interp1(X, Y, 1.5)
should give you a very rough approximation to 1.5^2. interp1 will match the graph exactly, but you might be interested in fancier curve-fitting operations, like spline approximations etc.
Does rxns stand for reactions? In that case, your curves are most likely exponential. An exponential function has the form: y = a*exp(b * x) . In your case, y is the width of mixing zone, and x is the time in years. Now, all you need to do is run exponential regression in Matlab to find the optimal values of parameters a and b, and you'll have your equations.
The advice, though there might be better answer, from me is: try to see the rate of increase in the curve. For example, cubic is more representative than quadratic if the rate of increase seems fast and find the polynomial and compute the deviation error. For irregular curves, you might try spline fitting. I guess there is also a toolbox in matlab for spline fitting.
There is a way to extract information with the current figure handle (gcf) from you graph.
For example, you can get the series that were plotted in a graph:
% Some figure is created and data are plotted on it
figure;
hold on;
A = [ 1 2 3 4 5 7] % Dummy data
B = A.*A % Some other dummy data
plot(A,B);
plot(A.*3,B-1);
% Those three lines of code will get you series that were plotted on your graph
lh=findall(gcf,'type','line'); % Extract the plotted line from the figure handle
xp=get(lh,'xdata'); % Extract the Xs
yp=get(lh,'ydata'); % Extract the Ys
There must be other informations that you can get from the "findall(gcf,...)" methods.