Skip to main content

Calculates multi-taper windowed and time-frequency reassignment spectrograms

Project description

ProjectStatus Version BuildStatus License PythonVersions DOI

Libtfr is a library for calculating multi-taper time-frequency reassignment (TFR) spectrograms. Time-frequency reassignment is a method that makes use of the instantaneous frequency and phase values in a spectrogram to ‘deconvolve’ the image, and can yield substantially sharper spectrograms with better signal-noise resolution than conventional windowed spectrograms (i.e. short-time Fourier transforms) or multi-taper spectrograms (using the discrete prolate spherical sequences).

The library will also calculate conventional windowed spectrograms and multitaper spectrograms.

Libtfr has C and Python APIs. The Python package has been tested on CPython 3.7-3.11 and PyPy 3.7-3.10.

Python package

To install from PyPI:

pip install libtfr

Wheels are built for most versions of linux and macosx using cibuildwheel. These are statically linked to generic LAPACK routines and a fairly old version of fftw, so if speed is a concern, consider compiling yourself against optimized libraries of your own following the instructions below. Windows wheels with statically linked FFTW and LAPACK libraries have kindly been developed by carlkl, but they very out of date now. Install with pip install -i https://pypi.anaconda.org/carlkl/simple libtfr

Installing from source

To build the python module, you’ll need to install some system dependencies first. On Debian:

sudo apt-get install libfftw3-dev liblapack-dev

On OS X with Macports:

sudo port install fftw-3

To build and install the python module from source:

pip install .

Use

To compute a time-frequency reassignment spectrogram in Python:

import libtfr
nfft = 256
Np = 201
shift = 10
K = 6
tm = 6.0
flock = 0.01
tlock = 5

# load signal of dimension (npoints,)
signal = ...
S = libtfr.tfr_spec(signal, nfft, shift, Np, K, tm, flock, tlock)

See below for more information on the parameters.

Mulitaper Spectral Analysis

Libtfr can also calculate multitaper and standard windowed Fourier transforms. For example, discrete prolate spherical sequences can be used to obtain multiple independent estimates of spectral statistics while maintaining optimal time-frequency tradeoffs (Prieto et al, 2007). The Python interface for MT calculations is somewhat different:

import libtfr

# load signal of dimension (npoints,)
signal = ...

# generate a transform object with size equal to signal length and 5 tapers
D = libtfr.mfft_dpss(npoints, 3, 5)
# complex windowed FFTs, one per taper
Z = D.mtfft(signal)
# power spectrum density estimate using adaptive method to average tapers
P = D.mtpsd(signal)

# generate a transform object with size 512 samples and 5 tapers for short-time analysis
D = libtfr.mfft_dpss(512, 3, 5)
# complex STFT with frame shift of 10 samples
Z = D.mtstft(signal, 10)
# spectrogram with frame shift of 10 samples
P = D.mtspec(signal, 10)

# generate a transform object with 200-sample hanning window padded to 256 samples
from numpy import hanning
D = libtfr.mfft_precalc(256, hanning(200))
# spectrogram with frame shift of 10 samples
P = D.mtspec(signal, 10)

C Library

To build the C library you will also need to have scons installed. You may need to edit the SConstruct file to make sure it points to the correct LAPACK libraries. To build the shared library:

scons lib

To install the libraries and header (default to /usr/local/lib and /usr/local/include):

scons install

A small test program, test_tfr, can be built with scons test. The program generates a signal with sinusoidally modulated frequency and then calculates a multitaper PSD, a multitaper spectrogram, and a time-frequency reassigned spectrogram. The results are output in ASCII format to tfr_in.dat, tfr_out_psd.dat, tfr_out_mtm.dat, and tfr_out_tfr.dat.

See src/test_tfr.c for an example of how to use the C API.

Documentation

The C header tfr.h and python module libtfr.pyx are both extensively documented.

Algorithm and usage notes

The software was assembled from various MATLAB sources, including the time-frequency toolkit, Xiao and Flandrin’s work on multitaper reassignment, and code from Gardner and Magnasco.

The basic principle is to use reassignment to increase the precision of the time-frequency localization, essentially by deconvolving the spectrogram with the TF representation of the window, recovering the center of mass of the spectrotemporal energy. Reassigned TFRs typically show a ‘froth’ for noise, and strong narrow lines for coherent signals like pure tones, chirps, and so forth. The use of multiple tapers reinforces the coherent signals while averaging out the froth, giving a very clean spectrogram with optimal precision and resolution properties.

Gardner & Magnasco (2006) calculate reassignment based on a different algorithm from Xiao and Flandrin (2007). The latter involves 3 different FFT operations on the signal windowed with the hermitian taper h(t), its derivative h’(t), and its time product t × h(t). The G&M algorithm only uses two FFTs, on the signal windowed with a Gaussian and its time derivative. If I understand their methods correctly, however, this derivation is based on properties of the fourier transform of the gaussian, and isn’t appropriate for window functions based on the Hermitian tapers, which have more optimal distribution of energy over the TF plane (i.e., it takes fewer Hermitian tapers than Gaussian tapers to achieve the same quality spectrogram)

Therefore, the algorithm is mostly from X&F, though I include time and frequency locking parameters from G&M, which specify how far energy is allowed to be reassigned in the TF plane. Large displacements generally arise from numerical errors, so this helps to sharpen the lines somewhat. I also included the time/frequency interpolation from Prieto et al (2007), which can be used to get higher precision (at the expense of less averaging) from smaller analysis windows.

Some fiddling with parameters is necessary to get the best spectrograms from a given sort of signal. Like the window size in an STFT, the taper parameters control the time-frequency resolution. However, in the reassignment spectrogram the precision (i.e. localization) is not affected by the taper size, so the effects of taper size will generally only be seen when two coherent signals are close to each other in time or frequency. Nh controls the size of the tapers; one can also adjust tm, the time support of the tapers, but depending on the number of tapers used, this shouldn’t get a whole lot smaller than 5. Increased values of Nh result in improved narrowband resolution (i.e. between pure tones) but closely spaced clicks can become smeared. Decreasing Nh increases the resolution between broadband components (i.e. clicks) but smears closely spaced narrowband components. The effect of smearing can be ameliorated to some extent by adjusting the frequency/time locking parameters.

The frequency zoom parameter can be used to speed up calculation quite a bit. Since calculating the multitaper reassigned spectrogram takes 3xNtapers FFT operations, smaller FFTs are generally better. The spectrogram can then be binned at a finer resolution during reassignment. These two sets of parameters should generate fairly similar results:

nfft=512, shift=10, tm=6, Nh=257, zoomf=1, zoomt=1 (default)
nfft=256, shift=10, tm=6, Nh=257, zoomf=2, zoomt=1

Increasing the order generally reduces the background ‘froth’, but interference between closely spaced components may increase.

Additional improvements in resolution may be achievable averaging across different window sizes, or by using other averaging methods (i.e. as in Xiao and Flandrin 2007)

License

libtfr was written by C Daniel Meliza and is licensed under the Gnu Public License (GPL) version 2; see COPYING for details.

some code is adapted from chronux (http://www.chronux.org), by Partha Mitra and Hemant Bokil, also licensed under GPL version 2

THE PROGRAMS ARE PROVIDED “AS IS” WITHOUT WARRANTY OF MERCANTABILITY OR FITNESS FOR A PARTICULAR PURPOSE OR ANY OTHER WARRANTY, EXPRESS OR IMPLIED. IN NO EVENT SHALL THE UNIVERSITY OF CHICAGO OR DR. MELIZA BE LIABLE FOR ANY DIRECT OR CONSEQUENTIAL DAMAGES RESULTING FROM USE OF THE PROGRAMS. THE USER BEARS THE ENTIRE RISK FOR USE OF THE PROGRAMS.

References

Project details


Download files

Download the file for your platform. If you're not sure which to choose, learn more about installing packages.

Source Distribution

libtfr-2.1.9.tar.gz (234.1 kB view hashes)

Uploaded Source

Built Distributions

libtfr-2.1.9-pp310-pypy310_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.1 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

libtfr-2.1.9-pp310-pypy310_pp73-macosx_11_0_arm64.whl (532.2 kB view hashes)

Uploaded PyPy macOS 11.0+ ARM64

libtfr-2.1.9-pp310-pypy310_pp73-macosx_10_15_x86_64.whl (605.3 kB view hashes)

Uploaded PyPy macOS 10.15+ x86-64

libtfr-2.1.9-pp39-pypy39_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.1 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

libtfr-2.1.9-pp39-pypy39_pp73-macosx_11_0_arm64.whl (532.1 kB view hashes)

Uploaded PyPy macOS 11.0+ ARM64

libtfr-2.1.9-pp39-pypy39_pp73-macosx_10_15_x86_64.whl (605.2 kB view hashes)

Uploaded PyPy macOS 10.15+ x86-64

libtfr-2.1.9-pp38-pypy38_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.1 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

libtfr-2.1.9-pp38-pypy38_pp73-manylinux_2_17_i686.manylinux2014_i686.whl (3.9 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ i686

libtfr-2.1.9-pp38-pypy38_pp73-macosx_11_0_arm64.whl (532.6 kB view hashes)

Uploaded PyPy macOS 11.0+ ARM64

libtfr-2.1.9-pp38-pypy38_pp73-macosx_10_9_x86_64.whl (607.5 kB view hashes)

Uploaded PyPy macOS 10.9+ x86-64

libtfr-2.1.9-pp37-pypy37_pp73-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.1 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ x86-64

libtfr-2.1.9-pp37-pypy37_pp73-manylinux_2_17_i686.manylinux2014_i686.whl (3.9 MB view hashes)

Uploaded PyPy manylinux: glibc 2.17+ i686

libtfr-2.1.9-pp37-pypy37_pp73-macosx_10_9_x86_64.whl (607.5 kB view hashes)

Uploaded PyPy macOS 10.9+ x86-64

libtfr-2.1.9-cp313-cp313-musllinux_1_2_x86_64.whl (7.0 MB view hashes)

Uploaded CPython 3.13 musllinux: musl 1.2+ x86-64

libtfr-2.1.9-cp313-cp313-musllinux_1_2_i686.whl (6.7 MB view hashes)

Uploaded CPython 3.13 musllinux: musl 1.2+ i686

libtfr-2.1.9-cp313-cp313-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.8 MB view hashes)

Uploaded CPython 3.13 manylinux: glibc 2.17+ x86-64

libtfr-2.1.9-cp313-cp313-manylinux_2_17_i686.manylinux2014_i686.whl (4.6 MB view hashes)

Uploaded CPython 3.13 manylinux: glibc 2.17+ i686

libtfr-2.1.9-cp313-cp313-macosx_11_0_arm64.whl (555.4 kB view hashes)

Uploaded CPython 3.13 macOS 11.0+ ARM64

libtfr-2.1.9-cp313-cp313-macosx_10_13_x86_64.whl (635.1 kB view hashes)

Uploaded CPython 3.13 macOS 10.13+ x86-64

libtfr-2.1.9-cp312-cp312-musllinux_1_2_x86_64.whl (7.0 MB view hashes)

Uploaded CPython 3.12 musllinux: musl 1.2+ x86-64

libtfr-2.1.9-cp312-cp312-musllinux_1_2_i686.whl (6.7 MB view hashes)

Uploaded CPython 3.12 musllinux: musl 1.2+ i686

libtfr-2.1.9-cp312-cp312-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.8 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ x86-64

libtfr-2.1.9-cp312-cp312-manylinux_2_17_i686.manylinux2014_i686.whl (4.6 MB view hashes)

Uploaded CPython 3.12 manylinux: glibc 2.17+ i686

libtfr-2.1.9-cp312-cp312-macosx_11_0_arm64.whl (557.0 kB view hashes)

Uploaded CPython 3.12 macOS 11.0+ ARM64

libtfr-2.1.9-cp312-cp312-macosx_10_13_x86_64.whl (637.6 kB view hashes)

Uploaded CPython 3.12 macOS 10.13+ x86-64

libtfr-2.1.9-cp311-cp311-musllinux_1_2_x86_64.whl (7.0 MB view hashes)

Uploaded CPython 3.11 musllinux: musl 1.2+ x86-64

libtfr-2.1.9-cp311-cp311-musllinux_1_2_i686.whl (6.7 MB view hashes)

Uploaded CPython 3.11 musllinux: musl 1.2+ i686

libtfr-2.1.9-cp311-cp311-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.8 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ x86-64

libtfr-2.1.9-cp311-cp311-manylinux_2_17_i686.manylinux2014_i686.whl (4.6 MB view hashes)

Uploaded CPython 3.11 manylinux: glibc 2.17+ i686

libtfr-2.1.9-cp311-cp311-macosx_11_0_arm64.whl (556.6 kB view hashes)

Uploaded CPython 3.11 macOS 11.0+ ARM64

libtfr-2.1.9-cp311-cp311-macosx_10_9_x86_64.whl (639.7 kB view hashes)

Uploaded CPython 3.11 macOS 10.9+ x86-64

libtfr-2.1.9-cp310-cp310-musllinux_1_2_x86_64.whl (6.9 MB view hashes)

Uploaded CPython 3.10 musllinux: musl 1.2+ x86-64

libtfr-2.1.9-cp310-cp310-musllinux_1_2_i686.whl (6.7 MB view hashes)

Uploaded CPython 3.10 musllinux: musl 1.2+ i686

libtfr-2.1.9-cp310-cp310-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.7 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ x86-64

libtfr-2.1.9-cp310-cp310-manylinux_2_17_i686.manylinux2014_i686.whl (4.5 MB view hashes)

Uploaded CPython 3.10 manylinux: glibc 2.17+ i686

libtfr-2.1.9-cp310-cp310-macosx_11_0_arm64.whl (556.2 kB view hashes)

Uploaded CPython 3.10 macOS 11.0+ ARM64

libtfr-2.1.9-cp310-cp310-macosx_10_9_x86_64.whl (639.2 kB view hashes)

Uploaded CPython 3.10 macOS 10.9+ x86-64

libtfr-2.1.9-cp39-cp39-musllinux_1_2_x86_64.whl (6.9 MB view hashes)

Uploaded CPython 3.9 musllinux: musl 1.2+ x86-64

libtfr-2.1.9-cp39-cp39-musllinux_1_2_i686.whl (6.7 MB view hashes)

Uploaded CPython 3.9 musllinux: musl 1.2+ i686

libtfr-2.1.9-cp39-cp39-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.7 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ x86-64

libtfr-2.1.9-cp39-cp39-manylinux_2_17_i686.manylinux2014_i686.whl (4.6 MB view hashes)

Uploaded CPython 3.9 manylinux: glibc 2.17+ i686

libtfr-2.1.9-cp39-cp39-macosx_11_0_arm64.whl (556.7 kB view hashes)

Uploaded CPython 3.9 macOS 11.0+ ARM64

libtfr-2.1.9-cp39-cp39-macosx_10_9_x86_64.whl (639.8 kB view hashes)

Uploaded CPython 3.9 macOS 10.9+ x86-64

libtfr-2.1.9-cp38-cp38-musllinux_1_2_x86_64.whl (6.9 MB view hashes)

Uploaded CPython 3.8 musllinux: musl 1.2+ x86-64

libtfr-2.1.9-cp38-cp38-musllinux_1_2_i686.whl (6.7 MB view hashes)

Uploaded CPython 3.8 musllinux: musl 1.2+ i686

libtfr-2.1.9-cp38-cp38-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.7 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ x86-64

libtfr-2.1.9-cp38-cp38-manylinux_2_17_i686.manylinux2014_i686.whl (4.6 MB view hashes)

Uploaded CPython 3.8 manylinux: glibc 2.17+ i686

libtfr-2.1.9-cp38-cp38-macosx_11_0_arm64.whl (555.5 kB view hashes)

Uploaded CPython 3.8 macOS 11.0+ ARM64

libtfr-2.1.9-cp38-cp38-macosx_10_9_x86_64.whl (638.1 kB view hashes)

Uploaded CPython 3.8 macOS 10.9+ x86-64

libtfr-2.1.9-cp37-cp37m-musllinux_1_2_x86_64.whl (6.9 MB view hashes)

Uploaded CPython 3.7m musllinux: musl 1.2+ x86-64

libtfr-2.1.9-cp37-cp37m-musllinux_1_2_i686.whl (6.6 MB view hashes)

Uploaded CPython 3.7m musllinux: musl 1.2+ i686

libtfr-2.1.9-cp37-cp37m-manylinux_2_17_x86_64.manylinux2014_x86_64.whl (4.7 MB view hashes)

Uploaded CPython 3.7m manylinux: glibc 2.17+ x86-64

libtfr-2.1.9-cp37-cp37m-manylinux_2_17_i686.manylinux2014_i686.whl (4.5 MB view hashes)

Uploaded CPython 3.7m manylinux: glibc 2.17+ i686

libtfr-2.1.9-cp37-cp37m-macosx_10_9_x86_64.whl (636.1 kB view hashes)

Uploaded CPython 3.7m macOS 10.9+ x86-64

Supported by

AWS AWS Cloud computing and Security Sponsor Datadog Datadog Monitoring Fastly Fastly CDN Google Google Download Analytics Microsoft Microsoft PSF Sponsor Pingdom Pingdom Monitoring Sentry Sentry Error logging StatusPage StatusPage Status page