├── .gitignore ├── .travis.yml ├── README.md ├── data └── .gitkeep ├── docs ├── build.sh └── source │ ├── conf.py │ ├── frft.rst │ ├── index.rst │ ├── installation.rst │ └── modules.rst ├── frft ├── __init__.py └── frft.py ├── requirements.txt ├── setup.cfg ├── setup.py ├── tests └── __init__.py └── tox.ini /.gitignore: -------------------------------------------------------------------------------- 1 | *.pyc 2 | *.pyo 3 | build 4 | dist 5 | src/*.egg-info 6 | *.egg 7 | *.egg-info 8 | *.so 9 | *.egg-info/ 10 | docs/build 11 | docs/source/api 12 | .tox 13 | -------------------------------------------------------------------------------- /.travis.yml: -------------------------------------------------------------------------------- 1 | language: python 2 | python: 3 | - 2.7 4 | # - 3.2 # Broken, see https://github.com/travis-ci/travis-ci/issues/2277 5 | virtualenv: 6 | system_site_packages: true 7 | before_install: 8 | - sudo apt-get update -qq 9 | - sudo apt-get install -qq python-numpy python-scipy python-nose python-matplotlib 10 | - sudo apt-get install -qq python3-numpy python3-scipy python3-nose 11 | - sudo apt-get install -qq libatlas-dev libatlas-base-dev liblapack-dev gfortran 12 | - pip install python-dateutil 13 | - pip install pytz 14 | install: 15 | - pip install -e . 16 | script: 17 | - nosetests 18 | -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | FRFT 2 | ==== 3 | 4 | This is a package for calculating fractional fourier transforms with NumPy. 5 | 6 | Installation 7 | ------------ 8 | 9 | You can install this library using `pip`: 10 | 11 | pip install git+ssh://git@github.com/audiolabs/python_frft.git#egg=frft 12 | -------------------------------------------------------------------------------- /data/.gitkeep: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/nanaln/python_frft/767ca3553fedff77603b2dae7a96f6cb4808b57a/data/.gitkeep -------------------------------------------------------------------------------- /docs/build.sh: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env bash 2 | 3 | rm -rf build 4 | rm -rf source/api 5 | sphinx-apidoc -e -o source/api .. 6 | sphinx-build -c . source/ build 7 | -------------------------------------------------------------------------------- /docs/source/conf.py: -------------------------------------------------------------------------------- 1 | #!/usr/bin/env python 2 | # -*- coding: utf-8 -*- 3 | # 4 | # frft documentation build configuration file, created by 5 | # sphinx-quickstart on Sun Apr 20 14:28:17 2014. 6 | # 7 | # This file is execfile()d with the current directory set to its 8 | # containing dir. 9 | # 10 | # Note that not all possible configuration values are present in this 11 | # autogenerated file. 12 | # 13 | # All configuration values have a default; values that are commented out 14 | # serve to show the default. 15 | 16 | import sys 17 | import os 18 | import sphinx_rtd_theme 19 | 20 | # If extensions (or modules to document with autodoc) are in another directory, 21 | # add these directories to sys.path here. If the directory is relative to the 22 | # documentation root, use os.path.abspath to make it absolute, like shown here. 23 | #sys.path.insert(0, os.path.abspath('.')) 24 | 25 | # -- General configuration ------------------------------------------------ 26 | 27 | # If your documentation needs a minimal Sphinx version, state it here. 28 | #needs_sphinx = '1.0' 29 | 30 | # Add any Sphinx extension module names here, as strings. They can be 31 | # extensions coming with Sphinx (named 'sphinx.ext.*') or your custom 32 | # ones. 33 | extensions = [ 34 | 'sphinx.ext.autodoc', 35 | 'sphinx.ext.doctest', 36 | 'sphinx.ext.pngmath', 37 | 'sphinx.ext.viewcode', 38 | 'sphinxcontrib.napoleon', 39 | ] 40 | 41 | # Add any paths that contain templates here, relative to this directory. 42 | templates_path = ['_templates'] 43 | 44 | # The suffix of source filenames. 45 | source_suffix = '.rst' 46 | 47 | # The encoding of source files. 48 | #source_encoding = 'utf-8-sig' 49 | 50 | # The master toctree document. 51 | master_doc = 'index' 52 | 53 | # General information about the project. 54 | project = 'frft' 55 | copyright = '2014, International AudioLabs Erlangen' 56 | 57 | # The version info for the project you're documenting, acts as replacement for 58 | # |version| and |release|, also used in various other places throughout the 59 | # built documents. 60 | # 61 | # The short X.Y version. 62 | version = '0.1' 63 | # The full version, including alpha/beta/rc tags. 64 | release = '0.1' 65 | 66 | # The language for content autogenerated by Sphinx. Refer to documentation 67 | # for a list of supported languages. 68 | #language = None 69 | 70 | # There are two options for replacing |today|: either, you set today to some 71 | # non-false value, then it is used: 72 | #today = '' 73 | # Else, today_fmt is used as the format for a strftime call. 74 | #today_fmt = '%B %d, %Y' 75 | 76 | # List of patterns, relative to source directory, that match files and 77 | # directories to ignore when looking for source files. 78 | exclude_patterns = ['_build','**tests**','**setup**','**extern**','**data**'] 79 | 80 | # The reST default role (used for this markup: `text`) to use for all 81 | # documents. 82 | #default_role = None 83 | 84 | # If true, '()' will be appended to :func: etc. cross-reference text. 85 | #add_function_parentheses = True 86 | 87 | # If true, the current module name will be prepended to all description 88 | # unit titles (such as .. function::). 89 | #add_module_names = True 90 | 91 | # If true, sectionauthor and moduleauthor directives will be shown in the 92 | # output. They are ignored by default. 93 | #show_authors = False 94 | 95 | # The name of the Pygments (syntax highlighting) style to use. 96 | pygments_style = 'sphinx' 97 | 98 | # A list of ignored prefixes for module index sorting. 99 | #modindex_common_prefix = [] 100 | 101 | # If true, keep warnings as "system message" paragraphs in the built documents. 102 | #keep_warnings = False 103 | 104 | 105 | # -- Options for HTML output ---------------------------------------------- 106 | 107 | # The theme to use for HTML and HTML Help pages. See the documentation for 108 | # a list of builtin themes. 109 | html_theme = "sphinx_rtd_theme" 110 | 111 | # Theme options are theme-specific and customize the look and feel of a theme 112 | # further. For a list of options available for each theme, see the 113 | # documentation. 114 | #html_theme_options = {} 115 | 116 | # Add any paths that contain custom themes here, relative to this directory. 117 | html_theme_path = [sphinx_rtd_theme.get_html_theme_path()] 118 | 119 | # The name for this set of Sphinx documents. If None, it defaults to 120 | # " v documentation". 121 | #html_title = None 122 | 123 | # A shorter title for the navigation bar. Default is the same as html_title. 124 | #html_short_title = None 125 | 126 | # The name of an image file (relative to this directory) to place at the top 127 | # of the sidebar. 128 | #html_logo = None 129 | 130 | # The name of an image file (within the static path) to use as favicon of the 131 | # docs. This file should be a Windows icon file (.ico) being 16x16 or 32x32 132 | # pixels large. 133 | #html_favicon = None 134 | 135 | # Add any paths that contain custom static files (such as style sheets) here, 136 | # relative to this directory. They are copied after the builtin static files, 137 | # so a file named "default.css" will overwrite the builtin "default.css". 138 | html_static_path = ['_static'] 139 | 140 | # Add any extra paths that contain custom files (such as robots.txt or 141 | # .htaccess) here, relative to this directory. These files are copied 142 | # directly to the root of the documentation. 143 | #html_extra_path = [] 144 | 145 | # If not '', a 'Last updated on:' timestamp is inserted at every page bottom, 146 | # using the given strftime format. 147 | #html_last_updated_fmt = '%b %d, %Y' 148 | 149 | # If true, SmartyPants will be used to convert quotes and dashes to 150 | # typographically correct entities. 151 | #html_use_smartypants = True 152 | 153 | # Custom sidebar templates, maps document names to template names. 154 | #html_sidebars = {} 155 | 156 | # Additional templates that should be rendered to pages, maps page names to 157 | # template names. 158 | #html_additional_pages = {} 159 | 160 | # If false, no module index is generated. 161 | #html_domain_indices = True 162 | 163 | # If false, no index is generated. 164 | #html_use_index = True 165 | 166 | # If true, the index is split into individual pages for each letter. 167 | #html_split_index = False 168 | 169 | # If true, links to the reST sources are added to the pages. 170 | #html_show_sourcelink = True 171 | 172 | # If true, "Created using Sphinx" is shown in the HTML footer. Default is True. 173 | #html_show_sphinx = True 174 | 175 | # If true, "(C) Copyright ..." is shown in the HTML footer. Default is True. 176 | #html_show_copyright = True 177 | 178 | # If true, an OpenSearch description file will be output, and all pages will 179 | # contain a tag referring to it. The value of this option must be the 180 | # base URL from which the finished HTML is served. 181 | #html_use_opensearch = '' 182 | 183 | # This is the file name suffix for HTML files (e.g. ".xhtml"). 184 | #html_file_suffix = None 185 | 186 | # Output file base name for HTML help builder. 187 | htmlhelp_basename = 'frftdoc' 188 | 189 | 190 | # -- Options for LaTeX output --------------------------------------------- 191 | 192 | latex_elements = { 193 | # The paper size ('letterpaper' or 'a4paper'). 194 | #'papersize': 'letterpaper', 195 | 196 | # The font size ('10pt', '11pt' or '12pt'). 197 | #'pointsize': '10pt', 198 | 199 | # Additional stuff for the LaTeX preamble. 200 | #'preamble': '', 201 | } 202 | 203 | # Grouping the document tree into LaTeX files. List of tuples 204 | # (source start file, target name, title, 205 | # author, documentclass [howto, manual, or own class]). 206 | latex_documents = [ 207 | ('index', 'frft.tex', 'frft Documentation', 208 | 'International AudioLabs Erlangen', 'manual'), 209 | ] 210 | 211 | # The name of an image file (relative to this directory) to place at the top of 212 | # the title page. 213 | #latex_logo = None 214 | 215 | # For "manual" documents, if this is true, then toplevel headings are parts, 216 | # not chapters. 217 | #latex_use_parts = False 218 | 219 | # If true, show page references after internal links. 220 | #latex_show_pagerefs = False 221 | 222 | # If true, show URL addresses after external links. 223 | #latex_show_urls = False 224 | 225 | # Documents to append as an appendix to all manuals. 226 | #latex_appendices = [] 227 | 228 | # If false, no module index is generated. 229 | #latex_domain_indices = True 230 | 231 | 232 | # -- Options for manual page output --------------------------------------- 233 | 234 | # One entry per manual page. List of tuples 235 | # (source start file, name, description, authors, manual section). 236 | man_pages = [ 237 | ('index', 'frft', 'frft Documentation', 238 | ['International AudioLabs Erlangen'], 1) 239 | ] 240 | 241 | # If true, show URL addresses after external links. 242 | #man_show_urls = False 243 | 244 | 245 | # -- Options for Texinfo output ------------------------------------------- 246 | 247 | # Grouping the document tree into Texinfo files. List of tuples 248 | # (source start file, target name, title, author, 249 | # dir menu entry, description, category) 250 | texinfo_documents = [ 251 | ('index', 'frft', 'frft Documentation', 252 | 'International AudioLabs Erlangen', 'frft', 'One line description of project.', 253 | 'Miscellaneous'), 254 | ] 255 | 256 | # Documents to append as an appendix to all manuals. 257 | #texinfo_appendices = [] 258 | 259 | # If false, no module index is generated. 260 | #texinfo_domain_indices = True 261 | 262 | # How to display URL addresses: 'footnote', 'no', or 'inline'. 263 | #texinfo_show_urls = 'footnote' 264 | 265 | # If true, do not generate a @detailmenu in the "Top" node's menu. 266 | #texinfo_no_detailmenu = False 267 | -------------------------------------------------------------------------------- /docs/source/frft.rst: -------------------------------------------------------------------------------- 1 | frft package 2 | ============ 3 | 4 | Submodules 5 | ---------- 6 | 7 | frft.frft module 8 | ---------------- 9 | 10 | .. automodule:: frft.frft 11 | :members: 12 | :undoc-members: 13 | :show-inheritance: 14 | 15 | 16 | Module contents 17 | --------------- 18 | 19 | .. automodule:: frft 20 | :members: 21 | :undoc-members: 22 | :show-inheritance: 23 | -------------------------------------------------------------------------------- /docs/source/index.rst: -------------------------------------------------------------------------------- 1 | Welcome to this FRFT's documentation! 2 | ===================================== 3 | 4 | This is a package for calculating fractional fourier transforms with NumPy. 5 | 6 | Contents: 7 | 8 | .. toctree:: 9 | :maxdepth: 2 10 | 11 | installation 12 | api/frft 13 | 14 | 15 | Indices and tables 16 | ================== 17 | 18 | * :ref:`genindex` 19 | * :ref:`modindex` 20 | * :ref:`search` 21 | 22 | -------------------------------------------------------------------------------- /docs/source/installation.rst: -------------------------------------------------------------------------------- 1 | Installation 2 | ============ 3 | -------------------------------------------------------------------------------- /docs/source/modules.rst: -------------------------------------------------------------------------------- 1 | frft 2 | ==== 3 | 4 | .. toctree:: 5 | :maxdepth: 4 6 | 7 | frft 8 | -------------------------------------------------------------------------------- /frft/__init__.py: -------------------------------------------------------------------------------- 1 | from .frft import frft, ifrft 2 | -------------------------------------------------------------------------------- /frft/frft.py: -------------------------------------------------------------------------------- 1 | """ 2 | Module to calculate the fast fractional fourier transform. 3 | 4 | """ 5 | 6 | from __future__ import division 7 | import numpy 8 | import scipy 9 | import scipy.signal 10 | 11 | 12 | def frft(f, a): 13 | """ 14 | Calculate the fast fractional fourier transform. 15 | 16 | Parameters 17 | ---------- 18 | f : numpy array 19 | The signal to be transformed. 20 | a : float 21 | fractional power 22 | 23 | Returns 24 | ------- 25 | data : numpy array 26 | The transformed signal. 27 | 28 | 29 | References 30 | --------- 31 | .. [1] This algorithm implements `frft.m` from 32 | https://nalag.cs.kuleuven.be/research/software/FRFT/ 33 | 34 | """ 35 | ret = numpy.zeros_like(f, dtype=numpy.complex) 36 | f = f.copy().astype(numpy.complex) 37 | N = len(f) 38 | shft = numpy.fmod(numpy.arange(N) + numpy.fix(N / 2), N).astype(int) 39 | sN = numpy.sqrt(N) 40 | a = numpy.remainder(a, 4.0) 41 | 42 | # Special cases 43 | if a == 0.0: 44 | return f 45 | if a == 2.0: 46 | return numpy.flipud(f) 47 | if a == 1.0: 48 | ret[shft] = numpy.fft.fft(f[shft]) / sN 49 | return ret 50 | if a == 3.0: 51 | ret[shft] = numpy.fft.ifft(f[shft]) * sN 52 | return ret 53 | 54 | # reduce to interval 0.5 < a < 1.5 55 | if a > 2.0: 56 | a = a - 2.0 57 | f = numpy.flipud(f) 58 | if a > 1.5: 59 | a = a - 1 60 | f[shft] = numpy.fft.fft(f[shft]) / sN 61 | if a < 0.5: 62 | a = a + 1 63 | f[shft] = numpy.fft.ifft(f[shft]) * sN 64 | 65 | # the general case for 0.5 < a < 1.5 66 | alpha = a * numpy.pi / 2 67 | tana2 = numpy.tan(alpha / 2) 68 | sina = numpy.sin(alpha) 69 | f = numpy.hstack((numpy.zeros(N - 1), sincinterp(f), numpy.zeros(N - 1))).T 70 | 71 | # chirp premultiplication 72 | chrp = numpy.exp(-1j * numpy.pi / N * tana2 / 4 * 73 | numpy.arange(-2 * N + 2, 2 * N - 1).T ** 2) 74 | f = chrp * f 75 | 76 | # chirp convolution 77 | c = numpy.pi / N / sina / 4 78 | ret = scipy.signal.fftconvolve( 79 | numpy.exp(1j * c * numpy.arange(-(4 * N - 4), 4 * N - 3).T ** 2), 80 | f 81 | ) 82 | ret = ret[4 * N - 4:8 * N - 7] * numpy.sqrt(c / numpy.pi) 83 | 84 | # chirp post multiplication 85 | ret = chrp * ret 86 | 87 | # normalizing constant 88 | ret = numpy.exp(-1j * (1 - a) * numpy.pi / 4) * ret[N - 1:-N + 1:2] 89 | 90 | return ret 91 | 92 | 93 | def ifrft(f, a): 94 | """ 95 | Calculate the inverse fast fractional fourier transform. 96 | 97 | Parameters 98 | ---------- 99 | f : numpy array 100 | The signal to be transformed. 101 | a : float 102 | fractional power 103 | 104 | Returns 105 | ------- 106 | data : numpy array 107 | The transformed signal. 108 | 109 | """ 110 | return frft(f, -a) 111 | 112 | 113 | def sincinterp(x): 114 | N = len(x) 115 | y = numpy.zeros(2 * N - 1, dtype=x.dtype) 116 | y[:2 * N:2] = x 117 | xint = scipy.signal.fftconvolve( 118 | y[:2 * N], 119 | numpy.sinc(numpy.arange(-(2 * N - 3), (2 * N - 2)).T / 2), 120 | ) 121 | return xint[2 * N - 3: -2 * N + 3] 122 | -------------------------------------------------------------------------------- /requirements.txt: -------------------------------------------------------------------------------- 1 | nose 2 | numpy 3 | scipy 4 | sphinxcontrib-napoleon 5 | sphinx_rtd_theme 6 | tox 7 | -------------------------------------------------------------------------------- /setup.cfg: -------------------------------------------------------------------------------- 1 | [build_sphinx] 2 | source-dir = docs/source 3 | build-dir = docs/build 4 | all_files = 1 5 | 6 | [upload_sphinx] 7 | upload-dir = docs/build/html 8 | -------------------------------------------------------------------------------- /setup.py: -------------------------------------------------------------------------------- 1 | import setuptools 2 | import setuptools.command.develop 3 | 4 | 5 | setuptools.setup( 6 | # Name of the project 7 | name='frft', 8 | 9 | # Version 10 | version='0.1', 11 | 12 | # Description 13 | description='Fractional Fourier transform for NumPy.', 14 | 15 | # Your contact information 16 | author='Nils Werner', 17 | author_email='nils.werner@gmail.com', 18 | 19 | # License 20 | license='MIT', 21 | 22 | # Packages in this project 23 | # find_packages() finds all these automatically for you 24 | packages=setuptools.find_packages(exclude=['tests']), 25 | 26 | # Dependencies, this installs the entire Python scientific 27 | # computations stack 28 | install_requires=[ 29 | 'numpy>=1.6', 30 | 'scipy>=0.9', 31 | ], 32 | 33 | tests_require=[ 34 | 'nose>=1.3.0' 35 | ], 36 | test_suite="nose.collector", 37 | 38 | classifiers=[ 39 | 'Development Status :: 2 - Alpha', 40 | 'Environment :: Console', 41 | 'Intended Audience :: Telecommunications Industry', 42 | 'Intended Audience :: Science/Research', 43 | 'Programming Language :: Python :: 2.7', 44 | 'Programming Language :: Python :: 3', 45 | 'Topic :: Multimedia :: Sound/Audio :: Analysis', 46 | 'Topic :: Multimedia :: Sound/Audio :: Sound Synthesis' 47 | ], 48 | zip_safe=False, 49 | ) 50 | -------------------------------------------------------------------------------- /tests/__init__.py: -------------------------------------------------------------------------------- 1 | import frft 2 | import numpy 3 | 4 | 5 | def precision(a): 6 | """ 7 | Test if transform-inverse identity holds 8 | 9 | """ 10 | siglen = 2048 11 | 12 | i = numpy.random.random(siglen) 13 | x = frft.frft(i, a) 14 | y = frft.ifrft(x, a) 15 | 16 | assert numpy.allclose(i, y) 17 | 18 | 19 | def test_precision(): 20 | for a in range(40): 21 | yield precision, a / 10.0 22 | -------------------------------------------------------------------------------- /tox.ini: -------------------------------------------------------------------------------- 1 | [tox] 2 | envlist = py27, py34 3 | 4 | [testenv] 5 | deps=nose 6 | commands=nosetests 7 | --------------------------------------------------------------------------------