Hi there,
I would like to ask how exactly can I plot 3D plot such as this
from my 2D plot, which represents X-Y axes.
I´m using this code
load m2.txt;
i=m2(:,2);
ia=i*1000;
fs=50000;
T=1/fs;
L=length(ia);
t=(0:L-1)*T;
nfft=2^nextpow2(L);
w=hann(L);
io=ia.*w;
I=fft(io,nfft)/L;
Ia=abs(I);
f=fs/2*linspace(0,1,nfft/2+1);
%Normal.
Iref=max(Ia);
Inorm=20*log10(Ia/Iref);
figure;
plot(f,(Inorm(1:nfft/2+1)));
set(gca, 'YLim',[-130,0]);
set(gca, 'XLim',[0,500]);
xlabel('f (Hz)','FontSize',9);
ylabel('Magnituda (dB)','FontSize',9);
hold on;
So I obviously need to add the Z-axis, which represents length of the signal (time). I need to find out for how long ceratin frequencies were present during the measurement.
Tried to use "surf" and "plot3" commands, but all my attempts failed, so I would be really, really thankful for any insight.
Regards,
Patrik

2 Comments

"but all my attempts failed"
What have you tried so far? What errors did you get?
Well,
something like this
L=16777217;
t=(0:L-1)*T;
figure;
surf(f,(Inorm(1:nfft/2+1)),t);
and I got an error, that the Z should be a matrix, not a vector or scalar.
Also something like
L=16777217;
t=(0:L-1)*T;
figure;
plot3(f,(Inorm(1:nfft/2+1)),t);
but that returned a blank figure to me. This command makes the best sence to me, but apparently it doesn´t work the way I would expect.

Sign in to comment.

 Accepted Answer

Star Strider
Star Strider on 26 Apr 2018

1 vote

The image in your Question is a Signal Processing Toolbox spectrogram (link) plot, although with a different view. The spectrogram function produces a surf plot with a default view(0,90) so you are looking down at it as a 2D plot rather than viewing it as a 3D plot. You can use the GUI to rotate it, or simply experiment with different arguments to the view function after you plot it. The documentation for the spectrogram function describes how to do all of this, so I will not discuss it in detail here.

10 Comments

Than you very much for the effort, Spectrogram command works perfectly.
My pleasure.
If my Answer helped you solve your problem, please Accept it!
When I got deeper into the problem, I realised that the results I got are not in good enough resolution. Let´s say I have 8 388 608 samples for the FFT. When I want to plot a spectrogram, as the amount of samples exceeded 16 384, I have to use the divisor 128 (correct?) to get 128 segments of the signal.
There comes the first error - not enough memory. So I tried to use the 32 divisor, got some results but in my opinion, the resolution of spectrogram is insufficient.
Another thing is overlaping. How exactly should I set a number of samples I want to overlap in each chunk, if I want to overlap a different amount of samples other than 50 %?
I used this
figure;
spectrogram(ia,8388608/32,50,nfft,fs);
so the "50" means that 50 % of the segment would overlap with the previous and the next one?
The ‘50’ are the number of samples that overlap, according to the documentation.
The second argument is the Hamming (default window) length. (Windowing reduces the effect of a finite sample length on the fft result.)
You most likely have to experiment to get the result you want. I would go through the ‘Materials and Methods’ section of the paper you got the original image from, and see what options those authors chose. That accomplishes two things: it significantly reduces your workload, and makes it more likely that you can reproduce their results (assuming that is what you want to do).
Thanks for info,
idea I got is that there might be some way to make the spectrogram compute only 0-500 Hz spectrum, as I most likely don´t need to display higher frequencies and thus the procces might be easier to accomplish.
In my code I command to compute the spectrum up to 4,5 kHz and then set the axis limit to 500 Hz. So obviously a lot of unnecessary work is done.
Any idea how to compute only 0-500 Hz spectrum?
As always, my pleasure.
The spectrogram function allows you to specify the frequencies it returns. From the documentation:
  • [s,w,t] = spectrogram(x,window,noverlap,w) returns the spectrogram at the normalized frequencies specified in w.
See the second example in the section on Spectrogram of Complex Signal (link) for a specific illustration.
That is not exactly what I need. Tried the spectrogram command and the output was "solid", but not perfect, as the displayed result was kind of fuzzy. Isn´t there any way how to plot the spectrogram as a 3D graph with x=frequency, y=amplitude, z=time with the possibility of rotating the graph to display xz axes?
Use the view function to rotate the plot:
view(0,0) % ‘Z’ As Function Of ‘X’
The easiest way to determine the azimuth and elevation values is to use the ‘Rotate 3D’ tool in the plot figure GUI. The values will be displayed in the lower left corner.
First of all, I would like to get back to creating a surf plot (I assume). I would like to plot x-axis (freq), y-axis (amplitude of the fft) and z-axis (time), to know when and for how long specified frequencies are present. When I do the most plain thing that comes to my mind, something like
figure;
surf(f,(Inorm(1:nfft/2+1)),t);
It returns an error that the index exceeds the matrix dimension. I have absolutely no idea what I´m doing wrong. I can plot the original time domain signal against the time without problems, then I can plot the fft against freq without problems, but I feel like plotting XY "against" Z, which is the time of time domain signal, doesn´t make sence in general as there´s no bond between fft and the time of original signal?
I´m simply trying to create a good looking spectrogram plot, but the classic spectrogram command is insufficient. Any insight in plain English would be highly, highly appreciated.
The only option I can think of is to use the rotate (link) function. That will rotate the surface object.

Sign in to comment.

More Answers (1)

The figure you posted can be made using plot3. Try Running this script. You will get the idea how to use plot3 to draw such graphs.
f = figure;
t = 0:0.01:10;
plot3(0, 0, 0);
ax = gca;
delete(ax.Children);
hold on;
for i=1:5
plot3(ax, t, 2*i*ones(size(t)), sin(i*t)+rand(size(t)));
end

4 Comments

Well,
I tried your code and got this type of error - Attempt to reference field of non-structure array.
I would like to emphasise, that I´m not that good at Matlab, so I would really appreciate exact code that might work for me.
Are you using a version of MATLAB earlier than 2014b?
try replacing
delete(ax.Children);
with
delete(get(ax, 'Children'));
Also, you should also try @Star Strider answer below about spectrogram.
Than you very much for the effort, Spectrogram command works perfectly.
I really have same problem. Could you help me to plot it but in my case i was to plot x= frequency, y =time, z = amplitude .
Thank you.
Regards.
Sorn

Sign in to comment.

Community Treasure Hunt

Find the treasures in MATLAB Central and discover how the community can help you!

Start Hunting!