8

I am trying to achieve waterfall graph of wav file. In my attempts I noticed that this is basically a spectogram in 3d (or as close to what I need). I am trying to do this in Python with numpy and matplotlib.

My main problem is I don't know how to change the plot of specgram from matplotlib into a 3d plot.

Sample of my "code":

sample ,data = wavfile.read('file.wav')
F = Figure()
a = F.add_subplot(111,projection='3d') 
Spec, t, freq, im = a.specgram(data,Fs=2)

I've got this far and have no clue what to do next. I wanna change already existing plot into 3d. I have no code of changing it to 3d, due to lack of my knowledge.

Is it possible to convert 2d plot to 3d ? If so how ? Am i better off constructing a new plot with data from specgram?

The desired outcome would be something like the following: desired result another desired result Thanks for any replies.

8
  • Okay. Sorry for being too broad. I improved my question/ Commented Feb 3, 2018 at 15:39
  • Have you tried plot_surface? The actual problem is still not clear to me. Commented Feb 3, 2018 at 15:52
  • While the images will probably help a mathematician to understand the higher order problem you are trying to solve, they don't add that much to understanding what specific programming question you have. The best way to get specific answers on Stack Overflow is to include actual code that you wrote trying to solve your problem. Commented Feb 3, 2018 at 15:57
  • ... and to add, of course code needs to be a minimal reproducible example. Commented Feb 3, 2018 at 16:22
  • 2
    You may use spec, freqs, t = matplotlib.mlab.specgram(...) to generate the data without automatically creating a plot. Commented Feb 3, 2018 at 17:40

1 Answer 1

3

Here are 3D & 2D spectrogram plots of an example signal from scipy that you can find at the end of this page.

enter image description here

enter image description here

from matplotlib import mlab
import matplotlib.pyplot as plt
import numpy as np

# Fixing random state for reproducibility
np.random.seed(666)

title = ('2 Vrms sine wave with modulated frequency around 3kHz, '
         'corrupted by white noise of exponentially decreasing '
         'magnitude sampled at 10 kHz.')

fs = 10e3
N = 1e5
amp = 2 * np.sqrt(2)
noise_power = 0.01 * fs / 2
t = np.arange(N) / float(fs)
mod = 500*np.cos(2*np.pi*0.25*t)
carrier = amp * np.sin(2*np.pi*3e3*t + mod)
noise = np.random.normal(scale=np.sqrt(noise_power), size=t.shape)
noise *= np.exp(-t/5)
y = carrier + noise

def specgram3d(y, srate=44100, ax=None, title=None):
  if not ax:
    ax = plt.axes(projection='3d')
  ax.set_title(title, loc='center', wrap=True)
  spec, freqs, t = mlab.specgram(y, Fs=srate)
  X, Y, Z = t[None, :], freqs[:, None],  20.0 * np.log10(spec)
  ax.plot_surface(X, Y, Z, cmap='viridis')
  ax.set_xlabel('time (s)')
  ax.set_ylabel('frequencies (Hz)')
  ax.set_zlabel('amplitude (dB)')
  ax.set_zlim(-140, 0)
  return X, Y, Z

def specgram2d(y, srate=44100, ax=None, title=None):
  if not ax:
    ax = plt.axes()
  ax.set_title(title, loc='center', wrap=True)
  spec, freqs, t, im = ax.specgram(y, Fs=fs, scale='dB', vmax=0)
  ax.set_xlabel('time (s)')
  ax.set_ylabel('frequencies (Hz)')
  cbar = plt.colorbar(im, ax=ax)
  cbar.set_label('Amplitude (dB)')
  cbar.minorticks_on()
  return spec, freqs, t, im

fig1, ax1 = plt.subplots()
specgram2d(y, srate=fs, title=title, ax=ax1)

fig2, ax2 = plt.subplots(subplot_kw={'projection': '3d'})
specgram3d(y, srate=fs, title=title, ax=ax2)
  
plt.show()

BONUS:

You can listen to the signal by creating a wav file using scipy:

from scipy.io import wavfile
wavfile.write('sig.wav', int(fs), y)
Sign up to request clarification or add additional context in comments.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.