From: <ry...@us...> - 2008-11-11 16:30:08
|
Revision: 6389 http://matplotlib.svn.sourceforge.net/matplotlib/?rev=6389&view=rev Author: ryanmay Date: 2008-11-11 16:30:03 +0000 (Tue, 11 Nov 2008) Log Message: ----------- Add 'pad_to' and 'sides' parameters to mlab.psd() to allow controlling of zero padding and returning of negative frequency components, respecitively. These are added in a way that does not change the API. Modified Paths: -------------- trunk/matplotlib/CHANGELOG trunk/matplotlib/lib/matplotlib/mlab.py Modified: trunk/matplotlib/CHANGELOG =================================================================== --- trunk/matplotlib/CHANGELOG 2008-11-11 08:04:24 UTC (rev 6388) +++ trunk/matplotlib/CHANGELOG 2008-11-11 16:30:03 UTC (rev 6389) @@ -1,3 +1,8 @@ +2008-11-11 Add 'pad_to' and 'sides' parameters to mlab.psd() to + allow controlling of zero padding and returning of + negative frequency components, respecitively. These are + added in a way that does not change the API. - RM + 2008-11-10 Fix handling of c kwarg by scatter; generalize is_string_like to accept numpy and numpy.ma string array scalars. - RM and EF Modified: trunk/matplotlib/lib/matplotlib/mlab.py =================================================================== --- trunk/matplotlib/lib/matplotlib/mlab.py 2008-11-11 08:04:24 UTC (rev 6388) +++ trunk/matplotlib/lib/matplotlib/mlab.py 2008-11-11 16:30:03 UTC (rev 6389) @@ -239,7 +239,7 @@ return y - (b*x + a) def psd(x, NFFT=256, Fs=2, detrend=detrend_none, - window=window_hanning, noverlap=0): + window=window_hanning, noverlap=0, pad_to=None, sides='default'): """ The power spectral density by Welch's average periodogram method. The vector *x* is divided into *NFFT* length blocks. Each block @@ -273,22 +273,36 @@ :func:`numpy.blackman`, :func:`numpy.hamming`, :func:`numpy.bartlett`, :func:`scipy.signal`, :func:`scipy.signal.get_window`, etc. The default is - :func:`window_hanning`. + :func:`window_hanning`. If a function is passed as the + argument, it must take a data segment as an argument and + return the windowed version of the segment. *noverlap* The number of points of overlap between blocks. The default value is 0 (no overlap). + *pad_to* + The number of points to which the data segment is padd when + performing the FFT. This can be different from *NFFT*, which + specifies the number of data points used. While not increasing + the actual resolution of the psd (the minimum distance between + resolvable peaks), this can give more points in the plot, + allowing for more detail. This corresponds to the *n* parameter + in the call to fft(). The default is None, which sets *pad_to* + equal to *NFFT* + + *sides* [ 'default' | 'onesided' | 'twosided' ] + Specifies which sides of the PSD to return. Default gives the + default behavior, which returns one-sided for real data and both + for complex data. 'one' forces the return of a one-sided PSD, while + 'both' forces two-sided. + Returns the tuple (*Pxx*, *freqs*). Refs: Bendat & Piersol -- Random Data: Analysis and Measurement Procedures, John Wiley & Sons (1986) """ - # I think we could remove this condition without hurting anything. - if NFFT % 2: - raise ValueError('NFFT must be even') - x = np.asarray(x) # make sure we're dealing with a numpy array # zero pad x up to NFFT if it is shorter than NFFT @@ -297,24 +311,34 @@ x = np.resize(x, (NFFT,)) # Can't use resize method. x[n:] = 0 + if pad_to is None: + pad_to = NFFT + # for real x, ignore the negative frequencies - if np.iscomplexobj(x): numFreqs = NFFT - else: numFreqs = NFFT//2+1 + if (sides == 'default' and np.iscomplexobj(x)) or sides == 'twosided': + numFreqs = pad_to + elif sides in ('default', 'onesided'): + numFreqs = pad_to//2 + 1 + else: + raise ValueError("sides must be one of: 'default', 'onesided', or " + "twosided") if cbook.iterable(window): assert(len(window) == NFFT) windowVals = window else: - windowVals = window(np.ones((NFFT,),x.dtype)) - step = NFFT-noverlap - ind = range(0,len(x)-NFFT+1,step) + windowVals = window(np.ones((NFFT,), x.dtype)) + + step = NFFT - noverlap + ind = range(0, len(x) - NFFT + 1, step) n = len(ind) Pxx = np.zeros((numFreqs,n), np.float_) - # do the ffts of the slices + + # do the FFTs of the slices for i in range(n): thisX = x[ind[i]:ind[i]+NFFT] thisX = windowVals * detrend(thisX) - fx = np.absolute(np.fft.fft(thisX))**2 + fx = np.absolute(np.fft.fft(thisX, n=pad_to))**2 Pxx[:,i] = fx[:numFreqs] if n>1: @@ -323,7 +347,7 @@ # windowing loss; see Bendat & Piersol Sec 11.5.2 Pxx /= (np.abs(windowVals)**2).sum() - freqs = Fs/NFFT * np.arange(numFreqs) + freqs = float(Fs) / pad_to * np.arange(numFreqs) return Pxx, freqs This was sent by the SourceForge.net collaborative development platform, the world's largest Open Source development site. |