Source code for spectrum.tools

"""
.. topic:: Tools module

    .. autosummary::

        db2mag
        db2pow
        mag2db
        nextpow2
        pow2db
        onesided_2_twosided
        twosided_2_onesided
        centerdc_2_twosided
        twosided_2_centerdc

    .. codeauthor:: Thomas Cokelaer, 2011
"""
import numpy as np
from numpy import ceil, log2
from collections import deque


#__all__ = ["cshift", "pow2dB", "nextpow2", "twosided", "twosided_zerolag",
#           "fftshift"]


[docs]def fftshift(x): """wrapper to numpy.fft.fftshift .. doctest:: >>> from spectrum import fftshift >>> x = [100, 2, 3, 4, 5] >>> fftshift(x) array([ 4, 5, 100, 2, 3]) """ return np.fft.fftshift(x)
def _swapsides(data): """todo is it really useful ? Swap sides .. doctest:: >>> from spectrum import swapsides >>> x = [-2, -1, 1, 2] >>> swapsides(x) array([ 2, -2, -1]) """ N = len(data) return np.concatenate((data[N//2+1:], data[0:N//2]))
[docs]def twosided_2_onesided(data): """Convert a one-sided PSD to a twosided PSD In order to keep the power in the onesided PSD the same as in the twosided version, the onesided values are twice as much as in the input data (except for the zero-lag value). :: >>> twosided_2_onesided([10, 2,3,3,2,8]) array([ 10., 4., 6., 8.]) """ assert len(data) % 2 == 0 N = len(data) psd = np.array(data[0:N//2+1]) * 2. psd[0] /= 2. psd[-1] = data[-1] return psd
[docs]def onesided_2_twosided(data): """Convert a two-sided PSD to a one-sided PSD In order to keep the power in the twosided PSD the same as in the onesided version, the twosided values are 2 times lower than the input data (except for the zero-lag and N-lag values). :: >>> twosided_2_onesided([10, 4, 6, 8]) array([ 10., 2., 3., 3., 2., 8.]) """ psd = np.concatenate((data[0:-1], cshift(data[-1:0:-1], -1)))/2. psd[0] *= 2. psd[-1] *= 2. return psd
[docs]def twosided_2_centerdc(data): """Convert a two-sided PSD to a center-dc PSD""" N = len(data) # could us int() or // in python 3 newpsd = np.concatenate((cshift(data[N//2:], 1), data[0:N//2])) newpsd[0] = data[-1] return newpsd
[docs]def centerdc_2_twosided(data): """Convert a center-dc PSD to a twosided PSD""" N = len(data) newpsd = np.concatenate((data[N//2:], (cshift(data[0:N//2], -1)))) return newpsd
[docs]def twosided(data): """return a twosided vector with non-duplication of the first element .. doctest:: >>> from spectrum import twosided >>> a = [1,2,3] >>> twosided(a) array([3, 2, 1, 2, 3]) """ twosided = np.concatenate((data[::-1], data[1:])) return twosided #remove the first element to have a power of 2 and compatiable with pylab.psd
def _twosided_zerolag(data, zerolag): """Build a symmetric vector out of stricly positive lag vector and zero-lag .. doctest:: >>> data = [3,2,1] >>> zerolag = 4 >>> twosided_zerolag(data, zerolag) array([1, 2, 3, 4, 3, 2, 1]) .. seealso:: Same behaviour as :func:`twosided_zerolag` """ res = twosided(np.insert(data, 0, zerolag)) return res
[docs]def cshift(data, offset): """Circular shift to the right (within an array) by a given offset :param array data: input data (list or numpy.array) :param int offset: shift the array with the offset .. doctest:: >>> from spectrum import cshift >>> cshift([0, 1, 2, 3, -2, -1], 2) array([-2, -1, 0, 1, 2, 3]) """ # the deque method is suppose to be optimal when using rotate to shift the # data that playing with the data to build a new list. if isinstance(offset, float): offset = int(offset) a = deque(data) a.rotate(offset) return np.array(a) #convert back to an array. Is it necessary?
[docs]def pow2db(x): """returns the corresponding decibel (dB) value for a power value x. The relationship between power and decibels is: .. math:: X_{dB} = 10 * \log_{10}(x) .. doctest:: >>> from spectrum import pow2db >>> x = pow2db(0.1) >>> x -10.0 """ return 10 * log10(x)
[docs]def db2pow(xdb): """Convert decibels (dB) to power .. doctest:: >>> from spectrum import db2pow >>> p = db2pow(-10) >>> p 0.1 .. seealso:: :func:`pow2db` """ return 10.**(xdb/10.)
[docs]def nextpow2(x): """returns the smallest power of two that is greater than or equal to the absolute value of x. This function is useful for optimizing FFT operations, which are most efficient when sequence length is an exact power of two. :Example: .. doctest:: >>> from spectrum import nextpow2 >>> x = [255, 256, 257] >>> nextpow2(x) array([8, 8, 9]) """ res = ceil(log2(x)) return res.astype('int') #we want integer values only but ceil gives float
[docs]def db2mag(xdb): """Convert decibels (dB) to magnitude .. doctest:: >>> from spectrum import db2mag >>> db2mag(-20) 0.1 .. seealso:: :func:`pow2db` """ return 10.**(xdb/20.)
[docs]def mag2db(x): """Convert magnitude to decibels (dB) The relationship between magnitude and decibels is: .. math:: X_{dB} = 20 * \log_{10}(x) .. doctest:: >>> from spectrum import mag2db >>> mag2db(0.1) -20.0 .. seealso:: :func:`db2mag` """ return 20. * log10(x)
[docs]def log10(data): np.seterr(divide='ignore') data = np.log10(data) np.seterr(divide='warn') return data