Related
There are pitch and duration and sample rate fs where "pitch" is the vector of note pitch in semitones (with 0 indicating silence), "duration" is the vector of note duration in seconds, "fs" is the sample rate of the output wave signals for playback.
pitch= [55 55 55 55 57 55 0 57 60 0 ];
duration=[23 23 23 23 23 35 9 23 69 18 ]/64;
fs=16000;
I want to use above info to return audio signal in MATLAB.
Can somebody teach me?
THX
This requires some thought and might just take some time to write down before everything is working.
Personally, I'd split the task up into multiple functions which in my mind would involve:
1. Semitone to frequency
2. Time to sample number
3. Frequency and sample number to output waveform
And if possible you should add another array which involves level for further progress later on/ helps simplify the problem into stages.
As im not sure which semitone scaling you are using you will have to confirm this for yourself but you will need some sort of converter/look up table that does something like (formulas according to Physics of Music website):
function [frequency] = semitone2frequency(semitone)
%Your input is how many semitones ABOVE middle C your note is
frequency = 440*((2^(1/12))^semitone); % where 440 Hz is middle C
end
This is based on an equal tempered scale. Now you know the frequency of your notes you could generate their sound, but wait theres more....
Now you can calculate the time of each sound in samples by writing another function...
function [nSamples] = time2samples(time, Fs)
dt = 1/Fs;
nSamples = time*dt;
end
Now that you have both of these values you can generate your audio signal!
frequency = semitone2frequency(55); %55 semitones above middle C
nSamples = time2samples(2,16000); %How many samples does it need to play 2 seconds
%Generate time array from 0 to how long you want the sound to be
time = 0:1:nSamples; %Starts at 0 increases by 1 sample each time up until 2 seconds worth of samples
%Create your output waveform!
outputAudio = sin(2*pi*frequency.*time);
This will create an array which you could play that will sound a note 55 semitones greater than middle C (not sure what note that actually is) for 2 seconds. Listen to it by using:
sound(outputAudio, 16000);
You can build on this to create multiple sounds one after the other (I would recommend creating one master function that lets you pass all arrays in and outputs one audio waveform), but this should be enough to create certain semitones for given durations!
P.s. To make the level 0 at any time simply multiply your outputAudio variable by 0
outputAudio = outputAudio.*0; %The . in .* is important!
Or for further control multiply it by any level between 0 and 1 for complete volume control.
I hope this is enough! good luck.
I am interested in creating a Matlab script that will consider a rectangle and allow me to calculate the length of vectors between one point and several other points placed along the perimeter of the rectangle. For example, calculating the length of all the vectors indicated in red on the image below, using point 9 as the origin.
This will need to include the ability to specify the location of each point and should be adaptable to rectangles with different dimensions. I would like to be able to calculate the vector lengths using any of the specified points as the origin. For example from point 1 to all other points on the perimeter.
I realize this is a potentially time consuming task so any help would be greatly appreciated, as I am a novice with Matlab. Look forward to seeing some ideas! Cheers.
Building on top of #ihcgeneva's post, I would avoid using loops all together and use bsxfun instead. The code by #ihcgeneva can be greatly simplified to:
xList = [1, 2, 3, 4, 5];
yList = [5, 4, 2, 2, 1];
rootPoint = 3; %The point you want as your 'base'
Distance = sqrt(sum(bsxfun(#minus, [xList; yList].', [xList(rootPoint) yList(rootPoint)]).^2, 2));
Note that there is no need to define the anonymous function d. In addition, there is also no need for a loop. With MATLAB, you are always encouraged to vectorize your code. What vectorization means is that there are certain functions in MATLAB that will accept an array or matrix of inputs and the function will operate on each entry individually. The output of these functions will give you an array or matrix of the same size that has each of those values having the function applied to those elements. It has been shown to be much faster over looping through each element in your array or matrix and applying the function to each element one at a time. It's mostly due to function call overhead. It would be more efficient to just call the function once rather than many times for as many elements as you want to apply the function to.
Now, the above code is quite a handful to absorb, but still pretty easy to understand once you get the hang of it. bsxfun stands for Binary Singleton Expansion Function. If we look inside the function, we are invoking the minus function between a single point in your rectangle found at the index rootPoint with all of the other co-ordinates in the rectangle. What we will do is place the co-ordinates into a 2D matrix where the first column denotes the x co-ordinate and the second column denotes the y co-ordinate. Next, what bsxfun is doing is that it duplicates the point located at rootPoint so that it is the same size as this 2D matrix. bsxfun will then do an element by element subtraction between this duplicated matrix with the original 2D matrix that you created.
This will perform the first part of the Euclidean distance where you subtract the corresponding dimensions. This creates an output 2D matrix where the first column is the subtraction of the x components and the second column is the subtraction of the y components. We then square each value in the matrix, then sum over the columns then take the square root, thus completing the Euclidean distance operation. #lhcgeneva has put you on the right track where the shortest distance between the point you are looking at with the other points in the rectangle is the Euclidean distance.
Now if you want to plot the lines from one point to another like you have in your image, you actually don't need to calculate the lengths at all. You just need to know where the points along the rectangle are located, show the image, then use plot and plot lines from each point in the rectangle to the source point. This looks very much like an IC Pin layout diagram, so I'm going to use one that I found on the Internet:
Let's use pin #3 as the source. I've also gone through the image and pin-pointed the location of the middle of each pin:
points = [49 84; 49 133; 49 178; 49 229; 49 277; 49 325; 49 372; 205 374; 205 325; 205 276; 205 228; 205 181; 205 131; 205 87];
The first column is the x or column co-ordinate while the second column is the y or row co-ordinate of where the centre is for each pin in this image. Now, all you have to do is show this image, use hold on to make sure that you can place multiple lines on the plot without it erasing, and plot lines from the source point to each point in the matrix:
im = imread('http://www.infraredremote.com/images/14-pin-IC.jpg');
imshow(im);
hold on;
points = [49 84; 49 133; 49 178; 49 229; 49 277; 49 325; 49 372; 205 374; 205 325; 205 276; 205 228; 205 181; 205 131; 205 87];
rootPoint = 3;
for idx = 1 : size(points, 1)
plot([points(rootPoint, 1) points(idx, 1)], [points(rootPoint, 2) points(idx, 2)], 'r', 'LineWidth', 5);
end
The above code loads in the image directly from the Internet. We then show the image with imshow then use hold on like we talked about before. Next, we choose our root point, which is pin 3, then we loop over all of the points and draw a line from the root point to each pin. We make the line red, as well as making the width of the line 5 pixels thick. In this case, we do need to loop over the points to make it easy. We can vectorize the plotting, but it will become a bit sophisticated given your knowledge of MATLAB so far.
In any case, this is what I get:
Edit
In your comments, you said you wanted to display the distances from the root point to each point in your rectangle. You can do this with a loop. Unfortunately when it comes to printing, there isn't a way to do it easily with vectorization, but looping just to print out statements should take very little time so we shouldn't worry about vectorization here.
As such, you can do something like this:
%// Define points along rectangle and root point
points = [49 84; 49 133; 49 178; 49 229; 49 277; 49 325; 49 372; 205 374; 205 325; 205 276; 205 228; 205 181; 205 131; 205 87];
rootPoint = 3;
%// Find distances
Distance = sqrt(sum(bsxfun(#minus, points, points(rootPoint,:)).^2, 2));
for idx = 1 : numel(Distance)
fprintf('Distance between reference point %d and point %d is %f\n', ...
rootPoint, idx, Distance(idx));
end
Note that I had to modify the code slightly with respect to the distances. Because our points are now in a 2D array, the core algorithm is still the same, but I had to get the points in a slightly different way. Specifically, I didn't need to construct the 2D matrix inside bsxfun as that was created already. I can also easily extract out the root point by getting all of the columns for a single row located at the row indexed by rootPoint. Next, we loop over each distance from the root point to each point in the rectangle and we simply print those out. This is the output I get:
Distance between reference point 3 and point 1 is 94.000000
Distance between reference point 3 and point 2 is 45.000000
Distance between reference point 3 and point 3 is 0.000000
Distance between reference point 3 and point 4 is 51.000000
Distance between reference point 3 and point 5 is 99.000000
Distance between reference point 3 and point 6 is 147.000000
Distance between reference point 3 and point 7 is 194.000000
Distance between reference point 3 and point 8 is 250.503493
Distance between reference point 3 and point 9 is 214.347848
Distance between reference point 3 and point 10 is 184.228119
Distance between reference point 3 and point 11 is 163.816971
Distance between reference point 3 and point 12 is 156.028843
Distance between reference point 3 and point 13 is 162.926364
Distance between reference point 3 and point 14 is 180.601772
This looks about right, and certainly makes sense as the distance between point 3 and itself (3rd row of the print-out) is 0.
I have a matrix
tst=[20 15 26 32 18 28 35 14 26 22 17]
meantst= mean(tst)=23
stdtst= std(tst)=6.6
Matlab command
s = std(X)
one get standard deviation.
http://www.mathworks.de/de/help/matlab/ref/std.html
How can I get std with 1-sigma(68%), 2 sigma(95%), 3sigma(99%)".
I think you are not actually looking for the standarddeviation, but rather the quantiles of your distribution.
Assuming they are normally distributed, you could go for norminv:
X = norminv(P,mu,sigma)
In your particular examples says that 68 percent of data present between 16.4 to 29.6. If you consider 2Sigma, Then 95% of data present between 9.8 to 35.5. Standard deviation just tells, how much data is deviating from its mean value. If just consider standard deviation then standard deviation gives a range around mean, and in that range 68% of data exist. If we take 2Sigma, we increase that range twice and now 95% of data fall in that range.
Maybe what you want is the percentiles of the distribution?
prctile(tst,68) % or prctile(tst,100-68), depending on which direction you need
prctile(tst,95) % or prctile(tst,100-95)
prctile(tst,99) % or prctile(tst,100-99)
Note that you would need many more samples than your example contains in order to obtain accurate percentile values.
I'm hoping there is a MATLAB function similar to this Arduino function:
http://arduino.cc/en/Reference/map
Basically I have a time based variable with 67 data points ranging from 0 to 1.15, and I want to map that from 0 to 100% (so, 101 data points). In Arduino that would look something like:
map(value, fromLow, fromHigh, toLow, toHigh)
I can use interp1 in MATLAB to get me the 101 data points, but I just get 101 data points between 0 and 1.15. I know I can just multiply each value by 100/1.15, but this is inexact. Is there a more elegant way to do this in MATLAB that I'm overlooking?
(This post looked hopeful, but it's not what I'm looking for:
Map function in MATLAB?)
Thanks
If you have neural networks toolbox available, then you can try mapminmax function. By default, function maps to [-1 1] interaval and gets input bounds from data. But I believe that filling settings structure with your values and then calling mapminmax should help.
you can use linspace, for example
linspace(0,1.15,101)
will get you 101 points spread uniformly between the limits 0 and 1.15.
My FEX submission maptorange can do exactly that. It takes initial value(s), the range from which they originate, and the range onto which they should be mapped, and returns the mapped value(s). In your example, that would be:
maptorange(values, [0 1.15], [0 100]);
(This is assuming linear mapping. The script can also map along an exponential function.)
To go from 67 to 101 values, you would indeed need interpolation. This can be done either before or after mapping.
I have a dataset 6x1000 of binary data (6 data points, 1000 boolean dimensions).
I perform cluster analysis on it
[idx, ctrs] = kmeans(x, 3, 'distance', 'hamming');
And I get the three clusters. How can I visualize my result?
I have 6 rows of data each having 1000 attributes; 3 of them should be alike or similar in a way. Applying clustering will reveal the clusters. Since I know the number of clusters
I only need to find similar rows. Hamming distance tell us the similarity between rows and the result is correct that there are 3 clusters.
[EDIT: for any reasonable data, kmeans will always finds asked number
of clusters]
I want to take that knowledge
and make it easily observable and understandable without having to write huge explanations.
Matlab's example is not suitable since it deals with numerical 2D data while my questions concerns n-dimensional categorical data.
The dataset is here http://pastebin.com/cEWJfrAR
[EDIT1: how to check if clusters are significant?]
For more information please visit the following link:
https://chat.stackoverflow.com/rooms/32090/discussion-between-oleg-komarov-and-justcurious
If the question is not clear ask, for anything you are missing.
For representing the differences between high-dimensional vectors or clusters, I have used Matlab's dendrogram function. For instance, after loading your dataset into the matrix x I ran the following code:
l = linkage(a, 'average');
dendrogram(l);
and got the following plot:
The height of the bar that connects two groups of nodes represents the average distance between members of those two groups. In this case it looks like (5 and 6), (1 and 2), and (3 and 4) are clustered.
If you would rather use the hamming distance rather than the euclidian distance (which linkage does by default), then you can just do
l = linkage(x, 'average', {'hamming'});
although it makes little difference to the plot.
You can start by visualizing your data with a 'barcode' plot and then labeling rows with the cluster group they belong:
% Create figure
figure('pos',[100,300,640,150])
% Calculate patch xy coordinates
[r,c] = find(A);
Y = bsxfun(#minus,r,[.5,-.5,-.5, .5])';
X = bsxfun(#minus,c,[.5, .5,-.5,-.5])';
% plot patch
patch(X,Y,ones(size(X)),'EdgeColor','none','FaceColor','k');
% Set axis prop
set(gca,'pos',[0.05,0.05,.9,.9],'ylim',[0.5 6.5],'xlim',[0.5 1000.5],'xtick',[],'ytick',1:6,'ydir','reverse')
% Cluster
c = kmeans(A,3,'distance','hamming');
% Add lateral labeling of the clusters
nc = numel(c);
h = text(repmat(1010,nc,1),1:nc,reshape(sprintf('%3d',c),3,numel(c))');
cmap = hsv(max(c));
set(h,{'Background'},num2cell(cmap(c,:),2))
Definition
The Hamming distance for binary strings a and b the Hamming distance is equal to the number of ones (population count) in a XOR b (see Hamming distance).
Solution
Since you have six data strings, so you could create a 6 by 6 matrix filled with the Hamming distance. The matrix would be symetric (distance from a to b is the same as distance from b to a) and the diagonal is 0 (distance for a to itself is nul).
For example, the Hamming distance between your first and second string is:
hamming_dist12 = sum(xor(x(1,:),x(2,:)));
Loop that and fill your matrix:
hamming_dist = zeros(6);
for i=1:6,
for j=1:6,
hamming_dist(i,j) = sum(xor(x(i,:),x(j,:)));
end
end
(And yes this code is a redundant given the symmetry and zero diagonal, but the computation is minimal and optimizing not worth the effort).
Print your matrix as a spreadsheet in text format, and let the reader find which data string is similar to which.
This does not use your "kmeans" approach, but your added description regarding the problem helped shaping this out-of-the-box answer. I hope it helps.
Results
0 182 481 495 490 500
182 0 479 489 492 488
481 479 0 180 497 517
495 489 180 0 503 515
490 492 497 503 0 174
500 488 517 515 174 0
Edit 1:
How to read the table? The table is a simple distance table. Each row and each column represent a series of data (herein a binary string). The value at the intersection of row 1 and column 2 is the Hamming distance between string 1 and string 2, which is 182. The distance between string 1 and 2 is the same as between string 2 and 1, this is why the matrix is symmetric.
Data analysis
Three clusters can readily be identified: 1-2, 3-4 and 5-6, whose Hamming distance are, respectively, 182, 180, and 174.
Within a cluster, the data has ~18% dissimilarity. By contrast, data not part of a cluster has ~50% dissimilarity (which is random given binary data).
Presentation
I recommend Kohonen network or similar technique to present your data in, say, 2 dimensions. In general this area is called Dimensionality reduction.
I you can also go simpler way, e.g. Principal Component Analysis, but there's no quarantee you can effectively remove 9998 dimensions :P
scikit-learn is a good Python package to get you started, similar exist in matlab, java, ect. I can assure you it's rather easy to implement some of these algorithms yourself.
Concerns
I have a concern over your data set though. 6 data points is really a small number. moreover your attributes seem boolean at first glance, if that's the case, manhattan distance if what you should use. I think (someone correct me if I'm wrong) Hamming distance only makes sense if your attributes are somehow related, e.g. if attributes are actually a 1000-bit long binary string rather than 1000 independent 1-bit attributes.
Moreover, with 6 data points, you have only 2 ** 6 combinations, that means 936 out of 1000 attributes you have are either truly redundant or indistinguishable from redundant.
K-means almost always finds as many clusters as you ask for. To test significance of your clusters, run K-means several times with different initial conditions and check if you get same clusters. If you get different clusters every time or even from time to time, you cannot really trust your result.
I used a barcode type visualization for my data. The code which was posted here earlier by Oleg was too heavy for my solution (image files were over 500 kb) so I used image() to make the figures
function barcode(A)
B = (A+1)*2;
image(B);
colormap flag;
set(gca,'Ydir','Normal')
axis([0 size(B,2) 0 size(B,1)]);
ax = gca;
ax.TickDir = 'out'
end