pythonscipysignal-processingspectrogramtime-frequency

what is the ideal parameters for spectrogram of eeg signal?


I am trying to plot a spectrogram of an EEG signal whose sampling rate of 1000Hz and is filtered with a bandpass of 14 - 70 Hz, and the length of the signal is 440 ( and I cant increase the length of the signal). The signal(data link here) looks like this:

image_orginal_signal

I have tried the following parameter values to plot the spectrogram:

#plot spectrogram for a single channel
fs = 1000
nperseg = 200

plt.figure(figsize=(10,10))

f, t, Sxx = signal.spectrogram(Oz[0], fs, nperseg=nperseg, noverlap=nperseg-1)

plt.pcolormesh(t, f, Sxx, shading='gouraud')
plt.ylim([0,70])
plt.ylabel('Frequency [Hz]')
plt.xlabel('Time [sec]')
plt.show()

which gave a plot like this:

spectrogram_of_signal

Can anyone suggest ideal parameter settings to improve the spectrogram resolution?

EDIT: To enhance my query, I want to know how the value of parameters like nperseg, nfft, window_size and noverlap are decided. And How would they be related if I have sampling rate(fs) and length of signal.


Solution

  • I don't know what output you expect but out can try to change the shading of the pcolormesh. Also you can add a window to the computation of the spectrogram. You can also change the colors use to represent the spectrogram with cmap.

    import matplotlib.pyplot as plt
    import numpy as np
    from scipy import signal
    
    my_data = np.genfromtxt('signal_value_spectro.csv', delimiter=',',skip_header=0)
    
    Oz=my_data[1:,0]
    fs = 1000
    t = np.arange(len(Oz))/fs
    
    
    # nperseg = len(Oz[0])-1
    nperseg=50
    f50, t50, Sxx_50 = signal.spectrogram(Oz, fs, nperseg=nperseg , noverlap=nperseg-1,window=signal.get_window('hann',nperseg))
    nperseg=150
    f150, t150, Sxx_150 = signal.spectrogram(Oz, fs, nperseg=nperseg , noverlap=nperseg-1,window=signal.get_window('hann',nperseg))
    nperseg=350
    f350, t350, Sxx_350 = signal.spectrogram(Oz, fs, nperseg=nperseg , noverlap=nperseg-1,window=signal.get_window('hann',nperseg))
    
    plt.figure(figsize=(10,10))
    plt.subplot(211)
    plt.plot(np.arange(len(Oz))/fs,Oz)  
    plt.subplot(234)
    plt.pcolormesh(t50, f50, Sxx_50, shading='auto',cmap = 'inferno')
    plt.ylim([0,70])
    plt.ylabel('Frequency [Hz]')
    plt.xlabel('Time [sec], nperseg = 50')
    plt.subplot(235)
    plt.pcolormesh(t150, f150, Sxx_150, shading='auto',cmap = 'inferno')
    plt.ylim([0,70])
    plt.ylabel('Frequency [Hz]')
    plt.xlabel('Time [sec], nperseg = 150')
    plt.subplot(236)
    plt.pcolormesh(t350, f350, Sxx_350, shading='auto',cmap = 'inferno')
    plt.ylim([0,70])
    plt.ylabel('Frequency [Hz]')
    plt.xlabel('Time [sec], nperseg = 350')
    
    
    plt.show()
    

    But your big issue is the length of your signal. You are limited by the time-frequency resolution. Basically the number of frequency band you will get is the length of nperseg divided by 2, spread over the interval [0, FS/2]. As your signal is 440 samples, the nperseg should be lover. But if you increase the nperseg too much, you will loose the time resolution. For instance, if nperseg = 50, there will be 390 point in time but id nperseg = 350 there will only be 90 point in time.

    enter image description here

    Info are avaialable in the doc https://docs.scipy.org/doc/scipy/reference/generated/scipy.signal.spectrogram.html