You are now following this question
- You will see updates in your followed content feed.
- You may receive emails, depending on your communication preferences.
How to change time to amplitude in a spectrogram?
6 views (last 30 days)
Show older comments
Hi experts,
I have created an 11k wav file and am reading it into MATLAB. From here I am using the data given from the wav file and using a spectrogram to view it.
When I run the code, the spectrogram returned is given in time and frequency. The frequency returned is correct. Is it possible to change the time to amplitude? this would be very useful for my results.
Here is my code :
clear; [y, fs] = audioread('11k_wav.wav'); figure(1); spectrogram(y,256,224,512,fs,'xaxis');
Thank you in advance.
Accepted Answer
Star Strider
on 10 Mar 2016
Amplitude in a spectrogram is the z-axis value. The pectrogram is actually a surf plot, so you can use the interactive image rotation in the plot GUI or the view function to make the amplitude correspond to the y-axis.
23 Comments
Noel Sharpe
on 14 Mar 2016
hi,
yes i have managed to get the 3d spectrogram but with the incorrect dimensions. is there a book or online resource which describes how to change these axis.
this is the addition i made so far :
colormap bone view(-30,60)
so your suggestion is to use the command surf plot?
kind regards noel
Star Strider
on 14 Mar 2016
I am not certain what you mean by ‘incorrect dimensions’. If the plot is not scaling as you believe it should, you may want to experiment with the overlap or other parameters.
I doubt any documentation exists other than that provided. The only other resource I would refer you to is Yair Altman’s Undocumented MATLAB site.
In the earlier documentation versions (I don’t remember which one just now), there was a description of the spectrogram being a surf plot with view([90 0]), if I remember correctly. So it already is a surf plot, unless the code changed between versions. You can set the view to rotate the plot as you wish, or plot it yourself as any 3D plot that accepts gridded coordinates, if you request the first three outputs.
Noel Sharpe
on 25 Mar 2016
ah okay, so as the function is :
[X Y Z] = spectrogram(y,256,224,512,fs,'xaxis');
can i input values into the spectrogram? ex. X=12, Y=13, Z=155 and then have the spectrogram plot that?
if so, can i use the amplitude values from my FFT function? the values are of a multifrequency waveform. can i input these values into the Y section of [X Y Z] ?
thanks
Star Strider
on 25 Mar 2016
I’m not entirely certain what you want to do.
To overplot X=12, Y=13, Z=155 on the spectrogram, use the hold function, and then use plot3 or scatter3 to plot a particular point. Be sure to use ‘X’ and ‘Y’ in the units the spectrogram is plotted in to get the result you want.
Noel Sharpe
on 26 Mar 2016
My main aim is to plot a wav file on a spectrogram. The wav file is rock you by queen.
I have made an FFT program to break up the wav file into frequency phase and magnitude so i can see the song in these dimensions.
So for my axis, X relates to frequency , Y relates to magnitude and Z will represent the phase of the song.
My main question is : can I take the values given from my FFT for frequency, magnitude and phase and input these value into the [X Y Z] variables so they are plotted on the spectrogram? or do I have to do this a different way?
I was just testing the spectrogram with an 11K tone in a wav format.
thank you
Star Strider
on 26 Mar 2016
My pleasure.
If you segmented the song and want to give that to the spectrogram function, it might be interesting to compare the segments.
Otherwise, at least as I understand it and what you want to do, the spectrogram will do all that for you for the complete song, and will also output the complex Fourier transform and the time and frequency arrays. You can use the complex output to calculate and plot the magnitude and phase, although I’m not certain the phase information will be of any value in such a mixture of frequencies. (They will ‘heterodyne’ — multiply together to create entirely new frequencies with correspondingly new phase information — in any non-linear system such as a microphone or ‘railed’ amplifier.)
You can then use the surf function to plot the absolute value of the first output of spectrogram (complex Fourier transform) of the signal as a function of the other two outputs, and then use another surf call to plot the phase. I would plot them independently at first, because the Z-axis scaling for the magnitude would swamp the phase information that by definition would be limited to ± π.
If you already calculated the magnitude and phase and have a matrix of results, then consider plotting them directly with surf. You may be duplicating (at least in part) what spectrogram does, and may not need it.
Noel Sharpe
on 30 Mar 2016
sorry at the moment i am a bit confused,
"If you segmented the song and want to give that to the spectrogram function, it might be interesting to compare the segments." does this mean to break the song into chunks and preform an FFT on the chunk ? or just send each chunk to the spectrogram? the reason for the FFT is to get a value for the amplitude and phase with respect to the frequencies.
"Otherwise, at least as I understand it and what you want to do, the spectrogram will do all that for you for the complete song, and will also output the complex Fourier transform and the time and frequency arrays." i did not know that the spectrogram would do this ? but my objective is to use the FFT on the wav file and then display my results on the spectrogram.
"You can use the complex output to calculate and plot the magnitude and phase" Is this done through a figure or another spectrogram?
Can the surf plot plot multiple chunks one after the other ?
ah okay i will try to implement this again with my better understanding.
Star Strider
on 30 Mar 2016
I’m not quite sure I understand what you’ve already done. If you want to do a time-frequency analysis, I would let the spectrogram function do it, with the appropriate argument options.
Noel Sharpe
on 30 Mar 2016
So far I have a MATLAB script that performs an FFT on an specified wav file.
The script returns values to the workspace. From these values i can use the plot function to see the results. the results are normally correct. for example, i can take a wav file which has an 11k tone in it with an amplitude of 1 and with the plot function produce a graph. this graph has a spike at 11k on the x axis and an amplitude of 1 on the y axis.
I want to use the FFT script i have created on a different wav file (a song) and using the resulting values for frequency, amplitude and phase, plot them on a spectrogram. This is my goal.
Therefore:
[X Y Z] = spectrogram(x,window,noverlap,pfft) is the format of the spectrogram i will be using.is this correct ?
The question i have is: can i input values to the [X Y Z] on the left hand side of the function for the spectrogram above? the values i would like to input are the returned values in the workspace from my FFT script. is this possible ?
Star Strider
on 30 Mar 2016
The [X,Y,Z] are the outputs of the spectrogram function. You cannot input values to the spectrogram function using them. You can only use them to plot their values in the surf or mesh or other such functions that accept matrix arguments.
If you want to plot the matrix you created from your own function, experiment with it in the surf or mesh functions.
Noel Sharpe
on 6 Apr 2016
okay so Iv swapped to a surf plot. I have tried to set it up like so in the screen shot. I get the error about the matrix but every example I see has an equation (e.g. Z = x^2 + y^2). I do not have an equation for what I am trying to do. Can you suggest a way to fix this ?
My goal is to simply have a 3d representation of my data (magnitude,frequency and phase) that will change when I input chunks one after another.
Kind regards, Noel Sharpe.
Star Strider
on 6 Apr 2016
The spectrogram function may have changed a bit in R2016a. I have to check the Release Notes again.
See if this does what you want:
t = linspace(0, 2*pi, 10000);
s = sin(t*1000) .* sin(t*250);
figure(1)
spectrogram(s)
sdata = get(gca);
[s,f,t] = spectrogram(s);
figure(2)
surf(abs(s))
grid on
axis([1 size(s,2) 1 size(s,1) zlim])
set(gca, 'XTick',[1:length(t)], 'XTickLabel',t)
set(gca, 'YTick',[1:205:2049], 'YTickLabel',f(1:205:2049)/pi)
xlabel('Time (s)')
ylabel('Frequency (rad)')
title('Magnitude')
figure(3)
surf(20*log10(abs(s)))
grid on
axis([1 size(s,2) 1 size(s,1) zlim])
set(gca, 'XTick',[1:length(t)], 'XTickLabel',t)
set(gca, 'YTick',[1:205:2049], 'YTickLabel',f(1:205:2049)/pi)
xlabel('Time (s)')
ylabel('Frequency (rad)')
title('Magnitude (dB)')
figure(4)
mesh(unwrap(angle(s)))
grid on
axis([1 size(s,2) 1 size(s,1) zlim])
set(gca, 'XTick',[1:length(t)], 'XTickLabel',t)
set(gca, 'YTick',[1:205:2049], 'YTickLabel',f(1:205:2049)/pi)
xlabel('Time (s)')
ylabel('Frequency (rad)')
title('Phase (Unwrapped)')
You will likely have to change it somewhat to work with your signal, but it should provide some direction. Note that here the frequency axis is normalised to (0,pi).
Noel Sharpe
on 11 Apr 2016
In my Matlab script I already have this done except I just plot them. This is my code :
clear all;
fs = 44100; %setting the sampling frequency of music
t= 0:1/fs:0.01; % setting the step size with the end lenght = 10ms (1 chunk)
n = 441; %no of samples for fft under recomendation
filename = '11k_wav.wav';
[y1,Fs] = audioread('11k_wav.wav');
figure(1)
plot(y1)
%w=y1;
%w= g.*transpose(hamming(length(g)));
% figure(2)
% plot(w)
fftres = fft(y1,n); %using the fft on the sine wave with n number of samples
figure(3);
plot(real(fftres)) % plot the real part of the vector grid on % turn on the grid for data points and clarity
ylabel('Real') % set label for y axis
title('Raw FFT spectrum') % set label for title
figure(4)
imagfft = imag(fifties);
plot(imag(fftres)) % plot the imaginary part of the vector grid on % turn on the grid for data points and clarity
ylabel('Imaginary') % set label for y axis
xlabel('Index number') % set label for title
%first two elements of spectrum, DC is the first
DCfirst = fftres(1:2); % extract the first and second elements out of the matrix
indexNyquist = n/2+1; % setting the frequency range
NyquistMiddle = fftres(indexNyquist-2:indexNyquist+2); %vicinity of Nyquist, which is in the middle
fftres = fftres(1:indexNyquist); %truncate
fftres = fftres/n; %scale
fftres(2:end) = 2 * fftres(2:end); %compensate for truncating the negative frequencies
%Calculate the magnitude
mag = abs(fftres); %abs for complex numbers returns their magnitude df = fs/n; %frequency resolution
frequencyAxis = [0:indexNyquist-1]'*df; %values on frequency axis
figure(5);
plot(frequencyAxis, mag) %plot freq plot of fat
grid on % turn on the grid for data points and clarity
xlabel('Frequency [Hz]') % set label for y axis
ylabel('Magnitude [units]') % set label for title
%Position and value of maximum magnitude
[magMax,indexMax] = max(mag); % returns the largest elements of vector mag
freqMax = frequencyAxis(indexMax);
%Display in title
title(sprintf('Max magnitude=%f @ %fHz, \\Deltaf=%fHz', magMax, freqMax,df)) %Plot the spectrum as lines using stem function and removing the markers at %the end of lines
handleStem=stem(frequencyAxis,mag);
set(handleStem(1),'Marker','none')
grid on
xlabel('Frequency [Hz]')
ylabel('Magnitude [units]')
%Display in title
title(sprintf('Max magnitude=%f @ %fHz, \\Deltaf=%fHz ',... magMax, freqMax,df))
From the returned variables, I took the values frequencyAxis (the different frequencies), mag (the different magnitudes relating to the frequencies) and fftres (as the complex pairs will be used as phase)
I would like to plot these values on a surf plot. But when I try to do this i get an error relating to the Z variable.
this is how I try to plot the values:
x = frequencyAxis;
y = mag;
Z = fftres;
rotate3d on;
[X,Y] = meshgrid(x,y);
surf(X,Y,Z)
the error that comes up is : Error using surf (line 69) Z must be a matrix, not a scalar or vector.
Error in Week8_fft_on_11k (line 75) surf(X,Y,Z)
I do not understand why.
Noel Sharpe
on 11 Apr 2016
I have since learned that with the surf plot, the X axis now represents frequency, the Y axis now represents phase and Z is now now represents magnitude.
I have also learned that the error was because I did not have the input to Z like the following : z=[1,2,3;1,2,3;1,2,3]
so to plot the elements outlined already, how do I input the values from X and Y into Z and have them make sense ? on all my attempts it is wrong.
Star Strider
on 11 Apr 2016
First, formatting your code (use the [{}Code] button) would help. See the ‘Help’ tab at the top of the page for details.
Second, I don’t know what you’re doing with this line:
fftres = fft(y1,n); %using the fft on the sine wave with n number of samples
I don’t know how long your ‘y1’ signal is, but you’re only taking 441 samples. This yields a fft vector that has only 221 points. The surf function requires a matrix for its Z argument. If you want a matrix instead, consider using the reshape function. I cannot assure you that you will get the result you want, but you will at least get a matrix output. Your ‘y1’ variable needs to be a column vector for this to work optimally. You may have to trim ‘y1’ to be an integer multiple of 441 (in your example here) for reshape to work.
I would simply experiment with the spectrogram function, particularly the number of samples you want to overlap, to get the results you want. This is easier than coding your own version.
Noel Sharpe
on 18 Apr 2016
sorry about that i will use that function from now on. yes that line in the code is wrong, i was just experimenting with something else and forgot to take it out.
I have implemented the reshape function manually in the code. it has worked out for the Z axis and it is now plotting data. thank you for that.
another problem I have encountered is that i cannot plot more than 3 values on the Y variable. why is this so ?
This is my code so far :
x = [1,2,3,4,5,6,7,8,9,10] ;
y = [-1,2,12] ; %%%how to add more than 3 values?
Z = [0,1,0,0,9,1,0,1,0,0;0,1,0,0,9,1,0,1,0,0;0,2,0,0,9,1,0,1,0,0] ; % has to be the same amount per set as in X
figure(6)
[X,Y] = meshgrid(x,y);
surf(X,Y,Z)
The error I get is error - data dimensions must agree.
Thanks for your help.
Star Strider
on 18 Apr 2016
My pleasure.
Since ‘Z’ is a (3x10) matrix, to add more values to ‘y’ (a (1x3) vector) you have to add more rows to ‘Z’ as well.
Noel Sharpe
on 21 Apr 2016
When I was plotting my data, I found my phase code was not correct. I am trying to plot the phase of the waveform, with respect to the frequencies.
In the code with figure 3 I am doing the FFT on the waveform. In the code with figure 6 I am using the results of the FFT to get the phase.
This is the code I originally thought was correct :
g = sin(2*pi*17800*t+pi/4) + 0.5*sin(2*pi*18000*t+pi/2) + 2*sin(2*pi*19000*t+3*pi/2);% creating the sine wave with phase offsets
fftres = fft(g,n); %using the fft on the sine wave with n number of samples
figure(3);
plot(real(fftres)) % plot the real part of the vector
grid on % turn on the grid for data points and clarity
ylabel('Real') % set label for y axis
title('Raw FFT spectrum') % set label for title
figure(6); %Calculate the phase versus frequency
phase = angle(fftres); %abs for complex numbers returns their magnitude
plot(phase);
But I get what looks like noise when I was trying to do this. Can you suggest how I can fix this error ?
Thank you.
Noel Sharpe
on 21 Apr 2016
This is the other attempt of unwrapping the phase :
figure(6); %Calculate the phase versus frequency
phase = unwrap(angle(fftres));
plot(frequencyAxis, phase);
Star Strider
on 21 Apr 2016
You didn’t provide ‘t’, so I don’t know what your signal or its Fourier transform looks like. The sampling interval (difference between adjacent time samples, and length of the signal) will affect both.
The usual procedure is to plot the absolute value of the fft, rather than the real part. The phase unwrapping code appears to be correct.
The other usual procedure is to use the subplot function to plot the amplitude in the upper plot and the phase in the lower plot, using the same frequency axis for both, creating a Bode plot. It makes the information easier to interpret.
Noel Sharpe
on 22 Apr 2016
fs = 44100; %setting the sampling frequency of music
t= 0:1/fs:0.01; % setting the step size with the end lenght = 10ms (1 chunk)
n = 441; %no of samples for fat under recommendation
g = sin(2*pi*17800*t+pi/4) + 0.5*sin(2*pi*18000*t+pi/2) + 2*sin(2*pi*19000*t+3*pi/2);% creating the sine wave with phase offsets
fftres = fft(g,n); %using the fft on the sine wave with n number of samples
figure(3);
plot(real(fftres)) % plot the real part of the vector
grid on % turn on the grid for data points and clarity
ylabel('Real') % set label for y axis
title('Raw FFT spectrum') % set label for title
figure(6); %Calculate the phase versus frequency
phase = unwrap(angle(fftres));
plot(phase);
The set up parameters for the sine wave are as above.
Sorry but I do not understand why you would plot the absolute value of the FFT for phase? I thought that you would need the imaginary values for the phase ?
Noel Sharpe
on 22 Apr 2016
so due to research and trials and error I have gotten the plot of the phase to certain point. This point is having a spike at the correct frequency. The phase is still incorrect. Can you see where my error is and a suggestion on how to fix this error please?
here is my code and resulting plot:
fs = 44100; %setting the sampling frequency of music
t= 0:1/fs:0.01; % setting the step size with the end lenght = 10ms (1 chunk)
n = 441; %no of samples for fat under recommendation
g = sin(2*pi*17800*t+pi); %+ 0.5*sin(2*pi*18000*t+pi/2) + 2*sin(2*pi*19000*t+3*pi/2);% creating the sine wave with phase offsets
fftres = fft(g,n); %using the fft on the sine wave with n number of samples
% figure(3);
plot(real(fftres)) % plot the real part of the vector
grid on % turn on the grid for data points and clarity
ylabel('Real') % set label for y axis
title('Raw FFT spectrum') % set label for title
figure(6); %Calculate the phase versus frequency
phase = angle(fftres);
imag = imag(fftres)*180/pi;
plot(frequencyAxis,imag);
xlabel ('Hz');
ylabel ('Phase');
grid on;
Thank you.
Star Strider
on 22 Apr 2016
I needed to make a few changes:
fs = 44100; %setting the sampling frequency of music
t= 0:1/fs:0.01; % setting the step size with the end lenght = 10ms (1 chunk)
n = 441; %no of samples for fat under recommendation
g = sin(2*pi*17800*t+pi); %+ 0.5*sin(2*pi*18000*t+pi/2) + 2*sin(2*pi*19000*t+3*pi/2);% creating the sine wave with phase offsets
fftres = fft(g,n); %using the fft on the sine wave with n number of samples
frequencyAxis = linspace(0, 1, fix(length(fftres)/2)+1)*fs/2; % <— Created My Own Version
Iv = 1:length(frequencyAxis);
figure(3);
plot(frequencyAxis,abs(fftres(Iv))) % plot the real part of the vector
grid on % turn on the grid for data points and clarity
ylabel('Real') % set label for y axis
title('Raw FFT spectrum') % set label for title
figure(6); %Calculate the phase versus frequency
phase = angle(fftres);
imag = imag(fftres)*180/pi;
plot(frequencyAxis,phase(Iv));
xlabel ('Hz');
ylabel ('Phase');
grid on;
First, you need to plot the absolute value to get the magnitude.
Second, the phase should reverse at the resonant frequency, and it does. (In a tuned circuit, the impedance goes from leading, or capacitive, to lagging, or inductive, at resonance, and becomes purely resistive at resonance, so the phase is zero there.) You can prove that easily enough analytically (much easier if you have the Symbolic Math Toolbox).
The phase looks correct to me, and goes to zero at the same frequency as the peak magnitude of the absolute value of the Fourier transform.
Third, the imaginary part of the fft is simply an amplitude, not an angle, so multiplying it by 180/pi simply scales it.
Fourth, please do not use ‘imag’ as a variable name. That is the name of the function (the same function you used to create it), so MATLAB will refer to the variable, not the function, if you call it later in your code. This is called ‘overshadowing’. Avoid it.
More Answers (0)
See Also
Categories
Find more on Spectral Measurements in Help Center and File Exchange
Community Treasure Hunt
Find the treasures in MATLAB Central and discover how the community can help you!
Start Hunting!An Error Occurred
Unable to complete the action because of changes made to the page. Reload the page to see its updated state.
Select a Web Site
Choose a web site to get translated content where available and see local events and offers. Based on your location, we recommend that you select: .
You can also select a web site from the following list
How to Get Best Site Performance
Select the China site (in Chinese or English) for best site performance. Other MathWorks country sites are not optimized for visits from your location.
Americas
- América Latina (Español)
- Canada (English)
- United States (English)
Europe
- Belgium (English)
- Denmark (English)
- Deutschland (Deutsch)
- España (Español)
- Finland (English)
- France (Français)
- Ireland (English)
- Italia (Italiano)
- Luxembourg (English)
- Netherlands (English)
- Norway (English)
- Österreich (Deutsch)
- Portugal (English)
- Sweden (English)
- Switzerland
- United Kingdom (English)
Asia Pacific
- Australia (English)
- India (English)
- New Zealand (English)
- 中国
- 日本Japanese (日本語)
- 한국Korean (한국어)