[SciPy-User] frequency components of a signal buried in a noisy time domain signal

Nils Wagner nwagner at iam.uni-stuttgart.de
Sat Feb 27 05:06:38 EST 2010


On Fri, 26 Feb 2010 22:03:08 -0500
  Ivo Maljevic <ivo.maljevic at gmail.com> wrote:
> Nils,
> I modified a little bit your code. Try this version, 
>maybe you will find it
> helpful. I wouldn't bother much
> with the next power of 2 unless you are going to 
>implement something in real
> time - FFT calculation
> with non-power of 2 on a PC is just fine. Also, I would 
>consider
> periodograms only if the signal changes over time, and 
>you want
> to be able to track these changes over time. Otherwise, 
>taking the whole
> signal and doing one FFT may be OK.
> 
> Take a look at the code below (blue) , which is a 
>modified version of your
> code (and read the comments).
> 
> Ivo
> 
> 
> import numpy as np
> import matplotlib.pyplot as plt
> from scipy.fftpack import fft, fftshift
> 
> def signal_spectrum(x, Fs):
>  n = len(x)
>  f = np.linspace(-Fs/2, Fs/2, n)
>  X=abs(fftshift(fft(x)))  # move the upper spectrum to 
>negative freqs
>  return [f, X]
> 
> pi = np.pi
>Fs = 1000. #                          Sampling frequency
> T  = 1./Fs #                          Sample time
> L  = 1000  #                          length of signal
> t  = np.arange(0,L)*T
> x  = 0.7*np.sin(2*pi*50*t)+np.sin(2*pi*120*t)
> y  = x + 2*np.random.randn(len(t))
> plt.figure()
> plt.plot(Fs*t[:50],y[:50])
> plt.title('Signal corrupted with zero-mean random 
>noise')
> plt.xlabel('Time (milliseconds)')
> 
> NFFT = 2**np.ceil(np.log2(L)) # only if you really want 
>this
> 
> plt.figure()
> Y = fft(y,NFFT)/L
> f = Fs/2*np.linspace(0,1,NFFT/2+1)
> plt.plot(f,2*abs(Y[:NFFT/2+1]))
> plt.title('Single-sided amplitude spectrum of y(t)')
> plt.xlabel('Frequency (Hz)')
> plt.ylabel('|Y(f)|')
> 
> # Another way of calculating and plotting the spectrum
> f,Yd = signal_spectrum(y, Fs)
> plt.figure()  # you want to add this to be able to see 
>multiple plots
> plt.plot(f,Yd)
> plt.title('Spectrum of the the signal')
> plt.xlabel('Frequency (Hz)')
> plt.ylabel('|Y(f)|')
> plt.grid(True)
> 
> plt.show()
  
Hi Ivo,

Thank you very much for your hints.
My experience is, that spectrograms work well with 
synthetic signals.

What is needed to use spectrograms for real-life signals ?
I mean do I need a filter etc. ?


Nils

from scipy import linspace, vectorize, cos, pi
from pylab import plot, show, imshow, subplot, specgram, 
xlabel, ylabel, savefig
#
# Example taken from 
http://en.wikipedia.org/wiki/Short-time_Fourier_transform
#
def x(t):
     " Synthetic signal "
     if t < 5:
        return cos(2*pi*10*t)
     if t >= 5. and t < 10:
        return cos(2*pi*25*t)
     if t >=10. and t< 15:
        return cos(2*pi*50*t)
     if t >=15. and t<= 20:
        return cos(2*pi*100*t)

t = linspace(0.,20.,8001)     # sampled at 400 Hz
dt = t[1]-t[0]
NFFT = 512                    # the length of the 
windowing segments
Fs = int(1.0/dt)              # the sampling frequency
x_vec = vectorize(x)
signal = x_vec(t)

ax1=subplot(211)
plot(t,signal)
subplot(212,sharex=ax1)
Pxx, freqs, bins, im = specgram(signal, NFFT=NFFT, Fs=Fs, 
noverlap=5)
xlabel(r'Time $t$ [s]')
ylabel('Frequency $f$ [Hz]')
savefig('spectrogram',dpi=60)
show()



More information about the SciPy-User mailing list