Commit 18f7987f authored by Florent Jaillet's avatar Florent Jaillet

Initial release of pyteuf v1.0.0

parents
Pipeline #1494 passed with stage
in 6 minutes and 31 seconds
[run]
branch = True
source = pyteuf
include = */pyteuf/*
omit =
*/setup.py
*/__init__.py
*/test_*
[report]
exclude_lines =
pragma: no cover
if self.debug:
if settings.DEBUG
raise AssertionError
raise NotImplementedError
if 0:
if __name__ == .__main__.:
if obj is None: return
if verbose > 0:
if self.verbose > 0:
if verbose > 1:
if self.verbose > 1:
pass
def __str__(self):
*.py[co]
# Packages
*.egg
*.egg-info
dist
build
eggs
parts
bin
var
sdist
develop-eggs
.installed.cfg
# Installer logs
pip-log.txt
# Mac OS X files
.DS_Store
.DS_Store?
._*
.Spotlight-V100
.Trashes
ehthumbs.db
Thumbs.db
# Sphinx stuff
docs/generated/
docs/build/
# jupyter notebook
.ipynb_checkpoints
# coverage
htmlcov
.coverage
# ide
.idea
.spyderproject
# Misc
.cache
.pytest_cache
# run the test suite
tests:
image: registry.gitlab.lis-lab.fr:5005/skmad-suite/madarrays/ubuntu:18.04
tags:
- docker
script:
- pip3 install --no-deps ltfatpy madarrays
- pip3 install --no-deps .
- pytest-3
# generate the documentation
pages:
image: registry.gitlab.lis-lab.fr:5005/skmad-suite/madarrays/ubuntu:18.04
tags:
- docker
only:
- master
script:
- pip3 install --no-deps ltfatpy madarrays
- pip3 install --no-deps .
- python3 setup.py build_sphinx
- cp -r build/sphinx/html public
artifacts:
paths:
- public
This diff is collapsed.
include *.txt
include *.rst
include VERSION
recursive-include doc *.rst *.py *.ipynb
include pyteuf/tests/*.py
prune doc/build
pyteuf
======
pyteuf is a package for time-frequency analysis in Python.
Install
-------
Install the current release with ``pip``::
pip install pyteuf
For additional details, see doc/install.rst.
Usage
-----
See the `documentation <http://skmad-suite.pages.lis-lab.fr/pyteuf/>`_.
Bugs
----
Please report any bugs that you find through the `pyteuf GitLab project
<https://gitlab.lis-lab.fr/skmad-suite/pyteuf/issues>`_.
You can also fork the repository and create a merge request.
Source code
-----------
The source code of pyteuf is available via its `GitLab project
<https://gitlab.lis-lab.fr/skmad-suite/pyteuf>`_.
You can clone the git repository of the project using the command::
git clone git@gitlab.lis-lab.fr:skmad-suite/pyteuf.git
Copyright © 2017-2018
---------------------
* `Laboratoire d'Informatique et Systèmes <http://www.lis-lab.fr/>`_
* `Université d'Aix-Marseille <http://www.univ-amu.fr/>`_
* `Centre National de la Recherche Scientifique <http://www.cnrs.fr/>`_
* `Université de Toulon <http://www.univ-tln.fr/>`_
Contributors
------------
* `Ronan Hamon <mailto:ronan.hamon@lis-lab.fr>`_
* `Valentin Emiya <mailto:valentin.emiya@lis-lab.fr>`_
* `Florent Jaillet <mailto:florent.jaillet@lis-lab.fr>`_
License
-------
Released under the GNU General Public License version 3 or later
(see `LICENSE.txt`).
pyteuf:1.0.0
# Makefile for Sphinx documentation
#
# You can set these variables from the command line.
SPHINXOPTS =
SPHINXBUILD = python -m sphinx
PAPER =
# Internal variables.
PAPEROPT_a4 = -D latex_paper_size=a4
PAPEROPT_letter = -D latex_paper_size=letter
ALLSPHINXOPTS = -d build/doctrees $(PAPEROPT_$(PAPER)) $(SPHINXOPTS) .
.PHONY: help clean html dirhtml pickle json htmlhelp qthelp latex changes linkcheck doctest epub
help:
@echo "Please use \`make <target>' where <target> is one of"
@echo " html to make standalone HTML files"
@echo " dirhtml to make HTML files named index.html in directories"
@echo " pickle to make pickle files"
@echo " epub to make an epub"
@echo " json to make JSON files"
@echo " htmlhelp to make HTML files and a HTML help project"
@echo " qthelp to make HTML files and a qthelp project"
@echo " latex to make LaTeX files, you can set PAPER=a4 or PAPER=letter"
@echo " changes to make an overview of all changed/added/deprecated items"
@echo " linkcheck to check all external links for integrity"
@echo " doctest to run all doctests embedded in the documentation (if enabled)"
@echo " gitwash to update the gitwash documentation"
clean:
-rm -rf build/*
-rm -rf ghpages_build
-rm -rf auto_examples modules
-rm -rf reference/generated reference/algorithms/generated reference/classes/generated reference/readwrite/generated
dist: html
test -d build/latex || make latex
make -C build/latex all-pdf
-rm -rf build/dist
(cd build/html; cp -r . ../../build/dist)
(cd build/dist && tar czf ../dist.tar.gz .)
html:
$(SPHINXBUILD) -b html $(ALLSPHINXOPTS) build/html
@echo
@echo "Build finished. The HTML pages are in build/html."
dirhtml:
$(SPHINXBUILD) -b dirhtml $(ALLSPHINXOPTS) build/dirhtml
@echo
@echo "Build finished. The HTML pages are in build/dirhtml."
pickle:
$(SPHINXBUILD) -b pickle $(ALLSPHINXOPTS) build/pickle
@echo
@echo "Build finished; now you can process the pickle files."
json:
$(SPHINXBUILD) -b json $(ALLSPHINXOPTS) build/json
@echo
@echo "Build finished; now you can process the JSON files."
htmlhelp:
$(SPHINXBUILD) -b htmlhelp $(ALLSPHINXOPTS) build/htmlhelp
@echo
@echo "Build finished; now you can run HTML Help Workshop with the" \
".hhp project file in build/htmlhelp."
qthelp:
$(SPHINXBUILD) -b qthelp $(ALLSPHINXOPTS) build/qthelp
@echo
@echo "Build finished; now you can run "qcollectiongenerator" with the" \
".qhcp project file in build/qthelp, like this:"
@echo "# qcollectiongenerator build/qthelp/test.qhcp"
@echo "To view the help file:"
@echo "# assistant -collectionFile build/qthelp/test.qhc"
epub:
$(SPHINXBUILD) -b epub $(ALLSPHINXOPTS) build/epub
@echo
@echo "Build finished. The epub file is in $(BUILDDIR)/epub."
latex:
$(SPHINXBUILD) -b latex $(ALLSPHINXOPTS) build/latex
@echo
@echo "Build finished; the LaTeX files are in build/latex."
@echo "Run \`make all-pdf' or \`make all-ps' in that directory to" \
"run these through (pdf)latex."
changes:
$(SPHINXBUILD) -b changes $(ALLSPHINXOPTS) build/changes
@echo
@echo "The overview file is in build/changes."
linkcheck:
$(SPHINXBUILD) -b linkcheck $(ALLSPHINXOPTS) build/linkcheck
@echo
@echo "Link check complete; look for any errors in the above output " \
"or in build/linkcheck/output.txt."
doctest:
$(SPHINXBUILD) -b doctest $(ALLSPHINXOPTS) build/doctest
@echo "Testing of doctests in the sources finished, look at the " \
"results in build/doctest/output.txt."
latexpdf: latex
@echo "Running LaTeX files through latexmk..."
$(MAKE) -C build/latex all-pdf
@echo "latexmk finished; the PDF files are in build/latex."
docs: clean html latexpdf
cp build/latex/networkx_reference.pdf build/html/_downloads/.
gitwash-update:
python ../tools/gitwash_dumper.py developer networkx \
--project-url=http://networkx.github.io \
--project-ml-url=http://groups.google.com/group/networkx-discuss/ \
--gitwash-url git@github.com:matthew-brett/gitwash.git
If you only want to get the documentation, note that a pre-built
version for the latest release is available
[online](http://skmad-suite.pages.lis-lab.fr/pyteuf/).
Sphinx is used to generate the API and reference documentation for all
packages from the [`skmad-suite`](https://gitlab.lis-lab.fr/skmad-suite/).
## Instructions to build the documentation
In addition to installing ``pyteuf`` and its dependencies, install the
Python packages needed to build the documentation by entering
```
pip install -r ../requirements/doc.txt
```
in the ``doc/`` directory.
To build the HTML documentation, run:
```
make html
```
in the ``doc/`` directory. This will generate a ``build/html`` subdirectory
containing the built documentation.
To build the PDF documentation, run:
```
make latexpdf
```
You will need to have Latex installed for this.
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"autoscroll": "json-false",
"ein.tags": [
"worksheet-0"
],
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"%pylab inline"
]
},
{
"cell_type": "markdown",
"metadata": {
"ein.tags": [
"worksheet-0"
],
"slideshow": {
"slide_type": "-"
}
},
"source": [
"# ``TfData`` objects\n",
"\n",
"A ``TfData`` is a ``MaskedArray`` dedicated to handle Time-Frequency representations obtained from a real signal. As such, it has two attributes ``tf_params`` and ``signal_params``, giving respectively the parameters of the STFT used to obtain the representation, and the parameters of the real signali, as well as dedicated methods to facilitate the manipulation of time-frequency data."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"autoscroll": "json-false",
"collapsed": true,
"ein.tags": [
"worksheet-0"
],
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"from pyteuf import TfData, Stft\n",
"import numpy as np\n",
"import matplotlib.pyplot as plt\n",
"import matplotlib\n",
"matplotlib.rcParams['figure.figsize'] = (14, 4)\n",
"\n",
"# Data parameters\n",
"tf_params = {'hop': 32, 'n_bins': 128, 'win_len': 64, 'win_name': 'hanning'}\n",
"signal_params = {'len':1024, 'fs':44100}"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example of TF representation of a complex signal, with binary masking"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"As for ``MaskedArray``, ``TfData`` can be initialized from a 2D complex nd-array with or without mask. Parameters ``stft_params`` and ``signal_params`` are explicitly given if available. For a complex signal, coefficients for both negative and positive frequencies are handled and displayed"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Data ans mask for a complex signal (no symetry in TF)\n",
"tf_shape_complex = (tf_params['n_bins'], signal_params['len'] // tf_params['hop'])\n",
"mask_complex = np.zeros(tf_shape_complex)\n",
"mask_complex[int(0.2*tf_shape_complex[0]):int(0.6*tf_shape_complex[0]), \n",
" int(0.25*tf_shape_complex[1]):int(0.7*tf_shape_complex[1])] = True\n",
"data_complex = np.random.randn(*tf_shape_complex) + 1j * np.random.randn(*tf_shape_complex)\n",
"\n",
"# TF data\n",
"X = TfData(data=data_complex, mask=mask_complex, tf_params=tf_params, signal_params=signal_params)\n",
"\n",
"plt.subplot(121)\n",
"X.plot_spectrogram()\n",
"plt.subplot(122)\n",
"X.plot_mask()\n",
"print(X)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example of TF representation of a real signal, with binary masking"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"For a real signal, only the non-negative frequencies area is handled due to Hermitian symetry."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Data and mask for a real signal (Hermitian symetry in TF)\n",
"tf_shape_real = (tf_params['n_bins'] // 2 + 1, signal_params['len'] // tf_params['hop'])\n",
"mask_real = np.zeros(tf_shape_real)\n",
"mask_real[int(0.2*tf_shape_real[0]):int(0.6*tf_shape_real[0]), \n",
" int(0.25*tf_shape_real[1]):int(0.7*tf_shape_real[1])] = True\n",
"data_real = np.random.randn(*tf_shape_real) + 1j * np.random.randn(*tf_shape_real)\n",
"\n",
"# TF data\n",
"X = TfData(data=data_real, mask=mask_real, tf_params=tf_params, signal_params=signal_params)\n",
"\n",
"plt.subplot(121)\n",
"X.plot_spectrogram()\n",
"plt.subplot(122)\n",
"X.plot_mask()\n",
"print(X)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Example of TF representation with complex masking"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"With complex masking, two masks are handled: a mask for amplitudes and a mask for phases."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"# Data and mask for a real signal (Hermitian symetry in TF)\n",
"tf_shape_real = (tf_params['n_bins'] // 2 + 1, signal_params['len'] // tf_params['hop'])\n",
"mask_mag = np.zeros(tf_shape_real)\n",
"mask_mag[int(0.2*tf_shape_real[0]):int(0.6*tf_shape_real[0]), \n",
" int(0.25*tf_shape_real[1]):int(0.7*tf_shape_real[1])] = True\n",
"mask_phi = np.zeros(tf_shape_real)\n",
"mask_phi[int(0.5*tf_shape_real[0]):int(0.65*tf_shape_real[0]), \n",
" int(0.65*tf_shape_real[1]):int(0.75*tf_shape_real[1])] = True\n",
"data_real = np.random.randn(*tf_shape_real) + 1j * np.random.randn(*tf_shape_real)\n",
"\n",
"# TF data\n",
"X = TfData(data=data_real,\n",
" mask_magnitude=mask_mag, mask_phase=mask_phi,\n",
" tf_params=tf_params, signal_params=signal_params)\n",
"print(X)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"One may select one of the masks or a combination of them for display."
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for mask_type in ['any', 'all', 'magnitude', 'phase', 'magnitude only', 'phase only']:\n",
" plt.figure()\n",
" plt.subplot(121)\n",
" X.plot_spectrogram(mask_type=mask_type)\n",
" plt.title('mask type: {}'.format(mask_type))\n",
" plt.subplot(122)\n",
" X.plot_mask(mask_type=mask_type)\n",
" plt.title('mask type: {}'.format(mask_type))\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Selecting a mask type can also be used to extract the related mask:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"for mask_type in ['any', 'all', 'magnitude', 'phase', 'magnitude only', 'phase only']:\n",
" mask = X.get_unknown_mask(mask_type)\n",
" print('Ratio of \"{}\" unknown coefficients: {:.1%}'.format(mask_type, np.mean(mask)))\n",
" mask = X.get_known_mask(mask_type)\n",
" print('Ratio of \"{}\" known coefficients: {:.1%}'.format(mask_type, np.mean(mask)))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Other useful properties:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"print('Number of frequencies: {}'.format(X.n_frequencies))\n",
"print('Number of frames: {}'.format(X.n_frames))\n",
"print('Start time of frames: {}'.format(X.start_times))\n",
"print('Center time of frames: {}'.format(X.mid_times))\n",
"print('End time of frames: {}'.format(X.end_times))"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Current operations between two ``TfData`` objects are not recommended since resulting operations on masks are not designed adequately:"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"ein.tags": [
"worksheet-0"
],
"slideshow": {
"slide_type": "-"
}
},
"outputs": [],
"source": [
"mask1 = np.zeros(tf_shape_real)\n",
"mask1[int(0.2*tf_shape_real[0]):int(0.6*tf_shape_real[0]), \n",
" int(0.25*tf_shape_real[1]):int(0.7*tf_shape_real[1])] = True\n",
"mask2 = np.zeros(tf_shape_real)\n",
"mask2[int(0.5*tf_shape_real[0]):int(0.65*tf_shape_real[0]), \n",
" int(0.65*tf_shape_real[1]):int(0.75*tf_shape_real[1])] = True\n",
"data_real = np.random.randn(*tf_shape_real) + 1j * np.random.randn(*tf_shape_real)\n",
"\n",
"# TF data\n",
"X1 = TfData(data=np.random.randn(*tf_shape_real) + 1j * np.random.randn(*tf_shape_real),\n",
" mask=mask1, tf_params=tf_params, signal_params=signal_params)\n",
"X2 = TfData(data=np.random.randn(*tf_shape_real) + 1j * np.random.randn(*tf_shape_real),\n",
" mask=mask2, tf_params=tf_params, signal_params=signal_params)\n",
"\n",
"plt.figure()\n",
"plt.subplot(121)\n",
"X1.plot_spectrogram()\n",
"plt.subplot(122)\n",
"X2.plot_spectrogram()\n",
"\n",
"plt.figure()\n",
"X3 = X1 + X2\n",
"X4 = X1 - X2\n",
"plt.subplot(121)\n",
"X3.plot_spectrogram()\n",
"plt.subplot(122)\n",
"X4.plot_spectrogram()\n",
"\n",
"plt.figure()\n",
"X3 = X1 * X2\n",
"X4 = X1 / X2\n",
"plt.subplot(121)\n",
"X3.plot_spectrogram()\n",
"plt.subplot(122)\n",
"X4.plot_spectrogram()\n",
"pass"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": []
}
],
"metadata": {
"kernelspec": {
"display_name": "Python 3",
"language": "python",
"name": "python3"
},
"language_info": {
"codemirror_mode": {
"name": "ipython",
"version": 3
},
"file_extension": ".py",
"mimetype": "text/x-python",
"name": "python",
"nbconvert_exporter": "python",
"pygments_lexer": "ipython3",
"version": "3.6.2"
},
"name": "data_structures.ipynb"
},
"nbformat": 4,
"nbformat_minor": 1
}
</
{
"cells": [
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"%pylab inline"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"# Time-Frequency analysis with missing data\n",
"\n",
"## `Stft` objects\n",
"\n",
"Short-time Fourier transforms (STFT) of signals can be handled using `Stft` objects. This is a wrapper for the `ltfatpy` package. \n",
"\n",
"### Transform and inverse transform\n",
"`Stft` takes as input the parameters of the STFT, namely the hop size `hop`, the number of bins `n_bins`, the window type `win_name` and length `win_len`, as well as two other parameters, `param_constraint` (see tutorial on the constraints on the transform length) and `zero_pad_full_sig` (see tutorial on boundary effects).\n",
" \n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"from pyteuf import Stft\n",
"from madarrays import Waveform"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"stft = Stft(hop=16, n_bins=512, win_name='sine', win_len=256,\n",
" param_constraint='pad', zero_pad_full_sig=False)\n",
"print(stft)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"The inverse transform may obtained from the direct transform by"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"istft = stft.get_istft()\n",
"print(istft)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"### Example on a synthetic real signal"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Create a signal composed of two sines"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": true
},
"outputs": [],
"source": [
"nu1 = 1/33\n",
"nu2 = 3/16\n",
"duration = 0.5\n",
"fs = 8000\n",
"t = np.arange(0, int(duration*fs)) / fs\n",
"x = np.cos(2*np.pi*t*nu1*fs) + 0.5*np.cos(2*np.pi*t*nu2*fs)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Compute STFT and display the spectrogram"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {},
"outputs": [],
"source": [
"X = stft.apply(x, fs=fs)\n",
"print(X)\n",
"_ = X.plot_spectrogram(dynrange=100.)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Note that the negative frequencies are not displayed since the STFT of a real signal is symetric hermitian, and that boundary effects appear at the beginning and the end of the time axis.\n",