[matlab]Creating Random Gaussian variables using covariance matrix - matlab

[(Workspace)][1]I created random variables using covariance Matrix. I want to generate 300 random two dimensional feature data (length & weight) of each specie ω1 (salmon) and ω 2(bass).
Salmon (ω 1): mean: 65 cm, 22 kg covariance: [20 0.1; 0.1 70]
Sea bass (ω 2): mean : 80 cm, 31 kg covariance: [40 5; 5 50]
After I created Samples, I computed covariance Matrix again just to check out. But I found it totally wrong from the original covariance matrix. Can somebody help me out please? Attached is my code and different result. Please Help Me :(

I believe you might be creating the wrong data, try creating it this way:
% 0. INITILIZATION
clc, clear all, close all
rng default % For reproducibility
N = 200; %Number of samples
% 1. Data info
mu1 = [65 22]';
mu2 = [80 31]';
mu = [mu1 mu2];
covar1 = [20 0.1;0.1 70];
covar2 = [40 5;5 50];
% Data generation
Dset1 = mvnrnd(mu1,covar1,N)';
Dset2 = mvnrnd(mu2,covar2,N)';
figure('name', 'Data set X and X'''), hold on
% Plot the data
plot(Dset1(1,:),Dset1(2,:), 'b.',Dset2(1,:),Dset2(2,:), 'r.')
Also, if you want to check if the data has indeed the proper covariance, use a bigger N, say 5000 for example.

Related

How to scale amplitude of polar plot?

I have a matrix of data. I used the polarplot command in MATLAB to plot this matrix with respect to theta.
The data oscillates between 3999.20 and 4001.52 As you can see in the following plot, the order of magnitude of oscillation of data is too small to see.
How can I modify my polar plot to see small oscillations?
My code is as below:
yf=[%750 data point]
theta = 0:4*pi/749:4*pi;
rho = yf
pax = polaraxes;
polarplot(theta,rho)
pax.ThetaDir = 'counterclockwise';
pax.ThetaZeroLocation='right'
pax.ThetaColor='r'
pax.ThetaTick=[0 30 60 90 120 150 180 210 240 270 300 330 ];
pax.RDir='normal';
pax.RTick=[3999.34 3999.67 4000 4000.33 4000.66 4000.99 4001.33 ]
pax.FontSize = 12;
Desired output:
Actual output
2-axis plot
To give an example of setting the r limits as suggested by #beaker
The following code uses the same data with using rlim to set manual limits in the second example. This scales the polar axis so that it only plots values between [3999,4000], exaggerating the scale of the oscillation.
theta = 0:0.01:2*pi;
rho = sin(2*theta).*cos(2*theta) + 3999 %To approximate your data
figure;
subplot(1,2,1)
polarplot(theta,rho)
title('Automatic r-limits')
subplot(1,2,2)
polarplot(theta,rho)
rlim([3999, 4000])
title('rlim([3999, 4000])')
Something like that maybe, where you subtract the mean of the data and scale the amplitude by a factor of 10?
yf=[%750 data point]
amp = yf - mean(yf);
amp = amp*10; % choose whatever scaling factor works for you
theta = 0:4*pi/749:4*pi;
rho = mean(yf) + amp;
Without the actual data, it's difficult to say what this will look like, but the general principle should work.

MATLAB: add a line to 3D plot

I would like to add a reference line on a 3d plot which follows the surface built with mesh(). I have 3 points in the x and y axis to build the line and so will need to interpolate to find z axis coordinates. Here is my code (with reproducible data) so far:
acceleration_dB = [0 109.3699 118.0084 133.9584 104.3017 110.5423 120.6332 140.6567 144.4194 129.7292]';
frequency = [1 50 50 50 100 100 100 100 100 500]';
voltage = [ 1.0e-04 * 0.0001 0.0968 0.1645 0.2983 0.0278 0.0368 0.0893 0.2785 0.4928 0.0780 ]';
xlin=linspace(0, max(frequency),33);
ylin=linspace(min(acceleration_dB), max(acceleration_dB),33);
[X, Y] = meshgrid(xlin,ylin);
f = scatteredInterpolant(frequency,acceleration_dB,log(voltage));
Z=f(X,Y);
figure();
mesh(X,Y,Z);
hold on
% Add threshold reference line
threshAccel = [97.0870 104.4212 109.5787]
threshFreq = [50 100 500]
Zthresh=f(threshFreq,threshAccel);
plot3(threshFreq,threshAccel,Zthresh,'Color','black','LineWidth',1)
Which gives:
What I would like is the black line following the plane of the surface for the whole length of the x-axis.
Any advice would be greatly appreciated. Thank you!
It is just a problem of range I think. This seems to work pretty well:
threshAccel = [97 97.0870 104.4212 109.5787]
threshFreq = [0 50 100 500]
but I am not sure about that 97 and 0 are the precise values. You should correct them probably.

Translating 2D image with RGB colours along axes

I am trying to create my own voronoi diagram. I have an arbitrary shape defined by their x and y coordinates stored in separate vectors. Inside this shape are some points of interest (with known coordinates) that belong to two different groups and act as seeds to the voronoi diagram. As an example, the whole diagram ranges from x=-10 to x=90 and y=-20 to y=60. The boundary shape is not rectangular but falls within the axes range above.
What I have done so far is to create a 3D matrix (100 X 80 X 3), C, with all ones so that the default colour will be white. I then looped through from i=1:100, j=1:80, testing individual pixels to see if they fall within the shape using inpolygon. If they do, I then find out which point is the pixel closest to and assign it a colour based on whether the closest point belongs to group 1 or 2.
All is good so far. I then used imagesc to display the image with a custom axis range. The problem is that the voronoi diagram has the general shape but it is off in terms of position as the pixel coordinates are different from the actual world coordinates.
I tried to map it using imref2d but I do not know how it really works or how to display the image after using imref2d. Please help me on this.
I am open to other methods too!
Thank you!
Edit:
As requested, let me give a more detailed example and explanation of my problem.
Let us assume a simple diamond shape boundary with the following vectors and 4 points with the following coordinate vectors:
%Boundary vectors
Boundary_X = [-5 40 85 40 -5];
Boundary_Y = [20 50 20 -10 20];
%Point vectors
Group_One_X = [20 30];
Group_One_Y = [10 40];
Group_Two_X = [50 70];
Group_Two_Y = [5 20];
Next I plot all of them, with different groups having different colours.
%Plot boundary and points
hold on
plot(Boundary_X,Boundary_Y)
scatter(Group_One_X,Group_One_Y,10,'MarkerFaceColor','Black',...
'MarkerEdgeColor','Black')
scatter(Group_Two_X,Group_Two_Y,10,'MarkerFaceColor','Red',...
'MarkerEdgeColor','Red')
hold off
axis([-10, 90, -20, 60])
This is the result:
Boundary with points
Next I test the whole graph area pixel by pixel, and colour them either cyan or yellow depending on whether they are closer to group 1 or 2 points.
%Create pixel vector with default white colour
C=ones(100,80,3);
Colour_One = [0 1 1];
Colour_Two = [1 1 0];
%Loop through whole diagram
for i=1:100
for j=1:80
x=i;
y=j
if inpolygon(x,y,Boundary_X,Boundary_Y)
%Code for testing which point is pixel closest to
%If closest to group 1, assign group 1 colour, else group 2
%colour
end
end
end
%Display image
hold on
imagesc(C)
hold off
This is the result
Failed Voronoi Diagram
The shape is somewhat correct for the right side but not for the others. I understand that this because my world coordinates start from negative values but the pixel coordinates start from 1.
Hence I am at a lost as to how can I solve this problem.
Thank you!
One thing to notice is that you have to convert between image and plot coordinates. The plot coordinates are (x,y) where x goes to the right, and y goes up. The matrix coordinates are (i,j) where i goes down, and j to the right. An easy way to do this is with the use of vec_X,vec_Y as shown below.
Another solution for the newer Matlab versions would be - as you said - using imref2d but unfortunately I have no experience with that command.
%Boundary vectors
Boundary_X = [-5 40 85 40 -5];
Boundary_Y = [20 50 20 -10 20];
%Point vectors
Group_One_X = [20 30];
Group_One_Y = [10 40];
Group_Two_X = [50 70];
Group_Two_Y = [5 20];
%Coordinate system
min_X = -10;
max_X = 90;
min_Y = -20;
max_Y = 60;
axis([min_X, max_X, min_Y, max_Y])
%Create pixel vector with default white colour
rows_N = 100;
columns_N = 80;
C=ones(rows_N,columns_N,3);
%These vectors say where each of the pixels is in the plot coordinate
%system
vec_X = linspace(min_X,max_X,columns_N);
vec_Y = linspace(min_Y,max_Y,rows_N);
Colour_One = [0 1 1];
Colour_Two = [1 1 0];
%Loop through whole diagram
for i=1:100
for j=1:80
if inpolygon(vec_X(j),vec_Y(i),Boundary_X,Boundary_Y)
%calculate distance to each point
Distances_One = zeros(size(Group_One_X));
Distances_Two = zeros(size(Group_Two_X));
for k=1:numel(Group_One_X);
Distances_One(k) = norm([Group_One_X(k),Group_One_Y(k)]-[vec_X(j),vec_Y(i)]);%assuming euclidean norm, but can be adjusted to whatever norm you need
end
for k=1:numel(Group_Two_X);
Distances_Two(k) = norm([Group_Two_X(k),Group_Two_Y(k)]-[vec_X(j),vec_Y(i)]);%assuming euclidean norm, but can be adjusted to whatever norm you need
end
if min(Distances_One) < min(Distances_Two);
C(i,j,:) = Colour_One;
else
C(i,j,:) = Colour_Two;
end
end
end
end
%Display image
imagesc(vec_X,vec_Y,C) %lets you draw the image according to vec_X and vec_Y
%Plot boundary and points
hold on
plot(Boundary_X,Boundary_Y)
scatter(Group_One_X,Group_One_Y,10,'MarkerFaceColor','Black',...
'MarkerEdgeColor','Black')
scatter(Group_Two_X,Group_Two_Y,10,'MarkerFaceColor','Red',...
'MarkerEdgeColor','Red')
hold off

Normal PDF's integral not equal to one using MATLAB's normpdf

The following methods are supposed to compute a PDF:
bins = [20 23 31.5 57 62.5 89 130]; % classes of values of my random variable
mean = 23;
std = mean/2;
values = mean + std*randn(1000,1); % the actual values of the RV
% method 1
[num, bins] = hist(values, bins); % histogram on the previously defined bins
pdf2 = num/trapz(bins, num);
trapz(bins, pdf2) % checking the integral under the curve, which is indeed 1
ans =
1
% method 2
pdf1 = normpdf(bins, mean, std); % the Matlab command for creating o normal PDF
trapz(bins, pdf1) % this is NOT equal to 1
ans =
0.7069
However if I consider the bins something like
bins = [0:46];
the results are
ans =
1
ans =
0.9544
so I still have not the value 1 for the integral in the case of normpdf.
Why does the normpdf not give the integral equal to 1 for the PDFs? Is there something I'm missing in the codes above?
The problem is that you are missing a lot of values from your PDF, if you take bins = [0:46], you have the following curve:
Which means you are missing all the part x < 0 and x > 46, so the integral you are computing is not from -oo to +oo as you expect but from 0 to 46, obvisouly you won't get the correct answer.
Note that you have mean = 23 and std = 11.5, thus if you have bins = 0:46 you have a band around the mean with a width of one std on each side, so according to the 68–95–99.7 rule, 95% of the values lie in this band, which is consistent with the 0.9544 you get.
If you take bins = -11.5:57.5, you now have three standard deviations on each side, and you will get 99.7% of the values in this band (MATLAB gives me 0.9973, the filled area are the ones you did not have with bins = 0:46):
Note that if you want to reach 1.000 with an error better than 10-3, you need about 3.4 standard deviations1:
>> bins = (mean - 3.4 * std):(mean + 3.4 * std) ;
>> pdf = normpdf(bins, mean, std) ;
>> trapz(bins, pdf)
0.9993
Note that with bins = [20 23 31.5 57 62.5 89 130];, you have both a problem of precision and a problem of missing values (your curve is the blue one, the red one was generated using bins = 20:130):
Obvisouly, if you compute the area under the blue curve, you won't get the value of the area under the red one, and you won't certainly get a value close to the integral of the red curve between -oo and +oo.

MATLAB Data Interpolation - Basics

I have a dataset consisting of a position and a signal - the signal is sampled at scattered positions (0, 115, 230....):
0 1.709219858
115 1.676595745
230 1.643026005
345 1.609456265
460 1.574940898
575 1.540898345
690 1.506855792
806 1.473286052
I would like to smooth this data and then interpolate it to fill in the intervening positions i.e.:
0 x
1 x
2 x
3 x
4 x
5 x
6 x
7 x
8 x
9 x
10 x
Where x is the smoothed signal. I've been smoothing data with the commands:
>> hann250=hanning(250);
>> smooth250=conv(signal,hann250,'same');
But I am not sure at all how to interpolate the data - what commands can I use and what would I type? I'm totally new to MATLAB! I am also not sure what interpolation method I need but I intend to try various one's and see (once I know how!). Thanks,
T
You could try spline interpolation:
http://www.mathworks.com/help/matlab/ref/spline.html
% read x, y from your file
xx = linspace(min(x), max(x), 1000); % generate 1000 equally spaced points
yy = spline(x,y,xx); % interpolate
plot(x,y); % original
hold all;
plot(xx,yy); % new
You can use interp1:
data = [0 1.7092
115.0000 1.6766
230.0000 1.6430
345.0000 1.6095
460.0000 1.5749
575.0000 1.5409
690.0000 1.5069
806.0000 1.4733];
index_interp = 0:806; %// indices on which to interpolate
data_interp = interp1(data(:,1),data(:,2),index_interp,'linear');
There are other interpolation methods available in addition to 'linear'; see the above link.