Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
17 changes: 15 additions & 2 deletions doc/source/ref/wavelets.rst
Original file line number Diff line number Diff line change
Expand Up @@ -262,21 +262,30 @@ from plain Python lists of filter coefficients and a *filter bank-like* object.
``ContinuousWavelet`` object
----------------------------

.. class:: ContinuousWavelet(name, dtype=np.float64)
.. class:: ContinuousWavelet(name, dtype=np.float64, lower_bound=None, upper_bound=None)

Describes properties of a continuous wavelet identified by the specified wavelet ``name``.
In order to use a built-in wavelet the ``name`` parameter must be a valid
wavelet name from the :func:`pywt.wavelist` list.

:param name: Wavelet name
:param dtype: numpy.dtype to use for the wavelet. Can be numpy.float64 or numpy.float32.
:param lower_bound: Lower bound of the effective support. ``None`` keeps the family's default.
:param upper_bound: Upper bound of the effective support. ``None`` keeps the family's default.

The bounds determine the interval sampled by :meth:`wavefun` and used in
:func:`pywt.cwt`. Defaults depend on the wavelet family: for example, ``gaus1``
uses [-5, 5], while ``morl`` uses [-8, 8]. They remain writable after construction.

**Example:**

.. try_examples::

>>> import pywt
>>> wavelet = pywt.ContinuousWavelet('gaus1')
>>> wavelet = pywt.ContinuousWavelet('gaus1', lower_bound=-4, upper_bound=4)
>>> psi, x = wavelet.wavefun()
>>> float(x[0]), float(x[-1])
(-4.0, 4.0)

.. attribute:: name

Expand Down Expand Up @@ -340,6 +349,8 @@ from plain Python lists of filter coefficients and a *filter bank-like* object.
DWT: False
CWT: True
Complex CWT: False
Lower bound: -5.0
Upper bound: 5.0

Approximating wavelet functions - ``ContinuousWavelet.wavefun()``
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
Expand Down Expand Up @@ -398,3 +409,5 @@ Approximating wavelet functions - ``ContinuousWavelet.wavefun()``
DWT: False
CWT: True
Complex CWT: False
Lower bound: -5.0
Upper bound: 5.0
40 changes: 33 additions & 7 deletions pywt/_extensions/_pywt.pyx
Original file line number Diff line number Diff line change
Expand Up @@ -680,15 +680,34 @@ cdef public class Wavelet [type WaveletType, object WaveletObject]:

cdef public class ContinuousWavelet [type ContinuousWaveletType, object ContinuousWaveletObject]:
"""
ContinuousWavelet(name, dtype) object describe properties of
a continuous wavelet identified by name.
ContinuousWavelet(name, dtype=np.float64, lower_bound=None, upper_bound=None)

In order to use a built-in wavelet the parameter name must be
a valid name from the wavelist() list.
Describe the properties of a continuous wavelet identified by name.

Parameters
----------
name : str
Built-in continuous wavelet name from ``wavelist(kind='continuous')``.
dtype : numpy.dtype, optional
Data type for wavelet evaluation: ``numpy.float64`` (default) or
``numpy.float32``.
lower_bound, upper_bound : float or None, optional
Bounds of the effective support used by ``wavefun`` and the continuous
wavelet transform. Each ``None`` retains the wavelet family's default
bound. For example, ``morl`` uses [-8, 8] and ``gaus1`` uses [-5, 5].
The bounds can also be changed after construction using the attributes
of the same names.

Examples
--------
>>> import pywt
>>> wavelet = pywt.ContinuousWavelet('morl', lower_bound=-6, upper_bound=6)
>>> wavelet.lower_bound, wavelet.upper_bound
(-6.0, 6.0)
"""
#cdef readonly properties
def __cinit__(self, name=u"", dtype=np.float64):
def __cinit__(self, name=u"", dtype=np.float64, lower_bound=None,
upper_bound=None):
cdef object family_code, family_number

# builtin wavelet
Expand Down Expand Up @@ -771,14 +790,19 @@ cdef public class ContinuousWavelet [type ContinuousWaveletType, object Continuo
raise ValueError(
"Invalid continuous wavelet name '%s'." % self.name)

if lower_bound is not None:
self.lower_bound = lower_bound
if upper_bound is not None:
self.upper_bound = upper_bound

def __dealloc__(self):
if self.w is not NULL:
wavelet.free_continuous_wavelet(self.w)
self.w = NULL

def __reduce__(self):
return (ContinuousWavelet, (self.name, self.dt))
return (ContinuousWavelet, (self.name, self.dt,
self.w.lower_bound, self.w.upper_bound))

property family_number:
"Wavelet family number"
Expand Down Expand Up @@ -987,7 +1011,9 @@ cdef public class ContinuousWavelet [type ContinuousWaveletType, object Continuo
u" Symmetry: %s" % self.symmetry,
u" DWT: False",
u" CWT: True",
u" Complex CWT: %s" % self.complex_cwt
u" Complex CWT: %s" % self.complex_cwt,
u" Lower bound: %s" % self.lower_bound,
u" Upper bound: %s" % self.upper_bound
]:
s.append(x.rstrip())
return u'\n'.join(s)
Expand Down
41 changes: 41 additions & 0 deletions pywt/tests/test_cwt_wavelets.py
Original file line number Diff line number Diff line change
Expand Up @@ -561,3 +561,44 @@ def test_cwt_discrete_wavelet_raises():
# a continuous wavelet still works
out, _ = pywt.cwt(data, [1, 2], 'morl')
assert out.shape == (2, 100)


@pytest.mark.parametrize('name', ['gaus1', 'morl', 'cmor1.5-1.0', 'shan1-1'])
@pytest.mark.parametrize('dtype', [np.float32, np.float64])
def test_continuous_wavelet_constructor_bounds(name, dtype):
wavelet = pywt.ContinuousWavelet(name, dtype, lower_bound=-4, upper_bound=6)
assigned = pywt.ContinuousWavelet(name, dtype)
assigned.lower_bound = -4
assigned.upper_bound = 6
for actual, expected in zip(wavelet.wavefun(), assigned.wavefun()):
assert_equal(actual, expected)
data = np.sin(np.arange(64))
for actual, expected in zip(pywt.cwt(data, [1, 2], wavelet),
pywt.cwt(data, [1, 2], assigned)):
assert_equal(actual, expected)
assert 'Lower bound: -4.0' in str(wavelet)
assert 'Upper bound: 6.0' in str(wavelet)
for protocol in range(pickle.HIGHEST_PROTOCOL + 1):
restored = pickle.loads(pickle.dumps(wavelet, protocol=protocol))
assert restored.lower_bound == -4
assert restored.upper_bound == 6
for actual, expected in zip(restored.wavefun(), wavelet.wavefun()):
assert_equal(actual, expected)


@pytest.mark.parametrize('name', ['gaus1', 'morl', 'shan1-1'])
def test_continuous_wavelet_constructor_default_bounds(name):
default = pywt.ContinuousWavelet(name)
lower = pywt.ContinuousWavelet(name, lower_bound=-3)
upper = pywt.ContinuousWavelet(name, upper_bound=3)
assert (lower.lower_bound, lower.upper_bound) == (-3, default.upper_bound)
assert (upper.lower_bound, upper.upper_bound) == (default.lower_bound, 3)
explicit_none = pywt.ContinuousWavelet(name, lower_bound=None, upper_bound=None)
assert explicit_none.lower_bound == default.lower_bound
assert explicit_none.upper_bound == default.upper_bound


@pytest.mark.parametrize('bound', ['lower_bound', 'upper_bound'])
def test_continuous_wavelet_invalid_constructor_bound(bound):
with pytest.raises(TypeError):
pywt.ContinuousWavelet('morl', **{bound: object()})