MATLAB vectors, angles, plots - matlab

I apologize for the ambiguous title, but I am not entirely sure how to phrase this one. So bear with me.
I have a matrix of data. Each column and row represents a certain vector (column 1 = row 1, column 2 = row 2, etc.), and every cell value is the cosine similarity between the corresponding vectors. So every value in the matrix is a cosine.
There are a couple of things I want to do with this. First, I want to create a figure that shows all of the vectors on it. I know the cosine of the angle between every vector, and I know the magnitude of each vector, but that is the only information I have - is there some algorithm I can implement that will run through all of the various pair-wise angles and display it graphically? That is, I don't know where all the vectors are in relation to each other, and there are too many data points to do this by hand (e.g. if I only had three vectors, and the angles between them all were 45, 12, and 72 degrees it would be trivial). So how do I go about doing this? I don't even have the slightest idea what sort of mathematical function I would need to do this. (I have 83 vectors, so that's thousands of cosine values). So basically this figure (it could be either 2D or multidimensional, and to be honest I would like to do both) would show all of the vectors and how they relate to each other in space (so I could compare both angles and relative magnitudes).
The other thing I would like to do is simpler but I am having a hard time figuring it out. I can convert the cosine values into Cartesian coordinates and display them in a scatter plot. Is there a way to connect each of the points of a scatter plot to (0,0) on the plot?
Finally, in trying to figure out how to do some of the above on my own I have run into some inconsistencies. I calculated the mean angles and Cartesian coordinates for each of the 83 vectors. The math for this is easy, and I have checked and double-checked it. However, when I try to plot it, different plotting methods give me radically different things. So, if I plot the Cartesian coordinates as a scatter plot I get this:
If I plot the mean angles in a compass plot I get this:
And if I use a quiver plot I get something like this (I transformed this a little by shifting the origin up and to the right just so you can see it better):
Am I doing something wrong, or am I misunderstanding the plotting functions I am using? Because these results all seem pretty inconsistent. The mean angles on the compass plot are all <30 degrees or so, but on the quiver plot some seem to exceed 90 degrees, and on the scatter plot they extend above 30 as well. What's going on here?
(Here is my code:)
cosine = load('LSA.txt');
[rows,columns]=size(cosine);
p = cosine.^2;
pp = bsxfun(#minus, 1, p);
sine = sqrt(pp);
tangent = sine./cosine;
Xx = zeros(rows,1);
Yy = zeros(rows,1);
for i = 1:columns
x = cosine(:,i);
y = sine(:,i);
Xx(i,1) = sum(x) * (1/columns);
Yy(i,1) = sum(y) * (1/columns);
end
scatter(Xx,Yy);
Rr = zeros(rows,1);
Uu = zeros(rows,1);
for j = 1:rows
Rr(j,1) = sqrt(Xx(j,1).^2 + Yy(j,1).^2);
Uu(j,1) = atan2(Xx(j,1),Yy(j,2));
end
%COMPASS PLOT
[theta,rho] = pol2cart(Uu,1);
compass(theta,rho);
%QUIVER PLOT
r = 7;
sx = ones(size(cosine))*2; sy = ones(size(cosine))*2;
pu = r * cosine;
pv = r * sine;
h = quiver(sx,sy,pu,pv);
set(gca, 'XLim', [1 10], 'YLim', [1 10]);

You can exactly solve this problem. The dot product calculates the cosine. This means your matrix is actually M=V'*V
This should be solvable through eigenvalues. And you said you also have the length.
Your only problem - as your original matrix the vectors will be 83 dimensional. Not easy to plot in 2 or 3 dimensions. I think you are over simplifying by just using the average angle. There are some techniques called dimensionality reduction - here's a toolbox. I would suggest a sammon projection on 1-cosine (as this would be the distance of points on the unit ball) to calculate the vectors for such a plot.

In the quiver plot, you are plotting all of the data in the cosine and sine matrices. In the other plots, you are only plotting the means. The first two plots appear to match up, so no problem there.
A few other things. I notice that in
Uu(j,1) = atan2(Xx(j,1),Yy(j,2));
Yy(j,2) is not actually defined, so it seems like this code should fail.
Furthermore, you could define Yy and Xx as:
Xx = mean(cosine,2);
Yy = mean(sine,2);
And also get rid of the other for loop:
Rr = sqrt(Xx.^2 + Yy.^2)
Uu = atan2(Xx,Yy)
I still have to think about your first question, but I hope this was helpful.

Related

Interpolation between curves that may overlap

I try to interpolate curves in the gaps of some already existing curves using matlab (and the interp1-function).
Start of edit 1
I already have the data of 5 Torque over rpm curves that I obtained with a number of simulations for each curve. Since simulation time is precious, I would like to save time with the interpolation of curves that "fill the gap" between the already existing ones.
I'm looking to form the following:
Further thoughts of me down below.
End of edit 1
I tried to follow the steps from the question in the thread Interpolation between two curves (matlab) but it does not seem to work with my code. I am not sure if the code is actually applicable since the curves might overlap...
I tried to edit the code from the link above like the following:
% Save the data in one array each. The original data is stored in the
% arrays "x/yOriginal" row-wise.
curve1_data = [xOriginal(:,1) yOriginal(:,1)];
curve2_data = [xOriginal(:,2) yOriginal(:,2)];
% This was to try if the code from the link works
yy = [0:1:60];
xx1 = interp1(curve1_data(:,2),curve1_data(:,1),yy,'spline');
xx2 = interp1(curve2_data(:,2),curve2_data(:,1),yy,'spline');
m = 3; % Curve_Offset
mm(:,m) = xx1 + (xx2-xx1)*(m/(8750-5000));
% With the following I tried to interpolate over x
xx = (xOriginal(1,1):1:xOriginal(1,2));
yy1 = interp1(curve1_data(:,1),curve1_data(:,2),xx,'spline');
yy2 = interp1(curve2_data(:,1),curve2_data(:,2),xx,'spline');
m = 3; % Curve_Offset
% From the original code:
mm(:,m) = xx1 + (xx2-xx1)*(m/(8750-5000));
% Interpolation over x
yINT = yy1 + (yy2-yy1)*(m/8750-5000);
None of the interpolation-techniques worked, the y-values are either 90% negative (with the code from the link) or way too high (10e8 with the interpolation over x).
What I expected was that it creates a curve a little less steep than the curve "to its left" and a bit steeper than the curve "to its right".
My further thoughts:
The existing curves are the product of big 3-dimensional arrays. I.e. it could be that it is more the way to go to interpolate the arrays and then "read out" the Torque-over-rpm-Curves. On the other hand, I don't see a way to interpolate between two 1001-by-7001-by-5 arrays...
Moreover, for the next steps with the programm, the curve-interpolation needs to be quite fine (it is necessary to have way more than 1 interpolated curve between two existing curves) which makes the problem even more difficult.
If I understand right, the plot is generated with something like this:
plot(xOriginal(:,1),yOriginal(:,1))
plot(xOriginal(:,2),yOriginal(:,2))
% ...
If so, you can plot an intermediate curve with
plot((xOriginal(:,1) + xOriginal(:,2))/2, (yOriginal(:,1) + yOriginal(:,2))/2)
That is, the average between each pair of coordinates forms a curve that is exactly half-way between the two original curves.
Use weighted averages to generate more of these curves. This is linear interpolation.
d = 0.2;
plot(d*xOriginal(:,1) + (1-d)*xOriginal(:,2), d*yOriginal(:,1) + (1-d)*yOriginal(:,2))
Setting d = 0.5 we go back to the half-way case above.
Example:
xOriginal(:,1) = linspace(0.2,0.5,100);
yOriginal(:,1) = 3 * cos(xOriginal(:,1)*10-2.5) + 3;
xOriginal(:,2) = linspace(0.6,0.8,100);
yOriginal(:,2) = cos(xOriginal(:,2)*20-13.5) + 1;
clf; hold on
plot(xOriginal(:,1),yOriginal(:,1))
plot(xOriginal(:,2),yOriginal(:,2))
plot((xOriginal(:,1)+xOriginal(:,2))/2,(yOriginal(:,1)+yOriginal(:,2))/2)
(the interpolated line is in orange)

Properly finding peaks in MATLAB in 3D spectrogram

I am trying to do a spectrogram analysis on a song. Currently I have about a 10 second clip from a song and am attempting to find the local peaks.
All I really want is to have a scatter plot showing local maxima within some NxN neighborhood worth of amplitudes
[y,fs] = audioread('audio_file.wav');
window = hamming(512);
num_overlap = 256;
nfft = 1024;
[S,F,T,P] = spectrogram(y(:,1), window, num_overlap, nfft, fs, 'yaxis');
surf(T,F,10*log10(P), 'edgecolor', 'none'); axis tight; view(0, 90); colormap hot;
This results in the below image:
Where the x-axis is of course time [0,~10], y-axis is frequency [0,22.5 KHz] and the z-axis is the amplitude
Now What I would like to do is create a 3D scatter plot over this surf to show where the peaks are. The dimensions of S, F, T, P are
S: 513 x 1770 complex double
F: 513 x 1 double
T: 1 x 1770 double
P: 513 x 1770 double
Now this is where I am pretty sure I am doing something wrong or not understanding MATLAB entirely.
msk = true(3,3,3);
msk(2,2,2) = false;
dil = imdilate(10*log10(P), msk);
M = 10*log10(P) > dil;
My understanding is that will get me a 1 wherever my local peak is
Now let's just say that amp = 10*log10(P), I would like to just be able to call scatter3 the same way I called surf, like so:
scatter3(T, F, amp(M))
but of course I get X, Y and Z must be vectors of the same length. I suppose that makes sense to me so I decided to repeat the values as many times as they needed to be to get the axes equal.
Tr = repelem(T, 513)';
Fr = repelem(F, 1770);
Zr = reshape(amp, [908010, 1]);
[pks, locs] = findpeaks(Zr);
scatter3(Tr(locs), Fr(locs), Zr(locs));
This results in a 3D scatter plot like so:
And that is definitely not right because there should be many local peaks throughout the amplitude shown. I'm not really sure what I'm doing wrong, but I'm also almost positive that there's an easier way to achieve what I want. All I really want is to have a scatter plot showing local maxima within some NxN neighborhood worth of amplitudes
If I understand want you want, you have a matrix M with local peaks and your want to draw scatter in the locations of the peaks. You can get the row\col of each peak using find and the linear index using sub2ind:
[Fi,Ti] = find(10*log10(P) > dil);
Pi = sub2ind(size(P),Fi,Ti);
scatter3(T(Ti),F(Fi),amp(Pi));

What interpolation technique does Matlab plot function use to show the data?

It seems to be very basic question, but I wonder when I plot x values against y values, what interpolation technique is used behind the scene to show me the discrete data as continuous? Consider the following example:
x = 0:pi/100:2*pi;
y = sin(x);
plot(x,y)
My guess is it is a Lagrangian interpolation?
No, it's just a linear interpolation. Your example uses a quite long dataset, so you can't tell the difference. Try plotting a short dataset and you'll see it.
MATLAB's plot performs simple linear interpolation. For finer resolution you'd have to supply more sample points or interpolate between the given x values.
For example taking the sinus from the answer of FamousBlueRaincoat, one can just create an x vector with more equidistant values. Note, that the linear interpolated values coincide with the original plot lines, as the original does use linear interpolation as well. Note also, that the x_ip vector does not include (all) of the original points. This is why the do not coincide at point (~0.8, ~0.7).
Code
x = 0:pi/4:2*pi;
y = sin(x);
x_ip = linspace(x(1),x(end),5*numel(x));
y_lin = interp1(x,y,x_ip,'linear');
y_pch = interp1(x,y,x_ip,'pchip');
y_v5c = interp1(x,y,x_ip,'v5cubic');
y_spl = interp1(x,y,x_ip,'spline');
plot(x,y,x_ip,y_lin,x_ip,y_pch,x_ip,y_v5c,x_ip,y_spl,'LineWidth',1.2)
set(gca,'xlim',[pi/5 pi/2],'ylim',[0.5 1],'FontSize',16)
hLeg = legend(...
'No Interpolation','Linear Interpolation',...
'PChip Interpolation','v5cubic Interpolation',...
'Spline Interpolation');
set(hLeg,'Location','south','Fontsize',16);
By the way..this does also apply to mesh and others
[X,Y] = meshgrid(-8:2:8);
R = sqrt(X.^2 + Y.^2) + eps;
Z = sin(R)./R;
figure
mesh(Z)
No, Lagrangian interpolation with 200 equally spaced points would be an incredibly bad idea. (See: Runge's phenomenon).
The plot command simply connects the given (x,y) points by straight lines, in the order given. To see this for yourself, use fewer points:
x = 0:pi/4:2*pi;
y = sin(x);
plot(x,y)

How to make a vector that follows a certain trend?

I have a set of data with over 4000 points. I want to exclude grooves from them, ideally from the point from which they start. The data look for example like this:
The problem with this is the noise I get at the top of the plateaus. I have an idea, in which I would take an average value of the most common within some boundaries (again, ideally sth like the red line here:
and then I would construct a temporary matrix, which would fill up one by one with Y if they are less than this average. If the Y(i) would rise above average, the matrix would find its minima and compare it with the global minima. If the temporary matrix's minima wouldn't be sth like 80% of the global minima, it would be discarded as noise.
I've tried using mean(Y), interpolating and fitting it in a polynomial (the green line) - none of those method would cut it to the point I would be satisfied.
I need this to be extremely robust and it doesn't need to be quick. The top and bottom values can vary a lot, as well as the shape of the plateaus. The groove width is more or less the same.
Do you have any ideas? Again, the point is to extract the values that would make the groove.
How about a median filter?
Let's define some noisy data similar to yours, and plot it in blue:
x = .2*sin((0:9999)/1000); %// signal
x(1000:1099) = x(1000:1099) + sin((0:99)/50*pi); %// noise: spike
x(5000:5199) = x(5000:5199) - sin((0:199)/100*pi); %// noise: wider spike
x = x + .05*sin((0:9999)/10); %// noise: high-freq ripple
plot(x)
Now apply the median filter (using medfilt2 from the Image Processing Toolbox) and plot in red. The parameter k controls the filter memory. It should chosen to be large compared to noise variations, and small compared to signal variations:
k = 500; %// filter memory. Choose as needed
y = medfilt2(x,[1 k]);
hold on
plot(y, 'r', 'linewidth', 2)
In case you don't have the image processing toolbox and can't use medfilt2 a method that's more manual. Skip the extreme values, and do a curve fit with sin1 as curve type. Note that this will only work if the signal is in fact a sine wave!
x = linspace(0,3*pi,1000);
y1 = sin(x) + rand()*sin(100*x).*(mod(round(10*x),5)<3);
y2 = 20*(mod(round(5*x),5) == 0).*sin(20*x);
y = y1 + y2; %// A messy sine-wave
yy = y; %// Store the messy sine-wave
[~, idx] = sort(y);
y(idx(1:round(0.15*end))) = y(idx(round(0.15*end))); %// Flatten out the smallest values
y(idx(round(0.85*end):end)) = y(idx(round(0.85*end)));%// Flatten out the largest values
[foo goodness output] = fit(x.',y.', 'sin1'); %// Do a curve fit
plot(foo,x,y) %// Plot it
hold on
plot(x,yy,'black')
Might not be perfect, but it's a step in the right direction.

vectorizing 4 nested for-loops in Matlab

I'm writing a program for school and I have nested for-loops that create a 4-dimensional array (of the distances between two points with coordinates (x,y) and (x',y')) as below:
pos_x=1:20;
pos_y=1:20;
Lx = length(pos_x);
Ly = length(pos_y);
Lx2 = Lx/2;
Ly2 = Ly/2;
%Distance function, periodic boundary conditions
d_x=abs(repmat(1:Lx,Lx,1)-repmat((1:Lx)',1,Lx));
d_x(d_x>Lx2)=Lx-d_x(d_x>Lx2);
d_y=abs(repmat(1:Ly,Ly,1)-repmat((1:Ly)',1,Ly));
d_y(d_y>Ly2)=Ly-d_y(d_y>Ly2);
for l=1:Ly
for k=1:Lx
for j=1:Ly
for i=1:Lx
distance(l,k,j,i)=sqrt(d_x(k,i).^2+d_y(l,j).^2);
end
end
end
end
d_x and d_y are just 20x20 matrices and Lx=Ly for trial purposes. It's very slow and obviously not a very elegant way of doing it. I tried to vectorize the nested loops and succeeded in getting rid of the two inner loops as:
dx2=zeros(Ly,Lx,Ly,Lx);
dy2=zeros(Ly,Lx,Ly,Lx);
distance=zeros(Ly,Lx,Ly,Lx);
for l=1:Ly
for k=1:Lx
dy2(l,k,:,:)=repmat(d_y(l,:),Ly,1);
dx2(l,k,:,:)=repmat(d_x(k,:)',1,Lx);
end
end
distance=sqrt(dx2.^2+dy2.^2);
which basically replaces the 4 for-loops above. I've now been trying for 2 days but I couldn't find a way to vectorize all the loops. I wanted to ask:
whether it's possible to actually get rid of these 2 loops
if so, i'd appreciate any tips and tricks to do so.
I have so far tried using repmat again in 4 dimensions, but you can't transpose a 4 dimensional matrix so I tried using permute and repmat together in many different combinations to no avail.
Any advice will be greatly appreciated.
thanks for the replies. Sorry for the bad wording, what I basically want is to have a population of oscillators uniformly located on the x-y plane. I want to simulate their coupling and the coupling function is a function of the distance between every oscillator. And every oscillator has an x and a y coordinate, so i need to find the distance between osci(1,1) and osci(1,1),..osci(1,N),osci(2,1),..osci(N,N)... and then the same for osci(1,2) and osci(1,1)...osci(N,N) and so on.. (so basically the distance between all oscillators and all other oscillators plus the self-coupling) if there's an easier way to do it other than using a 4-D array, i'd also definitely like to know it..
If I understand you correctly, you have oscillators all over the place, like this:
Then you want to calculate the distance between oscillator 1 and oscillators 1 through 100, and then between oscillator 2 and oscillators 1 through 100 etc. I believe that this can be represented by a 2D distance matrix, were the first dimension goes from 1 to 100, and the second dimension goes from 1 to 100.
For example
%# create 100 evenly spaced oscillators
[xOscillator,yOscillator] = ndgrid(1:10,1:10);
oscillatorXY = [xOscillator(:),yOscillator(:)];
%# calculate the euclidean distance between the oscillators
xDistance = abs(bsxfun(#minus,oscillatorXY(:,1),oscillatorXY(:,1)')); %'# abs distance x
xDistance(xDistance>5) = 10-xDistance; %# add periodic boundary conditions
yDistance = abs(bsxfun(#minus,oscillatorXY(:,2),oscillatorXY(:,2)')); %'# abs distance y
yDistance(yDistance>5) = 10-yDistance; %# add periodic boundary conditions
%# and we get the Euclidean distance
euclideanDistance = sqrt(xDistance.^2 + yDistance.^2);
I find that imaginary numbers can sometimes help convey coupled information quite well while reducing clutter. My method will double the number of calculations necessary (i.e. I find the distance X and Y then Y and X), and I still need a single for loop
x = 1:20;
y = 1:20;
[X,Y] = meshgrid(x,y);
Z =X + Y*i;
z = Z(:);
leng = length(z);
store = zeros(leng);
for looper = 1:(leng-1)
dummyz = circshift(z,looper);
store(:,looper+1) = z - dummyz;
end
final = abs(store);