├── .gitignore ├── .hgignore ├── .hgtags ├── .travis.yml ├── CHANGES.txt ├── COPYING.txt ├── MANIFEST.in ├── README.rst ├── THANKS.txt ├── demo ├── benchmark.py ├── data │ └── aero.png ├── dwt_decompose.c ├── dwt_multidim.py ├── dwt_signal_decomposition.py ├── dwt_swt_show_coeffs.py ├── image_blender.py ├── plot_wavelets.py ├── sample_data.py ├── swt2.py ├── user_filter_banks.py ├── wavedec.py ├── waveinfo.py ├── wp_2d.py ├── wp_scalogram.py ├── wp_tree.py └── wp_visualize_coeffs_distribution.py ├── doc ├── Makefile ├── doc2html.bat ├── make.bat └── source │ ├── COPYING.txt │ ├── _static │ ├── comments.png │ ├── favicon.ico │ ├── github.png │ ├── page_edit.png │ ├── twitter.png │ └── wave.png │ ├── _templates │ ├── editdocument.html │ ├── page.html │ └── quicklinks.html │ ├── conf.py │ ├── contents.rst │ ├── dev │ ├── building_extension.rst │ ├── index.rst │ ├── installing_build_dependencies.rst │ ├── preparing_linux_build_environment.rst │ ├── preparing_windows_build_environment.rst │ └── testing.rst │ ├── index.rst │ ├── overview.rst │ ├── ref │ ├── 2d-dwt-and-idwt.rst │ ├── dwt-discrete-wavelet-transform.rst │ ├── idwt-inverse-discrete-wavelet-transform.rst │ ├── index.rst │ ├── other-functions.rst │ ├── signal-extension-modes.rst │ ├── swt-stationary-wavelet-transform.rst │ ├── thresholding-functions.rst │ ├── wavelet-packets.rst │ └── wavelets.rst │ ├── regression │ ├── dwt-idwt.rst │ ├── gotchas.rst │ ├── index.rst │ ├── modes.rst │ ├── multilevel.rst │ ├── wavelet.rst │ ├── wp.rst │ └── wp2d.rst │ ├── resources.rst │ └── substitutions.rst ├── setup.cfg ├── setup.py ├── src ├── _pywt.pxi ├── _pywt.pyx ├── array_interface.h ├── arraytools.pxi ├── c_array_interface.pxd ├── c_math.pxd ├── c_python.pxd ├── c_string.pxd ├── c_wt.template.pxd ├── common.c ├── common.h ├── convolution.template.c ├── convolution.template.h ├── pywt │ ├── __init__.py │ ├── functions.py │ ├── multidim.py │ ├── multilevel.py │ ├── numerix.py │ ├── thresholding.py │ └── wavelet_packets.py ├── wavelets.template.c ├── wavelets.template.h ├── wavelets_coeffs.template.h ├── wavelets_list.pxi ├── wt.template.c └── wt.template.h ├── tests ├── __init__.py ├── test_doc.py ├── test_matlab_compatibility.py ├── test_perfect_reconstruction.py └── test_regression.py ├── tox.ini └── util ├── __init__.py ├── commands.py ├── setenv_build32.bat ├── setenv_build64.bat └── templating.py /.gitignore: -------------------------------------------------------------------------------- 1 | *.py[co] 2 | *.pyd 3 | 4 | # Packages 5 | *.egg 6 | *.egg-info 7 | dist 8 | build 9 | eggs 10 | parts 11 | bin 12 | var 13 | sdist 14 | develop-eggs 15 | .installed.cfg 16 | 17 | # Installer logs 18 | pip-log.txt 19 | 20 | # Unit test / coverage reports 21 | .coverage 22 | .tox 23 | 24 | # Translations 25 | *.mo 26 | 27 | # Editors 28 | .idea 29 | 30 | # Project working files 31 | _pywt.[ch] 32 | c_wt.pxd 33 | convolution.[ch] 34 | wavelets.[ch] 35 | wavelets_coeffs.h 36 | wt.[ch] -------------------------------------------------------------------------------- /.hgignore: -------------------------------------------------------------------------------- 1 | syntax: glob 2 | *.pyc 3 | build/ 4 | dist/ 5 | PyWavelets.egg-info/ 6 | src/_pywt.c 7 | src/_pywt.h 8 | .idea/ 9 | -------------------------------------------------------------------------------- /.hgtags: -------------------------------------------------------------------------------- 1 | 46f0d1da89b99b6e1748559cefb87823c959b4f5 release_0_1_4 2 | 50e1b1b9d1200c0a479cfd9300c10314a68d3697 release_0_1_6 3 | a2990c5f78301da4602957875bcc1058188f311d 0.2.0 4 | adfad310dacd3bbbc36c603eef55cf8127ec6f4f 0.2.2 5 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | 3 | python: 4 | - 2.6 5 | - 2.7 6 | 7 | branches: 8 | only: 9 | - develop 10 | - master 11 | 12 | before_install: 13 | - pip install -q --use-mirrors Cython numpy 14 | 15 | install: 16 | - pip install . 17 | 18 | script: 19 | - python setup.py test 20 | -------------------------------------------------------------------------------- /CHANGES.txt: -------------------------------------------------------------------------------- 1 | Changelog 2 | 3 | 0.2.2 4 | maintenance release: 5 | - resolved setup and build issues 6 | - support for compilation using MSVC compiler 7 | - updated documentation 8 | - moved main repository to GitHub (https://github.com/nigma/pywt) 9 | 10 | 0.2.0 11 | 12 | changes: 13 | - 2D Wavelet Packet and Inverse Wavelet Packet Transforms 14 | - 2D Stationary Wavelet Transform 15 | - Single and double precision computations 16 | - DWT and IDWT optimizations 17 | - refactored Wavelet Packet code 18 | 19 | 0.1.6 20 | changes: 21 | - argument order changed for wavedec to be more consistent with other 22 | functions. Now is (data, wavelet, *mode*, *level*). 23 | - added 2D DWT and IDWT (dwt2, idwt2) 24 | - added 2D multilevel transform - wavedec2 and waverec2 25 | - added support for Python 2.5 (requires modified Pyrex, see the documentation) 26 | - using Python memory management functions instead of C stdlib ones 27 | fixes: 28 | - rbior wavelets filters corrected 29 | 30 | 0.1.4 31 | changes: 32 | - Wavelet class can be subclassed 33 | - requires NumPy, edit numerix.py to use with other numeric modules, 34 | array.array is no more directly supported 35 | - code cleanup & comments 36 | - wavedec and waverec Pyrex code moved to pure Python multilevel.py 37 | module 38 | - doctesting doc examples 39 | 40 | fixes: 41 | - fixed swt for too high level value 42 | - fixed bug in upcoef wrapper code for some take values 43 | 44 | 0.1.2 45 | changes: 46 | - support for custom filter banks 47 | - now compiles without numpy installed 48 | 49 | fixes: 50 | - fixed handling of non-contiguous arrays 51 | 52 | 0.1.0 53 | initial release 54 | -------------------------------------------------------------------------------- /COPYING.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006-2012 Filip Wasilewski 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /MANIFEST.in: -------------------------------------------------------------------------------- 1 | include setup.py setup.cfg 2 | include README.rst CHANGES.txt COPYING.txt THANKS.txt 3 | include MANIFEST.in 4 | 5 | graft demo 6 | graft doc 7 | graft src 8 | graft tests 9 | graft util 10 | 11 | prune build 12 | prune doc/build 13 | 14 | global-exclude *.py[cod] *.egg *.egg-info 15 | -------------------------------------------------------------------------------- /README.rst: -------------------------------------------------------------------------------- 1 | Important 2 | ========= 3 | 4 | **We're moving! The new home for the project is https://github.com/PyWavelets.** 5 | 6 | Thanks everyone for starring, forking and following this repository on Github. 7 | 8 | The PyWavelets project has a new home and maintainers. 9 | 10 | Please go to https://github.com/PyWavelets/pywt and follow the development and new releases there. 11 | 12 | PyWavelets - Discrete Wavelet Transform in Python 13 | ================================================= 14 | 15 | PyWavelets is a free Open Source wavelet transform software for Python_ 16 | programming language. It is written in Python, Cython and C for a mix of easy 17 | and powerful high-level interface and the best performance. 18 | 19 | PyWavelets is very easy to start with and use, and currently is capable of: 20 | 21 | * 1D and 2D Forward and Inverse Discrete Wavelet Transform (DWT and IDWT) 22 | * 1D and 2D Stationary Wavelet Transform (Undecimated Wavelet Transform) 23 | * 1D and 2D Wavelet Packet decomposition and reconstruction 24 | * Approximating wavelet and scaling functions 25 | * Over seventy built-in wavelet filters and custom wavelets supported 26 | * Single and double precision calculations 27 | * Results compatibility with Matlab Wavelet Toolbox (tm) 28 | 29 | .. image:: 30 | https://secure.travis-ci.org/nigma/pywt.png?branch=develop 31 | :alt: Build Status 32 | :target: https://secure.travis-ci.org/nigma/pywt 33 | 34 | 35 | Requirements 36 | ------------ 37 | 38 | PyWavelets is a package for the Python programming language. It requires: 39 | 40 | - Python_ 2.6 or 2.7 41 | - numpy_ numeric array module 42 | 43 | Download 44 | -------- 45 | 46 | The most recent *development* version can be found on GitHub at 47 | https://github.com/nigma/pywt. 48 | 49 | Latest release, including source and binary package for Windows, is available 50 | for download from the `Python Package Index`_. 51 | 52 | Install 53 | ------- 54 | 55 | In order to build PyWavelets from source, a working C compiler (GCC or MSVC) 56 | and a recent version of Cython_ is required. 57 | 58 | - To install PyWavelets open shell prompt and type ``pip install PyWavelets`` 59 | or ``easy_install PyWavelets``. 60 | 61 | - To build and install from source, navigate to downloaded PyWavelets source 62 | code directory and type ``python setup.py install``. 63 | 64 | - The `in-development version`_ of PyWavelets can be installed with 65 | ``pip install PyWavelets==dev`` or ``easy_install PyWavelets==dev``. 66 | 67 | Prebuilt Windows binaries and source code packages are also 68 | available from `Python Package Index`_. 69 | 70 | Binary packages for several Linux distributors are maintained by Open Source 71 | community contributors. Query your Linux package manager tool 72 | for `python-wavelets`, `python-pywt` or similar package name. 73 | 74 | Documentation 75 | ------------- 76 | 77 | Documentation with detailed examples and links to more resources is available 78 | online at http://www.pybytes.com/pywavelets/ and 79 | http://pywavelets.readthedocs.org. 80 | 81 | For more usage examples see the `demo`_ directory in the source package. 82 | 83 | Contributing 84 | ------------ 85 | 86 | PyWavelets started in 2006 as an academic project for a master thesis 87 | on `Analysis and Classification of Medical Signals using Wavelet Transforms` 88 | and is maintained by its `original developer`_. 89 | 90 | All contributions including bug reports, bug fixes, new feature implementations 91 | and documentation improvements are welcome. 92 | 93 | Go and fork on `GitHub`_ today! 94 | 95 | Python 3 96 | -------- 97 | 98 | Python 3 development branch is at https://github.com/nigma/pywt/tree/py-3. 99 | Check out the `changelog `_ for 100 | info. Currently the code and examples are ported to work on Python 2.7 and 3.2 101 | from the same codebase. 102 | 103 | Contact 104 | ------- 105 | 106 | Use `GitHub Issues`_ or `PyWavelets discussions group`_ to post your 107 | comments or questions. 108 | 109 | License 110 | ------- 111 | 112 | PyWavelets is a free Open Source software released under the MIT license. 113 | 114 | Commercial Support 115 | ------------------ 116 | 117 | For information on commercial support and development email me at en@ig.ma. 118 | 119 | 120 | .. _Cython: http://cython.org/ 121 | .. _demo: https://github.com/nigma/pywt/tree/master/demo 122 | .. _GitHub: https://github.com/nigma/pywt 123 | .. _GitHub Issues: https://github.com/nigma/pywt/issues 124 | .. _in-development version: https://github.com/nigma/pywt/tarball/develop#egg=PyWavelets-dev 125 | .. _numpy: http://numpy.scipy.org/ 126 | .. _original developer: http://en.ig.ma 127 | .. _Python: http://python.org/ 128 | .. _Python Package Index: http://pypi.python.org/pypi/PyWavelets/ 129 | .. _PyWavelets discussions group: http://groups.google.com/group/pywavelets 130 | 131 | -------------------------------------------------------------------------------- /THANKS.txt: -------------------------------------------------------------------------------- 1 | A special thanks goes to: 2 | 3 | * Fernando Perez and people behind scipy.org for 4 | help with wavelets.scipy.org wiki and SVN hosting 5 | 6 | -------------------------------------------------------------------------------- /demo/benchmark.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import gc 5 | import sys 6 | import time 7 | 8 | import numpy 9 | import pylab 10 | 11 | import pywt 12 | 13 | if sys.platform == 'win32': 14 | clock = time.clock 15 | else: 16 | clock = time.time 17 | 18 | sizes = [20, 50, 100, 120, 150, 200, 250, 300, 400, 500, 600, 750, 19 | 1000, 2000, 3000, 4000, 5000, 6000, 7500, 20 | 10000, 15000, 20000, 25000, 30000, 40000, 50000, 75000, 21 | 100000, 150000, 200000, 250000, 300000, 400000, 500000, 22 | 600000, 750000, 1000000, 2000000, 5000000][:-4] 23 | 24 | wavelet_names = ['db1', 'db2', 'db3', 'db4', 'db5', 'db6', 'db7', 25 | 'db8', 'db9', 'db10', 'sym10', 'coif1', 'coif2', 26 | 'coif3', 'coif4', 'coif5'] 27 | 28 | dtype = numpy.float64 29 | 30 | wavelets = [pywt.Wavelet(n) for n in wavelet_names] 31 | mode = pywt.MODES.zpd 32 | 33 | times_dwt = [[] for i in range(len(wavelets))] 34 | times_idwt = [[] for i in range(len(wavelets))] 35 | 36 | repeat = 5 37 | 38 | for j, size in enumerate(sizes): 39 | #if size > 500000: 40 | # warnings.warn("Warning, too big data size may cause page swapping.") 41 | 42 | data = numpy.ones((size,), dtype) 43 | 44 | print ("%d/%d" % (j + 1, len(sizes))).rjust(6), str(size).rjust(9), 45 | for i, w in enumerate(wavelets): 46 | min_t1, min_t2 = 9999., 9999. 47 | for _ in xrange(repeat): 48 | t1 = clock() 49 | (a, d) = pywt.dwt(data, w, mode) 50 | t1 = clock() - t1 51 | min_t1 = min(t1, min_t1) 52 | 53 | t2 = clock() 54 | a0 = pywt.idwt(a, d, w, mode) 55 | t2 = clock() - t2 56 | min_t2 = min(t2, min_t2) 57 | 58 | times_dwt[i].append(min_t1) 59 | times_idwt[i].append(min_t2) 60 | print '.', 61 | print 62 | gc.collect() 63 | 64 | for j, (times, name) in enumerate([(times_dwt, 'dwt'), (times_idwt, 'idwt')]): 65 | pylab.figure(j) 66 | pylab.title(name) 67 | 68 | for i, n in enumerate(wavelet_names): 69 | pylab.loglog(sizes, times[i], label=n) 70 | 71 | pylab.legend(loc='best') 72 | pylab.xlabel('len(x)') 73 | pylab.ylabel('time [s]') 74 | 75 | pylab.show() 76 | -------------------------------------------------------------------------------- /demo/data/aero.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nigma/pywt/035e1fa14c2cd70ca270da20b1523e834a7ae635/demo/data/aero.png -------------------------------------------------------------------------------- /demo/dwt_decompose.c: -------------------------------------------------------------------------------- 1 | #include 2 | 3 | #include "wt.h" 4 | 5 | int main(){ 6 | 7 | // Using C API to decompose 1D signal. 8 | // Results equivalent to pywt.dwt([1,2,3,4,5,6,7,8], 'db2', 'zpd'). 9 | // Compile: gcc -I../src dwt_decompose.c ../src/wt.c ../src/wavelets.c ../src/common.c ../src/convolution.c 10 | 11 | Wavelet *w = wavelet('d', 2); 12 | MODE mode = MODE_ZEROPAD; 13 | 14 | int i; 15 | float input[] = {1,2,3,4,5,6,7,8,9}; 16 | float *cA, *cD; 17 | index_t input_len, output_len; 18 | 19 | input_len = sizeof input / sizeof input[0]; 20 | output_len = dwt_buffer_length(input_len, w->dec_len, mode); 21 | 22 | cA = wtcalloc(output_len, sizeof(float)); 23 | cD = wtcalloc(output_len, sizeof(float)); 24 | 25 | printf("Wavelet: %s %d\n\n", w->family_name, w->vanishing_moments_psi); 26 | 27 | float_dec_a(input, input_len, w, cA, output_len, mode); 28 | float_dec_d(input, input_len, w, cD, output_len, mode); 29 | 30 | for(i=0; i 5 | # See COPYING for license details. 6 | 7 | """ 8 | Wavelet Image Blender. 9 | 10 | Blend image A with texture extracted from image B by selecting 11 | detail coefficients: 12 | 13 | ----------------- ----------------- 14 | | | | | 15 | | | | | 16 | | | | | 17 | | A | | B | 18 | | | | | 19 | | | | | 20 | | | | | 21 | ----------------- ----------------- 22 | 23 | | | 24 | 2D DWT | 2D DWT | 25 | V V 26 | 27 | ----------------- --------- ----------------- 28 | | | | | | | | 29 | | A(LL) | H(LH) | | H(LH) | | | 30 | | | | | | IDWT | | 31 | ----------------- + ----------------- -----> | C | 32 | | | | | | | | | 33 | | V(HL) | D(HH) | | V(HL) | D(HH) | | | 34 | | | | | | | | | 35 | ----------------- ----------------- ----------------- 36 | (details only) 37 | """ 38 | 39 | import optparse 40 | import os 41 | import sys 42 | if os.name == 'nt': 43 | from time import clock # noqa 44 | else: 45 | from time import time as clock # noqa 46 | 47 | import Image # PIL 48 | import numpy # http://www.scipy.org 49 | 50 | import pywt 51 | 52 | 53 | def image2array(image): 54 | """PIL Image to NumPy array""" 55 | assert image.mode in ('L', 'RGB', 'CMYK') 56 | arr = numpy.fromstring(image.tostring(), numpy.uint8) 57 | arr.shape = (image.size[1], image.size[0], len(image.getbands())) 58 | return arr.swapaxes(0, 2).swapaxes(1, 2).astype(numpy.float32) 59 | 60 | 61 | def array2image(arr, mode): 62 | """NumPy array to PIL Image""" 63 | arr = arr.swapaxes(1, 2).swapaxes(0, 2) 64 | arr[arr < 0] = 0 65 | arr[arr > 255] = 255 66 | arr = numpy.fix(arr).astype(numpy.uint8) 67 | return Image.fromstring(mode, arr.shape[1::-1], arr.tostring()) 68 | 69 | 70 | def load_image(path, mode=None, size=None): 71 | """Load image""" 72 | im = Image.open(path) 73 | 74 | if im.mode not in ('L', 'P', 'RGB', 'CMYK'): 75 | raise TypeError("Image mode must be 'L', 'P', 'RGB' or 'CMYK'") 76 | 77 | if mode is not None: 78 | if mode == 'P': 79 | raise ValueError("Mode must be 'L', 'RGB' or 'CMYK'") 80 | im = im.convert(mode) 81 | elif im.mode == 'P': 82 | im = im.convert('RGB') 83 | 84 | if size is not None and im.size != size: 85 | im = im.resize(size, Image.ANTIALIAS) 86 | return im 87 | 88 | 89 | def blend_images(base, texture, wavelet, level, mode='sp1', base_gain=None, 90 | texture_gain=None): 91 | """Blend loaded images at `level` of granularity using `wavelet`""" 92 | 93 | base_data = image2array(base) 94 | texture_data = image2array(texture) 95 | output_data = [] 96 | 97 | # process color bands 98 | for base_band, texture_band in zip(base_data, texture_data): 99 | # multilevel dwt 100 | base_band_coeffs = pywt.wavedec2(base_band, wavelet, mode, level) 101 | texture_band_coeffs = pywt.wavedec2(texture_band, wavelet, mode, level) 102 | 103 | # average coefficients of base image 104 | output_band_coeffs = [base_band_coeffs[0]] # cA 105 | del base_band_coeffs[0], texture_band_coeffs[0] 106 | 107 | # blend details coefficients 108 | for n, (base_band_details, texture_band_details) in enumerate( 109 | zip(base_band_coeffs, texture_band_coeffs)): 110 | blended_details = [] 111 | for (base_detail, texture_detail) in zip(base_band_details, 112 | texture_band_details): 113 | if base_gain is not None: 114 | base_detail *= base_gain 115 | if texture_gain is not None: 116 | texture_detail *= texture_gain 117 | 118 | # select coeffs with greater energy 119 | blended = numpy.where(abs(base_detail) > abs(texture_detail), 120 | base_detail, texture_detail) 121 | blended_details.append(blended) 122 | 123 | base_band_coeffs[n] = texture_band_coeffs[n] = None 124 | output_band_coeffs.append(blended_details) 125 | 126 | # multilevel idwt 127 | new_band = pywt.waverec2(output_band_coeffs, wavelet, mode) 128 | output_data.append(new_band) 129 | del new_band, base_band_coeffs, texture_band_coeffs 130 | 131 | del base_data, texture_data 132 | output_data = numpy.array(output_data) 133 | 134 | return array2image(output_data, base.mode) 135 | 136 | 137 | def main(): 138 | usage = "usage: %prog -b BASE -t TEXTURE -o OUTPUT "\ 139 | "[-w WAVELET] [-l LEVEL] [-m MODE]" 140 | parser = optparse.OptionParser(usage=usage) 141 | parser.add_option("-b", "--base", dest="base", metavar="BASE", 142 | help="base image name") 143 | parser.add_option("-t", "--texture", dest="texture", metavar="TEXTURE", 144 | help="texture image name") 145 | parser.add_option("-o", "--output", dest="output", metavar="OUTPUT", 146 | help="output image name") 147 | parser.add_option("-w", "--wavelet", dest="wavelet", metavar="WAVELET", 148 | default='db2', help="wavelet name [default: %default]") 149 | parser.add_option("-l", "--level", dest="level", metavar="LEVEL", 150 | type="int", default=4, 151 | help="decomposition level [default: %default]") 152 | parser.add_option("-m", "--mode", dest="mode", metavar="MODE", 153 | default='sym', help="decomposition mode. Adjust this if" 154 | " getting edge artifacts [default: %default]") 155 | parser.add_option("-x", "--base_gain", dest="base_gain", metavar="BG", 156 | type="float", default=None, 157 | help="Base image gain [default: %default]") 158 | parser.add_option("-y", "--texture_gain", dest="texture_gain", 159 | metavar="TG", type="float", default=None, 160 | help="Texture image gain [default: %default]") 161 | parser.add_option("--timeit", dest="timeit", action="store_true", 162 | default=False, help="time blending operations") 163 | 164 | (options, args) = parser.parse_args() 165 | 166 | if None in (options.base, options.texture, options.output): 167 | parser.print_help() 168 | sys.exit(-1) 169 | 170 | base = load_image(options.base) 171 | texture = load_image(options.texture, base.mode, base.size) 172 | 173 | if options.timeit: 174 | t = clock() 175 | 176 | im = blend_images(base, texture, options.wavelet, options.level, 177 | options.mode, options.base_gain, options.texture_gain) 178 | 179 | if options.timeit: 180 | print "%.3fs" % (clock() - t) 181 | 182 | im.save(options.output) 183 | 184 | if __name__ == '__main__': 185 | main() 186 | -------------------------------------------------------------------------------- /demo/plot_wavelets.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Plot scaling and wavelet functions for db, sym, coif, bior and rbio families 5 | 6 | import itertools 7 | 8 | import pylab 9 | 10 | import pywt 11 | 12 | iterations = 5 13 | 14 | plot_data = [ 15 | ('db', (4, 3)), 16 | ('sym', (4, 3)), 17 | ('coif', (3, 2)) 18 | ] 19 | 20 | for family, (rows, cols) in plot_data: 21 | f = pylab.figure() 22 | f.subplots_adjust( 23 | hspace=0.2, wspace=0.2, bottom=.02, left=.06, right=.97, top=.94 24 | ) 25 | colors = itertools.cycle('bgrcmyk') 26 | 27 | wnames = pywt.wavelist(family) 28 | print wnames 29 | i = iter(wnames) 30 | for col in xrange(cols): 31 | for row in xrange(rows): 32 | try: 33 | wavelet = pywt.Wavelet(i.next()) 34 | except StopIteration: 35 | break 36 | phi, psi, x = wavelet.wavefun(iterations) 37 | 38 | color = colors.next() 39 | ax = pylab.subplot(rows, 2 * cols, 1 + 2 * (col + row * cols)) 40 | pylab.title(wavelet.name + " phi") 41 | pylab.plot(x, phi, color) 42 | pylab.xlim(min(x), max(x)) 43 | 44 | ax = pylab.subplot(rows, 2 * cols, 1 + 2 * (col + row * cols) + 1) 45 | pylab.title(wavelet.name + " psi") 46 | pylab.plot(x, psi, color) 47 | pylab.xlim(min(x), max(x)) 48 | 49 | for family, (rows, cols) in [('bior', (4, 3)), ('rbio', (4, 3))]: 50 | f = pylab.figure() 51 | f.subplots_adjust(hspace=0.5, wspace=0.2, bottom=.02, left=.06, right=.97, 52 | top=.94) 53 | 54 | colors = itertools.cycle('bgrcmyk') 55 | wnames = pywt.wavelist(family) 56 | i = iter(wnames) 57 | for col in xrange(cols): 58 | for row in xrange(rows): 59 | try: 60 | wavelet = pywt.Wavelet(i.next()) 61 | except StopIteration: 62 | break 63 | phi, psi, phi_r, psi_r, x = wavelet.wavefun(iterations) 64 | row *= 2 65 | 66 | color = colors.next() 67 | ax = pylab.subplot(2 * rows, 2 * cols, 1 + 2 * (col + row * cols)) 68 | pylab.title(wavelet.name + " phi") 69 | pylab.plot(x, phi, color) 70 | pylab.xlim(min(x), max(x)) 71 | 72 | ax = pylab.subplot(2 * rows, 2 * cols, 73 | 1 + 2 * (col + row * cols) + 1) 74 | pylab.title(wavelet.name + " psi") 75 | pylab.plot(x, psi, color) 76 | pylab.xlim(min(x), max(x)) 77 | 78 | row += 1 79 | ax = pylab.subplot(2 * rows, 2 * cols, 1 + 2 * (col + row * cols)) 80 | pylab.title(wavelet.name + " phi_r") 81 | pylab.plot(x, phi_r, color) 82 | pylab.xlim(min(x), max(x)) 83 | 84 | ax = pylab.subplot(2 * rows, 2 * cols, 85 | 1 + 2 * (col + row * cols) + 1) 86 | pylab.title(wavelet.name + " psi_r") 87 | pylab.plot(x, psi_r, color) 88 | pylab.xlim(min(x), max(x)) 89 | 90 | pylab.show() 91 | -------------------------------------------------------------------------------- /demo/swt2.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import pylab 5 | import numpy 6 | import Image # PIL 7 | 8 | import pywt 9 | 10 | im = Image.open("data/aero.png").convert('L') 11 | arr = numpy.fromstring(im.tostring(), numpy.uint8) 12 | arr.shape = (im.size[1], im.size[0]) 13 | 14 | pylab.imshow(arr, interpolation="nearest", cmap=pylab.cm.gray) 15 | 16 | for LL, (LH, HL, HH) in pywt.swt2(arr, 'bior1.3', level=3, start_level=0): 17 | pylab.figure() 18 | for i, a in enumerate([LL, LH, HL, HH]): 19 | pylab.subplot(2, 2, i + 1) 20 | pylab.imshow(a, origin='image', interpolation="nearest", 21 | cmap=pylab.cm.gray) 22 | 23 | pylab.show() 24 | -------------------------------------------------------------------------------- /demo/user_filter_banks.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import pywt 5 | 6 | 7 | class FilterBank(object): 8 | """Sample filter bank with Quadrature Mirror Filters for Haar wavelet""" 9 | dec_lo = [0.70710678118654757, 0.70710678118654757] 10 | dec_hi = [-0.70710678118654757, 0.70710678118654757] 11 | rec_lo = [0.70710678118654757, 0.70710678118654757] 12 | rec_hi = [0.70710678118654757, -0.70710678118654757] 13 | 14 | def __init__(self): 15 | self.filter_bank = self.dec_lo, self.dec_hi, self.rec_lo, self.rec_hi 16 | 17 | data = [1, 2, 3, 4, 5, 6] 18 | 19 | ############################################################################ 20 | print "Case 1 (custom filter bank - Haar wavelet)" 21 | 22 | myBank = FilterBank() 23 | # pass the user supplied filter bank as argument 24 | myWavelet = pywt.Wavelet(name="UserSuppliedWavelet", filter_bank=myBank) 25 | #print myWavelet.get_filters_coeffs() 26 | 27 | print "data:", data 28 | a, d = pywt.dwt(data, myWavelet) 29 | print "a:", a 30 | print "d:", d 31 | print "rec:", pywt.idwt(a, d, myWavelet) 32 | 33 | ############################################################################ 34 | print "-" * 75 35 | print "Case 2 (Wavelet object as filter bank - db2 wavelet)" 36 | 37 | # builtin wavelets can also be treated as filter banks with theirs 38 | # filter_bank attribute 39 | 40 | builtinWavelet = pywt.Wavelet('db2') 41 | myWavelet = pywt.Wavelet( 42 | name="UserSuppliedWavelet", 43 | filter_bank=builtinWavelet 44 | ) 45 | 46 | print "data:", data 47 | a, d = pywt.dwt(data, myWavelet) 48 | print "a:", a 49 | print "d:", d 50 | print "rec:", pywt.idwt(a, d, myWavelet) 51 | -------------------------------------------------------------------------------- /demo/wavedec.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import pywt 5 | 6 | data = range(16) 7 | wavelet = 'db4' 8 | level = 2 9 | mode = 'cpd' 10 | 11 | print "original data:" 12 | print data 13 | print 14 | 15 | # dec = [cA(n-1) cD(n-1) cD(n-2) ... cD(2) cD(1)] 16 | dec = pywt.wavedec(data, wavelet, mode, level) 17 | 18 | print "decomposition:" 19 | 20 | print "cA%d:" % (len(dec) - 1) 21 | print ' '.join([("%.3f" % val) for val in dec[0]]) 22 | 23 | for i, d in enumerate(dec[1:]): 24 | print "cD%d:" % (len(dec) - 1 - i) 25 | print ' '.join([("%.3f" % val) for val in d]) 26 | 27 | print 28 | print "reconstruction:" 29 | 30 | print ' '.join([("%.3f" % val) for val in pywt.waverec(dec, wavelet, mode)]) 31 | -------------------------------------------------------------------------------- /demo/waveinfo.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import os 5 | import sys 6 | 7 | import pylab 8 | 9 | import pywt 10 | 11 | usage = """Usage:\n %s wavelet [refinement level]""" % os.path.basename( 12 | sys.argv[0]) 13 | 14 | try: 15 | wavelet = pywt.Wavelet(sys.argv[1]) 16 | try: 17 | level = int(sys.argv[2]) 18 | except IndexError, e: 19 | level = 10 20 | except ValueError, e: 21 | print "Unknown wavelet" 22 | raise SystemExit 23 | except IndexError, e: 24 | print usage 25 | raise SystemExit 26 | 27 | print wavelet 28 | 29 | data = wavelet.wavefun(level) 30 | funcs, x = data[:-1], data[-1] 31 | 32 | n = (len(data) - 1) // 2 33 | labels = [ 34 | "scaling function (phi)", "wavelet function (psi)", 35 | "r. scaling function (phi)", "r. wavelet function (psi)" 36 | ] 37 | colours = ("r", "g", "r", "g") 38 | for i, (d, label, colour) in enumerate(zip(funcs, labels, colours)): 39 | mi, ma = d.min(), d.max() 40 | margin = (ma - mi) * 0.05 41 | ax = pylab.subplot(n, 2, 1 + i) 42 | 43 | pylab.plot(x, d, colour) 44 | pylab.title(label) 45 | pylab.ylim(mi - margin, ma + margin) 46 | pylab.xlim(x[0], x[-1]) 47 | 48 | pylab.show() 49 | -------------------------------------------------------------------------------- /demo/wp_2d.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import Image # PIL 5 | import numpy 6 | import pylab 7 | 8 | from pywt import WaveletPacket2D 9 | 10 | im = Image.open("data/aero.png").convert('L') 11 | arr = numpy.fromstring(im.tostring(), numpy.uint8) 12 | arr.shape = (im.size[1], im.size[0]) 13 | 14 | wp2 = WaveletPacket2D(arr, 'db2', 'sym', maxlevel=2) 15 | 16 | pylab.imshow(arr, interpolation="nearest", cmap=pylab.cm.gray) 17 | 18 | path = ['d', 'v', 'h', 'a'] 19 | 20 | #mod = lambda x: x 21 | #mod = lambda x: abs(x) 22 | mod = lambda x: numpy.sqrt(abs(x)) 23 | 24 | pylab.figure() 25 | for i, p2 in enumerate(path): 26 | pylab.subplot(2, 2, i + 1) 27 | p1p2 = p2 28 | pylab.imshow(mod(wp2[p1p2].data), origin='image', interpolation="nearest", 29 | cmap=pylab.cm.gray) 30 | pylab.title(p1p2) 31 | 32 | for p1 in path: 33 | pylab.figure() 34 | for i, p2 in enumerate(path): 35 | pylab.subplot(2, 2, i + 1) 36 | p1p2 = p1 + p2 37 | pylab.imshow(mod(wp2[p1p2].data), origin='image', 38 | interpolation="nearest", cmap=pylab.cm.gray) 39 | pylab.title(p1p2) 40 | 41 | pylab.figure() 42 | i = 1 43 | for row in wp2.get_level(2, 'freq'): 44 | for node in row: 45 | pylab.subplot(len(row), len(row), i) 46 | pylab.title("%s=(%s row, %s col)" % ( 47 | (node.path,) + wp2.expand_2d_path(node.path))) 48 | pylab.imshow(mod(node.data), origin='image', interpolation="nearest", 49 | cmap=pylab.cm.gray) 50 | i += 1 51 | 52 | pylab.show() 53 | -------------------------------------------------------------------------------- /demo/wp_scalogram.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import matplotlib.cm as cm 5 | import pylab 6 | 7 | import pywt 8 | 9 | x = pylab.arange(0, 1, 1. / 512) 10 | data = pylab.sin((5 * 50 * pylab.pi * x ** 2)) 11 | 12 | wavelet = 'db2' 13 | level = 4 14 | order = "freq" # "normal" 15 | interpolation = 'nearest' 16 | cmap = cm.cool 17 | 18 | wp = pywt.WaveletPacket(data, wavelet, 'sym', maxlevel=level) 19 | nodes = wp.get_level(level, order=order) 20 | labels = [n.path for n in nodes] 21 | values = pylab.array([n.data for n in nodes], 'd') 22 | values = abs(values) 23 | 24 | f = pylab.figure() 25 | f.subplots_adjust(hspace=0.2, bottom=.03, left=.07, right=.97, top=.92) 26 | pylab.subplot(2, 1, 1) 27 | pylab.title("linchirp signal") 28 | pylab.plot(x, data, 'b') 29 | pylab.xlim(0, x[-1]) 30 | 31 | ax = pylab.subplot(2, 1, 2) 32 | pylab.title("Wavelet packet coefficients at level %d" % level) 33 | pylab.imshow(values, interpolation=interpolation, cmap=cmap, aspect="auto", 34 | origin="lower", extent=[0, 1, 0, len(values)]) 35 | pylab.yticks(pylab.arange(0.5, len(labels) + 0.5), labels) 36 | #pylab.setp(ax.get_xticklabels(), visible=False) 37 | 38 | #pylab.figure(2) 39 | #pylab.specgram(data, NFFT=64, noverlap=32, cmap=cmap) 40 | #pylab.imshow(values, origin='upper', extent=[-1,1,-1,1], 41 | # interpolation='nearest') 42 | 43 | pylab.show() 44 | -------------------------------------------------------------------------------- /demo/wp_tree.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | from pywt import WaveletPacket 5 | 6 | wp = WaveletPacket(range(16), 'db2', maxlevel=3) 7 | print [node.path for node in wp.get_leaf_nodes(decompose=False)] 8 | print [node.path for node in wp.get_leaf_nodes(decompose=True)] 9 | coeffs = [(node.path, node.data) for node in wp.get_leaf_nodes(decompose=True)] 10 | print coeffs 11 | 12 | wp2 = WaveletPacket(None, 'db2', maxlevel=3) 13 | for path, data in coeffs: 14 | wp2[path] = data 15 | #print wp["a"] 16 | print [node.path for node in wp2.get_leaf_nodes(decompose=False)] 17 | print wp2.reconstruct() 18 | -------------------------------------------------------------------------------- /demo/wp_visualize_coeffs_distribution.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import numpy 5 | import pylab 6 | 7 | from pywt import WaveletPacket 8 | 9 | x = numpy.arange(612 - 80, 20, -0.5) / 150. 10 | data = numpy.sin(20 * pylab.log(x)) * numpy.sign((pylab.log(x))) 11 | from sample_data import ecg as data 12 | 13 | wp = WaveletPacket(data, 'sym5', maxlevel=4) 14 | 15 | pylab.bone() 16 | pylab.subplot(wp.maxlevel + 1, 1, 1) 17 | pylab.plot(data, 'k') 18 | pylab.xlim(0, len(data) - 1) 19 | pylab.title("Wavelet packet coefficients") 20 | 21 | for i in range(1, wp.maxlevel + 1): 22 | ax = pylab.subplot(wp.maxlevel + 1, 1, i + 1) 23 | nodes = wp.get_level(i, "freq") 24 | nodes.reverse() 25 | labels = [n.path for n in nodes] 26 | values = -abs(numpy.array([n.data for n in nodes])) 27 | pylab.imshow(values, interpolation='nearest', aspect='auto') 28 | pylab.yticks(numpy.arange(len(labels) - 0.5, -0.5, -1), labels) 29 | pylab.setp(ax.get_xticklabels(), visible=False) 30 | 31 | pylab.show() 32 | -------------------------------------------------------------------------------- /doc/Makefile: -------------------------------------------------------------------------------- 1 | # Makefile for Sphinx documentation 2 | # 3 | 4 | # You can set these variables from the command line. 5 | SPHINXOPTS = 6 | SPHINXBUILD = sphinx-build 7 | PAPER = 8 | BUILDDIR = build 9 | 10 | # Internal variables. 11 | PAPEROPT_a4 = -D latex_paper_size=a4 12 | PAPEROPT_letter = -D latex_paper_size=letter 13 | ALLSPHINXOPTS = -d $(BUILDDIR)/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) source 14 | 15 | .PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest 16 | 17 | help: 18 | @echo "Please use \`make ' where is one of" 19 | @echo " html to make standalone HTML files" 20 | @echo " dirhtml to make HTML files named index.html in directories" 21 | @echo " pickle to make pickle files" 22 | @echo " json to make JSON files" 23 | @echo " htmlhelp to make HTML files and a HTML help project" 24 | @echo " qthelp to make HTML files and a qthelp project" 25 | @echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter" 26 | @echo " changes to make an overview of all changed/added/deprecated items" 27 | @echo " linkcheck to check all external links for integrity" 28 | @echo " doctest to run all doctests embedded in the documentation (if enabled)" 29 | 30 | clean: 31 | -rm -rf $(BUILDDIR)/* 32 | 33 | html: 34 | $(SPHINXBUILD) -b html $(ALLSPHINXOPTS) $(BUILDDIR)/html 35 | @echo 36 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/html." 37 | 38 | dirhtml: 39 | $(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) $(BUILDDIR)/dirhtml 40 | @echo 41 | @echo "Build finished. The HTML pages are in $(BUILDDIR)/dirhtml." 42 | 43 | pickle: 44 | $(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) $(BUILDDIR)/pickle 45 | @echo 46 | @echo "Build finished; now you can process the pickle files." 47 | 48 | json: 49 | $(SPHINXBUILD) -b json $(ALLSPHINXOPTS) $(BUILDDIR)/json 50 | @echo 51 | @echo "Build finished; now you can process the JSON files." 52 | 53 | htmlhelp: 54 | $(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) $(BUILDDIR)/htmlhelp 55 | @echo 56 | @echo "Build finished; now you can run HTML Help Workshop with the" \ 57 | ".hhp project file in $(BUILDDIR)/htmlhelp." 58 | 59 | qthelp: 60 | $(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) $(BUILDDIR)/qthelp 61 | @echo 62 | @echo "Build finished; now you can run "qcollectiongenerator" with the" \ 63 | ".qhcp project file in $(BUILDDIR)/qthelp, like this:" 64 | @echo "# qcollectiongenerator $(BUILDDIR)/qthelp/PyWavelets.qhcp" 65 | @echo "To view the help file:" 66 | @echo "# assistant -collectionFile $(BUILDDIR)/qthelp/PyWavelets.qhc" 67 | 68 | latex: 69 | $(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) $(BUILDDIR)/latex 70 | @echo 71 | @echo "Build finished; the LaTeX files are in $(BUILDDIR)/latex." 72 | @echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \ 73 | "run these through (pdf)latex." 74 | 75 | changes: 76 | $(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) $(BUILDDIR)/changes 77 | @echo 78 | @echo "The overview file is in $(BUILDDIR)/changes." 79 | 80 | linkcheck: 81 | $(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) $(BUILDDIR)/linkcheck 82 | @echo 83 | @echo "Link check complete; look for any errors in the above output " \ 84 | "or in $(BUILDDIR)/linkcheck/output.txt." 85 | 86 | doctest: 87 | $(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) $(BUILDDIR)/doctest 88 | @echo "Testing of doctests in the sources finished, look at the " \ 89 | "results in $(BUILDDIR)/doctest/output.txt." 90 | -------------------------------------------------------------------------------- /doc/doc2html.bat: -------------------------------------------------------------------------------- 1 | sphinx-build -b html -a -E source build\html 2 | -------------------------------------------------------------------------------- /doc/make.bat: -------------------------------------------------------------------------------- 1 | @ECHO OFF 2 | 3 | REM Command file for Sphinx documentation 4 | 5 | set SPHINXBUILD=sphinx-build 6 | set BUILDDIR=build 7 | set ALLSPHINXOPTS=-d %BUILDDIR%/doctrees %SPHINXOPTS% source 8 | if NOT "%PAPER%" == "" ( 9 | set ALLSPHINXOPTS=-D latex_paper_size=%PAPER% %ALLSPHINXOPTS% 10 | ) 11 | 12 | if "%1" == "" goto help 13 | 14 | if "%1" == "help" ( 15 | :help 16 | echo.Please use `make ^` where ^ is one of 17 | echo. html to make standalone HTML files 18 | echo. dirhtml to make HTML files named index.html in directories 19 | echo. pickle to make pickle files 20 | echo. json to make JSON files 21 | echo. htmlhelp to make HTML files and a HTML help project 22 | echo. qthelp to make HTML files and a qthelp project 23 | echo. latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter 24 | echo. changes to make an overview over all changed/added/deprecated items 25 | echo. linkcheck to check all external links for integrity 26 | echo. doctest to run all doctests embedded in the documentation if enabled 27 | goto end 28 | ) 29 | 30 | if "%1" == "clean" ( 31 | for /d %%i in (%BUILDDIR%\*) do rmdir /q /s %%i 32 | del /q /s %BUILDDIR%\* 33 | goto end 34 | ) 35 | 36 | if "%1" == "html" ( 37 | %SPHINXBUILD% -b html %ALLSPHINXOPTS% %BUILDDIR%/html 38 | echo. 39 | echo.Build finished. The HTML pages are in %BUILDDIR%/html. 40 | goto end 41 | ) 42 | 43 | if "%1" == "dirhtml" ( 44 | %SPHINXBUILD% -b dirhtml %ALLSPHINXOPTS% %BUILDDIR%/dirhtml 45 | echo. 46 | echo.Build finished. The HTML pages are in %BUILDDIR%/dirhtml. 47 | goto end 48 | ) 49 | 50 | if "%1" == "pickle" ( 51 | %SPHINXBUILD% -b pickle %ALLSPHINXOPTS% %BUILDDIR%/pickle 52 | echo. 53 | echo.Build finished; now you can process the pickle files. 54 | goto end 55 | ) 56 | 57 | if "%1" == "json" ( 58 | %SPHINXBUILD% -b json %ALLSPHINXOPTS% %BUILDDIR%/json 59 | echo. 60 | echo.Build finished; now you can process the JSON files. 61 | goto end 62 | ) 63 | 64 | if "%1" == "htmlhelp" ( 65 | %SPHINXBUILD% -b htmlhelp %ALLSPHINXOPTS% %BUILDDIR%/htmlhelp 66 | echo. 67 | echo.Build finished; now you can run HTML Help Workshop with the ^ 68 | .hhp project file in %BUILDDIR%/htmlhelp. 69 | goto end 70 | ) 71 | 72 | if "%1" == "qthelp" ( 73 | %SPHINXBUILD% -b qthelp %ALLSPHINXOPTS% %BUILDDIR%/qthelp 74 | echo. 75 | echo.Build finished; now you can run "qcollectiongenerator" with the ^ 76 | .qhcp project file in %BUILDDIR%/qthelp, like this: 77 | echo.^> qcollectiongenerator %BUILDDIR%\qthelp\PyWavelets.qhcp 78 | echo.To view the help file: 79 | echo.^> assistant -collectionFile %BUILDDIR%\qthelp\PyWavelets.ghc 80 | goto end 81 | ) 82 | 83 | if "%1" == "latex" ( 84 | %SPHINXBUILD% -b latex %ALLSPHINXOPTS% %BUILDDIR%/latex 85 | echo. 86 | echo.Build finished; the LaTeX files are in %BUILDDIR%/latex. 87 | goto end 88 | ) 89 | 90 | if "%1" == "changes" ( 91 | %SPHINXBUILD% -b changes %ALLSPHINXOPTS% %BUILDDIR%/changes 92 | echo. 93 | echo.The overview file is in %BUILDDIR%/changes. 94 | goto end 95 | ) 96 | 97 | if "%1" == "linkcheck" ( 98 | %SPHINXBUILD% -b linkcheck %ALLSPHINXOPTS% %BUILDDIR%/linkcheck 99 | echo. 100 | echo.Link check complete; look for any errors in the above output ^ 101 | or in %BUILDDIR%/linkcheck/output.txt. 102 | goto end 103 | ) 104 | 105 | if "%1" == "doctest" ( 106 | %SPHINXBUILD% -b doctest %ALLSPHINXOPTS% %BUILDDIR%/doctest 107 | echo. 108 | echo.Testing of doctests in the sources finished, look at the ^ 109 | results in %BUILDDIR%/doctest/output.txt. 110 | goto end 111 | ) 112 | 113 | :end 114 | -------------------------------------------------------------------------------- /doc/source/COPYING.txt: -------------------------------------------------------------------------------- 1 | Copyright (c) 2006-2012 Filip Wasilewski 2 | 3 | Permission is hereby granted, free of charge, to any person obtaining a copy of 4 | this software and associated documentation files (the "Software"), to deal in 5 | the Software without restriction, including without limitation the rights to 6 | use, copy, modify, merge, publish, distribute, sublicense, and/or sell copies 7 | of the Software, and to permit persons to whom the Software is furnished to do 8 | so, subject to the following conditions: 9 | 10 | The above copyright notice and this permission notice shall be included in all 11 | copies or substantial portions of the Software. 12 | 13 | THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR 14 | IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, 15 | FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE 16 | AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER 17 | LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, 18 | OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE 19 | SOFTWARE. 20 | -------------------------------------------------------------------------------- /doc/source/_static/comments.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nigma/pywt/035e1fa14c2cd70ca270da20b1523e834a7ae635/doc/source/_static/comments.png -------------------------------------------------------------------------------- /doc/source/_static/favicon.ico: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nigma/pywt/035e1fa14c2cd70ca270da20b1523e834a7ae635/doc/source/_static/favicon.ico -------------------------------------------------------------------------------- /doc/source/_static/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nigma/pywt/035e1fa14c2cd70ca270da20b1523e834a7ae635/doc/source/_static/github.png -------------------------------------------------------------------------------- /doc/source/_static/page_edit.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nigma/pywt/035e1fa14c2cd70ca270da20b1523e834a7ae635/doc/source/_static/page_edit.png -------------------------------------------------------------------------------- /doc/source/_static/twitter.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nigma/pywt/035e1fa14c2cd70ca270da20b1523e834a7ae635/doc/source/_static/twitter.png -------------------------------------------------------------------------------- /doc/source/_static/wave.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nigma/pywt/035e1fa14c2cd70ca270da20b1523e834a7ae635/doc/source/_static/wave.png -------------------------------------------------------------------------------- /doc/source/_templates/editdocument.html: -------------------------------------------------------------------------------- 1 | {% set repo="nigma/pywt" %} 2 | {% set branch="develop" %} 3 | 4 |
5 |

Edit this document

6 |

7 | 8 | 9 | The source code of this file is hosted on GitHub. Everyone can 10 | update and fix errors in this document with few clicks - 11 | no downloads needed. 12 | 13 |

14 | 42 |
-------------------------------------------------------------------------------- /doc/source/_templates/page.html: -------------------------------------------------------------------------------- 1 | {# Drop version number from the HTML documentation title #} 2 | {%- set docstitle = "PyWavelets Documentation" %} 3 | 4 | {% extends "!page.html" %} 5 | 6 | {% block extrahead %} 7 | {{ super() }} 8 | 9 | 10 | 11 | 12 | 13 | 14 | 24 | 37 | {% endblock %} 38 | 39 | {# Remove version number from the top and bottom path bars #} 40 | {%- block rootrellink %} 41 |
  • Home{{ reldelim1 }}
  • 42 | {%- endblock %} 43 | -------------------------------------------------------------------------------- /doc/source/_templates/quicklinks.html: -------------------------------------------------------------------------------- 1 | -------------------------------------------------------------------------------- /doc/source/conf.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # 3 | # PyWavelets documentation build configuration file, created by 4 | # sphinx-quickstart on Sun Mar 14 10:46:18 2010. 5 | # 6 | # This file is execfile()d with the current directory set to its containing dir. 7 | # 8 | # Note that not all possible configuration values are present in this 9 | # autogenerated file. 10 | # 11 | # All configuration values have a default; values that are commented out 12 | # serve to show the default. 13 | 14 | import sys, os 15 | import datetime 16 | import jinja2.filters 17 | 18 | # If extensions (or modules to document with autodoc) are in another directory, 19 | # add these directories to sys.path here. If the directory is relative to the 20 | # documentation root, use os.path.abspath to make it absolute, like shown here. 21 | #sys.path.append(os.path.abspath('.')) 22 | 23 | # -- General configuration ----------------------------------------------------- 24 | 25 | # Add any Sphinx extension module names here, as strings. They can be extensions 26 | # coming with Sphinx (named 'sphinx.ext.*') or your custom ones. 27 | extensions = ['sphinx.ext.doctest', 'sphinx.ext.autodoc', 'sphinx.ext.todo', 'sphinx.ext.extlinks'] 28 | 29 | # Add any paths that contain templates here, relative to this directory. 30 | templates_path = ['_templates'] 31 | 32 | # The suffix of source filenames. 33 | source_suffix = '.rst' 34 | 35 | # The encoding of source files. 36 | #source_encoding = 'utf-8' 37 | 38 | # The master toctree document. 39 | master_doc = 'index' 40 | 41 | # General information about the project. 42 | project = 'PyWavelets' 43 | copyright = jinja2.filters.do_mark_safe('2006-%s, Filip Wasilewski' % datetime.date.today().year) 44 | 45 | # The version info for the project you're documenting, acts as replacement for 46 | # |version| and |release|, also used in various other places throughout the 47 | # built documents. 48 | # 49 | # The short X.Y version. 50 | version = '0.2.2' 51 | # The full version, including alpha/beta/rc tags. 52 | release = '0.2.2' 53 | 54 | # The language for content autogenerated by Sphinx. Refer to documentation 55 | # for a list of supported languages. 56 | #language = None 57 | 58 | # There are two options for replacing |today|: either, you set today to some 59 | # non-false value, then it is used: 60 | #today = '' 61 | # Else, today_fmt is used as the format for a strftime call. 62 | #today_fmt = '%B %d, %Y' 63 | 64 | # List of documents that shouldn't be included in the build. 65 | unused_docs = ['substitutions', 'overview'] 66 | 67 | # List of directories, relative to source directory, that shouldn't be searched 68 | # for source files. 69 | exclude_trees = ['_build'] 70 | 71 | # The reST default role (used for this markup: `text`) to use for all documents. 72 | #default_role = None 73 | 74 | # If true, '()' will be appended to :func: etc. cross-reference text. 75 | #add_function_parentheses = True 76 | 77 | # If true, the current module name will be prepended to all description 78 | # unit titles (such as .. function::). 79 | #add_module_names = True 80 | 81 | # If true, sectionauthor and moduleauthor directives will be shown in the 82 | # output. They are ignored by default. 83 | #show_authors = False 84 | 85 | # The name of the Pygments (syntax highlighting) style to use. 86 | pygments_style = 'sphinx' 87 | 88 | # A list of ignored prefixes for module index sorting. 89 | modindex_common_prefix = ['pywt.'] 90 | 91 | 92 | # -- Options for HTML output --------------------------------------------------- 93 | 94 | # The theme to use for HTML and HTML Help pages. Major themes that come with 95 | # Sphinx are currently 'default' and 'sphinxdoc'. 96 | html_theme = 'nature' 97 | 98 | # Theme options are theme-specific and customize the look and feel of a theme 99 | # further. For a list of options available for each theme, see the 100 | # documentation. 101 | #html_theme_options = {} 102 | 103 | # Add any paths that contain custom themes here, relative to this directory. 104 | #html_theme_path = [] 105 | 106 | # The name for this set of Sphinx documents. If None, it defaults to 107 | # " v documentation". 108 | html_title = 'PyWavelets Documentation' 109 | 110 | # A shorter title for the navigation bar. Default is the same as html_title. 111 | #html_short_title = None 112 | 113 | # The name of an image file (relative to this directory) to place at the top 114 | # of the sidebar. 115 | #html_logo = None 116 | 117 | # The name of an image file (within the static path) to use as favicon of the 118 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 119 | # pixels large. 120 | html_favicon = 'favicon.ico' 121 | 122 | # Add any paths that contain custom static files (such as style sheets) here, 123 | # relative to this directory. They are copied after the builtin static files, 124 | # so a file named "default.css" will overwrite the builtin "default.css". 125 | html_static_path = ['_static'] 126 | 127 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 128 | # using the given strftime format. 129 | html_last_updated_fmt = '%b %d, %Y' 130 | 131 | # If true, SmartyPants will be used to convert quotes and dashes to 132 | # typographically correct entities. 133 | #html_use_smartypants = True 134 | 135 | # Custom sidebar templates, maps document names to template names. 136 | #html_sidebars = {} 137 | html_sidebars = { 138 | '**': ['localtoc.html', "relations.html", 'quicklinks.html', 'searchbox.html', 'editdocument.html'], 139 | } 140 | 141 | # Additional templates that should be rendered to pages, maps page names to 142 | # template names. 143 | #html_additional_pages = {} 144 | 145 | # If false, no module index is generated. 146 | #html_use_modindex = True 147 | 148 | # If false, no index is generated. 149 | #html_use_index = True 150 | 151 | # If true, the index is split into individual pages for each letter. 152 | #html_split_index = False 153 | 154 | # If true, links to the reST sources are added to the pages. 155 | html_show_sourcelink = False 156 | 157 | # If true, an OpenSearch description file will be output, and all pages will 158 | # contain a tag referring to it. The value of this option must be the 159 | # base URL from which the finished HTML is served. 160 | html_use_opensearch = 'http://pybytes.com/pywavelets' 161 | 162 | # If nonempty, this is the file name suffix for HTML files (e.g. ".xhtml"). 163 | #html_file_suffix = '' 164 | 165 | # Output file base name for HTML help builder. 166 | htmlhelp_basename = 'PyWaveletsdoc' 167 | 168 | 169 | # -- Options for LaTeX output -------------------------------------------------- 170 | 171 | # The paper size ('letter' or 'a4'). 172 | #latex_paper_size = 'letter' 173 | 174 | # The font size ('10pt', '11pt' or '12pt'). 175 | #latex_font_size = '10pt' 176 | 177 | # Grouping the document tree into LaTeX files. List of tuples 178 | # (source start file, target name, title, author, documentclass [howto/manual]). 179 | latex_documents = [ 180 | ('index', 'PyWavelets.tex', 'PyWavelets Documentation', 181 | 'Filip Wasilewski', 'manual'), 182 | ] 183 | 184 | # The name of an image file (relative to this directory) to place at the top of 185 | # the title page. 186 | #latex_logo = None 187 | 188 | # For "manual" documents, if this is true, then toplevel headings are parts, 189 | # not chapters. 190 | #latex_use_parts = False 191 | 192 | # Additional stuff for the LaTeX preamble. 193 | #latex_preamble = '' 194 | 195 | # Documents to append as an appendix to all manuals. 196 | #latex_appendices = [] 197 | 198 | # If false, no module index is generated. 199 | #latex_use_modindex = True 200 | -------------------------------------------------------------------------------- /doc/source/contents.rst: -------------------------------------------------------------------------------- 1 | .. _contents: 2 | 3 | PyWavelets 4 | ========== 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | ref/index 10 | regression/index 11 | dev/index 12 | resources 13 | 14 | Indices and tables 15 | ================== 16 | 17 | * :ref:`genindex` 18 | * :ref:`search` 19 | -------------------------------------------------------------------------------- /doc/source/dev/building_extension.rst: -------------------------------------------------------------------------------- 1 | .. _dev-building-extension: 2 | 3 | Building and installing PyWavelets 4 | ================================== 5 | 6 | Installing from source code 7 | --------------------------- 8 | 9 | Go to https://github.com/nigma/pywt GitHub project page, fork and clone the 10 | repository or use the upstream repository to get the source code:: 11 | 12 | git clone https://github.com/nigma/pywt.git PyWavelets 13 | 14 | Activate your Python virtual environment, go to the cloned source directory 15 | and type the following commands to build and install the package:: 16 | 17 | python setup.py build 18 | python setup.py install 19 | 20 | To verify the installation run the following command:: 21 | 22 | python setup.py test 23 | 24 | To build docs:: 25 | 26 | cd doc 27 | make html 28 | 29 | Installing a development version 30 | -------------------------------- 31 | 32 | You can also install directly from the source repository:: 33 | 34 | pip install -e git+https://github.com/nigma/pywt.git#egg=PyWavelets 35 | 36 | or:: 37 | 38 | pip install PyWavelets==dev 39 | 40 | 41 | Installing a regular release from PyPi 42 | -------------------------------------- 43 | 44 | A regular release can be installed with pip or easy_install:: 45 | 46 | pip install PyWavelets 47 | 48 | -------------------------------------------------------------------------------- /doc/source/dev/index.rst: -------------------------------------------------------------------------------- 1 | .. _dev-index: 2 | 3 | 4 | Development notes 5 | ================= 6 | 7 | This section contains information on building and installing PyWavelets 8 | from source code as well as instructions for preparing the build environment 9 | on Windows and Linux. 10 | 11 | .. toctree:: 12 | :maxdepth: 2 13 | 14 | preparing_windows_build_environment 15 | preparing_linux_build_environment 16 | installing_build_dependencies 17 | building_extension 18 | testing 19 | 20 | Something not working? 21 | ---------------------- 22 | 23 | If these instructions are not clear or you need help setting up your 24 | development environment, go ahead and ask on the PyWavelets discussion 25 | group at http://groups.google.com/group/pywavelets or open a ticket on GitHub_. 26 | 27 | .. _GitHub: https://github.com/nigma/pywt 28 | -------------------------------------------------------------------------------- /doc/source/dev/installing_build_dependencies.rst: -------------------------------------------------------------------------------- 1 | .. _dev-installing-build-dependencies: 2 | 3 | Installing build dependencies 4 | ============================= 5 | 6 | Setting up Python virtual environment 7 | ------------------------------------- 8 | 9 | A good practice is to create a separate Python virtual environment for each 10 | project. If you don't have `virtualenv`_ yet, install and activate it using:: 11 | 12 | curl -O https://raw.github.com/pypa/virtualenv/master/virtualenv.py 13 | python virtualenv.py 14 | . /bin/activate 15 | 16 | 17 | Installing Cython 18 | ----------------- 19 | 20 | Use ``pip`` (http://pypi.python.org/pypi/pip) to install Cython_:: 21 | 22 | 23 | pip install Cython>=0.16 24 | 25 | 26 | Installing numpy 27 | ---------------- 28 | 29 | Use ``pip`` to install numpy_:: 30 | 31 | pip install numpy 32 | 33 | It takes some time to compile numpy, so it might be more convenient to install 34 | it from a binary release. 35 | 36 | .. note:: 37 | 38 | Installing numpy in a virtual environment on Windows is not straightforward. 39 | 40 | It is recommended to download a suitable binary ``.exe`` release from 41 | http://www.scipy.org/Download/ and install it using ``easy_install`` 42 | (i.e. ``easy_install numpy-1.6.2-win32-superpack-python2.7.exe``). 43 | 44 | .. note:: 45 | 46 | You can find binaries for 64-bit Windows on http://www.lfd.uci.edu/~gohlke/pythonlibs/. 47 | 48 | 49 | Installing Sphinx 50 | ----------------- 51 | 52 | Sphinx_ is a documentation tool that converts reStructuredText files into 53 | nicely looking html documentation. Install it with:: 54 | 55 | pip install Sphinx 56 | 57 | 58 | .. _virtualenv: http://pypi.python.org/pypi/virtualenv 59 | .. _numpy: http://numpy.scipy.org/ 60 | .. _Cython: http://cython.org/ 61 | .. _Sphinx: http://sphinx.pocoo.org 62 | -------------------------------------------------------------------------------- /doc/source/dev/preparing_linux_build_environment.rst: -------------------------------------------------------------------------------- 1 | .. _dev-preparing-linux-build-environment: 2 | 3 | 4 | Preparing Linux build environment 5 | ================================= 6 | 7 | There is a good chance that you already have a working build environment. 8 | Just skip steps that you don't need to execute. 9 | 10 | 11 | Installing basic build tools 12 | ---------------------------- 13 | 14 | Note that the example below uses ``aptitude`` package manager, which is 15 | specific to Debian and Ubuntu Linux distributions. Use your favourite package 16 | manager to install these packages on your OS. 17 | 18 | :: 19 | 20 | aptitude install build-essential gcc python-dev git-core 21 | 22 | 23 | Next steps 24 | ---------- 25 | 26 | After completing these steps continue with 27 | :ref:`Installing build dependencies `. 28 | -------------------------------------------------------------------------------- /doc/source/dev/preparing_windows_build_environment.rst: -------------------------------------------------------------------------------- 1 | .. _dev-building-on-windows: 2 | 3 | 4 | Preparing Windows build environment 5 | =================================== 6 | 7 | To start developing PyWavelets code on Windows you will have to install 8 | a C compiler and prepare the build environment. 9 | 10 | Installing Windows SDK C/C++ compiler 11 | ------------------------------------- 12 | 13 | Microsoft Visual C++ 2008 (Microsoft Visual Studio 9.0) is the compiler that 14 | is suitable for building extensions for Python 2.6, 2.7, 3.0, 3.1 and 3.2 15 | (both 32 and 64 bit). 16 | 17 | .. note:: For reference: 18 | 19 | - the *MSC v.1500* in the Python version string is Microsoft Visual 20 | C++ 2008 (Microsoft Visual Studio 9.0 with msvcr90.dll runtime) 21 | - *MSC v.1600* is MSVC 2010 (10.0 with msvcr100.dll runtime) 22 | - *MSC v.1700* is MSVC 2011 (11.0) 23 | 24 | :: 25 | 26 | Python 2.7.3 (default, Apr 10 2012, 23:31:26) [MSC v.1500 32 bit (Intel)] on win32 27 | Python 3.2 (r32:88445, Feb 20 2011, 21:30:00) [MSC v.1500 64 bit (AMD64)] on win32 28 | 29 | 30 | To get started first download, extract and install *Microsoft Windows SDK for 31 | Windows 7 and .NET Framework 3.5 SP1* from 32 | http://www.microsoft.com/downloads/en/details.aspx?familyid=71DEB800-C591-4F97-A900-BEA146E4FAE1&displaylang=en. 33 | 34 | There are several ISO images on the site, so just grab the one that is suitable 35 | for your platform: 36 | 37 | - ``GRMSDK_EN_DVD.iso`` for 32-bit x86 platform 38 | - ``GRMSDKX_EN_DVD.iso`` for 64-bit AMD64 platform (AMD64 is the codename for 39 | 64-bit CPU architecture, not the processor manufacturer) 40 | 41 | After installing the SDK and before compiling the extension you have 42 | to configure some environment variables. 43 | 44 | For 32-bit build execute the ``util/setenv_build32.bat`` script in the cmd 45 | window: 46 | 47 | .. sourcecode:: bat 48 | 49 | rem Configure the environment for 32-bit builds. 50 | rem Use "vcvars32.bat" for a 32-bit build. 51 | "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars32.bat" 52 | rem Convince setup.py to use the SDK tools. 53 | set MSSdk=1 54 | setenv /x86 /release 55 | set DISTUTILS_USE_SDK=1 56 | 57 | For 64-bit use ``util/setenv_build64.bat``: 58 | 59 | .. sourcecode:: bat 60 | 61 | rem Configure the environment for 64-bit builds. 62 | rem Use "vcvars32.bat" for a 32-bit build. 63 | "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat" 64 | rem Convince setup.py to use the SDK tools. 65 | set MSSdk=1 66 | setenv /x64 /release 67 | set DISTUTILS_USE_SDK=1 68 | 69 | See also http://wiki.cython.org/64BitCythonExtensionsOnWindows. 70 | 71 | MinGW C/C++ compiler 72 | -------------------- 73 | 74 | MinGW distribution can be downloaded from 75 | http://sourceforge.net/projects/mingwbuilds/. 76 | 77 | In order to change the settings and use MinGW as the default compiler, 78 | edit or create a Distutils configuration file 79 | ``c:\Python2*\Lib\distutils\distutils.cfg`` and place the following 80 | entry in it:: 81 | 82 | [build] 83 | compiler = mingw32 84 | 85 | You can also take a look at Cython's "Installing MinGW on Windows" 86 | page at http://wiki.cython.org/InstallingOnWindows for more info. 87 | 88 | 89 | .. note:: 90 | 91 | Python 2.7/3.2 distutils package is incompatible with the current version 92 | (4.7+) of MinGW (MinGW dropped the ``-mno-cygwin`` flag, which is still 93 | passed by distutils). 94 | 95 | To use MinGW to compile Python extensions you have to patch the 96 | ``distutils/cygwinccompiler.py`` library module and remove every occurrence 97 | of ``-mno-cygwin``. 98 | 99 | See http://bugs.python.org/issue12641 bug report for more information 100 | on the issue. 101 | 102 | 103 | Next steps 104 | ---------- 105 | 106 | After completing these steps continue with 107 | :ref:`Installing build dependencies `. 108 | 109 | 110 | .. _Python: http://python.org/ 111 | .. _numpy: http://numpy.scipy.org/ 112 | .. _Cython: http://cython.org/ 113 | .. _Sphinx: http://sphinx.pocoo.org/ 114 | .. _MinGW C compiler: http://sourceforge.net/projects/mingwbuilds/ 115 | -------------------------------------------------------------------------------- /doc/source/dev/testing.rst: -------------------------------------------------------------------------------- 1 | .. _dev-testing: 2 | 3 | Testing 4 | ======= 5 | 6 | Continous integration with Travis-CI 7 | ------------------------------------ 8 | 9 | The project is using `Travis-CI `_ service 10 | for continous integration and testing. 11 | 12 | Current build status is: 13 | 14 | .. image:: 15 | https://secure.travis-ci.org/nigma/pywt.png?branch=develop 16 | :alt: Build Status 17 | :target: https://secure.travis-ci.org/nigma/pywt 18 | 19 | 20 | If you are submitting a patch or pull request please make sure it 21 | does not break the build. 22 | 23 | 24 | Running tests locally 25 | --------------------- 26 | 27 | Simply:: 28 | 29 | python setup.py test 30 | 31 | 32 | Running tests with Tox 33 | ---------------------- 34 | 35 | There's also a config file for running tests with Tox (``pip install tox``):: 36 | 37 | tox 38 | 39 | It is not however very convenient at the moment because Tox recreates 40 | the test environment (which is a good thing) and builds numpy from 41 | source on every run (which takes a lot of time). 42 | -------------------------------------------------------------------------------- /doc/source/index.rst: -------------------------------------------------------------------------------- 1 | PyWavelets - Discrete Wavelet Transform in Python 2 | ================================================= 3 | 4 | PyWavelets is a free Open Source wavelet transform software for Python_ 5 | programming language. It is written in Python, Cython and C for a mix of easy 6 | and powerful high-level interface and the best performance. 7 | 8 | PyWavelets is very easy to start with and use. Just install the package, open 9 | the Python interactive shell and type: 10 | 11 | .. sourcecode:: python 12 | 13 | >>> import pywt 14 | >>> cA, cD = pywt.dwt([1, 2, 3, 4], 'db1') 15 | 16 | Voilà! Computing wavelet transforms never before has been so simple :) 17 | 18 | Main features 19 | ------------- 20 | 21 | The main features of PyWavelets are: 22 | 23 | * 1D and 2D Forward and Inverse Discrete Wavelet Transform (DWT and IDWT) 24 | * 1D and 2D Stationary Wavelet Transform (Undecimated Wavelet Transform) 25 | * 1D and 2D Wavelet Packet decomposition and reconstruction 26 | * Approximating wavelet and scaling functions 27 | * Over seventy `built-in wavelet filters`_ 28 | and custom wavelets supported 29 | * Single and double precision calculations 30 | * Results compatibility with Matlab Wavelet Toolbox |tm| 31 | 32 | Requirements 33 | ------------ 34 | 35 | PyWavelets is a package for the Python programming language. It requires: 36 | 37 | - Python_ 2.6 or 2.7 38 | - numpy_ numeric array module 39 | 40 | Download 41 | -------- 42 | 43 | The most recent *development* version can be found on GitHub at 44 | https://github.com/nigma/pywt. 45 | 46 | Latest release, including source and binary package for Windows, is available 47 | for download from the `Python Package Index`_. 48 | 49 | Install 50 | ------- 51 | 52 | In order to build PyWavelets from source, a working C compiler (GCC or MSVC) 53 | and a recent version of Cython_ is required. 54 | 55 | - To install PyWavelets open shell prompt and type ``pip install PyWavelets`` 56 | or ``easy_install PyWavelets``. 57 | 58 | - To build and install from source, navigate to downloaded PyWavelets source 59 | code directory and type ``python setup.py install``. 60 | 61 | - The `in-development version`_ of PyWavelets can be installed with 62 | ``pip install PyWavelets==dev`` or ``easy_install PyWavelets==dev``. 63 | 64 | Prebuilt Windows binaries and source code packages are also 65 | available from `Python Package Index`_. 66 | 67 | Binary packages for several Linux distributors are maintained by Open Source 68 | community contributors. Query your Linux package manager tool 69 | for `python-wavelets`, `python-pywt` or similar package name. 70 | 71 | .. seealso:: :ref:`Development notes ` section contains more 72 | information on building and installing from source code. 73 | 74 | Documentation 75 | ------------- 76 | 77 | Documentation with detailed examples and links to more resources is available 78 | online at http://www.pybytes.com/pywavelets/ and 79 | http://pywavelets.readthedocs.org. 80 | 81 | For more usage examples see the `demo`_ directory in the source package. 82 | 83 | Contributing 84 | ------------ 85 | 86 | PyWavelets started in 2006 as an academic project for a master thesis 87 | on `Analysis and Classification of Medical Signals using Wavelet Transforms` 88 | and is maintained by its `original developer`_. 89 | 90 | All contributions including bug reports, bug fixes, new feature implementations 91 | and documentation improvements are welcome. 92 | 93 | Go and fork on `GitHub`_ today! 94 | 95 | Python 3 96 | -------- 97 | 98 | Python 3 development branch is at https://github.com/nigma/pywt/tree/py-3. 99 | Check out the `changelog `_ for 100 | info. Currently the code and examples are ported to work on Python 2.7 and 3.2 101 | from the same codebase. 102 | 103 | Contact 104 | ------- 105 | 106 | Use `GitHub Issues`_ or `PyWavelets discussions group`_ to post your 107 | comments or questions. 108 | 109 | License 110 | ------- 111 | 112 | PyWavelets is a free Open Source software released under the MIT license. 113 | 114 | Commercial Support 115 | ------------------ 116 | 117 | For information on commercial support and development email me at en@ig.ma. 118 | 119 | 120 | .. |tm| unicode:: U+2122 .. trademark sign 121 | :ltrim: 122 | 123 | 124 | Contents 125 | -------- 126 | 127 | .. toctree:: 128 | :maxdepth: 1 129 | 130 | ref/index 131 | regression/index 132 | dev/index 133 | resources 134 | contents 135 | 136 | 137 | .. _built-in wavelet filters: http://wavelets.pybytes.com/ 138 | .. _Cython: http://cython.org/ 139 | .. _demo: https://github.com/nigma/pywt/tree/master/demo 140 | .. _GitHub: https://github.com/nigma/pywt 141 | .. _GitHub Issues: https://github.com/nigma/pywt/issues 142 | .. _in-development version: https://github.com/nigma/pywt/tarball/develop#egg=PyWavelets-dev 143 | .. _numpy: http://numpy.scipy.org/ 144 | .. _original developer: http://en.ig.ma 145 | .. _Python: http://python.org/ 146 | .. _Python Package Index: http://pypi.python.org/pypi/PyWavelets/ 147 | .. _PyWavelets discussions group: http://groups.google.com/group/pywavelets 148 | -------------------------------------------------------------------------------- /doc/source/overview.rst: -------------------------------------------------------------------------------- 1 | Moved to :ref:`index `. -------------------------------------------------------------------------------- /doc/source/ref/2d-dwt-and-idwt.rst: -------------------------------------------------------------------------------- 1 | .. _ref-dwt2: 2 | 3 | .. currentmodule:: pywt 4 | .. include:: ../substitutions.rst 5 | 6 | ================================================= 7 | 2D Forward and Inverse Discrete Wavelet Transform 8 | ================================================= 9 | 10 | 11 | Single level ``dwt2`` 12 | ~~~~~~~~~~~~~~~~~~~~~ 13 | 14 | .. function:: dwt2(data, wavelet[, mode='sym']) 15 | 16 | The :func:`dwt2` function performs single level 2D Discrete Wavelet Transform. 17 | 18 | :param data: 2D input data. 19 | 20 | :param wavelet: |wavelet| 21 | 22 | :param mode: |mode| This is only important when DWT was performed 23 | in :ref:`periodization ` mode. 24 | 25 | .. compound:: 26 | 27 | Returns one average and three details 2D coefficients arrays. The 28 | coefficients arrays are organized in tuples in the following form: 29 | 30 | :: 31 | 32 | (cA, (cH, cV, cD)) 33 | 34 | where *cA*, *cH*, *cV*, *cD* denote approximation, horizontal 35 | detail, vertical detail and diagonal detail coefficients respectively. 36 | 37 | The relation to the other common data layout where all the approximation and 38 | details coefficients are stored in one big 2D array is as follows: 39 | 40 | :: 41 | 42 | ------------------- 43 | | | | 44 | | cA(LL) | cH(LH) | 45 | | | | 46 | (cA, (cH, cV, cD)) <---> ------------------- 47 | | | | 48 | | cV(HL) | cD(HH) | 49 | | | | 50 | ------------------- 51 | 52 | PyWavelets does not follow this pattern because of pure practical reasons of simple 53 | access to particular type of the output coefficients. 54 | 55 | **Example:** 56 | 57 | .. sourcecode:: python 58 | 59 | >>> import pywt, numpy 60 | >>> data = numpy.ones((4,4), dtype=numpy.float64) 61 | >>> coeffs = pywt.dwt2(data, 'haar') 62 | >>> cA, (cH, cV, cD) = coeffs 63 | >>> print cA 64 | [[ 2. 2.] 65 | [ 2. 2.]] 66 | >>> print cV 67 | [[ 0. 0.] 68 | [ 0. 0.]] 69 | 70 | 71 | Single level ``idwt2`` 72 | ~~~~~~~~~~~~~~~~~~~~~~ 73 | 74 | .. function:: idwt2(coeffs, wavelet[, mode='sym']) 75 | 76 | The :func:`idwt2` function reconstructs data from the given coefficients 77 | set by performing single level 2D Inverse Discrete Wavelet Transform. 78 | 79 | :param coeffs: A tuple with approximation coefficients and three details 80 | coefficients 2D arrays like from :func:`dwt2`:: 81 | 82 | (cA, (cH, cV, cD)) 83 | 84 | :param wavelet: |wavelet| 85 | 86 | :param mode: |mode| This is only important when the :func:`dwt` was performed 87 | in the :ref:`periodization ` mode. 88 | 89 | **Example:** 90 | 91 | .. sourcecode:: python 92 | 93 | >>> import pywt, numpy 94 | >>> data = numpy.array([[1,2], [3,4]], dtype=numpy.float64) 95 | >>> coeffs = pywt.dwt2(data, 'haar') 96 | >>> print pywt.idwt2(coeffs, 'haar') 97 | [[ 1. 2.] 98 | [ 3. 4.]] 99 | 100 | 101 | 2D multilevel decomposition using ``wavedec2`` 102 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 103 | 104 | .. function:: wavedec2(data, wavelet[, mode='sym'[, level=None]]) 105 | 106 | .. compound:: 107 | 108 | Performs multilevel 2D Discrete Wavelet Transform decomposition and 109 | returns coefficients list:: 110 | 111 | [cAn, (cHn, cVn, cDn), ..., (cH1, cV1, cD1)] 112 | 113 | where *n* denotes the level of decomposition and *cA*, *cH*, *cV* and *cD* 114 | are approximation, horizontal detail, vertical detail and diagonal detail 115 | coefficients arrays respectively. 116 | 117 | :param data: |data| 118 | 119 | :param wavelet: |wavelet| 120 | 121 | :param mode: |mode| 122 | 123 | :param level: Decomposition level. This should not be greater than the 124 | reasonable maximum value computed with the :func:`dwt_max_level` 125 | function for the smaller dimension of the input data. 126 | 127 | **Example:** 128 | 129 | .. sourcecode:: python 130 | 131 | >>> import pywt, numpy 132 | >>> coeffs = pywt.wavedec2(numpy.ones((8,8)), 'db1', level=2) 133 | >>> cA2, (cH2, cV2, cD2), (cH1, cV1, cD1) = coeffs 134 | >>> print cA2 135 | [[ 4. 4.] 136 | [ 4. 4.]] 137 | 138 | 139 | 2D multilevel reconstruction using ``waverec2`` 140 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 141 | 142 | .. function:: waverec2(coeffs, wavelet[, mode='sym']) 143 | 144 | Performs multilevel reconstruction from the given coefficients set. 145 | 146 | :param coeffs: Coefficients set must be in the form like that 147 | from :func:`wavedec2` decomposition:: 148 | 149 | [cAn, (cHn, cVn, cDn), ..., (cH1, cV1, cD1)] 150 | 151 | :param wavelet: |wavelet| 152 | 153 | :param mode: |mode| 154 | 155 | **Example:** 156 | 157 | .. sourcecode:: python 158 | 159 | >>> import pywt, numpy 160 | >>> coeffs = pywt.wavedec2(numpy.ones((4,4)), 'db1') 161 | >>> print "levels:", len(coeffs)-1 162 | levels: 2 163 | >>> print pywt.waverec2(coeffs, 'db1') 164 | [[ 1. 1. 1. 1.] 165 | [ 1. 1. 1. 1.] 166 | [ 1. 1. 1. 1.] 167 | [ 1. 1. 1. 1.]] 168 | -------------------------------------------------------------------------------- /doc/source/ref/dwt-discrete-wavelet-transform.rst: -------------------------------------------------------------------------------- 1 | .. _ref-dwt: 2 | 3 | .. currentmodule:: pywt 4 | .. include:: ../substitutions.rst 5 | 6 | ================================ 7 | Discrete Wavelet Transform (DWT) 8 | ================================ 9 | 10 | Wavelet transform has recently become a very popular when it comes to analysis, 11 | de-noising and compression of signals and images. This section describes 12 | functions used to perform single- and multilevel Discrete Wavelet Transforms. 13 | 14 | 15 | Single level ``dwt`` 16 | -------------------- 17 | 18 | .. function:: dwt(data, wavelet[, mode='sym']) 19 | 20 | The :func:`dwt` function is used to perform single level, one dimensional 21 | Discrete Wavelet Transform. 22 | 23 | :: 24 | 25 | (cA, cD) = dwt(data, wavelet, mode='sym') 26 | 27 | :param data: |data| 28 | 29 | :param wavelet: |wavelet| 30 | 31 | :param mode: |mode| 32 | 33 | The transform coefficients are returned as two arrays containing 34 | approximation (*cA*) and detail (*cD*) coefficients respectively. Length 35 | of returned arrays depends on the selected signal extension *mode* - see 36 | the :ref:`signal extension modes ` section for the list of 37 | available options and the :func:`dwt_coeff_len` function for information on 38 | getting the expected result length: 39 | 40 | * for all :ref:`modes ` except :ref:`periodization `:: 41 | 42 | len(cA) == len(cD) == floor((len(data) + wavelet.dec_len - 1) / 2) 43 | 44 | * for :ref:`periodization ` mode (``"per"``):: 45 | 46 | len(cA) == len(cD) == ceil(len(data) / 2) 47 | 48 | **Example:** 49 | 50 | .. sourcecode:: python 51 | 52 | >>> import pywt 53 | >>> (cA, cD) = pywt.dwt([1,2,3,4,5,6], 'db1') 54 | >>> print cA 55 | [ 2.12132034 4.94974747 7.77817459] 56 | >>> print cD 57 | [-0.70710678 -0.70710678 -0.70710678] 58 | 59 | 60 | Multilevel decomposition using ``wavedec`` 61 | ------------------------------------------ 62 | 63 | .. function:: wavedec(data, wavelet, mode='sym', level=None) 64 | 65 | .. compound:: 66 | 67 | The :func:`wavedec` function performs 1D multilevel Discrete Wavelet 68 | Transform decomposition of given signal and returns ordered list of 69 | coefficients arrays in the form: 70 | 71 | :: 72 | 73 | [cA_n, cD_n, cD_n-1, ..., cD2, cD1], 74 | 75 | where *n* denotes the level of decomposition. The first element (*cA_n*) of 76 | the result is approximation coefficients array and the following elements 77 | (*cD_n* - *cD_1*) are details coefficients arrays. 78 | 79 | :param data: |data| 80 | 81 | :param wavelet: |wavelet| 82 | 83 | :param mode: |mode| 84 | 85 | :param level: Number of decomposition steps to perform. If the level is 86 | ``None``, then the full decomposition up to the level computed 87 | with :func:`dwt_max_level` function for the given data and 88 | wavelet lengths is performed. 89 | 90 | **Example:** 91 | 92 | .. sourcecode:: python 93 | 94 | >>> import pywt 95 | >>> coeffs = pywt.wavedec([1,2,3,4,5,6,7,8], 'db1', level=2) 96 | >>> cA2, cD2, cD1 = coeffs 97 | >>> print cD1 98 | [-0.70710678 -0.70710678 -0.70710678 -0.70710678] 99 | >>> print cD2 100 | [-2. -2.] 101 | >>> print cA2 102 | [ 5. 13.] 103 | 104 | 105 | Partial Discrete Wavelet Transform data decomposition ``downcoef`` 106 | ------------------------------------------------------------------ 107 | 108 | .. function:: downcoef(part, data, wavelet[, mode='sym'[, level=1]]) 109 | 110 | Similar to :func:`~pywt.dwt`, but computes only one set of coefficients. 111 | Useful when you need only approximation or only details at the given level. 112 | 113 | :param part: decomposition type. For ``a`` computes approximation 114 | coefficients, for ``d`` - details coefficients. 115 | 116 | :param data: |data| 117 | 118 | :param wavelet: |wavelet| 119 | 120 | :param mode: |mode| 121 | 122 | :param level: Number of decomposition steps to perform. 123 | 124 | 125 | 126 | Maximum decomposition level - ``dwt_max_level`` 127 | ----------------------------------------------- 128 | 129 | .. function:: dwt_max_level(data_len, filter_len) 130 | 131 | The :func:`~pywt.dwt_max_level` function can be used to compute the maximum 132 | *useful* level of decomposition for the given *input data length* and *wavelet 133 | filter length*. 134 | 135 | The returned value equals to:: 136 | 137 | floor( log(data_len/(filter_len-1)) / log(2) ) 138 | 139 | Although the maximum decomposition level can be quite high for long signals, 140 | usually smaller values are chosen depending on the application. 141 | 142 | The *filter_len* can be either an ``int`` or :class:`Wavelet` object for 143 | convenience. 144 | 145 | **Example:** 146 | 147 | .. sourcecode:: python 148 | 149 | >>> import pywt 150 | >>> w = pywt.Wavelet('sym5') 151 | >>> print pywt.dwt_max_level(data_len=1000, filter_len=w.dec_len) 152 | 6 153 | >>> print pywt.dwt_max_level(1000, w) 154 | 6 155 | 156 | .. _`dwt_coeff_len`: 157 | 158 | 159 | Result coefficients length - ``dwt_coeff_len`` 160 | ---------------------------------------------- 161 | 162 | .. function:: dwt_coeff_len(data_len, filter_len, mode) 163 | 164 | Based on the given *input data length*, Wavelet *decomposition filter length* 165 | and :ref:`signal extension mode `, the :func:`dwt_coeff_len` function 166 | calculates length of resulting coefficients arrays that would be created while 167 | performing :func:`dwt` transform. 168 | 169 | For :ref:`periodization ` mode this equals:: 170 | 171 | ceil(data_len / 2) 172 | 173 | which is the lowest possible length guaranteeing perfect reconstruction. 174 | 175 | For other :ref:`modes `:: 176 | 177 | floor((data_len + filter_len - 1) / 2) 178 | 179 | The *filter_len* can be either an *int* or :class:`Wavelet` object for 180 | convenience. 181 | -------------------------------------------------------------------------------- /doc/source/ref/idwt-inverse-discrete-wavelet-transform.rst: -------------------------------------------------------------------------------- 1 | .. _ref-idwt: 2 | 3 | .. currentmodule:: pywt 4 | .. include:: ../substitutions.rst 5 | 6 | ========================================= 7 | Inverse Discrete Wavelet Transform (IDWT) 8 | ========================================= 9 | 10 | 11 | Single level ``idwt`` 12 | --------------------- 13 | 14 | .. function:: idwt(cA, cD, wavelet[, mode='sym'[, correct_size=0]]) 15 | 16 | The :func:`idwt` function reconstructs data from the given coefficients by 17 | performing single level Inverse Discrete Wavelet Transform. 18 | 19 | :param cA: Approximation coefficients. 20 | 21 | :param cD: Detail coefficients. 22 | 23 | :param wavelet: |wavelet| 24 | 25 | :param mode: |mode| This is only important when DWT was performed in 26 | :ref:`periodization ` mode. 27 | 28 | :param correct_size: Typically, *cA* and *cD* coefficients lists must have 29 | equal lengths in order to perform IDWT. Setting 30 | *correct_size* to `True` allows *cA* to be greater in 31 | size by one element compared to the *cD* size. This 32 | option is very useful when doing multilevel decomposition 33 | and reconstruction (as for example with the 34 | :func:`wavedec` function) of non-dyadic length signals 35 | when such minor differences can occur at various levels 36 | of IDWT. 37 | 38 | **Example:** 39 | 40 | .. sourcecode:: python 41 | 42 | >>> import pywt 43 | >>> (cA, cD) = pywt.dwt([1,2,3,4,5,6], 'db2', 'sp1') 44 | >>> print pywt.idwt(cA, cD, 'db2', 'sp1') 45 | [ 1. 2. 3. 4. 5. 6.] 46 | 47 | One of the neat features of :func:`idwt` is that one of the *cA* and *cD* 48 | arguments can be set to ``None``. In that situation the reconstruction will be 49 | performed using only the other one. Mathematically speaking, this is 50 | equivalent to passing a zero-filled array as one of the arguments. 51 | 52 | **Example:** 53 | 54 | .. sourcecode:: python 55 | 56 | >>> import pywt 57 | >>> (cA, cD) = pywt.dwt([1,2,3,4,5,6], 'db2', 'sp1') 58 | >>> A = pywt.idwt(cA, None, 'db2', 'sp1') 59 | >>> D = pywt.idwt(None, cD, 'db2', 'sp1') 60 | >>> print A + D 61 | [ 1. 2. 3. 4. 5. 6.] 62 | 63 | 64 | 65 | Multilevel reconstruction using ``waverec`` 66 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 67 | 68 | .. function:: waverec(coeffs, wavelet[, mode='sym']) 69 | 70 | Performs multilevel reconstruction of signal from the given list of 71 | coefficients. 72 | 73 | :param coeffs: Coefficients list must be in the form like returned by :func:`wavedec` decomposition function, which is:: 74 | 75 | [cAn, cDn, cDn-1, ..., cD2, cD1] 76 | 77 | :param wavelet: |wavelet| 78 | 79 | :param mode: |mode| 80 | 81 | **Example:** 82 | 83 | .. sourcecode:: python 84 | 85 | >>> import pywt 86 | >>> coeffs = pywt.wavedec([1,2,3,4,5,6,7,8], 'db2', level=2) 87 | >>> print pywt.waverec(coeffs, 'db2') 88 | [ 1. 2. 3. 4. 5. 6. 7. 8.] 89 | 90 | 91 | Direct reconstruction with ``upcoef`` 92 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 93 | 94 | .. function:: upcoef(part, coeffs, wavelet[, level=1[, take=0]]) 95 | 96 | Direct reconstruction from coefficients. 97 | 98 | :param part: Defines the input coefficients type: 99 | 100 | - **'a'** - approximations reconstruction is performed 101 | - **'d'** - details reconstruction is performed 102 | 103 | :param coeffs: Coefficients array to reconstruct. 104 | 105 | :param wavelet: |wavelet| 106 | 107 | :param level: If *level* value is specified then a multilevel reconstruction is 108 | performed (first reconstruction is of type specified by *part* 109 | and all the following ones with *part* type ``a``) 110 | 111 | :param take: If *take* is specified then only the central part of length equal 112 | to the *take* parameter value is returned. 113 | 114 | **Example:** 115 | 116 | .. sourcecode:: python 117 | 118 | >>> import pywt 119 | >>> data = [1,2,3,4,5,6] 120 | >>> (cA, cD) = pywt.dwt(data, 'db2', 'sp1') 121 | >>> print pywt.upcoef('a', cA, 'db2') + pywt.upcoef('d', cD, 'db2') 122 | [-0.25 -0.4330127 1. 2. 3. 4. 5. 123 | 6. 1.78589838 -1.03108891] 124 | >>> n = len(data) 125 | >>> print pywt.upcoef('a',cA,'db2',take=n) + pywt.upcoef('d',cD,'db2',take=n) 126 | [ 1. 2. 3. 4. 5. 6.] 127 | -------------------------------------------------------------------------------- /doc/source/ref/index.rst: -------------------------------------------------------------------------------- 1 | .. _ref-index: 2 | 3 | API Reference 4 | ============= 5 | 6 | .. toctree:: 7 | :maxdepth: 2 8 | 9 | wavelets 10 | signal-extension-modes 11 | dwt-discrete-wavelet-transform 12 | idwt-inverse-discrete-wavelet-transform 13 | 2d-dwt-and-idwt 14 | swt-stationary-wavelet-transform 15 | wavelet-packets 16 | thresholding-functions 17 | other-functions 18 | -------------------------------------------------------------------------------- /doc/source/ref/other-functions.rst: -------------------------------------------------------------------------------- 1 | .. _ref-other: 2 | 3 | .. currentmodule:: pywt 4 | .. include:: ../substitutions.rst 5 | 6 | =============== 7 | Other functions 8 | =============== 9 | 10 | 11 | Single-level n-dimensional Discrete Wavelet Transform. 12 | ------------------------------------------------------ 13 | 14 | .. function:: dwtn(data, wavelet[, mode='sym']) 15 | 16 | Performs single-level n-dimensional Discrete Wavelet Transform. 17 | 18 | :param data: n-dimensional array 19 | :param wavelet: |wavelet| 20 | :param mode: |mode| 21 | 22 | Results are arranged in a dictionary, where key specifies 23 | the transform type on each dimension and value is a n-dimensional 24 | coefficients array. 25 | 26 | For example, for a 2D case the result will look something like this:: 27 | 28 | { 29 | 'aa': # A(LL) - approx. on 1st dim, approx. on 2nd dim 30 | 'ad': # H(LH) - approx. on 1st dim, det. on 2nd dim 31 | 'da': # V(HL) - det. on 1st dim, approx. on 2nd dim 32 | 'dd': # D(HH) - det. on 1st dim, det. on 2nd dim 33 | } 34 | 35 | 36 | Integrating wavelet functions - :func:`intwave` 37 | ----------------------------------------------- 38 | 39 | .. function:: intwave(wavelet[, precision=8]) 40 | 41 | Integration of wavelet function approximations as well as any other signals 42 | can be performed using the :func:`pywt.intwave` function. 43 | 44 | The result of the call depends on the *wavelet* argument: 45 | 46 | * for orthogonal wavelets - an integral of the wavelet function specified 47 | on an x-grid:: 48 | 49 | [int_psi, x] = intwave(wavelet, precision) 50 | 51 | * for other wavelets - integrals of decomposition and reconstruction 52 | wavelet functions and a corresponding x-grid:: 53 | 54 | [int_psi_d, int_psi_r, x] = intwave(wavelet, precision) 55 | 56 | * for a tuple of coefficients data and a x-grid - an integral of function 57 | and the given x-grid is returned (the x-grid is used for computations).:: 58 | 59 | [int_function, x] = intwave((data, x), precision) 60 | 61 | 62 | **Example:** 63 | 64 | .. sourcecode:: python 65 | 66 | >>> import pywt 67 | >>> wavelet1 = pywt.Wavelet('db2') 68 | >>> [int_psi, x] = pywt.intwave(wavelet1, precision=5) 69 | >>> wavelet2 = pywt.Wavelet('bior1.3') 70 | >>> [int_psi_d, int_psi_r, x] = pywt.intwave(wavelet2, precision=5) 71 | 72 | 73 | Central frequency of *psi* wavelet function 74 | ------------------------------------------- 75 | 76 | .. function:: centfrq(wavelet[, precision=8]) 77 | centfrq((function_approx, x)) 78 | 79 | :param wavelet: :class:`Wavelet`, wavelet name string or 80 | `(wavelet function approx., x grid)` pair 81 | 82 | :param precision: Precision that will be used for wavelet function 83 | approximation computed with the :meth:`Wavelet.wavefun` 84 | method. 85 | -------------------------------------------------------------------------------- /doc/source/ref/signal-extension-modes.rst: -------------------------------------------------------------------------------- 1 | .. _ref-modes: 2 | 3 | .. currentmodule:: pywt 4 | 5 | 6 | ====================== 7 | Signal extension modes 8 | ====================== 9 | 10 | .. _MODES: 11 | 12 | Because the most common and practical way of representing digital signals 13 | in computer science is with finite arrays of values, some extrapolation 14 | of the input data has to be performed in order to extend the signal before 15 | computing the :ref:`Discrete Wavelet Transform ` using the cascading 16 | filter banks algorithm. 17 | 18 | Depending on the extrapolation method, significant artifacts at the signal's 19 | borders can be introduced during that process, which in turn may lead to 20 | inaccurate computations of the :ref:`DWT ` at the signal's ends. 21 | 22 | PyWavelets provides several methods of signal extrapolation that can be used to 23 | minimize this negative effect: 24 | 25 | .. _`MODES.zpd`: 26 | 27 | * ``zpd`` - **zero-padding** - signal is extended by adding zero samples:: 28 | 29 | ... 0 0 | x1 x2 ... xn | 0 0 ... 30 | 31 | .. _`MODES.cpd`: 32 | 33 | * ``cpd`` - **constant-padding** - border values are replicated:: 34 | 35 | ... x1 x1 | x1 x2 ... xn | xn xn ... 36 | 37 | .. _`MODES.sym`: 38 | 39 | * ``sym`` - **symmetric-padding** - signal is extended by *mirroring* 40 | samples:: 41 | 42 | ... x2 x1 | x1 x2 ... xn | xn xn-1 ... 43 | 44 | .. _`MODES.ppd`: 45 | .. _`periodic-padding`: 46 | 47 | * ``ppd`` - **periodic-padding** - signal is treated as a periodic one:: 48 | 49 | ... xn-1 xn | x1 x2 ... xn | x1 x2 ... 50 | 51 | .. _`MODES.sp1`: 52 | 53 | * ``sp1`` - **smooth-padding** - signal is extended according to the first 54 | derivatives calculated on the edges (straight line) 55 | 56 | :ref:`DWT ` performed for these extension modes is slightly redundant, but ensures 57 | perfect reconstruction. To receive the smallest possible number of coefficients, 58 | computations can be performed with the `periodization`_ mode: 59 | 60 | .. _`periodization`: 61 | .. _`MODES.per`: 62 | 63 | * ``per`` - **periodization** - is like `periodic-padding`_ but gives the 64 | smallest possible number of decomposition coefficients. :ref:`IDWT ` must be 65 | performed with the same mode. 66 | 67 | **Example:** 68 | 69 | .. sourcecode:: python 70 | 71 | >>> import pywt 72 | >>> print pywt.MODES.modes 73 | ['zpd', 'cpd', 'sym', 'ppd', 'sp1', 'per'] 74 | 75 | 76 | Notice that you can use any of the following ways of passing wavelet and mode 77 | parameters: 78 | 79 | .. sourcecode:: python 80 | 81 | >>> import pywt 82 | >>> (a, d) = pywt.dwt([1,2,3,4,5,6], 'db2', 'sp1') 83 | >>> (a, d) = pywt.dwt([1,2,3,4,5,6], pywt.Wavelet('db2'), pywt.MODES.sp1) 84 | 85 | .. note:: 86 | Extending data in context of PyWavelets does not mean reallocation of the data 87 | in computer's physical memory and copying values, but rather computing 88 | the extra values only when they are needed. 89 | This feature saves extra memory and CPU resources and helps to avoid page 90 | swapping when handling relatively big data arrays on computers with low 91 | physical memory. 92 | -------------------------------------------------------------------------------- /doc/source/ref/swt-stationary-wavelet-transform.rst: -------------------------------------------------------------------------------- 1 | .. _ref-swt: 2 | 3 | .. currentmodule:: pywt 4 | .. include:: ../substitutions.rst 5 | 6 | 7 | Stationary Wavelet Transform 8 | ---------------------------- 9 | 10 | `Stationary Wavelet Transform (SWT) `_, 11 | also known as *Undecimated wavelet transform* or *Algorithme à trous* is a translation-invariance 12 | modification of the *Discrete Wavelet Transform* that does not decimate coefficients at every 13 | transformation level. 14 | 15 | Multilevel ``swt`` 16 | ~~~~~~~~~~~~~~~~~~ 17 | 18 | .. function:: swt(data, wavelet, level[, start_level=0]) 19 | 20 | Performs multilevel Stationary Wavelet Transform. 21 | 22 | :param data: |data| 23 | 24 | :param wavelet: |wavelet| 25 | 26 | :param int level: Required transform level. See the :func:`swt_max_level` function. 27 | 28 | :param int start_level: The level at which the decomposition will begin (it 29 | allows to skip a given number of transform steps and compute coefficients 30 | starting directly from the *start_level*) 31 | 32 | .. compound:: 33 | 34 | Returns list of coefficient pairs in the form:: 35 | 36 | [(cAn, cDn), ..., (cA2, cD2), (cA1, cD1)] 37 | 38 | where *n* is the *level* value. 39 | 40 | If *m* = *start_level* is given, then the beginning *m* steps are 41 | skipped:: 42 | 43 | [(cAm+n, cDm+n), ..., (cAm+1, cDm+1), (cAm, cDm)] 44 | 45 | 46 | Multilevel ``swt2`` 47 | ~~~~~~~~~~~~~~~~~~~~~ 48 | 49 | .. function:: swt2(data, wavelet, level[, start_level=0]) 50 | 51 | Performs multilevel 2D Stationary Wavelet Transform. 52 | 53 | :param data: 2D array with input data. 54 | 55 | :param wavelet: |wavelet| 56 | 57 | :param level: Number of decomposition steps to perform. 58 | 59 | :param start_level: The level at which the decomposition will begin. 60 | 61 | .. compound:: 62 | 63 | The result is a set of coefficients arrays over the range of decomposition 64 | levels:: 65 | 66 | [ 67 | (cA_n, 68 | (cH_n, cV_n, cD_n) 69 | ), 70 | (cA_n+1, 71 | (cH_n+1, cV_n+1, cD_n+1) 72 | ), 73 | ..., 74 | (cA_n+level, 75 | (cH_n+level, cV_n+level, cD_n+level) 76 | ) 77 | ] 78 | 79 | where *cA* is approximation, *cH* is horizontal details, *cV* is vertical 80 | details, *cD* is diagonal details, *n* is *start_level* and *m* equals 81 | *n+level*. 82 | 83 | 84 | Maximum decomposition level - ``swt_max_level`` 85 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 86 | 87 | .. function:: swt_max_level(input_len) 88 | 89 | Calculates the maximum level of Stationary Wavelet Transform for data of 90 | given length. 91 | 92 | :param input_len: Input data length. 93 | -------------------------------------------------------------------------------- /doc/source/ref/thresholding-functions.rst: -------------------------------------------------------------------------------- 1 | .. _ref-thresholding: 2 | 3 | 4 | Thresholding functions 5 | ====================== 6 | 7 | The :mod:`~pywt.thresholding` helper module implements the most popular signal 8 | thresholding functions. 9 | 10 | 11 | Hard thresholding 12 | ----------------- 13 | 14 | .. function:: hard(data, value[, substitute=0]) 15 | 16 | Hard thresholding. Replace all *data* values with *substitute* where their 17 | absolute value is less than the *value* param. 18 | 19 | *Data* values with absolute value greater or equal to the thresholding 20 | *value* stay untouched. 21 | 22 | :param data: numeric data 23 | :param value: thresholding value 24 | :param substitute: substitute value 25 | :returns: array 26 | 27 | 28 | Soft thresholding 29 | ----------------- 30 | .. function:: soft(data, value[, substitute=0]) 31 | 32 | Soft thresholding. 33 | 34 | :param data: numeric data 35 | :param value: thresholding value 36 | :param substitute: substitute value 37 | :returns: array 38 | 39 | Greater 40 | ------- 41 | 42 | .. function:: greater(data, value[, substitute=0]) 43 | 44 | Replace *data* with *substitute* where *data* is below the thresholding 45 | *value*. 46 | 47 | `Greater` *data* values pass untouched. 48 | 49 | :param data: numeric data 50 | :param value: thresholding value 51 | :param substitute: substitute value 52 | :returns: array 53 | 54 | Less 55 | ---- 56 | 57 | .. function:: less(data, value[, substitute=0]) 58 | 59 | Replace *data* with *substitute* where *data* is above the thresholding 60 | *value*. 61 | 62 | `Less` *data* values pass untouched. 63 | 64 | :param data: numeric data 65 | :param value: thresholding value 66 | :param substitute: substitute value 67 | :returns: array 68 | -------------------------------------------------------------------------------- /doc/source/regression/dwt-idwt.rst: -------------------------------------------------------------------------------- 1 | .. _reg-dwt-idwt: 2 | 3 | .. currentmodule:: pywt 4 | 5 | DWT and IDWT 6 | ============ 7 | 8 | Discrete Wavelet Transform 9 | -------------------------- 10 | 11 | Let's do a :func:`Discrete Wavelet Transform ` of a sample data *x* using 12 | the ``db2`` wavelet. It's simple.. 13 | 14 | >>> import pywt 15 | >>> x = [3, 7, 1, 1, -2, 5, 4, 6] 16 | >>> cA, cD = pywt.dwt(x, 'db2') 17 | 18 | And the approximation and details coefficients are in ``cA`` and ``cD`` 19 | respectively: 20 | 21 | >>> print cA 22 | [ 5.65685425 7.39923721 0.22414387 3.33677403 7.77817459] 23 | >>> print cD 24 | [-2.44948974 -1.60368225 -4.44140056 -0.41361256 1.22474487] 25 | 26 | Inverse Discrete Wavelet Transform 27 | ---------------------------------- 28 | 29 | Now let's do an opposite operation 30 | - :func:`Inverse Discrete Wavelet Transform `: 31 | 32 | >>> print pywt.idwt(cA, cD, 'db2') 33 | [ 3. 7. 1. 1. -2. 5. 4. 6.] 34 | 35 | Voilà! That's it! 36 | 37 | More Examples 38 | ------------- 39 | 40 | Now let's experiment with the :func:`dwt` some more. For example let's pass a 41 | :class:`Wavelet` object instead of the wavelet name and specify signal extension 42 | mode (the default is :ref:`sym `) for the border effect handling: 43 | 44 | >>> w = pywt.Wavelet('sym3') 45 | >>> cA, cD = pywt.dwt(x, wavelet=w, mode='cpd') 46 | >>> print cA 47 | [ 4.38354585 3.80302657 7.31813271 -0.58565539 4.09727044 7.81994027] 48 | >>> print cD 49 | [-1.33068221 -2.78795192 -3.16825651 -0.67715519 -0.09722957 -0.07045258] 50 | 51 | Note that the output coefficients arrays length depends not only on the input 52 | data length but also on the :class:Wavelet type (particularly on its 53 | :attr:`filters lenght <~Wavelet.dec_len>` that are used in the transformation). 54 | 55 | To find out what will be the output data size use the :func:`dwt_coeff_len` 56 | function: 57 | 58 | >>> # int() is for normalizing Python integers and long integers for documentation tests 59 | >>> int(pywt.dwt_coeff_len(data_len=len(x), filter_len=w.dec_len, mode='sym')) 60 | 6 61 | >>> int(pywt.dwt_coeff_len(len(x), w, 'sym')) 62 | 6 63 | >>> len(cA) 64 | 6 65 | 66 | Looks fine. (And if you expected that the output length would be a half of the 67 | input data length, well, that's the trade-off that allows for the perfect 68 | reconstruction...). 69 | 70 | The third argument of the :func:`dwt_coeff_len` is the already mentioned signal 71 | extension mode (please refer to the PyWavelets' documentation for the 72 | :ref:`modes ` description). Currently there are six 73 | :ref:`extension modes ` available: 74 | 75 | >>> pywt.MODES.modes 76 | ['zpd', 'cpd', 'sym', 'ppd', 'sp1', 'per'] 77 | 78 | >>> [int(pywt.dwt_coeff_len(len(x), w.dec_len, mode)) for mode in pywt.MODES.modes] 79 | [6, 6, 6, 6, 6, 4] 80 | 81 | As you see in the above example, the :ref:`per ` (periodization) mode 82 | is slightly different from the others. It's aim when doing the :func:`DWT ` 83 | transform is to output coefficients arrays that are half of the length of the 84 | input data. 85 | 86 | Knowing that, you should never mix the periodization mode with other modes when 87 | doing :func:`DWT ` and :func:`IDWT `. Otherwise, it will produce 88 | **invalid results**: 89 | 90 | >>> x 91 | [3, 7, 1, 1, -2, 5, 4, 6] 92 | >>> cA, cD = pywt.dwt(x, wavelet=w, mode='per') 93 | >>> print pywt.idwt(cA, cD, 'sym3', 'sym') # invalid mode 94 | [ 1. 1. -2. 5.] 95 | >>> print pywt.idwt(cA, cD, 'sym3', 'per') 96 | [ 3. 7. 1. 1. -2. 5. 4. 6.] 97 | 98 | 99 | Tips & tricks 100 | ------------- 101 | 102 | Passing ``None`` instead of coefficients data to :func:`idwt` 103 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 104 | 105 | Now some tips & tricks. Passing ``None`` as one of the coefficient arrays 106 | parameters is similar to passing a *zero-filled* array. The results are simply 107 | the same: 108 | 109 | >>> print pywt.idwt([1,2,0,1], None, 'db2', 'sym') 110 | [ 1.19006969 1.54362308 0.44828774 -0.25881905 0.48296291 0.8365163 ] 111 | 112 | >>> print pywt.idwt([1, 2, 0, 1], [0, 0, 0, 0], 'db2', 'sym') 113 | [ 1.19006969 1.54362308 0.44828774 -0.25881905 0.48296291 0.8365163 ] 114 | 115 | >>> print pywt.idwt(None, [1, 2, 0, 1], 'db2', 'sym') 116 | [ 0.57769726 -0.93125065 1.67303261 -0.96592583 -0.12940952 -0.22414387] 117 | 118 | >>> print pywt.idwt([0, 0, 0, 0], [1, 2, 0, 1], 'db2', 'sym') 119 | [ 0.57769726 -0.93125065 1.67303261 -0.96592583 -0.12940952 -0.22414387] 120 | 121 | Remember that only one argument at a time can be ``None``: 122 | 123 | >>> print pywt.idwt(None, None, 'db2', 'sym') 124 | Traceback (most recent call last): 125 | ... 126 | ValueError: At least one coefficient parameter must be specified. 127 | 128 | 129 | Coefficients data size in :attr:`idwt` 130 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 131 | 132 | When doing the :func:`IDWT ` transform, usually the coefficient arrays 133 | must have the same size. 134 | 135 | >>> print pywt.idwt([1, 2, 3, 4, 5], [1, 2, 3, 4], 'db2', 'sym') 136 | Traceback (most recent call last): 137 | ... 138 | ValueError: Coefficients arrays must have the same size. 139 | 140 | But for some applications like multilevel DWT and IDWT it is sometimes convenient 141 | to allow for a small departure from this behaviour. When the *correct_size* flag 142 | is set, the approximation coefficients array can be larger from the details 143 | coefficient array by one element: 144 | 145 | >>> print pywt.idwt([1, 2, 3, 4, 5], [1, 2, 3, 4], 'db2', 'sym', correct_size=True) 146 | [ 1.76776695 0.61237244 3.18198052 0.61237244 4.59619408 0.61237244] 147 | 148 | >>> print pywt.idwt([1, 2, 3, 4], [1, 2, 3, 4, 5], 'db2', 'sym', correct_size=True) 149 | Traceback (most recent call last): 150 | ... 151 | ValueError: Coefficients arrays must satisfy (0 <= len(cA) - len(cD) <= 1). 152 | 153 | 154 | Not every coefficient array can be used in :func:`IDWT `. In the following 155 | example the :func:`idwt` will fail because the input arrays are invalid - they 156 | couldn't be created as a result of :func:`DWT `, because the minimal output 157 | length for dwt using ``db4`` wavelet and the :ref:`sym ` mode is 158 | ``4``, not ``3``: 159 | 160 | >>> pywt.idwt([1,2,4], [4,1,3], 'db4', 'sym') 161 | Traceback (most recent call last): 162 | ... 163 | ValueError: Invalid coefficient arrays length for specified wavelet. Wavelet and mode must be the same as used for decomposition. 164 | 165 | >>> int(pywt.dwt_coeff_len(1, pywt.Wavelet('db4').dec_len, 'sym')) 166 | 4 167 | -------------------------------------------------------------------------------- /doc/source/regression/gotchas.rst: -------------------------------------------------------------------------------- 1 | .. _reg-gotchas: 2 | 3 | .. currentmodule:: pywt 4 | 5 | 6 | ======= 7 | Gotchas 8 | ======= 9 | 10 | PyWavelets utilizes ``NumPy`` under the hood. That's why handling the data 11 | containing ``None`` values can be surprising. ``None`` values are converted to 12 | 'not a number' (``numpy.NaN``) values: 13 | 14 | >>> import numpy, pywt 15 | >>> x = [None, None] 16 | >>> mode = 'sym' 17 | >>> wavelet = 'db1' 18 | >>> cA, cD = pywt.dwt(x, wavelet, mode) 19 | >>> numpy.all(numpy.isnan(cA)) 20 | True 21 | >>> numpy.all(numpy.isnan(cD)) 22 | True 23 | >>> rec = pywt.idwt(cA, cD, wavelet, mode) 24 | >>> numpy.all(numpy.isnan(rec)) 25 | True 26 | -------------------------------------------------------------------------------- /doc/source/regression/index.rst: -------------------------------------------------------------------------------- 1 | .. _reg-index: 2 | 3 | .. currentmodule:: pywt 4 | 5 | Usage examples 6 | ============== 7 | 8 | The following examples are used as doctest regression tests written using reST 9 | markup. They are included in the documentation since they contain various useful 10 | examples illustrating how to use and how not to use PyWavelets. 11 | 12 | .. toctree:: 13 | :maxdepth: 1 14 | 15 | wavelet 16 | modes 17 | dwt-idwt 18 | multilevel 19 | wp 20 | wp2d 21 | gotchas 22 | -------------------------------------------------------------------------------- /doc/source/regression/modes.rst: -------------------------------------------------------------------------------- 1 | .. _reg-modes: 2 | 3 | .. currentmodule:: pywt 4 | 5 | 6 | Signal Extension Modes 7 | ====================== 8 | 9 | Import :mod:`pywt` first 10 | 11 | >>> import pywt 12 | 13 | >>> def format_array(a): 14 | ... """Consistent array representation across different systems""" 15 | ... import numpy 16 | ... a = numpy.where(numpy.abs(a) < 1e-5, 0, a) 17 | ... return numpy.array2string(a, precision=5, separator=' ', suppress_small=True) 18 | 19 | List of available signal extension :ref:`modes `: 20 | 21 | >>> print pywt.MODES.modes 22 | ['zpd', 'cpd', 'sym', 'ppd', 'sp1', 'per'] 23 | 24 | 25 | Test that :func:`dwt` and :func:`idwt` can be performed using every mode: 26 | 27 | >>> x = [1,2,1,5,-1,8,4,6] 28 | >>> for mode in pywt.MODES.modes: 29 | ... cA, cD = pywt.dwt(x, 'db2', mode) 30 | ... print "Mode:", mode 31 | ... print "cA:", format_array(cA) 32 | ... print "cD:", format_array(cD) 33 | ... print "Reconstruction:", pywt.idwt(cA, cD, 'db2', mode) 34 | Mode: zpd 35 | cA: [-0.03468 1.73309 3.40612 6.32929 6.95095] 36 | cD: [-0.12941 -2.156 -5.95035 -1.21545 -1.8625 ] 37 | Reconstruction: [ 1. 2. 1. 5. -1. 8. 4. 6.] 38 | Mode: cpd 39 | cA: [ 1.2848 1.73309 3.40612 6.32929 7.51936] 40 | cD: [-0.48296 -2.156 -5.95035 -1.21545 0.25882] 41 | Reconstruction: [ 1. 2. 1. 5. -1. 8. 4. 6.] 42 | Mode: sym 43 | cA: [ 1.76777 1.73309 3.40612 6.32929 7.77817] 44 | cD: [-0.61237 -2.156 -5.95035 -1.21545 1.22474] 45 | Reconstruction: [ 1. 2. 1. 5. -1. 8. 4. 6.] 46 | Mode: ppd 47 | cA: [ 6.91627 1.73309 3.40612 6.32929 6.91627] 48 | cD: [-1.99191 -2.156 -5.95035 -1.21545 -1.99191] 49 | Reconstruction: [ 1. 2. 1. 5. -1. 8. 4. 6.] 50 | Mode: sp1 51 | cA: [-0.51764 1.73309 3.40612 6.32929 7.45001] 52 | cD: [ 0. -2.156 -5.95035 -1.21545 0. ] 53 | Reconstruction: [ 1. 2. 1. 5. -1. 8. 4. 6.] 54 | Mode: per 55 | cA: [ 4.05317 3.05257 2.85381 8.42522] 56 | cD: [ 0.18947 4.18258 4.33738 2.60428] 57 | Reconstruction: [ 1. 2. 1. 5. -1. 8. 4. 6.] 58 | 59 | 60 | Invalid mode name should rise a :exc:`ValueError`: 61 | 62 | >>> pywt.dwt([1,2,3,4], 'db2', 'invalid') 63 | Traceback (most recent call last): 64 | ... 65 | ValueError: Unknown mode name 'invalid'. 66 | 67 | 68 | You can also refer to modes via :ref:`MODES ` class attributes: 69 | 70 | >>> for mode_name in ['zpd', 'cpd', 'sym', 'ppd', 'sp1', 'per']: 71 | ... mode = getattr(pywt.MODES, mode_name) 72 | ... cA, cD = pywt.dwt([1,2,1,5,-1,8,4,6], 'db2', mode) 73 | ... print "Mode:", mode, "(%s)" % mode_name 74 | ... print "cA:", format_array(cA) 75 | ... print "cD:", format_array(cD) 76 | ... print "Reconstruction:", pywt.idwt(cA, cD, 'db2', mode) 77 | Mode: 0 (zpd) 78 | cA: [-0.03468 1.73309 3.40612 6.32929 6.95095] 79 | cD: [-0.12941 -2.156 -5.95035 -1.21545 -1.8625 ] 80 | Reconstruction: [ 1. 2. 1. 5. -1. 8. 4. 6.] 81 | Mode: 2 (cpd) 82 | cA: [ 1.2848 1.73309 3.40612 6.32929 7.51936] 83 | cD: [-0.48296 -2.156 -5.95035 -1.21545 0.25882] 84 | Reconstruction: [ 1. 2. 1. 5. -1. 8. 4. 6.] 85 | Mode: 1 (sym) 86 | cA: [ 1.76777 1.73309 3.40612 6.32929 7.77817] 87 | cD: [-0.61237 -2.156 -5.95035 -1.21545 1.22474] 88 | Reconstruction: [ 1. 2. 1. 5. -1. 8. 4. 6.] 89 | Mode: 4 (ppd) 90 | cA: [ 6.91627 1.73309 3.40612 6.32929 6.91627] 91 | cD: [-1.99191 -2.156 -5.95035 -1.21545 -1.99191] 92 | Reconstruction: [ 1. 2. 1. 5. -1. 8. 4. 6.] 93 | Mode: 3 (sp1) 94 | cA: [-0.51764 1.73309 3.40612 6.32929 7.45001] 95 | cD: [ 0. -2.156 -5.95035 -1.21545 0. ] 96 | Reconstruction: [ 1. 2. 1. 5. -1. 8. 4. 6.] 97 | Mode: 5 (per) 98 | cA: [ 4.05317 3.05257 2.85381 8.42522] 99 | cD: [ 0.18947 4.18258 4.33738 2.60428] 100 | Reconstruction: [ 1. 2. 1. 5. -1. 8. 4. 6.] 101 | 102 | 103 | Some invalid mode values: 104 | 105 | >>> pywt.dwt(x, 'db2', -1) 106 | Traceback (most recent call last): 107 | ... 108 | ValueError: Invalid mode. 109 | >>> pywt.dwt(x, 'db2', 7) 110 | Traceback (most recent call last): 111 | ... 112 | ValueError: Invalid mode. 113 | 114 | >>> pywt.dwt(x, 'db2', None) 115 | Traceback (most recent call last): 116 | ... 117 | TypeError: expected string or Unicode object, NoneType found 118 | 119 | 120 | The default mode is :ref:`sym `: 121 | 122 | >>> cA, cD = pywt.dwt(x, 'db2') 123 | >>> print cA 124 | [ 1.76776695 1.73309178 3.40612438 6.32928585 7.77817459] 125 | >>> print cD 126 | [-0.61237244 -2.15599552 -5.95034847 -1.21545369 1.22474487] 127 | >>> print pywt.idwt(cA, cD, 'db2') 128 | [ 1. 2. 1. 5. -1. 8. 4. 6.] 129 | 130 | 131 | And using a keyword argument: 132 | 133 | >>> cA, cD = pywt.dwt(x, 'db2', mode='sym') 134 | >>> print cA 135 | [ 1.76776695 1.73309178 3.40612438 6.32928585 7.77817459] 136 | >>> print cD 137 | [-0.61237244 -2.15599552 -5.95034847 -1.21545369 1.22474487] 138 | >>> print pywt.idwt(cA, cD, 'db2') 139 | [ 1. 2. 1. 5. -1. 8. 4. 6.] 140 | -------------------------------------------------------------------------------- /doc/source/regression/multilevel.rst: -------------------------------------------------------------------------------- 1 | .. _reg-multilevel: 2 | 3 | .. currentmodule:: pywt 4 | 5 | Multilevel DWT, IDWT and SWT 6 | ============================ 7 | 8 | Multilevel DWT decomposition 9 | ---------------------------- 10 | 11 | >>> import pywt 12 | >>> x = [3, 7, 1, 1, -2, 5, 4, 6] 13 | >>> db1 = pywt.Wavelet('db1') 14 | >>> cA3, cD3, cD2, cD1 = pywt.wavedec(x, db1) 15 | >>> print cA3 16 | [ 8.83883476] 17 | >>> print cD3 18 | [-0.35355339] 19 | >>> print cD2 20 | [ 4. -3.5] 21 | >>> print cD1 22 | [-2.82842712 0. -4.94974747 -1.41421356] 23 | 24 | >>> pywt.dwt_max_level(len(x), db1) 25 | 3 26 | 27 | >>> cA2, cD2, cD1 = pywt.wavedec(x, db1, mode='cpd', level=2) 28 | 29 | 30 | Multilevel IDWT reconstruction 31 | ------------------------------ 32 | 33 | >>> coeffs = pywt.wavedec(x, db1) 34 | >>> print pywt.waverec(coeffs, db1) 35 | [ 3. 7. 1. 1. -2. 5. 4. 6.] 36 | 37 | 38 | Multilevel SWT decomposition 39 | ---------------------------- 40 | 41 | >>> x = [3, 7, 1, 3, -2, 6, 4, 6] 42 | >>> (cA2, cD2), (cA1, cD1) = pywt.swt(x, db1, level=2) 43 | >>> print cA1 44 | [ 7.07106781 5.65685425 2.82842712 0.70710678 2.82842712 7.07106781 45 | 7.07106781 6.36396103] 46 | >>> print cD1 47 | [-2.82842712 4.24264069 -1.41421356 3.53553391 -5.65685425 1.41421356 48 | -1.41421356 2.12132034] 49 | >>> print cA2 50 | [ 7. 4.5 4. 5.5 7. 9.5 10. 8.5] 51 | >>> print cD2 52 | [ 3. 3.5 0. -4.5 -3. 0.5 0. 0.5] 53 | 54 | >>> [(cA2, cD2)] = pywt.swt(cA1, db1, level=1, start_level=1) 55 | >>> print cA2 56 | [ 7. 4.5 4. 5.5 7. 9.5 10. 8.5] 57 | >>> print cD2 58 | [ 3. 3.5 0. -4.5 -3. 0.5 0. 0.5] 59 | 60 | >>> coeffs = pywt.swt(x, db1) 61 | >>> len(coeffs) 62 | 3 63 | >>> pywt.swt_max_level(len(x)) 64 | 3 65 | -------------------------------------------------------------------------------- /doc/source/regression/wavelet.rst: -------------------------------------------------------------------------------- 1 | .. _reg-wavelet: 2 | 3 | .. currentmodule:: pywt 4 | 5 | The Wavelet object 6 | ================== 7 | 8 | Wavelet families and builtin Wavelets names 9 | ------------------------------------------- 10 | 11 | :class:`Wavelet` objects are really a handy carriers of a bunch of DWT-specific 12 | data like *quadrature mirror filters* and some general properties associated 13 | with them. 14 | 15 | At first let's go through the methods of creating a :class:`Wavelet` object. 16 | The easiest and the most convenient way is to use builtin named Wavelets. 17 | 18 | These wavelets are organized into groups called wavelet families. The most 19 | commonly used families are: 20 | 21 | >>> import pywt 22 | >>> pywt.families() 23 | ['haar', 'db', 'sym', 'coif', 'bior', 'rbio', 'dmey'] 24 | 25 | The :func:`wavelist` function with family name passed as an argument is used to 26 | obtain the list of wavelet names in each family. 27 | 28 | >>> for family in pywt.families(): 29 | ... print "%s family:" % family, ', '.join(pywt.wavelist(family)) 30 | haar family: haar 31 | db family: db1, db2, db3, db4, db5, db6, db7, db8, db9, db10, db11, db12, db13, db14, db15, db16, db17, db18, db19, db20 32 | sym family: sym2, sym3, sym4, sym5, sym6, sym7, sym8, sym9, sym10, sym11, sym12, sym13, sym14, sym15, sym16, sym17, sym18, sym19, sym20 33 | coif family: coif1, coif2, coif3, coif4, coif5 34 | bior family: bior1.1, bior1.3, bior1.5, bior2.2, bior2.4, bior2.6, bior2.8, bior3.1, bior3.3, bior3.5, bior3.7, bior3.9, bior4.4, bior5.5, bior6.8 35 | rbio family: rbio1.1, rbio1.3, rbio1.5, rbio2.2, rbio2.4, rbio2.6, rbio2.8, rbio3.1, rbio3.3, rbio3.5, rbio3.7, rbio3.9, rbio4.4, rbio5.5, rbio6.8 36 | dmey family: dmey 37 | 38 | To get the full list of builtin wavelets' names just use the :func:`wavelist` 39 | with no argument. As you can see currently there are 76 builtin wavelets. 40 | 41 | >>> len(pywt.wavelist()) 42 | 76 43 | 44 | 45 | Creating Wavelet objects 46 | ------------------------ 47 | 48 | Now when we know all the names let's finally create a :class:`Wavelet` object: 49 | 50 | >>> w = pywt.Wavelet('db3') 51 | 52 | So.. that's it. 53 | 54 | 55 | Wavelet properties 56 | ------------------ 57 | 58 | But what can we do with :class:`Wavelet` objects? Well, they carry some 59 | interesting information. 60 | 61 | First, let's try printing a :class:`Wavelet` object. This shows a brief 62 | information about its name, its family name and some properties like 63 | orthogonality and symmetry. 64 | 65 | >>> print w 66 | Wavelet db3 67 | Family name: Daubechies 68 | Short name: db 69 | Filters length: 6 70 | Orthogonal: True 71 | Biorthogonal: True 72 | Symmetry: asymmetric 73 | 74 | But the most important information are the wavelet filters coefficients, which 75 | are used in :ref:`Discrete Wavelet Transform `. These coefficients can 76 | be obtained via the :attr:`~Wavelet.dec_lo`, :attr:`Wavelet.dec_hi`, 77 | :attr:`~Wavelet.rec_lo` and :attr:`~Wavelet.rec_hi` attributes, which 78 | corresponds to lowpass and highpass decomposition filters and lowpass and 79 | highpass reconstruction filters respectively: 80 | 81 | >>> def print_array(arr): 82 | ... print "[%s]" % ", ".join(["%.14f" % x for x in arr]) 83 | 84 | >>> print_array(w.dec_lo) 85 | [0.03522629188210, -0.08544127388224, -0.13501102001039, 0.45987750211933, 0.80689150931334, 0.33267055295096] 86 | >>> print_array(w.dec_hi) 87 | [-0.33267055295096, 0.80689150931334, -0.45987750211933, -0.13501102001039, 0.08544127388224, 0.03522629188210] 88 | >>> print_array(w.rec_lo) 89 | [0.33267055295096, 0.80689150931334, 0.45987750211933, -0.13501102001039, -0.08544127388224, 0.03522629188210] 90 | >>> print_array(w.rec_hi) 91 | [0.03522629188210, 0.08544127388224, -0.13501102001039, -0.45987750211933, 0.80689150931334, -0.33267055295096] 92 | 93 | Another way to get the filters data is to use the :attr:`~Wavelet.filter_bank` 94 | attribute, which returns all four filters in a tuple: 95 | 96 | >>> w.filter_bank == (w.dec_lo, w.dec_hi, w.rec_lo, w.rec_hi) 97 | True 98 | 99 | 100 | Other Wavelet's properties are: 101 | 102 | Wavelet :attr:`~Wavelet.name`, :attr:`~Wavelet.short_family_name` and :attr:`~Wavelet.family_name`: 103 | 104 | >>> print w.name 105 | db3 106 | >>> print w.short_family_name 107 | db 108 | >>> print w.family_name 109 | Daubechies 110 | 111 | - Decomposition (:attr:`~Wavelet.dec_len`) and reconstruction 112 | (:attr:`~.Wavelet.rec_len`) filter lengths: 113 | 114 | >>> int(w.dec_len) # int() is for normalizing longs and ints for doctest 115 | 6 116 | >>> int(w.rec_len) 117 | 6 118 | 119 | - Orthogonality (:attr:`~Wavelet.orthogonal`) and biorthogonality (:attr:`~Wavelet.biorthogonal`): 120 | 121 | >>> w.orthogonal 122 | True 123 | >>> w.biorthogonal 124 | True 125 | 126 | - Symmetry (:attr:`~Wavelet.symmetry`): 127 | 128 | >>> print w.symmetry 129 | asymmetric 130 | 131 | - Number of vanishing moments for the scaling function *phi* 132 | (:attr:`~Wavelet.vanishing_moments_phi`) and the wavelet function *psi* 133 | (:attr:`~Wavelet.vanishing_moments_psi`) associated with the filters: 134 | 135 | >>> w.vanishing_moments_phi 136 | 0 137 | >>> w.vanishing_moments_psi 138 | 3 139 | 140 | Now when we know a bit about the builtin Wavelets, let's see how to create 141 | :ref:`custom Wavelets ` objects. These can be done in two ways: 142 | 143 | 1) Passing the filter bank object that implements the `filter_bank` 144 | attribute. The attribute must return four filters coefficients. 145 | 146 | 147 | >>> class MyHaarFilterBank(object): 148 | ... @property 149 | ... def filter_bank(self): 150 | ... from math import sqrt 151 | ... return ([sqrt(2)/2, sqrt(2)/2], [-sqrt(2)/2, sqrt(2)/2], 152 | ... [sqrt(2)/2, sqrt(2)/2], [sqrt(2)/2, -sqrt(2)/2]) 153 | 154 | 155 | >>> my_wavelet = pywt.Wavelet('My Haar Wavelet', filter_bank=MyHaarFilterBank()) 156 | 157 | 158 | 2) Passing the filters coefficients directly as the *filter_bank* parameter. 159 | 160 | >>> from math import sqrt 161 | >>> my_filter_bank = ([sqrt(2)/2, sqrt(2)/2], [-sqrt(2)/2, sqrt(2)/2], 162 | ... [sqrt(2)/2, sqrt(2)/2], [sqrt(2)/2, -sqrt(2)/2]) 163 | >>> my_wavelet = pywt.Wavelet('My Haar Wavelet', filter_bank=my_filter_bank) 164 | 165 | 166 | Note that such custom wavelets **will not** have all the properties set 167 | to correct values: 168 | 169 | >>> print my_wavelet 170 | Wavelet My Haar Wavelet 171 | Family name: 172 | Short name: 173 | Filters length: 2 174 | Orthogonal: False 175 | Biorthogonal: False 176 | Symmetry: unknown 177 | 178 | You can however set a few of them on your own: 179 | 180 | >>> my_wavelet.orthogonal = True 181 | >>> my_wavelet.biorthogonal = True 182 | 183 | >>> print my_wavelet 184 | Wavelet My Haar Wavelet 185 | Family name: 186 | Short name: 187 | Filters length: 2 188 | Orthogonal: True 189 | Biorthogonal: True 190 | Symmetry: unknown 191 | 192 | 193 | And now... the `wavefun`! 194 | ------------------------- 195 | 196 | We all know that the fun with wavelets is in wavelet functions. 197 | Now what would be this package without a tool to compute wavelet 198 | and scaling functions approximations? 199 | 200 | This is the purpose of the :meth:`~Wavelet.wavefun` method, which is used to 201 | approximate scaling function (*phi*) and wavelet function (*psi*) at the given 202 | level of refinement, based on the filters coefficients. 203 | 204 | The number of returned values varies depending on the wavelet's 205 | orthogonality property. For orthogonal wavelets the result is tuple 206 | with scaling function, wavelet function and xgrid coordinates. 207 | 208 | >>> w = pywt.Wavelet('sym3') 209 | >>> w.orthogonal 210 | True 211 | >>> (phi, psi, x) = w.wavefun(level=5) 212 | 213 | For biorthogonal (non-orthogonal) wavelets different scaling and wavelet 214 | functions are used for decomposition and reconstruction, and thus five 215 | elements are returned: decomposition scaling and wavelet functions 216 | approximations, reconstruction scaling and wavelet functions approximations, 217 | and the xgrid. 218 | 219 | >>> w = pywt.Wavelet('bior1.3') 220 | >>> w.orthogonal 221 | False 222 | >>> (phi_d, psi_d, phi_r, psi_r, x) = w.wavefun(level=5) 223 | 224 | .. seealso:: You can find live examples of :meth:`~Wavelet.wavefun` usage and 225 | images of all the built-in wavelets on the 226 | `Wavelet Properties Browser `_ page. 227 | -------------------------------------------------------------------------------- /doc/source/regression/wp.rst: -------------------------------------------------------------------------------- 1 | .. _reg-wp: 2 | 3 | .. currentmodule:: pywt 4 | 5 | Wavelet Packets 6 | =============== 7 | 8 | Import pywt 9 | ----------- 10 | 11 | >>> import pywt 12 | 13 | >>> def format_array(a): 14 | ... """Consistent array representation across different systems""" 15 | ... import numpy 16 | ... a = numpy.where(numpy.abs(a) < 1e-5, 0, a) 17 | ... return numpy.array2string(a, precision=5, separator=' ', suppress_small=True) 18 | 19 | 20 | Create Wavelet Packet structure 21 | ------------------------------- 22 | 23 | Ok, let's create a sample :class:`WaveletPacket`: 24 | 25 | >>> x = [1, 2, 3, 4, 5, 6, 7, 8] 26 | >>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='sym') 27 | 28 | The input *data* and decomposition coefficients are stored in the 29 | :attr:`WaveletPacket.data` attribute: 30 | 31 | >>> print wp.data 32 | [1, 2, 3, 4, 5, 6, 7, 8] 33 | 34 | :class:`Nodes ` are identified by :attr:`paths <~Node.path>`. For the root 35 | node the path is ``''`` and the decomposition level is ``0``. 36 | 37 | >>> print repr(wp.path) 38 | '' 39 | >>> print wp.level 40 | 0 41 | 42 | The *maxlevel*, if not given as param in the constructor, is automatically 43 | computed: 44 | 45 | >>> print wp['ad'].maxlevel 46 | 3 47 | 48 | 49 | Traversing WP tree: 50 | ------------------- 51 | 52 | Accessing subnodes: 53 | ~~~~~~~~~~~~~~~~~~~ 54 | 55 | >>> x = [1, 2, 3, 4, 5, 6, 7, 8] 56 | >>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='sym') 57 | 58 | First check what is the maximum level of decomposition: 59 | 60 | >>> print wp.maxlevel 61 | 3 62 | 63 | and try accessing subnodes of the WP tree: 64 | 65 | * 1st level: 66 | 67 | >>> print wp['a'].data 68 | [ 2.12132034 4.94974747 7.77817459 10.60660172] 69 | >>> print wp['a'].path 70 | a 71 | 72 | * 2nd level: 73 | 74 | >>> print wp['aa'].data 75 | [ 5. 13.] 76 | >>> print wp['aa'].path 77 | aa 78 | 79 | 80 | * 3rd level: 81 | 82 | >>> print wp['aaa'].data 83 | [ 12.72792206] 84 | >>> print wp['aaa'].path 85 | aaa 86 | 87 | 88 | Ups, we have reached the maximum level of decomposition and got an 89 | :exc:`IndexError`: 90 | 91 | >>> print wp['aaaa'].data 92 | Traceback (most recent call last): 93 | ... 94 | IndexError: Path length is out of range. 95 | 96 | Now try some invalid path: 97 | 98 | >>> print wp['ac'] 99 | Traceback (most recent call last): 100 | ... 101 | ValueError: Subnode name must be in ['a', 'd'], not 'c'. 102 | 103 | which just yielded a :exc:`ValueError`. 104 | 105 | 106 | Accessing Node's attributes: 107 | ~~~~~~~~~~~~~~~~~~~~~~~~~~~~ 108 | 109 | :class:`WaveletPacket` object is a tree data structure, which evaluates to a set 110 | of :class:`Node` objects. :class:`WaveletPacket` is just a special subclass 111 | of the :class:`Node` class (which in turn inherits from the :class:`BaseNode`). 112 | 113 | Tree nodes can be accessed using the *obj[x]* (:meth:`Node.__getitem__`) operator. 114 | Each tree node has a set of attributes: :attr:`~Node.data`, :attr:`~Node.path`, 115 | :attr:`~Node.node_name`, :attr:`~Node.parent`, :attr:`~Node.level`, 116 | :attr:`~Node.maxlevel` and :attr:`~Node.mode`. 117 | 118 | >>> x = [1, 2, 3, 4, 5, 6, 7, 8] 119 | >>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='sym') 120 | 121 | >>> print wp['ad'].data 122 | [-2. -2.] 123 | 124 | >>> print wp['ad'].path 125 | ad 126 | 127 | >>> print wp['ad'].node_name 128 | d 129 | 130 | >>> print wp['ad'].parent.path 131 | a 132 | 133 | >>> print wp['ad'].level 134 | 2 135 | 136 | >>> print wp['ad'].maxlevel 137 | 3 138 | 139 | >>> print wp['ad'].mode 140 | sym 141 | 142 | 143 | Collecting nodes 144 | ~~~~~~~~~~~~~~~~ 145 | 146 | >>> x = [1, 2, 3, 4, 5, 6, 7, 8] 147 | >>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='sym') 148 | 149 | 150 | We can get all nodes on the particular level either in ``natural`` order: 151 | 152 | >>> print [node.path for node in wp.get_level(3, 'natural')] 153 | ['aaa', 'aad', 'ada', 'add', 'daa', 'dad', 'dda', 'ddd'] 154 | 155 | or sorted based on the band frequency (``freq``): 156 | 157 | >>> print [node.path for node in wp.get_level(3, 'freq')] 158 | ['aaa', 'aad', 'add', 'ada', 'dda', 'ddd', 'dad', 'daa'] 159 | 160 | Note that :meth:`WaveletPacket.get_level` also performs automatic decomposition 161 | until it reaches the specified *level*. 162 | 163 | 164 | Reconstructing data from Wavelet Packets: 165 | ----------------------------------------- 166 | 167 | >>> x = [1, 2, 3, 4, 5, 6, 7, 8] 168 | >>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='sym') 169 | 170 | 171 | Now create a new :class:`Wavelet Packet ` and set its nodes with 172 | some data. 173 | 174 | >>> new_wp = pywt.WaveletPacket(data=None, wavelet='db1', mode='sym') 175 | 176 | >>> new_wp['aa'] = wp['aa'].data 177 | >>> new_wp['ad'] = [-2., -2.] 178 | 179 | For convenience, :attr:`Node.data` gets automatically extracted from the 180 | :class:`Node` object: 181 | 182 | >>> new_wp['d'] = wp['d'] 183 | 184 | And reconstruct the data from the ``aa``, ``ad`` and ``d`` packets. 185 | 186 | >>> print new_wp.reconstruct(update=False) 187 | [ 1. 2. 3. 4. 5. 6. 7. 8.] 188 | 189 | If the *update* param in the reconstruct method is set to ``False``, the node's 190 | :attr:`~Node.data` will not be updated. 191 | 192 | >>> print new_wp.data 193 | None 194 | 195 | Otherwise, the :attr:`~Node.data` attribute will be set to the reconstructed 196 | value. 197 | 198 | >>> print new_wp.reconstruct(update=True) 199 | [ 1. 2. 3. 4. 5. 6. 7. 8.] 200 | >>> print new_wp.data 201 | [ 1. 2. 3. 4. 5. 6. 7. 8.] 202 | 203 | 204 | >>> print [n.path for n in new_wp.get_leaf_nodes(False)] 205 | ['aa', 'ad', 'd'] 206 | 207 | >>> print [n.path for n in new_wp.get_leaf_nodes(True)] 208 | ['aaa', 'aad', 'ada', 'add', 'daa', 'dad', 'dda', 'ddd'] 209 | 210 | 211 | Removing nodes from Wavelet Packet tree: 212 | ---------------------------------------- 213 | 214 | Let's create a sample data: 215 | 216 | >>> x = [1, 2, 3, 4, 5, 6, 7, 8] 217 | >>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='sym') 218 | 219 | First, start with a tree decomposition at level 2. Leaf nodes in the tree are: 220 | 221 | >>> dummy = wp.get_level(2) 222 | >>> for n in wp.get_leaf_nodes(False): 223 | ... print n.path, format_array(n.data) 224 | aa [ 5. 13.] 225 | ad [-2. -2.] 226 | da [-1. -1.] 227 | dd [ 0. 0.] 228 | 229 | >>> node = wp['ad'] 230 | >>> print node 231 | ad: [-2. -2.] 232 | 233 | To remove a node from the WP tree, use Python's `del obj[x]` 234 | (:class:`Node.__delitem__`): 235 | 236 | >>> del wp['ad'] 237 | 238 | The leaf nodes that left in the tree are: 239 | 240 | >>> for n in wp.get_leaf_nodes(): 241 | ... print n.path, format_array(n.data) 242 | aa [ 5. 13.] 243 | da [-1. -1.] 244 | dd [ 0. 0.] 245 | 246 | And the reconstruction is: 247 | 248 | >>> print wp.reconstruct() 249 | [ 2. 3. 2. 3. 6. 7. 6. 7.] 250 | 251 | Now restore the deleted node value. 252 | 253 | >>> wp['ad'].data = node.data 254 | 255 | Printing leaf nodes and tree reconstruction confirms the original state of the 256 | tree: 257 | 258 | >>> for n in wp.get_leaf_nodes(False): 259 | ... print n.path, format_array(n.data) 260 | aa [ 5. 13.] 261 | ad [-2. -2.] 262 | da [-1. -1.] 263 | dd [ 0. 0.] 264 | 265 | >>> print wp.reconstruct() 266 | [ 1. 2. 3. 4. 5. 6. 7. 8.] 267 | 268 | 269 | Lazy evaluation: 270 | ---------------- 271 | 272 | .. note:: This section is for demonstration of pywt internals purposes 273 | only. Do not rely on the attribute access to nodes as presented in 274 | this example. 275 | 276 | >>> x = [1, 2, 3, 4, 5, 6, 7, 8] 277 | >>> wp = pywt.WaveletPacket(data=x, wavelet='db1', mode='sym') 278 | 279 | 1) At first the wp's attribute `a` is None 280 | 281 | >>> print wp.a 282 | None 283 | 284 | **Remember that you should not rely on the attribute access.** 285 | 286 | 2) At first attempt to access the node it is computed via decomposition 287 | of its parent node (the wp object itself). 288 | 289 | >>> print wp['a'] 290 | a: [ 2.12132034 4.94974747 7.77817459 10.60660172] 291 | 292 | 3) Now the `wp.a` is set to the newly created node: 293 | 294 | >>> print wp.a 295 | a: [ 2.12132034 4.94974747 7.77817459 10.60660172] 296 | 297 | And so is `wp.d`: 298 | 299 | >>> print wp.d 300 | d: [-0.70710678 -0.70710678 -0.70710678 -0.70710678] 301 | -------------------------------------------------------------------------------- /doc/source/resources.rst: -------------------------------------------------------------------------------- 1 | .. _ref-resources: 2 | 3 | ========= 4 | Resources 5 | ========= 6 | 7 | Code 8 | ---- 9 | 10 | The `GitHub repository`_ is now the main 11 | code repository. 12 | 13 | If you are using the Mercurial repository at Bitbucket, please switch 14 | to Git/GitHub and follow for development updates. 15 | 16 | 17 | Questions and bug reports 18 | ------------------------- 19 | 20 | Use `GitHub Issues`_ or `PyWavelets discussions group`_ to post questions 21 | and open tickets. 22 | 23 | 24 | Wavelet Properties Browser 25 | -------------------------- 26 | 27 | Browse properties and graphs of wavelets included in PyWavelets on 28 | `wavelets.pybytes.com`_. 29 | 30 | 31 | Articles 32 | -------- 33 | 34 | - `Denoising: wavelet thresholding `_ 35 | - `Wavelet Regression in Python `_ 36 | 37 | 38 | .. _GitHub repository: https://github.com/nigma/pywt 39 | .. _GitHub Issues: https://github.com/nigma/pywt/issues 40 | .. _PyWavelets discussions group: http://groups.google.com/group/pywavelets 41 | .. _wavelets.pybytes.com: http://wavelets.pybytes.com/ 42 | -------------------------------------------------------------------------------- /doc/source/substitutions.rst: -------------------------------------------------------------------------------- 1 | .. |mode| replace:: Signal extension mode to deal with the border distortion problem. See :ref:`MODES ` for details. 2 | 3 | .. |data| replace:: 4 | Input signal can be NumPy array, Python list or other iterable object. Both *single* and *double* precision floating-point data types are supported and the output type depends on the input type. If the input data is not in one of these types it will be converted to the default *double* precision data format before performing computations. 5 | 6 | .. |wavelet| replace:: 7 | Wavelet to use in the transform. This can be a name of the wavelet from the :func:`wavelist` list or a :class:`Wavelet` object instance. 8 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [build] 2 | #compiler = mingw32 3 | 4 | [bdist_rpm] 5 | release = 1 6 | 7 | [egg_info] 8 | tag_svn_revision = 0 9 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | #-*- coding: utf-8 -*- 3 | 4 | import os 5 | import sys 6 | 7 | try: 8 | from setuptools import setup 9 | has_setuptools = True 10 | except ImportError: 11 | from distutils.core import setup 12 | has_setuptools = False 13 | 14 | from util import commands 15 | 16 | if sys.platform == "darwin": 17 | # Don't create resource files on OS X tar. 18 | os.environ["COPY_EXTENDED_ATTRIBUTES_DISABLE"] = "true" 19 | os.environ["COPYFILE_DISABLE"] = "true" 20 | 21 | dwt = commands.Extension("pywt._pywt", 22 | sources=["src/_pywt.pyx", "src/common.c", "src/convolution.c", 23 | "src/wavelets.c", "src/wt.c"], 24 | include_dirs=["src"], 25 | define_macros=[("PY_EXTENSION", None)], 26 | ) 27 | 28 | ext_modules = [dwt] 29 | packages = ["pywt"] 30 | package_dir = {"pywt": "src/pywt"} 31 | 32 | cmdclass = { 33 | "build_ext": commands.BuildExtCommand, 34 | "sdist": commands.SdistCommand, 35 | "clean_build": commands.CleanCommand, 36 | } 37 | setup_args = {} 38 | 39 | if has_setuptools: 40 | setup_args["zip_safe"] = False 41 | setup_args["test_suite"] = "tests.test_doc.suite" 42 | if not os.path.exists(os.path.join("src", "_pywt.c")): 43 | setup_args["setup_requires"] = ["Cython>=0.16"] 44 | else: 45 | cmdclass["test"] = commands.TestCommand 46 | 47 | setup( 48 | name="PyWavelets", 49 | version="0.2.2", 50 | author="Filip Wasilewski", 51 | author_email="en@ig.ma", 52 | url="http://www.pybytes.com/pywavelets/", 53 | download_url="http://pypi.python.org/pypi/PyWavelets/", 54 | license="MIT", 55 | description="PyWavelets, wavelet transform module", 56 | long_description="""\ 57 | PyWavelets is a Python wavelet transforms module that includes: 58 | 59 | * 1D and 2D Forward and Inverse Discrete Wavelet Transform (DWT and IDWT) 60 | * 1D and 2D Stationary Wavelet Transform (Undecimated Wavelet Transform) 61 | * 1D and 2D Wavelet Packet decomposition and reconstruction 62 | * Computing Approximations of wavelet and scaling functions 63 | * Over seventy built-in wavelet filters and support for custom wavelets 64 | * Single and double precision calculations 65 | * Results compatibility with Matlab Wavelet Toolbox (tm) 66 | """, 67 | keywords=["wavelets", "wavelet transform", "DWT", "SWT", "scientific", 68 | "NumPy"], 69 | classifiers=[ 70 | "Development Status :: 5 - Production/Stable", 71 | "Intended Audience :: Developers", 72 | "Intended Audience :: Education", 73 | "Intended Audience :: Science/Research", 74 | "License :: OSI Approved :: MIT License", 75 | "Operating System :: OS Independent", 76 | "Programming Language :: C", 77 | "Programming Language :: Python", 78 | "Programming Language :: Python :: 2.6", 79 | "Programming Language :: Python :: 2.7", 80 | "Topic :: Software Development :: Libraries :: Python Modules" 81 | ], 82 | ext_modules=ext_modules, 83 | packages=packages, 84 | package_dir=package_dir, 85 | cmdclass=cmdclass, 86 | **setup_args 87 | ) 88 | -------------------------------------------------------------------------------- /src/_pywt.pxi: -------------------------------------------------------------------------------- 1 | cdef extern class _pywt.Wavelet: 2 | cdef Wavelet (*w) 3 | cdef object name 4 | cdef object number 5 | -------------------------------------------------------------------------------- /src/array_interface.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2006-2012 Filip Wasilewski 2 | // See COPYING for license details. 3 | 4 | // Based on http://numeric.scipy.org/array_interface.html by Travis E. Oliphant 5 | // See http://new.scipy.org/Wiki/Cookbook/ArrayStruct_and_Pyrex 6 | 7 | // Array interface (__array_struct__) constants and helpers 8 | 9 | #ifndef _ARRAY_INTERFACE_H_ 10 | #define _ARRAY_INTERFACE_H_ 11 | 12 | #include "Python.h" 13 | 14 | #define __PY_ARRAY_INTERFACE_VERSION__ 0x0002 // TODO: update for SVN's 0x0003 compatibility 15 | 16 | typedef Py_intptr_t intp; 17 | 18 | enum PyGenericArray_KINDS { 19 | PyArrayKind_BOOL = 'b', 20 | PyArrayKind_INT = 'i', 21 | PyArrayKind_UINT = 'u', 22 | PyArrayKind_FLOAT = 'f', 23 | PyArrayKind_COMPLEX = 'c', 24 | PyArrayKind_STRING = 'S', 25 | PyArrayKind_UNICODE = 'U', 26 | PyArrayKind_OBJECT = 'O', 27 | PyArrayKind_RECORD = 'R', 28 | PyArrayKind_VOID = 'V', 29 | PyArrayKind_BIT = 't', 30 | PyArrayKind_OTHER = 'X' 31 | }; 32 | 33 | enum { 34 | GA_CONTIGUOUS =0x001, 35 | GA_FORTRAN =0x010, 36 | GA_ALIGNED =0x100, 37 | GA_NOTSWAPPED =0x200, 38 | GA_WRITEABLE =0x400, 39 | GA_ARR_HAS_DESCR =0x800 40 | }; 41 | 42 | typedef struct { 43 | int two; // equals 2, sanity check 44 | int nd; // number of dimensions 45 | char typekind; // elements kind - PyDimArray_KINDS 46 | int itemsize; // size of each element 47 | int flags; // flags indicating how the data should be interpreted 48 | intp *shape; // A length-nd array of shape information 49 | intp *strides; // A length-nd array of stride information 50 | void *data; // A pointer to the first element of the array 51 | PyObject *descr; // NULL or data-description -- must set ARR_HAS_DESCR flag 52 | } PyGenericArrayInterface; 53 | 54 | #define GA_CONTINUOUS_C_RO (GA_CONTIGUOUS | GA_ALIGNED) 55 | #define GA_CONTINUOUS_C (GA_CONTIGUOUS | GA_ALIGNED | GA_WRITEABLE) 56 | 57 | #define PyArrayInterface_IS_KIND(ai, kind) ((ai->typekind) == kind) 58 | 59 | #define PyArrayInterface_IS_C_ARRAY(ai) ((((ai)->flags) & GA_CONTINUOUS_C) == GA_CONTINUOUS_C) 60 | #define PyArrayInterface_IS_C_ARRAY_RO(ai) ((((ai)->flags) & GA_CONTINUOUS_C_RO) == GA_CONTINUOUS_C_RO) 61 | 62 | #define PyArrayInterface_IS_CONTIGUOUS(ai) (((ai)->flags) & GA_CONTIGUOUS) 63 | #define PyArrayInterface_IS_FORTRAN(ai) (((ai)->flags) & GA_FORTRAN) 64 | #define PyArrayInterface_IS_WRITABLE(ai) (((ai)->flags) & GA_WRITABLE) 65 | #define PyArrayInterface_IS_ALIGNED(ai) (((ai)->flags) & GA_ALIGNED) 66 | #define PyArrayInterface_HAS_DESCR(ai) (((ai)->flags) & GA_ARR_HAS_DESCR) 67 | 68 | #define PyArrayInterface_TWO(ai) ((ai)->two) 69 | #define PyArrayInterface_ND(ai) ((ai)->nd) 70 | #define PyArrayInterface_TYPEKIND(ai) ((ai)->typekind) 71 | #define PyArrayInterface_ITEMSIZE(ai) ((ai)->itemsize) 72 | #define PyArrayInterface_FLAGS(ai) ((ai)->flags) 73 | #define PyArrayInterface_SHAPES(ai) ((ai)->shape) 74 | #define PyArrayInterface_SHAPE(ai, n) ((ai)->shape[n]) 75 | #define PyArrayInterface_STRIDES(ai) ((ai)->strides) 76 | #define PyArrayInterface_STRIDE(ai, n) ((ai)->strides[n]) 77 | #define PyArrayInterface_DATA(ai) ((ai)->data) 78 | #define PyArrayInterface_DESCR(ai) (PyArrayInterface_HAS_DESCR(ai) ? ((ai)->descr) : NULL) 79 | 80 | #define PyArrayInterface_DATA_AS_FLOAT64_C_ARRAY(ai) ( \ 81 | (PyArrayInterface_IS_C_ARRAY(ai) && PyArrayInterface_IS_KIND(ai, PyArrayKind_FLOAT) && (PyArrayInterface_ITEMSIZE(ai) == 8)) \ 82 | ? ((double*)(ai)->data) : NULL ) 83 | 84 | #define PyArrayInterface_DATA_AS_FLOAT64_C_ARRAY_RO(ai) ( \ 85 | (PyArrayInterface_IS_C_ARRAY_RO(ai) && PyArrayInterface_IS_KIND(ai, PyArrayKind_FLOAT) && (PyArrayInterface_ITEMSIZE(ai) == 8)) \ 86 | ? ((double*)(ai)->data) : NULL ) 87 | 88 | #define PyArrayInterface_DATA_AS_FLOAT32_C_ARRAY(ai) ( \ 89 | (PyArrayInterface_IS_C_ARRAY(ai) && PyArrayInterface_IS_KIND(ai, PyArrayKind_FLOAT) && (PyArrayInterface_ITEMSIZE(ai) == 4)) \ 90 | ? ((float*)(ai)->data) : NULL ) 91 | 92 | #define PyArrayInterface_DATA_AS_FLOAT32_C_ARRAY_RO(ai) ( \ 93 | (PyArrayInterface_IS_C_ARRAY_RO(ai) && PyArrayInterface_IS_KIND(ai, PyArrayKind_FLOAT) && (PyArrayInterface_ITEMSIZE(ai) == 4)) \ 94 | ? ((float*)(ai)->data) : NULL ) 95 | 96 | 97 | #define PyArrayInterface_DATA_AS_FLOAT_C_ARRAY_RO(ai) ( \ 98 | (PyArrayInterface_IS_C_ARRAY_RO(ai) && PyArrayInterface_IS_KIND(ai, PyArrayKind_FLOAT) \ 99 | && ((PyArrayInterface_ITEMSIZE(ai) == 4) || (PyArrayInterface_ITEMSIZE(ai) == 8))) \ 100 | ? ((void*)(ai)->data) : NULL ) 101 | 102 | #define PyArrayInterface_DATA_AS_FLOAT_C_ARRAY(ai) ( \ 103 | (PyArrayInterface_IS_C_ARRAY(ai) && PyArrayInterface_IS_KIND(ai, PyArrayKind_FLOAT) \ 104 | && ((PyArrayInterface_ITEMSIZE(ai) == 4) || (PyArrayInterface_ITEMSIZE(ai) == 8))) \ 105 | ? ((void*)(ai)->data) : NULL ) 106 | 107 | 108 | #define PyArrayInterface_CHECK(ai) (PyArrayInterface_TWO(ai) == 2) 109 | #define PyArrayInterface_CHECK_1D(ai) (PyArrayInterface_CHECK(ai) && PyArrayInterface_ND(ai) == 1) 110 | #define PyArrayInterface_CHECK_2D(ai) (PyArrayInterface_CHECK(ai) && PyArrayInterface_ND(ai) == 2) 111 | 112 | #endif 113 | -------------------------------------------------------------------------------- /src/arraytools.pxi: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2006-2012 Filip Wasilewski 2 | # See COPYING for license details. 3 | 4 | cdef enum DTYPE: # itemsize 5 | FLOAT32 = 4 6 | FLOAT64 = 8 7 | 8 | cdef struct Buffer: 9 | void* data 10 | index_t len 11 | DTYPE dtype 12 | 13 | cdef object memory_buffer_object(Py_ssize_t length, DTYPE dtype): 14 | if dtype == FLOAT64: 15 | return float64_memory_buffer_object(length) 16 | elif dtype == FLOAT32: 17 | return float32_memory_buffer_object(length) 18 | else: 19 | raise ValueError("dtype must be in (%s, %s), not %s." % (FLOAT32, FLOAT64, dtype)) 20 | 21 | ############################################################################### 22 | # buffer objects handling 23 | 24 | #void** buffer_addr, index_t* buffer_len, unsigned int* itemsize 25 | 26 | cdef int array_object_as_float_buffer(object source, Buffer* buffer, char rwmode) except -1: 27 | # Get object buffer for reading (rwmode = 'r') or writing (rwmode = 'w') 28 | # 29 | # source - source object exposing array interface 30 | # buffer_addr - will be set on success to 31 | # buffer_len - set to buffer length 32 | # itemsize - set to item size (4 for float32, 8 for float 64) 33 | # rwmode - read/write mode 34 | # 35 | # returns - 0 - ok 36 | # - -1 - no __array_struct__ attr 37 | # - -2, -3, -4 - other errors 38 | 39 | # TODO: extract and create object wrapper? 40 | # TODO: raise exceptions instead of return negative values? 41 | 42 | cdef c_array_interface.PyGenericArrayInterface* array_struct 43 | cdef object cobject 44 | cdef void* data 45 | cdef index_t data_len 46 | 47 | if hasattr(source, '__array_struct__'): 48 | cobject = source.__array_struct__ 49 | if c_python.PyCObject_Check(cobject): 50 | array_struct = c_python.PyCObject_AsVoidPtr(cobject) 51 | if not (c_array_interface.PyArrayInterface_CHECK_1D(array_struct)): 52 | raise ValueError("1D array expected.") 53 | return -1 54 | data_len = c_array_interface.PyArrayInterface_SHAPE(array_struct, 0) 55 | if data_len < 1: 56 | raise ValueError("invalid data size - %s." % data_len) 57 | return -1 58 | buffer.len = data_len 59 | 60 | if rwmode == c'w': 61 | data = c_array_interface.PyArrayInterface_DATA_AS_FLOAT_C_ARRAY(array_struct) 62 | elif rwmode == c'r': 63 | data = c_array_interface.PyArrayInterface_DATA_AS_FLOAT_C_ARRAY_RO(array_struct) 64 | else: 65 | raise ValueError("rwmode value not in (c'r', c'w').") 66 | return -1 67 | 68 | if data is NULL: 69 | return -2 # not C contiguous array or data type is not double or float, fail silently 70 | 71 | buffer.data = data 72 | buffer.dtype = c_array_interface.PyArrayInterface_ITEMSIZE(array_struct) 73 | assert buffer.dtype == FLOAT32 or buffer.dtype == FLOAT64 74 | 75 | return 0 # ok 76 | return -2 # not cobject, fail silently 77 | return -2 # no __array_struct__ attr, fail silently 78 | 79 | cdef object array_as_buffer(object input, Buffer* buffer, char mode): 80 | cdef object alt_input 81 | if array_object_as_float_buffer(input, buffer, mode) < 0: 82 | # try to convert the input 83 | alt_input = contiguous_float64_array_from_any(input) 84 | if array_object_as_float_buffer(alt_input, buffer, mode) < 0: 85 | raise TypeError("Invalid data type. 1D array or list object required.") 86 | return alt_input # return reference to the new object. This reference must 87 | # be kept until processing is finished! 88 | return input 89 | 90 | cdef object float64_array_to_list(double* data, index_t n): 91 | cdef index_t i 92 | cdef object app 93 | cdef object ret 94 | ret = [] 95 | app = ret.append 96 | for i from 0 <= i < n: 97 | app(data[i]) 98 | return ret 99 | 100 | 101 | #cdef int copy_object_to_float32_array(source, float* dest) except -1: 102 | #cdef index_t i 103 | #cdef index_t n 104 | #try: 105 | #n = len(source) 106 | #for i from 0 <= i < n: 107 | #dest[i] = source[i] 108 | #except Exception, e: 109 | #raise 110 | #return -1 111 | #return 0 112 | 113 | 114 | cdef void copy_object_to_float64_array(source, double* dest) except *: 115 | cdef index_t i 116 | cdef double x 117 | i = 0 118 | for x in source: 119 | dest[i] = x 120 | i = i + 1 121 | 122 | cdef void copy_object_to_float32_array(source, float* dest) except *: 123 | cdef index_t i 124 | cdef float x 125 | i = 0 126 | for x in source: 127 | dest[i] = x 128 | i = i + 1 129 | -------------------------------------------------------------------------------- /src/c_array_interface.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2006-2012 Filip Wasilewski 2 | # See COPYING for license details. 3 | 4 | # see http://numeric.scipy.org/array_interface.html 5 | # see http://new.scipy.org/Wiki/Cookbook/ArrayStruct_and_Pyrex 6 | 7 | cimport c_python 8 | 9 | cdef extern from "array_interface.h": 10 | 11 | ctypedef c_python.Py_intptr_t intp 12 | 13 | ctypedef struct PyGenericArrayInterface: 14 | int two # contains array interface version number (min. 2) 15 | int nd # number of dimensions 16 | char typekind # kind in array --- character code of typestr 17 | int itemsize # size of each element 18 | int flags # flags indicating how the data should be interpreted 19 | c_python.Py_intptr_t *shape # A length-nd array of shape information 20 | c_python.Py_intptr_t *strides # A length-nd array of stride information 21 | void *data # A pointer to the first element of the array 22 | c_python.PyObject* descr # NULL or data-description -- must set ARR_HAS_DESCR flag 23 | 24 | ctypedef enum PyGenericArray_KINDS: 25 | PyArrayKind_BOOL 26 | PyArrayKind_INT 27 | PyArrayKind_UINT 28 | PyArrayKind_FLOAT 29 | PyArrayKind_COMPLEX 30 | PyArrayKind_STRING 31 | PyArrayKind_UNICODE 32 | PyArrayKind_OBJECT 33 | PyArrayKind_RECORD 34 | PyArrayKind_VOID 35 | PyArrayKind_BIT 36 | PyArrayKind_OTHER 37 | 38 | ctypedef enum PyGenericArray_FLAGS: 39 | GA_CONTIGUOUS 40 | GA_FORTRAN 41 | GA_ALIGNED 42 | GA_NOTSWAPPED 43 | GA_WRITEABLE 44 | GA_ARR_HAS_DESCR 45 | 46 | cdef double* PyArrayInterface_DATA_AS_FLOAT64_C_ARRAY(PyGenericArrayInterface* ) 47 | cdef double* PyArrayInterface_DATA_AS_FLOAT64_C_ARRAY_RO(PyGenericArrayInterface* ) 48 | 49 | cdef float* PyArrayInterface_DATA_AS_FLOAT32_C_ARRAY(PyGenericArrayInterface* ) 50 | cdef float* PyArrayInterface_DATA_AS_FLOAT32_C_ARRAY_RO(PyGenericArrayInterface* ) 51 | 52 | cdef void* PyArrayInterface_DATA_AS_FLOAT_C_ARRAY(PyGenericArrayInterface* ) 53 | cdef void* PyArrayInterface_DATA_AS_FLOAT_C_ARRAY_RO(PyGenericArrayInterface* ) 54 | 55 | cdef int PyArrayInterface_IS_C_ARRAY(PyGenericArrayInterface* ) 56 | cdef int PyArrayInterface_IS_C_ARRAY_RO(PyGenericArrayInterface* ) 57 | 58 | cdef int PyArrayInterface_CHECK(PyGenericArrayInterface* ) 59 | cdef int PyArrayInterface_CHECK_1D(PyGenericArrayInterface* ) 60 | cdef int PyArrayInterface_CHECK_2D(PyGenericArrayInterface* ) 61 | 62 | cdef int PyArrayInterface_IS_KIND(PyGenericArrayInterface* , char) 63 | 64 | int PyArrayInterface_TWO(PyGenericArrayInterface*) 65 | int PyArrayInterface_ND(PyGenericArrayInterface*) 66 | char PyArrayInterface_TYPEKIND(PyGenericArrayInterface*) 67 | int PyArrayInterface_ITEMSIZE(PyGenericArrayInterface*) 68 | int PyArrayInterface_FLAGS(PyGenericArrayInterface*) 69 | c_python.Py_intptr_t * PyArrayInterface_SHAPES(PyGenericArrayInterface*) 70 | c_python.Py_intptr_t PyArrayInterface_SHAPE(PyGenericArrayInterface*, int) 71 | c_python.Py_intptr_t * PyArrayInterface_STRIDES(PyGenericArrayInterface*) 72 | c_python.Py_intptr_t PyArrayInterface_STRIDE(PyGenericArrayInterface*, int) 73 | void* PyArrayInterface_DATA(PyGenericArrayInterface*) 74 | c_python.PyObject* PyArrayInterface_DESCR(PyGenericArrayInterface*) 75 | -------------------------------------------------------------------------------- /src/c_math.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2006-2012 Filip Wasilewski 2 | # See COPYING for license details. 3 | 4 | cdef extern from "math.h": 5 | double sqrt (double x) 6 | double exp (double x) 7 | double pow (double x, double y) 8 | -------------------------------------------------------------------------------- /src/c_python.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2006-2012 Filip Wasilewski 2 | # See COPYING for license details. 3 | 4 | cdef extern from "Python.h": 5 | 6 | # typedefs 7 | ctypedef long size_t 8 | ctypedef int Py_intptr_t 9 | 10 | # structs 11 | ctypedef struct _typeobject: 12 | pass 13 | ctypedef struct PyObject: 14 | _typeobject* ob_type 15 | #pass 16 | 17 | # memory 18 | void* PyMem_Malloc(size_t n) 19 | void PyMem_Free(void* mem) 20 | object PyErr_NoMemory() 21 | 22 | void Py_DECREF(object) 23 | void Py_XDECREF(object) 24 | void Py_INCREF(object obj) 25 | void Py_XINCREF(object obj) 26 | 27 | # bool 28 | object PyBool_FromLong(long) 29 | 30 | # int 31 | object PyInt_FromLong(long v) 32 | long PyInt_AsLong(object io) 33 | 34 | # float 35 | #PyObject* PyFloat_FromDouble(double v) 36 | double PyFloat_AsDouble(PyObject* pyfloat) except? -1 # notice PyObject* 37 | # string 38 | object PyString_FromString(char*) 39 | object PyString_FromStringAndSize(char *v, int len) 40 | 41 | # list 42 | int PyList_Check(object p) 43 | int PyList_CheckExact(object p) 44 | object PyList_New( int len) 45 | int PyList_Size(object list) 46 | object PyList_GetItem(object list, int index) 47 | PyObject* PyList_GET_ITEM(object list, int index) # notice PyObject* 48 | int PyList_SetItem(object list, int index, PyObject* item) # notice PyObject* 49 | int PyList_Append(object list, object item) 50 | 51 | # tuple 52 | object PyTuple_New(int len) 53 | int PyTuple_Check(object p) 54 | int PyTuple_Size(object p) 55 | PyObject* PyTuple_GET_ITEM(object p, int pos) # notice PyObject* 56 | object PyTuple_GetItem(object p, int pos) 57 | void PyTuple_SET_ITEM(object p, int pos, object o) 58 | 59 | 60 | 61 | 62 | # cobject 63 | int PyCObject_Check(object p) 64 | object PyCObject_FromVoidPtrAndDesc(void* cobj, void* desc, void (*destr)(void *, void *)) 65 | void* PyCObject_AsVoidPtr(object cobj) 66 | 67 | 68 | # c buffer 69 | int PyObject_AsReadBuffer(object, void **rbuf, int *len) 70 | int PyObject_AsWriteBuffer(object, void **rbuf, int *len) 71 | 72 | 73 | PyObject* PyObject_GetAttrString(object, char*) 74 | object PyObject_GetAttr(object, char*) 75 | int PyObject_HasAttrString(object, char*) 76 | 77 | ctypedef struct PyTypeObject: 78 | pass 79 | ctypedef PyTypeObject PyInt_Type 80 | 81 | int PyObject_IsInstance(object inst, object cls) 82 | int PyObject_TypeCheck(object obj, PyTypeObject* type) 83 | 84 | int PyInt_Check(object o) 85 | 86 | 87 | PyObject* PyErr_Occurred() 88 | void PyErr_Print() 89 | void PyErr_Clear() 90 | 91 | 92 | 93 | -------------------------------------------------------------------------------- /src/c_string.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2006-2012 Filip Wasilewski 2 | # See COPYING for license details. 3 | 4 | cdef extern from "string.h": 5 | ctypedef long size_t 6 | void *memcpy(void *dst,void *src,size_t len) 7 | void *memmove(void *dst,void *src,size_t len) 8 | char *strdup(char *) 9 | -------------------------------------------------------------------------------- /src/c_wt.template.pxd: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2006-2012 Filip Wasilewski 2 | # See COPYING for license details. 3 | 4 | cdef extern from "common.h": 5 | 6 | ctypedef int index_t 7 | ctypedef int const_index_t 8 | 9 | cdef void* wtmalloc(long size) 10 | cdef void* wtcalloc(long len, long size) 11 | cdef void wtfree(void* ptr) 12 | 13 | ctypedef enum MODE: 14 | MODE_INVALID = -1 15 | MODE_ZEROPAD = 0 16 | MODE_SYMMETRIC 17 | MODE_ASYMMETRIC 18 | MODE_CONSTANT_EDGE 19 | MODE_SMOOTH 20 | MODE_PERIODIC 21 | MODE_PERIODIZATION 22 | MODE_MAX 23 | 24 | 25 | # buffers lengths 26 | cdef index_t dwt_buffer_length(index_t input_len, index_t filter_len, MODE mode) 27 | cdef index_t upsampling_buffer_length(index_t coeffs_len, index_t filter_len, MODE mode) 28 | cdef index_t idwt_buffer_length(index_t coeffs_len, index_t filter_len, MODE mode) 29 | cdef index_t swt_buffer_length(index_t coeffs_len) 30 | cdef index_t reconstruction_buffer_length(index_t coeffs_len, index_t filter_len) 31 | 32 | # max dec levels 33 | cdef int dwt_max_level(index_t input_len, index_t filter_len) 34 | cdef int swt_max_level(index_t input_len) 35 | 36 | 37 | cdef extern from "wavelets.h": 38 | 39 | ctypedef enum SYMMETRY: 40 | ASYMMETRIC 41 | NEAR_SYMMETRIC 42 | SYMMETRIC 43 | 44 | ctypedef struct Wavelet: 45 | //## FOR $DTYPE$ IN (double, float): 46 | $DTYPE$* dec_hi_$DTYPE$ # highpass decomposition 47 | $DTYPE$* dec_lo_$DTYPE$ # lowpass decomposition 48 | $DTYPE$* rec_hi_$DTYPE$ # highpass reconstruction 49 | $DTYPE$* rec_lo_$DTYPE$ # lowpass reconstruction 50 | //## ENDFOR $DTYPE$ 51 | 52 | index_t dec_len # length of decomposition filter 53 | index_t rec_len # length of reconstruction filter 54 | 55 | index_t dec_hi_offset 56 | index_t dec_lo_offset 57 | index_t rec_hi_offset 58 | index_t rec_lo_offset 59 | 60 | int vanishing_moments_psi 61 | int vanishing_moments_phi 62 | index_t support_width 63 | 64 | int orthogonal 65 | int biorthogonal 66 | 67 | int symmetry 68 | 69 | int compact_support 70 | 71 | int _builtin 72 | 73 | char* family_name 74 | char* short_name 75 | 76 | 77 | cdef Wavelet* wavelet(char name, int type) 78 | cdef Wavelet* blank_wavelet(index_t filter_length) 79 | cdef void free_wavelet(Wavelet* wavelet) 80 | 81 | 82 | cdef extern from "wt.h": 83 | 84 | //## FOR $DTYPE$ IN (double, float): 85 | 86 | cdef int $DTYPE$_dec_a($DTYPE$ input[], index_t input_len, Wavelet* wavelet, $DTYPE$ output[], index_t output_len, MODE mode) 87 | cdef int $DTYPE$_dec_d($DTYPE$ input[], index_t input_len, Wavelet* wavelet, $DTYPE$ output[], index_t output_len, MODE mode) 88 | 89 | cdef int $DTYPE$_rec_a($DTYPE$ coeffs_a[], index_t coeffs_len, Wavelet* wavelet, $DTYPE$ output[], index_t output_len) 90 | cdef int $DTYPE$_rec_d($DTYPE$ coeffs_d[], index_t coeffs_len, Wavelet* wavelet, $DTYPE$ output[], index_t output_len) 91 | 92 | cdef int $DTYPE$_idwt($DTYPE$ coeffs_a[], index_t coeffs_a_len, $DTYPE$ coeffs_d[], index_t coeffs_d_len, 93 | Wavelet* wavelet, $DTYPE$ output[], index_t output_len, MODE mode, int correct_size) 94 | 95 | cdef int $DTYPE$_swt_a($DTYPE$ input[], index_t input_len, Wavelet* wavelet, $DTYPE$ output[], index_t output_len, int level) 96 | cdef int $DTYPE$_swt_d($DTYPE$ input[], index_t input_len, Wavelet* wavelet, $DTYPE$ output[], index_t output_len, int level) 97 | 98 | //## ENDFOR $DTYPE$ 99 | 100 | -------------------------------------------------------------------------------- /src/common.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2006-2012 Filip Wasilewski 2 | // See COPYING for license details. 3 | 4 | #include "common.h" 5 | 6 | #ifdef PY_EXTENSION 7 | void *wtcalloc(size_t len, size_t size){ 8 | void *p = wtmalloc(len*size); 9 | if(p) 10 | memset(p, 0, len*size); 11 | return p; 12 | } 13 | #endif 14 | 15 | // buffers and max levels params 16 | 17 | index_t dwt_buffer_length(index_t input_len, index_t filter_len, MODE mode){ 18 | if(input_len < 1 || filter_len < 1) 19 | return 0; 20 | 21 | switch(mode){ 22 | case MODE_PERIODIZATION: 23 | return (index_t) ceil(input_len / 2.0); 24 | default: 25 | return (index_t) floor((input_len + filter_len - 1) / 2.0); 26 | } 27 | } 28 | 29 | index_t reconstruction_buffer_length(index_t coeffs_len, index_t filter_len){ 30 | if(coeffs_len < 1 || filter_len < 1) 31 | return 0; 32 | 33 | return 2*coeffs_len+filter_len-2; 34 | } 35 | 36 | index_t idwt_buffer_length(index_t coeffs_len, index_t filter_len, MODE mode){ 37 | if(coeffs_len < 0 || filter_len < 0) 38 | return 0; 39 | 40 | switch(mode){ 41 | case MODE_PERIODIZATION: 42 | return 2*coeffs_len; 43 | default: 44 | return 2*coeffs_len-filter_len+2; 45 | } 46 | } 47 | 48 | index_t swt_buffer_length(index_t input_len){ 49 | if(input_len < 0) 50 | return 0; 51 | 52 | return input_len; 53 | } 54 | 55 | int dwt_max_level(index_t input_len, index_t filter_len){ 56 | int i; 57 | if(input_len < 1 || filter_len < 2) 58 | return 0; 59 | 60 | i = (int) floor(log((double)input_len/(double)(filter_len-1)) /log(2.0)); 61 | return (i > 0) ? i : 0; 62 | } 63 | 64 | int swt_max_level(index_t input_len){ 65 | int i, j; 66 | i = (int) floor(log((double) input_len)/log(2.0)); 67 | 68 | // check how many times (maximum i times) input_len is divisible by 2 69 | for(j=0; j <= i; ++j){ 70 | if((input_len & 0x1)==1) 71 | return j; 72 | input_len >>= 1; 73 | } 74 | return (i > 0) ? i : 0; 75 | } 76 | -------------------------------------------------------------------------------- /src/common.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2006-2012 Filip Wasilewski 2 | // See COPYING for license details. 3 | 4 | // Common constants, typedefs and functions 5 | 6 | #ifndef _COMMON_H_ 7 | #define _COMMON_H_ 8 | 9 | #include 10 | #include 11 | #include 12 | 13 | 14 | /////////////////////////////////////////////////////////////////////////////// 15 | // Typedefs 16 | 17 | #ifdef PY_EXTENSION 18 | // another declaration is in .c file generated by Pyrex 19 | #ifndef PY_SSIZE_T_CLEAN 20 | #define PY_SSIZE_T_CLEAN 21 | #include "Python.h" 22 | #include "structmember.h" 23 | #ifndef PY_LONG_LONG 24 | #define PY_LONG_LONG LONG_LONG 25 | #endif 26 | #if PY_VERSION_HEX < 0x02050000 27 | typedef int Py_ssize_t; 28 | #define PY_SSIZE_T_MAX INT_MAX 29 | #define PY_SSIZE_T_MIN INT_MIN 30 | #define PyInt_FromSsize_t(z) PyInt_FromLong(z) 31 | #define PyInt_AsSsize_t(o) PyInt_AsLong(o) 32 | #endif 33 | #else 34 | #include "Python.h" 35 | #endif 36 | 37 | typedef Py_ssize_t index_t; 38 | 39 | // using Python's memory manager 40 | #define wtmalloc(size) PyMem_Malloc(size) 41 | #define wtfree(ptr) PyMem_Free(ptr) 42 | void *wtcalloc(size_t, size_t); 43 | #else 44 | typedef int index_t; 45 | // standard c memory management 46 | #define wtmalloc(size) malloc(size) 47 | #define wtfree(ptr) free(ptr) 48 | #define wtcalloc(len, size) calloc(len, size) 49 | #endif 50 | 51 | 52 | typedef const index_t const_index_t; 53 | 54 | 55 | // Signal extension modes 56 | typedef enum { 57 | MODE_INVALID = -1, 58 | MODE_ZEROPAD = 0, // default, signal extended with zeros 59 | MODE_SYMMETRIC, // signal extended symmetrically (mirror) 60 | MODE_CONSTANT_EDGE, // signal extended with the border value 61 | MODE_SMOOTH, // linear extrapolation (first derivative) 62 | MODE_PERIODIC, // signal is treated as being periodic 63 | MODE_PERIODIZATION, // signal is treated as being periodic, minimal output lenght 64 | MODE_MAX, 65 | MODE_ASYMMETRIC // TODO 66 | } MODE; 67 | 68 | 69 | /////////////////////////////////////////////////////////////////////////////// 70 | // Calculating buffer lengths for various operations 71 | 72 | // Length of DWT coeffs for specified input data length, filter length and 73 | // signal extension mode 74 | 75 | index_t dwt_buffer_length(index_t input_len, index_t filter_len, MODE mode); 76 | 77 | // Length of reconstructed signal for specified input coeffs length and filter 78 | // length. It is used for direct reconstruction from coefficients (normal 79 | // convolution of upsampled coeffs with filter). 80 | 81 | index_t reconstruction_buffer_length(index_t coeffs_len, index_t filter_len); 82 | 83 | // Length of IDWT reconstructed signal for specified input coeffs length, filter 84 | // length and extension mode. 85 | 86 | index_t idwt_buffer_length(index_t coeffs_len, index_t filter_len, MODE mode); 87 | 88 | // Length of SWT coefficients for specified input signal length. 89 | // Equals to input_len 90 | 91 | index_t swt_buffer_length(index_t input_len); 92 | 93 | 94 | /////////////////////////////////////////////////////////////////////////////// 95 | // Maximum useful level of DWT decomposition. 96 | 97 | int dwt_max_level(index_t input_len, index_t filter_len); 98 | 99 | 100 | /////////////////////////////////////////////////////////////////////////////// 101 | // Maximum useful level of SWT decomposition. 102 | 103 | int swt_max_level(index_t input_len); 104 | 105 | 106 | #endif //_COMMON_H_ 107 | -------------------------------------------------------------------------------- /src/convolution.template.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2006-2012 Filip Wasilewski 2 | // See COPYING for license details. 3 | 4 | #ifndef _CONVOLUTION_H_ 5 | #define _CONVOLUTION_H_ 6 | 7 | #include 8 | #include "common.h" 9 | 10 | 11 | /////////////////////////////////////////////////////////////////////////////// 12 | // Performs convolution of input with filter and downsamples by taking every 13 | // step-th element from the result. 14 | // 15 | // input - input data 16 | // N - input data length 17 | // filter - filter data 18 | // F - filter data length 19 | // output - output data 20 | // step - decimation step 21 | // mode - signal extension mode 22 | 23 | // memory efficient version 24 | 25 | //##FOR $DTYPE$ in (double, float): 26 | int $DTYPE$_downsampling_convolution(const $DTYPE$* input, const_index_t N, const $DTYPE$* filter, const_index_t F, $DTYPE$* output, const_index_t step, MODE mode); 27 | //##ENDFOR $DTYPE$ 28 | 29 | // Straightforward implementation with memory reallocation - for very short signals (shorter than filter). 30 | // This id called from downsampling_convolution 31 | 32 | //##FOR $DTYPE$ in (double, float): 33 | int $DTYPE$_allocating_downsampling_convolution(const $DTYPE$* input, const_index_t N, const $DTYPE$* filter, const_index_t F, $DTYPE$* output, const_index_t step, MODE mode); 34 | //##ENDFOR $DTYPE$ 35 | 36 | // standard convolution 37 | // decimation step = 1 38 | 39 | //##FOR $DTYPE$ in (double, float): 40 | // #define $DTYPE$_convolution(data, data_len, filter, filter_len, output) $DTYPE$_downsampling_convolution(data, data_len, filter, filter_len, output, 1, MODE_ZEROPAD); 41 | //##ENDFOR $DTYPE$ 42 | 43 | /////////////////////////////////////////////////////////////////////////////// 44 | // Performs normal (full) convolution of "upsampled" input coeffs array with filter 45 | // Requires zero-filled output buffer (adds values instead of overwriting - can 46 | // be called many times with the same output). 47 | // 48 | // input - input data 49 | // N - input data length 50 | // filter - filter data 51 | // F - filter data length 52 | // output - output data 53 | // O - output lenght (currently not used) 54 | // mode - signal extension mode 55 | 56 | //##FOR $DTYPE$ in (double, float): 57 | int $DTYPE$_upsampling_convolution_full(const $DTYPE$* input, const_index_t N, const $DTYPE$* filter, const_index_t F, $DTYPE$* output, const_index_t O); 58 | //##ENDFOR $DTYPE$ 59 | 60 | // Performs valid convolution (signals must overlap) 61 | // Extends (virtually) input for MODE_PERIODIZATION. 62 | 63 | //##FOR $DTYPE$ in (double, float): 64 | int $DTYPE$_upsampling_convolution_valid_sf(const $DTYPE$* input, const_index_t N, const $DTYPE$* filter, const_index_t F, $DTYPE$* output, const_index_t O, MODE mode); 65 | //##ENDFOR $DTYPE$ 66 | 67 | // TODO 68 | // for SWT 69 | // int upsampled_filter_convolution(const $DTYPE$* input, const int N, const $DTYPE$* filter, const int F, $DTYPE$* output, int step, int mode); 70 | 71 | #endif 72 | -------------------------------------------------------------------------------- /src/pywt/__init__.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | # flake8: noqa 3 | 4 | # Copyright (c) 2006-2012 Filip Wasilewski 5 | # See COPYING for license details. 6 | 7 | """ 8 | Discrete forward and inverse wavelet transform, stationary wavelet transform, 9 | wavelet packets signal decomposition and reconstruction module. 10 | """ 11 | 12 | import _pywt, multilevel, multidim, wavelet_packets, functions 13 | from _pywt import * 14 | from multilevel import * 15 | from multidim import * 16 | from wavelet_packets import * 17 | from functions import * 18 | import thresholding 19 | 20 | __all__ = [] 21 | __all__ += _pywt.__all__ 22 | __all__ += wavelet_packets.__all__ 23 | __all__ += multilevel.__all__ 24 | __all__ += multidim.__all__ 25 | __all__ += functions.__all__ 26 | __all__ += ['thresholding'] 27 | 28 | del multilevel, multidim, wavelet_packets, functions 29 | -------------------------------------------------------------------------------- /src/pywt/functions.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (c) 2006-2012 Filip Wasilewski 4 | # See COPYING for license details. 5 | 6 | """ 7 | Other wavelet related functions. 8 | """ 9 | 10 | __all__ = ["intwave", "centfrq", "scal2frq", "qmf", "orthfilt"] 11 | 12 | from math import sqrt 13 | 14 | from _pywt import Wavelet 15 | 16 | from numerix import asarray, array, float64 17 | from numerix import integrate 18 | from numerix import argmax 19 | from numerix import fft 20 | 21 | WAVELET_CLASSES = (Wavelet) 22 | 23 | 24 | def wavelet_for_name(name): 25 | if not isinstance(name, basestring): 26 | raise TypeError( 27 | "Wavelet name must be of string type, not %s" % type(name)) 28 | try: 29 | wavelet = Wavelet(name) 30 | except ValueError: 31 | raise 32 | #raise ValueError("Invalid wavelet name - %s." % name) 33 | return wavelet 34 | 35 | 36 | def intwave(wavelet, precision=8): 37 | """ 38 | intwave(wavelet, precision=8) -> [int_psi, x] 39 | - for orthogonal wavelets 40 | 41 | intwave(wavelet, precision=8) -> [int_psi_d, int_psi_r, x] 42 | - for other wavelets 43 | 44 | intwave((function_approx, x), precision=8) -> [int_function, x] 45 | - for (function approx., x grid) pair 46 | 47 | Integrate *psi* wavelet function from -Inf to x using the rectangle 48 | integration method. 49 | 50 | wavelet - Wavelet to integrate (Wavelet object, wavelet name string 51 | or (wavelet function approx., x grid) pair) 52 | 53 | precision = 8 - Precision that will be used for wavelet function 54 | approximation computed with the wavefun(level=precision) 55 | Wavelet's method. 56 | 57 | (function_approx, x) - Function to integrate on the x grid. Used instead 58 | of Wavelet object to allow custom wavelet functions. 59 | """ 60 | 61 | if isinstance(wavelet, tuple): 62 | psi, x = asarray(wavelet[0]), asarray(wavelet[1]) 63 | step = x[1] - x[0] 64 | return integrate(psi, step), x 65 | 66 | else: 67 | if not isinstance(wavelet, WAVELET_CLASSES): 68 | wavelet = wavelet_for_name(wavelet) 69 | 70 | functions_approximations = wavelet.wavefun(precision) 71 | if len(functions_approximations) == 2: # continuous wavelet 72 | psi, x = functions_approximations 73 | step = x[1] - x[0] 74 | return integrate(psi, step), x 75 | elif len(functions_approximations) == 3: # orthogonal wavelet 76 | phi, psi, x = functions_approximations 77 | step = x[1] - x[0] 78 | return integrate(psi, step), x 79 | else: # biorthogonal wavelet 80 | phi_d, psi_d, phi_r, psi_r, x = functions_approximations 81 | step = x[1] - x[0] 82 | return integrate(psi_d, step), integrate(psi_r, step), x 83 | 84 | 85 | def centfrq(wavelet, precision=8): 86 | """ 87 | centfrq(wavelet, precision=8) -> float 88 | - for orthogonal wavelets 89 | 90 | centfrq((function_approx, x), precision=8) -> float 91 | - for (function approx., x grid) pair 92 | 93 | Computes the central frequency of the *psi* wavelet function. 94 | 95 | wavelet - Wavelet (Wavelet object, wavelet name string 96 | or (wavelet function approx., x grid) pair) 97 | precision = 8 - Precision that will be used for wavelet function 98 | approximation computed with the wavefun(level=precision) 99 | Wavelet's method. 100 | 101 | (function_approx, xgrid) - Function defined on xgrid. Used instead 102 | of Wavelet object to allow custom wavelet functions. 103 | """ 104 | 105 | if isinstance(wavelet, tuple): 106 | psi, x = asarray(wavelet[0]), asarray(wavelet[1]) 107 | else: 108 | if not isinstance(wavelet, WAVELET_CLASSES): 109 | wavelet = wavelet_for_name(wavelet) 110 | functions_approximations = wavelet.wavefun(precision) 111 | 112 | if len(functions_approximations) == 2: 113 | psi, x = functions_approximations 114 | else: 115 | # (psi, x) for (phi, psi, x) 116 | # (psi_d, x) for (phi_d, psi_d, phi_r, psi_r, x) 117 | psi, x = functions_approximations[1], functions_approximations[-1] 118 | 119 | domain = float(x[-1] - x[0]) 120 | assert domain > 0 121 | 122 | index = argmax(abs(fft(psi)[1:])) + 2 123 | if index > len(psi) / 2: 124 | index = len(psi) - index + 2 125 | 126 | return 1.0 / (domain / (index - 1)) 127 | 128 | 129 | def scal2frq(wavelet, scale, delta, precision=8): 130 | """ 131 | scal2frq(wavelet, scale, delta, precision=8) -> float 132 | - for orthogonal wavelets 133 | 134 | scal2frq(wavelet, scale, delta, precision=8) -> float 135 | - for (function approx., x grid) pair 136 | 137 | wavelet 138 | scale 139 | delta - sampling 140 | """ 141 | return centfrq(wavelet, precision=precision) / (scale * delta) 142 | 143 | 144 | def qmf(filter): 145 | filter = array(filter)[::-1] 146 | filter[1::2] = -filter[1::2] 147 | return filter 148 | 149 | 150 | def orthfilt(scaling_filter): 151 | assert len(scaling_filter) % 2 == 0 152 | 153 | scaling_filter = asarray(scaling_filter, dtype=float64) 154 | 155 | rec_lo = sqrt(2) * scaling_filter / sum(scaling_filter) 156 | dec_lo = rec_lo[::-1] 157 | 158 | rec_hi = qmf(rec_lo) 159 | dec_hi = rec_hi[::-1] 160 | 161 | return (dec_lo, dec_hi, rec_lo, rec_hi) 162 | -------------------------------------------------------------------------------- /src/pywt/multilevel.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (c) 2006-2012 Filip Wasilewski 4 | # See COPYING for license details. 5 | 6 | """ 7 | Multilevel 1D and 2D Discrete Wavelet Transform 8 | and Inverse Discrete Wavelet Transform. 9 | """ 10 | 11 | __all__ = ['wavedec', 'waverec', 'wavedec2', 'waverec2'] 12 | 13 | from _pywt import Wavelet 14 | from _pywt import dwt, idwt, dwt_max_level 15 | from multidim import dwt2, idwt2 16 | from numerix import as_float_array 17 | 18 | 19 | def wavedec(data, wavelet, mode='sym', level=None): 20 | """ 21 | Multilevel 1D Discrete Wavelet Transform of data. 22 | Returns coefficients list - [cAn, cDn, cDn-1, ..., cD2, cD1] 23 | 24 | data - input data 25 | wavelet - wavelet to use (Wavelet object or name string) 26 | mode - signal extension mode, see MODES 27 | level - decomposition level. If level is None then it will be 28 | calculated using `dwt_max_level` function. 29 | """ 30 | 31 | if not isinstance(wavelet, Wavelet): 32 | wavelet = Wavelet(wavelet) 33 | 34 | if level is None: 35 | level = dwt_max_level(len(data), wavelet.dec_len) 36 | elif level < 0: 37 | raise ValueError( 38 | "Level value of %d is too low . Minimum level is 0." % level) 39 | 40 | coeffs_list = [] 41 | 42 | a = data 43 | for i in xrange(level): 44 | a, d = dwt(a, wavelet, mode) 45 | coeffs_list.append(d) 46 | 47 | coeffs_list.append(a) 48 | coeffs_list.reverse() 49 | 50 | return coeffs_list 51 | 52 | 53 | def waverec(coeffs, wavelet, mode='sym'): 54 | """ 55 | Multilevel 1D Inverse Discrete Wavelet Transform. 56 | 57 | coeffs - coefficients list [cAn, cDn, cDn-1, ..., cD2, cD1] 58 | wavelet - wavelet to use (Wavelet object or name string) 59 | mode - signal extension mode, see MODES 60 | """ 61 | 62 | if not isinstance(coeffs, (list, tuple)): 63 | raise ValueError("Expected sequence of coefficient arrays.") 64 | 65 | if len(coeffs) < 2: 66 | raise ValueError( 67 | "Coefficient list too short (minimum 2 arrays required).") 68 | 69 | a, ds = coeffs[0], coeffs[1:] 70 | 71 | for d in ds: 72 | a = idwt(a, d, wavelet, mode, 1) 73 | 74 | return a 75 | 76 | 77 | def wavedec2(data, wavelet, mode='sym', level=None): 78 | """ 79 | Multilevel 2D Discrete Wavelet Transform. 80 | 81 | data - 2D input data 82 | wavelet - wavelet to use (Wavelet object or name string) 83 | mode - signal extension mode, see MODES 84 | level - decomposition level. If level is None then it will be 85 | calculated using `dwt_max_level` function . 86 | 87 | Returns coefficients list - [cAn, (cHn, cVn, cDn), ... (cH1, cV1, cD1)] 88 | """ 89 | 90 | data = as_float_array(data) 91 | 92 | if len(data.shape) != 2: 93 | raise ValueError("Expected 2D input data.") 94 | 95 | if not isinstance(wavelet, Wavelet): 96 | wavelet = Wavelet(wavelet) 97 | 98 | if level is None: 99 | size = min(data.shape) 100 | level = dwt_max_level(size, wavelet.dec_len) 101 | elif level < 0: 102 | raise ValueError( 103 | "Level value of %d is too low . Minimum level is 0." % level) 104 | 105 | coeffs_list = [] 106 | 107 | a = data 108 | for i in xrange(level): 109 | a, ds = dwt2(a, wavelet, mode) 110 | coeffs_list.append(ds) 111 | 112 | coeffs_list.append(a) 113 | coeffs_list.reverse() 114 | 115 | return coeffs_list 116 | 117 | 118 | def waverec2(coeffs, wavelet, mode='sym'): 119 | """ 120 | Multilevel 2D Inverse Discrete Wavelet Transform. 121 | 122 | coeffs - coefficients list [cAn, (cHn, cVn, cDn), ... (cH1, cV1, cD1)] 123 | wavelet - wavelet to use (Wavelet object or name string) 124 | mode - signal extension mode, see MODES 125 | 126 | Returns 2D array of reconstructed data. 127 | """ 128 | 129 | if not isinstance(coeffs, (list, tuple)): 130 | raise ValueError("Expected sequence of coefficient arrays.") 131 | 132 | if len(coeffs) < 2: 133 | raise ValueError( 134 | "Coefficient list too short (minimum 2 arrays required).") 135 | 136 | a, ds = coeffs[0], coeffs[1:] 137 | 138 | for d in ds: 139 | a = idwt2((a, d), wavelet, mode) 140 | 141 | return a 142 | -------------------------------------------------------------------------------- /src/pywt/numerix.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (c) 2006-2012 Filip Wasilewski 4 | # See COPYING for license details. 5 | 6 | """ 7 | Thin wrapper for NumPy module. Modify this to use wavelets with libraries 8 | other than NumPy. 9 | 10 | Provides efficient numeric functions and array datatypes. 11 | """ 12 | 13 | from numpy import ( # noqa 14 | ndarray, array, asarray, 15 | empty, zeros, linspace, arange, 16 | intp, float64, float32, 17 | transpose, concatenate, 18 | cumsum, cos, diff, exp, sinc, argmax, mean, 19 | convolve, 20 | where, less, greater, 21 | apply_along_axis 22 | ) 23 | from numpy.fft import fft # noqa 24 | 25 | default_dtype = float64 26 | 27 | 28 | def as_float_array(source): 29 | if isinstance(source, ndarray) and source.dtype in [float64, float32]: 30 | return source 31 | return array(source, default_dtype) 32 | 33 | 34 | def contiguous_float64_array_from_any(source): 35 | return array(source, float64) 36 | 37 | 38 | def contiguous_float32_array_from_any(source): 39 | return array(source, float32) 40 | 41 | 42 | def astype(source, dtype): 43 | return asarray(source, dtype) 44 | 45 | 46 | def float64_memory_buffer_object(size): 47 | return zeros((size,), float64) 48 | 49 | 50 | def float32_memory_buffer_object(size): 51 | return zeros((size,), float32) 52 | 53 | 54 | def is_array_type(arr, typ): 55 | return isinstance(arr, ndarray) and arr.dtype == typ 56 | 57 | 58 | def keep(arr, keep_length): 59 | length = len(arr) 60 | if keep_length < length: 61 | left_bound = (length - keep_length) / 2 62 | return arr[left_bound:left_bound + keep_length] 63 | return arr 64 | 65 | 66 | def integrate(arr, step): 67 | integral = cumsum(arr) 68 | integral *= step 69 | return integral 70 | -------------------------------------------------------------------------------- /src/pywt/thresholding.py: -------------------------------------------------------------------------------- 1 | # -*- coding: utf-8 -*- 2 | 3 | # Copyright (c) 2006-2012 Filip Wasilewski 4 | # See COPYING for license details. 5 | 6 | """Thresholding routines""" 7 | 8 | __all__ = ['soft', 'hard', 'greater', 'less', 'zero', 'copy'] 9 | 10 | import numerix 11 | 12 | 13 | def soft(data, value, substitute=0): 14 | mvalue = -value 15 | 16 | cond_less = numerix.less(data, value) 17 | cond_greater = numerix.greater(data, mvalue) 18 | 19 | data = numerix.where(cond_less & cond_greater, substitute, data) 20 | data = numerix.where(cond_less, data + value, data) 21 | data = numerix.where(cond_greater, data - value, data) 22 | 23 | return data 24 | 25 | 26 | def hard(data, value, substitute=0): 27 | mvalue = -value 28 | 29 | cond = numerix.less(data, value) 30 | cond &= numerix.greater(data, mvalue) 31 | 32 | return numerix.where(cond, substitute, data) 33 | 34 | 35 | def greater(data, value, substitute=0): 36 | return numerix.where(numerix.less(data, value), substitute, data) 37 | 38 | 39 | def less(data, value, substitute=0): 40 | return numerix.where(numerix.greater(data, value), substitute, data) 41 | 42 | 43 | def zero(data, *args): 44 | if isinstance(data, numerix.ndarray): 45 | return numerix.zeros(data.shape, data.dtype) 46 | return numerix.zeros(len(data)) 47 | 48 | 49 | def copy(data, *args): 50 | return numerix.array(data) 51 | -------------------------------------------------------------------------------- /src/wavelets.template.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2006-2012 Filip Wasilewski 2 | // See COPYING for license details. 3 | 4 | // Wavelet struct 5 | 6 | #ifndef _WAVELETS_H_ 7 | #define _WAVELETS_H_ 8 | 9 | #include "common.h" 10 | 11 | // Wavelet symmetry properties 12 | typedef enum { 13 | UNKNOWN = -1, 14 | ASYMMETRIC = 0, 15 | NEAR_SYMMETRIC = 1, 16 | SYMMETRIC = 2 17 | } SYMMETRY; 18 | 19 | 20 | // Wavelet structure holding pointers to filter arrays and property attributes 21 | typedef struct { 22 | 23 | //## FOR $DTYPE$ IN (double, float): 24 | $DTYPE$* dec_hi_$DTYPE$; // highpass decomposition 25 | $DTYPE$* dec_lo_$DTYPE$; // lowpass decomposition 26 | $DTYPE$* rec_hi_$DTYPE$; // highpass reconstruction 27 | $DTYPE$* rec_lo_$DTYPE$; // lowpass reconstruction 28 | 29 | //## ENDFOR $DTYPE$ 30 | 31 | index_t dec_len; // length of decomposition filter 32 | index_t rec_len; // length of reconstruction filter 33 | 34 | /* 35 | index_t dec_hi_offset; // usually 0, but some filters can be zero-padded (ie. bior) 36 | index_t dec_lo_offset; 37 | index_t rec_hi_offset; // - || - 38 | index_t rec_lo_offset; // - || - 39 | */ 40 | 41 | // Wavelet properties 42 | int vanishing_moments_psi; 43 | int vanishing_moments_phi; 44 | index_t support_width; 45 | 46 | SYMMETRY symmetry; 47 | 48 | int orthogonal:1; 49 | int biorthogonal:1; 50 | int compact_support:1; 51 | 52 | // Set if filters arrays shouldn't be deallocated by free_wavelet(Wavelet) func 53 | int _builtin:1; 54 | 55 | char* family_name; 56 | char* short_name; 57 | 58 | } Wavelet; 59 | 60 | 61 | // Allocate Wavelet struct and set its attributes 62 | // name - (currently) a character codename of a wavelet family 63 | // order - order of the wavelet (ie. coif3 has order 3) 64 | // 65 | // _builtin field is set to 1 66 | 67 | Wavelet* wavelet(char name, int order); 68 | 69 | 70 | // Allocate blank Wavelet with zero-filled filters of given length 71 | // _builtin field is set to 0 72 | 73 | Wavelet* blank_wavelet(index_t filters_length); 74 | 75 | 76 | // Deep copy Wavelet 77 | 78 | Wavelet* copy_wavelet(Wavelet* base); 79 | 80 | 81 | // Free wavelet struct. Use this to free Wavelet allocated with 82 | // wavelet(...) or blank_wavelet(...) functions. 83 | 84 | void free_wavelet(Wavelet *wavelet); 85 | 86 | #endif 87 | -------------------------------------------------------------------------------- /src/wavelets_list.pxi: -------------------------------------------------------------------------------- 1 | # Copyright (c) 2006-2012 Filip Wasilewski 2 | # See COPYING for license details. 3 | 4 | ## Mapping of wavelet names to the C backend codes 5 | 6 | cdef __wname_to_code 7 | __wname_to_code = { 8 | "haar": (c"h", 0), 9 | 10 | "db1": (c"d", 1), 11 | "db2": (c"d", 2), 12 | "db3": (c"d", 3), 13 | "db4": (c"d", 4), 14 | "db5": (c"d", 5), 15 | "db6": (c"d", 6), 16 | "db7": (c"d", 7), 17 | "db8": (c"d", 8), 18 | "db9": (c"d", 9), 19 | 20 | "db10": (c"d", 10), 21 | "db11": (c"d", 11), 22 | "db12": (c"d", 12), 23 | "db13": (c"d", 13), 24 | "db14": (c"d", 14), 25 | "db15": (c"d", 15), 26 | "db16": (c"d", 16), 27 | "db17": (c"d", 17), 28 | "db18": (c"d", 18), 29 | "db19": (c"d", 19), 30 | "db20": (c"d", 20), 31 | 32 | "sym2": (c"s", 2), 33 | "sym3": (c"s", 3), 34 | "sym4": (c"s", 4), 35 | "sym5": (c"s", 5), 36 | "sym6": (c"s", 6), 37 | "sym7": (c"s", 7), 38 | "sym8": (c"s", 8), 39 | "sym9": (c"s", 9), 40 | 41 | "sym10": (c"s", 10), 42 | "sym11": (c"s", 11), 43 | "sym12": (c"s", 12), 44 | "sym13": (c"s", 13), 45 | "sym14": (c"s", 14), 46 | "sym15": (c"s", 15), 47 | "sym16": (c"s", 16), 48 | "sym17": (c"s", 17), 49 | "sym18": (c"s", 18), 50 | "sym19": (c"s", 19), 51 | "sym20": (c"s", 20), 52 | 53 | "coif1": (c"c", 1), 54 | "coif2": (c"c", 2), 55 | "coif3": (c"c", 3), 56 | "coif4": (c"c", 4), 57 | "coif5": (c"c", 5), 58 | 59 | "bior1.1": (c"b", 11), 60 | "bior1.3": (c"b", 13), 61 | "bior1.5": (c"b", 15), 62 | "bior2.2": (c"b", 22), 63 | "bior2.4": (c"b", 24), 64 | "bior2.6": (c"b", 26), 65 | "bior2.8": (c"b", 28), 66 | "bior3.1": (c"b", 31), 67 | "bior3.3": (c"b", 33), 68 | "bior3.5": (c"b", 35), 69 | "bior3.7": (c"b", 37), 70 | "bior3.9": (c"b", 39), 71 | "bior4.4": (c"b", 44), 72 | "bior5.5": (c"b", 55), 73 | "bior6.8": (c"b", 68), 74 | 75 | "rbio1.1": (c"r", 11), 76 | "rbio1.3": (c"r", 13), 77 | "rbio1.5": (c"r", 15), 78 | "rbio2.2": (c"r", 22), 79 | "rbio2.4": (c"r", 24), 80 | "rbio2.6": (c"r", 26), 81 | "rbio2.8": (c"r", 28), 82 | "rbio3.1": (c"r", 31), 83 | "rbio3.3": (c"r", 33), 84 | "rbio3.5": (c"r", 35), 85 | "rbio3.7": (c"r", 37), 86 | "rbio3.9": (c"r", 39), 87 | "rbio4.4": (c"r", 44), 88 | "rbio5.5": (c"r", 55), 89 | "rbio6.8": (c"r", 68), 90 | 91 | "dmey": (c"m", 0), 92 | } 93 | 94 | ## Lists of family names 95 | 96 | cdef __wfamily_list_short, __wfamily_list_long 97 | __wfamily_list_short = ["haar", "db", "sym", "coif", "bior", "rbio", "dmey"] 98 | __wfamily_list_long = ["Haar", "Daubechies", "Symlets", "Coiflets", "Biorthogonal", "Reverse biorthogonal", "Discrete Meyer (FIR Approximation)"] 99 | -------------------------------------------------------------------------------- /src/wt.template.c: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2006-2012 Filip Wasilewski 2 | // See COPYING for license details. 3 | 4 | #include "wt.h" 5 | 6 | // Decomposition of input with lowpass filter 7 | 8 | //## FOR $DTYPE$ IN (double, float): 9 | 10 | int $DTYPE$_dec_a($DTYPE$ input[], index_t input_len, 11 | Wavelet* wavelet, 12 | $DTYPE$ output[], index_t output_len, 13 | MODE mode){ 14 | 15 | // check output length 16 | if(output_len != dwt_buffer_length(input_len, wavelet->dec_len, mode)){ 17 | return -1; 18 | } 19 | 20 | return $DTYPE$_downsampling_convolution(input, input_len, wavelet->dec_lo_$DTYPE$, 21 | wavelet->dec_len, output, 2, mode); 22 | } 23 | 24 | 25 | // Decomposition of input with highpass filter 26 | 27 | int $DTYPE$_dec_d($DTYPE$ input[], index_t input_len, 28 | Wavelet* wavelet, 29 | $DTYPE$ output[], index_t output_len, 30 | MODE mode){ 31 | 32 | // check output length 33 | if(output_len != dwt_buffer_length(input_len, wavelet->dec_len, mode)) 34 | return -1; 35 | 36 | return $DTYPE$_downsampling_convolution(input, input_len, wavelet->dec_hi_$DTYPE$, 37 | wavelet->dec_len, output, 2, mode); 38 | } 39 | 40 | 41 | // Direct reconstruction with lowpass reconstruction filter 42 | 43 | int $DTYPE$_rec_a($DTYPE$ coeffs_a[], index_t coeffs_len, 44 | Wavelet* wavelet, 45 | $DTYPE$ output[], index_t output_len){ 46 | 47 | // check output length 48 | if(output_len != reconstruction_buffer_length(coeffs_len, wavelet->rec_len)) 49 | return -1; 50 | 51 | return $DTYPE$_upsampling_convolution_full(coeffs_a, coeffs_len, wavelet->rec_lo_$DTYPE$, 52 | wavelet->rec_len, output, output_len); 53 | } 54 | 55 | 56 | // Direct reconstruction with highpass reconstruction filter 57 | 58 | int $DTYPE$_rec_d($DTYPE$ coeffs_d[], index_t coeffs_len, 59 | Wavelet* wavelet, 60 | $DTYPE$ output[], index_t output_len){ 61 | 62 | // check for output length 63 | if(output_len != reconstruction_buffer_length(coeffs_len, wavelet->rec_len)) 64 | return -1; 65 | 66 | return $DTYPE$_upsampling_convolution_full(coeffs_d, coeffs_len, wavelet->rec_hi_$DTYPE$, 67 | wavelet->rec_len, output, output_len); 68 | } 69 | 70 | 71 | // IDWT reconstruction from approximation and detail coeffs 72 | // 73 | // If fix_size_diff is 1 then coeffs arrays can differ by one in length (this 74 | // is useful in multilevel decompositions and reconstructions of odd-length signals) 75 | // Requires zero-filled output buffer 76 | int $DTYPE$_idwt($DTYPE$ coeffs_a[], index_t coeffs_a_len, 77 | $DTYPE$ coeffs_d[], index_t coeffs_d_len, 78 | Wavelet* wavelet, 79 | $DTYPE$ output[], index_t output_len, 80 | MODE mode, int fix_size_diff){ 81 | 82 | index_t input_len; 83 | 84 | // If one of coeffs array is NULL then the reconstruction will be performed 85 | // using the other one 86 | 87 | if(coeffs_a != NULL && coeffs_d != NULL){ 88 | 89 | if(fix_size_diff){ 90 | if( (coeffs_a_len > coeffs_d_len ? coeffs_a_len - coeffs_d_len 91 | : coeffs_d_len-coeffs_a_len) > 1){ // abs(a-b) 92 | goto error; 93 | } 94 | 95 | input_len = coeffs_a_len>coeffs_d_len ? coeffs_d_len 96 | : coeffs_a_len; // min 97 | } else { 98 | if(coeffs_a_len != coeffs_d_len) 99 | goto error; 100 | 101 | input_len = coeffs_a_len; 102 | } 103 | 104 | } else if(coeffs_a != NULL){ 105 | input_len = coeffs_a_len; 106 | 107 | } else if (coeffs_d != NULL){ 108 | input_len = coeffs_d_len; 109 | 110 | } else { 111 | goto error; 112 | } 113 | 114 | // check output size 115 | if(output_len != idwt_buffer_length(input_len, wavelet->rec_len, mode)) 116 | goto error; 117 | 118 | // // set output to zero (this can be omitted if output array is already cleared) 119 | // memset(output, 0, output_len * sizeof($DTYPE$)); 120 | 121 | // reconstruct approximation coeffs with lowpass reconstruction filter 122 | if(coeffs_a){ 123 | if($DTYPE$_upsampling_convolution_valid_sf(coeffs_a, input_len, wavelet->rec_lo_$DTYPE$, 124 | wavelet->rec_len, output, output_len, mode) < 0){ 125 | goto error; 126 | } 127 | } 128 | // and add reconstruction of details coeffs performed with highpass reconstruction filter 129 | if(coeffs_d){ 130 | if($DTYPE$_upsampling_convolution_valid_sf(coeffs_d, input_len, wavelet->rec_hi_$DTYPE$, 131 | wavelet->rec_len, output, output_len, mode) < 0){ 132 | goto error; 133 | } 134 | } 135 | 136 | return 0; 137 | 138 | error: 139 | return -1; 140 | } 141 | 142 | // basic SWT step 143 | // TODO: optimize 144 | int $DTYPE$_swt_($DTYPE$ input[], index_t input_len, 145 | const $DTYPE$ filter[], index_t filter_len, 146 | $DTYPE$ output[], index_t output_len, 147 | int level){ 148 | 149 | $DTYPE$* e_filter; 150 | index_t i, e_filter_len; 151 | int ret; 152 | 153 | if(level < 1) 154 | return -1; 155 | 156 | if(level > swt_max_level(input_len)) 157 | return -2; 158 | 159 | if(output_len != swt_buffer_length(input_len)) 160 | return -1; 161 | 162 | // TODO: quick hack, optimize 163 | if(level > 1){ 164 | // allocate filter first 165 | e_filter_len = filter_len << (level-1); 166 | e_filter = wtcalloc(e_filter_len, sizeof($DTYPE$)); 167 | if(e_filter == NULL) 168 | return -1; 169 | 170 | // compute upsampled filter values 171 | for(i = 0; i < filter_len; ++i){ 172 | e_filter[i << (level-1)] = filter[i]; 173 | } 174 | ret = $DTYPE$_downsampling_convolution(input, input_len, e_filter, e_filter_len, output, 1, MODE_PERIODIZATION); 175 | wtfree(e_filter); 176 | return ret; 177 | 178 | } else { 179 | return $DTYPE$_downsampling_convolution(input, input_len, filter, filter_len, output, 1, MODE_PERIODIZATION); 180 | } 181 | } 182 | 183 | // Approximation at specified level 184 | // input - approximation coeffs from upper level or signal if level == 1 185 | int $DTYPE$_swt_a($DTYPE$ input[], index_t input_len, Wavelet* wavelet, $DTYPE$ output[], index_t output_len, int level){ 186 | return $DTYPE$_swt_(input, input_len, wavelet->dec_lo_$DTYPE$, wavelet->dec_len, output, output_len, level); 187 | } 188 | 189 | // Details at specified level 190 | // input - approximation coeffs from upper level or signal if level == 1 191 | int $DTYPE$_swt_d($DTYPE$ input[], index_t input_len, Wavelet* wavelet, $DTYPE$ output[], index_t output_len, int level){ 192 | return $DTYPE$_swt_(input, input_len, wavelet->dec_hi_$DTYPE$, wavelet->dec_len, output, output_len, level); 193 | } 194 | 195 | //## ENDFOR $DTYPE$ 196 | -------------------------------------------------------------------------------- /src/wt.template.h: -------------------------------------------------------------------------------- 1 | // Copyright (c) 2006-2012 Filip Wasilewski 2 | // See COPYING for license details. 3 | 4 | // Wavelet transforms using convolution functions defined in convolution.h 5 | 6 | #ifndef _WT_H_ 7 | #define _WT_H_ 8 | 9 | #include 10 | #include 11 | 12 | #include "common.h" 13 | #include "convolution.h" 14 | #include "wavelets.h" 15 | 16 | 17 | // _a suffix - wavelet transform approximations 18 | // _d suffix - wavelet transform details 19 | 20 | //## FOR $DTYPE$ IN (double, float): 21 | 22 | // Single level decomposition 23 | int $DTYPE$_dec_a($DTYPE$ input[], index_t input_len, 24 | Wavelet* wavelet, 25 | $DTYPE$ output[], index_t output_len, 26 | MODE mode); 27 | 28 | int $DTYPE$_dec_d($DTYPE$ input[], index_t input_len, 29 | Wavelet* wavelet, 30 | $DTYPE$ output[], index_t output_len, 31 | MODE mode); 32 | 33 | // Single level reconstruction 34 | int $DTYPE$_rec_a($DTYPE$ coeffs_a[], index_t coeffs_len, 35 | Wavelet* wavelet, 36 | $DTYPE$ output[], index_t output_len); 37 | 38 | int $DTYPE$_rec_d($DTYPE$ coeffs_d[], index_t coeffs_len, 39 | Wavelet* wavelet, 40 | $DTYPE$ output[], index_t output_len); 41 | 42 | // Single level IDWT reconstruction 43 | int $DTYPE$_idwt($DTYPE$ coeffs_a[], index_t coeffs_a_len, 44 | $DTYPE$ coeffs_d[], index_t coeffs_d_len, 45 | Wavelet* wavelet, 46 | $DTYPE$ output[], index_t output_len, 47 | MODE mode, int fix_size_diff); 48 | 49 | // SWT decomposition at given level 50 | int $DTYPE$_swt_a($DTYPE$ input[], index_t input_len, 51 | Wavelet* wavelet, 52 | $DTYPE$ output[], index_t output_len, 53 | int level); 54 | 55 | int $DTYPE$_swt_d($DTYPE$ input[], index_t input_len, 56 | Wavelet* wavelet, 57 | $DTYPE$ output[], index_t output_len, 58 | int level); 59 | 60 | //## ENDFOR $DTYPE$ 61 | 62 | #endif 63 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nigma/pywt/035e1fa14c2cd70ca270da20b1523e834a7ae635/tests/__init__.py -------------------------------------------------------------------------------- /tests/test_doc.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | import doctest 5 | import glob 6 | import os 7 | import unittest 8 | 9 | docs_base = os.path.abspath( 10 | os.path.join(os.path.dirname(__file__), os.path.pardir, "doc", "source")) 11 | 12 | files = glob.glob(os.path.join(docs_base, "*.rst"))\ 13 | + glob.glob(os.path.join(docs_base, "*", "*.rst")) 14 | 15 | assert files 16 | 17 | suite = doctest.DocFileSuite(*files, module_relative=False, encoding="utf-8") 18 | 19 | if __name__ == "__main__": 20 | unittest.TextTestRunner().run(suite) 21 | -------------------------------------------------------------------------------- /tests/test_matlab_compatibility.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Test used to verify PyWavelets Discrete Wavelet Transform computation 5 | accuracy against MathWorks Wavelet Toolbox. 6 | 7 | This way you can be perfectly sure about PyWavelets' results quality 8 | and reproducibility. 9 | """ 10 | 11 | import math 12 | 13 | import numpy 14 | from numpy import asarray, float64 15 | 16 | try: 17 | from mlabwrap import mlab 18 | except: 19 | print "To run this test you need to have MathWorks MATLAB, MathWorks " \ 20 | "Wavelet Toolbox and mlabwrap Python extension installed." 21 | raise SystemExit 22 | 23 | import pywt 24 | 25 | 26 | def mse(ar1, ar2): 27 | """Mean squared error""" 28 | ar1 = asarray(ar1, dtype=float64) 29 | ar2 = asarray(ar2, dtype=float64) 30 | dif = ar1 - ar2 31 | dif *= dif 32 | return dif.sum() / len(ar1) 33 | 34 | 35 | def rms(ar1, ar2): 36 | """Root mean squared error""" 37 | return math.sqrt(mse(ar1, ar2)) 38 | 39 | 40 | def test_accuracy(families, wavelets, modes, epsilon=1.0e-10): 41 | print "Testing decomposition".upper() 42 | 43 | for pmode, mmode in modes: 44 | for wavelet in wavelets: 45 | print "Wavelet: %-8s Mode: %s" % (wavelet, pmode) 46 | 47 | w = pywt.Wavelet(wavelet) 48 | data_size = range(w.dec_len, 40) + [100, 200, 500, 1000, 50000] 49 | 50 | for N in data_size: 51 | data = numpy.random.random(N) 52 | 53 | # PyWavelets result 54 | pa, pd = pywt.dwt(data, wavelet, pmode) 55 | 56 | # Matlab result 57 | ma, md = mlab.dwt(data, wavelet, 'mode', mmode, nout=2) 58 | ma = ma.flat 59 | md = md.flat 60 | 61 | # calculate error measures 62 | mse_a, mse_d = mse(pa, ma), mse(pd, md) 63 | rms_a, rms_d = math.sqrt(mse_a), math.sqrt(mse_d) 64 | 65 | if rms_a > epsilon: 66 | print '[RMS_A > EPSILON] for Mode: %s, Wavelet: %s, '\ 67 | 'Length: %d, rms=%.3g' % (pmode, wavelet, len(data), rms_a) 68 | 69 | if rms_d > epsilon: 70 | print '[RMS_D > EPSILON] for Mode: %s, Wavelet: %s, '\ 71 | 'Length: %d, rms=%.3g' % (pmode, wavelet, len(data), rms_d) 72 | 73 | 74 | if __name__ == '__main__': 75 | 76 | families = ('db', 'sym', 'coif', 'bior', 'rbio') 77 | wavelets = sum([pywt.wavelist(name) for name in families], []) 78 | # list of mode names in pywt and matlab 79 | modes = [('zpd', 'zpd'), ('cpd', 'sp0'), ('sym', 'sym'), 80 | ('ppd', 'ppd'), ('sp1', 'sp1'), ('per', 'per')] 81 | # max RMSE 82 | epsilon = 1.0e-10 83 | 84 | test_accuracy(families, wavelets, modes, epsilon) 85 | -------------------------------------------------------------------------------- /tests/test_perfect_reconstruction.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | """ 4 | Verify DWT perfect reconstruction. 5 | """ 6 | 7 | import math 8 | 9 | import numpy 10 | from numpy import asarray, float64, float32 11 | 12 | import pywt 13 | 14 | 15 | def mse(ar1, ar2): 16 | """Mean squared error""" 17 | ar1 = asarray(ar1, dtype=float64) 18 | ar2 = asarray(ar2, dtype=float64) 19 | dif = ar1 - ar2 20 | dif *= dif 21 | return dif.sum() / len(ar1) 22 | 23 | 24 | def rms(ar1, ar2): 25 | """Root mean squared error""" 26 | return math.sqrt(mse(ar1, ar2)) 27 | 28 | 29 | def test_perfect_reconstruction(families, wavelets, modes, epsilon, dtype): 30 | for wavelet in wavelets: 31 | for pmode, mmode in modes: 32 | print "Wavelet: %-8s Mode: %s" % (wavelet, pmode), 33 | 34 | data_size = range(2, 40) + [100, 200, 500, 1000, 2000, 10000, 35 | 50000, 100000] 36 | 37 | ok, over = 0, 0 38 | for N in data_size: 39 | data = numpy.asarray(numpy.random.random(N), dtype) 40 | 41 | # compute dwt coefficients 42 | pa, pd = pywt.dwt(data, wavelet, pmode) 43 | 44 | # compute reconstruction 45 | rec = pywt.idwt(pa, pd, wavelet, pmode) 46 | 47 | if len(data) % 2: 48 | rec = rec[:len(data)] 49 | 50 | rms_rec = rms(data, rec) 51 | if rms_rec > epsilon: 52 | if not over: 53 | print 54 | print '[RMS_REC > EPSILON] for Mode: %s, Wavelet: %s, ' \ 55 | 'Length: %d, rms=%.3g' % ( 56 | pmode, wavelet, len(data), rms_rec) 57 | over += 1 58 | else: 59 | ok += 1 60 | if not over: 61 | print "- RMSE for all %d cases was under %s" % ( 62 | len(data_size), epsilon) 63 | 64 | if __name__ == '__main__': 65 | 66 | families = ('db', 'sym', 'coif', 'bior', 'rbio') 67 | wavelets = sum([pywt.wavelist(name) for name in families], []) 68 | # list of mode names in pywt and matlab 69 | modes = [('zpd', 'zpd'), ('cpd', 'sp0'), ('sym', 'sym'), 70 | ('ppd', 'ppd'), ('sp1', 'sp1'), ('per', 'per')] 71 | 72 | print "Testing perfect reconstruction".upper() 73 | for dtype, name, epsilon in [ 74 | (float32, "float32", 1.0e-7), 75 | (float64, "float64", 0.5e-10) 76 | ][::-1]: 77 | print "#" * 80 78 | print "Precision: %s, max RMSE: %s" % (name, epsilon) 79 | print "#" * 80 + "\n" 80 | test_perfect_reconstruction(families, wavelets, modes, epsilon=epsilon, 81 | dtype=dtype) 82 | print 83 | -------------------------------------------------------------------------------- /tests/test_regression.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | 3 | # tests moved to test_doc.py 4 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | # Tox (http://tox.testrun.org/) is a tool for running tests 2 | # in multiple virtualenvs. This configuration file will run the 3 | # test suite on all supported python versions. To use it, "pip install tox" 4 | # and then run "tox" from this directory. 5 | 6 | [tox] 7 | envlist = py26, py27 8 | 9 | [testenv] 10 | commands = 11 | {envpython} -V 12 | {envpython} setup.py test 13 | flake8 --exit-zero util demo src\pywt 14 | 15 | deps = 16 | flake8 17 | cython 18 | numpy 19 | -------------------------------------------------------------------------------- /util/__init__.py: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nigma/pywt/035e1fa14c2cd70ca270da20b1523e834a7ae635/util/__init__.py -------------------------------------------------------------------------------- /util/commands.py: -------------------------------------------------------------------------------- 1 | #-*- coding: utf-8 -*- 2 | # Copyright Filip Wasilewski . All rights reserved. 3 | 4 | from __future__ import print_function 5 | 6 | import os 7 | import sys 8 | 9 | try: 10 | from setuptools import Command 11 | from setuptools.command.build_ext import build_ext as _build_ext 12 | from setuptools.command.sdist import sdist as _sdist 13 | from setuptools.extension import Extension as _Extension 14 | has_setuptools = True 15 | except ImportError: 16 | from distutils.cmd import Command # noqa 17 | from distutils.command.build_ext import build_ext as _build_ext 18 | from distutils.command.sdist import sdist as _sdist 19 | from distutils.core import Extension 20 | has_setuptools = False 21 | 22 | from distutils import dir_util 23 | from distutils.errors import DistutilsClassError 24 | 25 | import templating 26 | 27 | base_dir = os.path.join(os.path.abspath(os.path.dirname(__file__)), "..") 28 | 29 | if has_setuptools: 30 | # Remove special handling of .pyx files from class patched by setuptools 31 | class Extension(_Extension): 32 | def __init__(self, name, sources, *args, **kwargs): 33 | _Extension.__init__(self, name, sources, *args, **kwargs) 34 | self.sources = sources 35 | 36 | 37 | def replace_extension(path, newext): 38 | return os.path.splitext(path)[0] + newext 39 | 40 | 41 | def is_newer(file, than_file): 42 | return os.path.getmtime(file) > os.path.getmtime(than_file) 43 | 44 | 45 | class CleanCommand(Command): 46 | user_options = [] 47 | 48 | def initialize_options(self): 49 | self.base_roots = ["demo", "doc", "pywt", "src", "tests", "util"] 50 | self.dirty = [".pyc", ".so", ".o", ".pyd"] 51 | self.files = [] 52 | self.dirs = ["build", "dist"] 53 | 54 | def finalize_options(self): 55 | for base_root in self.base_roots: 56 | if os.path.exists(base_root): 57 | for root, dirs, files in os.walk(base_root): 58 | for f in files: 59 | if os.path.splitext(f)[-1] in self.dirty: 60 | self.files.append(os.path.join(root, f)) 61 | 62 | for d in dirs: 63 | if d == "__pycache__": 64 | self.dirs.append(os.path.join(root, d)) 65 | 66 | def run(self): 67 | for path in self.files: 68 | print("removing '{0}'".format(path)) 69 | if not self.dry_run: 70 | os.remove(path) 71 | 72 | for d in self.dirs: 73 | if os.path.exists(d): 74 | dir_util.remove_tree(d, dry_run=self.dry_run) 75 | 76 | 77 | class SdistCommand(_sdist): 78 | 79 | def initialize_options(self): 80 | _sdist.initialize_options(self) 81 | self._pyx = [] 82 | self._templates = [] 83 | for root, dirs, files in os.walk("src"): 84 | for f in files: 85 | if f.endswith(".pyx"): 86 | self._pyx.append(os.path.join(root, f)) 87 | elif ".template" in f: 88 | self._templates.append(os.path.join(root, f)) 89 | 90 | def validate_templates_expanded(self): 91 | for template_file in self._templates: 92 | destination_file = templating.get_destination_filepath( 93 | template_file) 94 | 95 | if not os.path.exists(destination_file): 96 | raise DistutilsClassError( 97 | "Expanded file '{0}' not found. " 98 | "Run build first.".format(destination_file)) 99 | 100 | if templating.needs_update(template_file, destination_file): 101 | raise DistutilsClassError( 102 | "Expanded file '{0}' seems out of date compared to '{1}'. " 103 | "Run build first.".format(destination_file, template_file)) 104 | 105 | def validate_pyx_expanded(self): 106 | for pyx_file in self._pyx: 107 | c_file = replace_extension(pyx_file, ".c") 108 | 109 | if not os.path.exists(c_file): 110 | raise DistutilsClassError( 111 | "C-source file '{0}' not found. " 112 | "Run build first.".format(c_file)) 113 | 114 | if is_newer(pyx_file, c_file): 115 | raise DistutilsClassError( 116 | "C-source file '{0}' seems out of date compared to '{1}'. " 117 | "Run build first.".format(c_file, pyx_file)) 118 | 119 | def run(self): 120 | self.force_manifest = 1 121 | self.validate_templates_expanded() 122 | self.validate_pyx_expanded() 123 | _sdist.run(self) 124 | 125 | 126 | class BuildExtCommand(_build_ext): 127 | templates_glob = os.path.join(base_dir, "src", "*.template.*") 128 | 129 | extra_compile_flags = { 130 | #"msvc": ["/W4", "/wd4127", "/wd4702", "/wd4100"] 131 | } 132 | 133 | user_options = _build_ext.user_options + [ 134 | ("force-pyx-compile", None, "always compile Cython files"), 135 | ("force-template-update", None, "always expand templates"), 136 | ] 137 | 138 | boolean_options = _build_ext.boolean_options + [ 139 | "force-pyx-compile", "force-template-update" 140 | ] 141 | 142 | def initialize_options(self): 143 | _build_ext.initialize_options(self) 144 | self.pyx_compile = True 145 | self.force_pyx_compile = False 146 | self.force_template_update = False 147 | 148 | def finalize_options(self): 149 | _build_ext.finalize_options(self) 150 | 151 | self.set_undefined_options("build", 152 | ("force_pyx_compile", "force_pyx_compile"), 153 | ("force_template_update", "force_template_update") 154 | ) 155 | 156 | def get_extra_compile_args(self): 157 | compiler_type = self.compiler.compiler_type 158 | return self.extra_compile_flags.get(compiler_type, []) 159 | 160 | def should_compile(self, source_file, compiled_file): 161 | if self.force_pyx_compile: 162 | return True 163 | if not os.path.exists(compiled_file): 164 | return True 165 | if is_newer(source_file, compiled_file): 166 | return True 167 | return False 168 | 169 | def compile_cython_file(self, extension, pyx_source_file): 170 | c_source_file = replace_extension(pyx_source_file, ".c") 171 | 172 | if not self.pyx_compile: 173 | print("Cython compilation disabled. Using compiled file:", 174 | c_source_file) 175 | return c_source_file 176 | 177 | try: 178 | from Cython.Compiler.Main import compile 179 | except ImportError: 180 | print("Cython is not installed. Using compiled file:", 181 | pyx_source_file) 182 | return c_source_file 183 | 184 | if not self.should_compile(pyx_source_file, c_source_file): 185 | print("Generated Cython file is up-to-date.") 186 | return c_source_file 187 | 188 | print("Compiling Cython file:", pyx_source_file) 189 | result = compile(pyx_source_file, full_module_name=extension.name) 190 | 191 | if result.c_file: 192 | c_source_file = result.c_file 193 | # Py2 distutils can't handle unicode file paths 194 | if sys.version_info[0] < 3: 195 | filename_encoding = sys.getfilesystemencoding() 196 | if filename_encoding is None: 197 | filename_encoding = sys.getdefaultencoding() 198 | c_source_file = c_source_file.encode(filename_encoding) 199 | else: 200 | print("Compilation failed:", pyx_source_file) 201 | return c_source_file 202 | 203 | def compile_sources(self, extension, sources): 204 | for i, source in enumerate(sources): 205 | base, ext = os.path.splitext(source) 206 | if ext == ".pyx": 207 | c_source_file = self.compile_cython_file(extension, source) 208 | # substitute .pyx file with compiled .c file 209 | sources[i] = c_source_file 210 | 211 | def build_extensions(self): 212 | templating.expand_files(self.templates_glob, 213 | force_update=self.force_template_update) 214 | _build_ext.build_extensions(self) 215 | 216 | def build_extension(self, ext): 217 | ext.extra_compile_args += self.get_extra_compile_args() 218 | self.compile_sources(ext, ext.sources) 219 | _build_ext.build_extension(self, ext) 220 | 221 | 222 | class TestCommand(Command): 223 | user_options = [] 224 | 225 | def initialize_options(self): 226 | pass 227 | 228 | def finalize_options(self): 229 | pass 230 | 231 | def run(self): 232 | import subprocess 233 | raise SystemExit( 234 | subprocess.call([sys.executable, "tests/test_doc.py"])) 235 | -------------------------------------------------------------------------------- /util/setenv_build32.bat: -------------------------------------------------------------------------------- 1 | rem Configure the environment for 32-bit builds. 2 | rem Use "vcvars32.bat" for a 32-bit build. 3 | "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars32.bat" 4 | setenv /x86 /release 5 | rem Convince setup.py to use the SDK tools. 6 | set MSSdk=1 7 | set DISTUTILS_USE_SDK=1 8 | -------------------------------------------------------------------------------- /util/setenv_build64.bat: -------------------------------------------------------------------------------- 1 | rem Configure the environment for 64-bit builds. 2 | rem Use "vcvars32.bat" for a 32-bit build. 3 | "C:\Program Files (x86)\Microsoft Visual Studio 9.0\VC\bin\vcvars64.bat" 4 | setenv /x64 /release 5 | rem Convince setup.py to use the SDK tools. 6 | set MSSdk=1 7 | set DISTUTILS_USE_SDK=1 8 | -------------------------------------------------------------------------------- /util/templating.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | 4 | # Author: Filip Wasilewski 5 | # Date: $Date$ 6 | 7 | # Ok, not really a full-featured templating language, but good enough 8 | # to keep the code easier to maintain. 9 | # PS. For internal use only ;) 10 | 11 | import glob 12 | import os 13 | import re 14 | 15 | pattern_for = re.compile(r"""(?P 16 | ^\s* 17 | (?:/{2,})? # optional C comment 18 | \s* 19 | \#{2} # two hashes 20 | \s* 21 | 22 | (FOR) 23 | \s+ (?P[\w$][\d\w$]*) \s+ 24 | (IN) 25 | \s+ \( 26 | (?P 27 | (?: 28 | \s* [^,\s]+ , \s* 29 | )+ 30 | (?: 31 | [^,\s]+ 32 | ){0,1} 33 | \s* 34 | ) 35 | \) 36 | \s* : \s* 37 | ) 38 | ^(?P.*?) 39 | (?P 40 | ^ 41 | \s* 42 | (?:/{2,})? # optional C comment 43 | \s* 44 | \#{2} # two hashes 45 | \s* 46 | (ENDFOR) 47 | \s+ (?P=variable) \s*?\n 48 | ) 49 | """, re.X | re.M | re.S | re.I) 50 | 51 | 52 | def expand_template(s): 53 | """ 54 | Currently it only does a simple repeat-and-replace in a loop: 55 | 56 | FOR $variable$ IN (value1, value2, ...): 57 | ... start block ... 58 | $variable$ 59 | ... end block ... 60 | ENDFOR $variable$ 61 | 62 | The above will repeat the block for every value from the list each time 63 | substituting the $variable$ with the current value. 64 | 65 | >>> s = \ 66 | ... ''' 67 | ... w = 9 68 | ... ## FOR $x$ IN (7, w): 69 | ... ## FOR $y$ IN ("{", 1): 70 | ... print $x$, $y$, "$x$_$y$" 71 | ... ## ENDFOR $y$ 72 | ... ## ENDFOR $x$''' 73 | >>> print expand_template(s) 74 | 75 | w = 9 76 | print 7, "{" 77 | print 7, 1 78 | print w, "{" 79 | print w, 1 80 | """ 81 | while True: 82 | m = pattern_for.search(s) 83 | if not m: 84 | break 85 | 86 | new_body = '' 87 | for value in [ 88 | v.strip() for v in m.group('values').split(',') if v.strip() 89 | ]: 90 | new_body += m.group('body').replace(m.group('variable'), value) 91 | 92 | s = s[:m.start()] + new_body + s[m.end():] 93 | 94 | return s 95 | 96 | 97 | def get_destination_filepath(source): 98 | root, template_name = os.path.split(source) 99 | 100 | # main extension 101 | destination_name, base_ext = os.path.splitext(template_name) 102 | 103 | while os.path.extsep in destination_name: 104 | # remove .template extension for files like file.template.c 105 | destination_name = os.path.splitext(destination_name)[0] 106 | return os.path.join(root, destination_name + base_ext) 107 | 108 | 109 | def needs_update(template_path, destination_path): 110 | if not os.path.exists(destination_path): 111 | return True 112 | if os.path.getmtime(destination_path) < os.path.getmtime(template_path): 113 | return True 114 | return False 115 | 116 | 117 | def expand_files(glob_pattern, force_update=False): 118 | files = glob.glob(glob_pattern) 119 | for template_path in files: 120 | destination_path = get_destination_filepath(template_path) 121 | if force_update or needs_update(template_path, destination_path): 122 | print "expanding template: %s -> %s" % ( 123 | template_path, destination_path) 124 | content = expand_template(open(template_path, "rb").read()) 125 | new_file = open(destination_path, "wb") 126 | new_file.write(content) 127 | new_file.close() 128 | --------------------------------------------------------------------------------