{ "cells": [ { "cell_type": "markdown", "metadata": {}, "source": [ "# Time-frequency transforms : boundary effects\n", "The examples below illustrate the effects of setting Stft-object flag zero_pad_full_sig to True (False) in order to avoid (obtain) a circular transform." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "%pylab inline\n", "import numpy as np\n", "from madarrays import Waveform\n", "from pyteuf import Stft" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Examples with isolated diracs\n", "The signal with length 16 samples is composed of a dirac at initial time $t=0$ for testing the boundary effects and another dirac time $t=9$ for control." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "signal_params_nopad = {'sig_len': 16, 'fs': 1}\n", "x_nopad = Waveform(np.zeros(signal_params_nopad['sig_len']), \n", " fs = signal_params_nopad['fs'])\n", "x_nopad[0] = x_nopad[9] = 1\n", "print(x_nopad)\n", "x_nopad.plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "# Note that the signal length is increased by 1 in order \n", "# to satisfy the `param_constraint='fix'` parameter of Stft (see tutorial on transform length)\n", "signal_params_pad = {'sig_len': signal_params_nopad['sig_len']+1, 'fs': signal_params_nopad['fs']}\n", "x_pad = Waveform(np.zeros(signal_params_pad['sig_len']), \n", " fs = signal_params_pad['fs'])\n", "x_pad[0] = x_pad[9] = 1\n", "print(x_pad)\n", "x_pad.plot()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Two similar `Stft` objects are defined, that differ only on the use of additional zero-padding. By setting `zero_pad_full_sig=False`, no additional zero-padding results in a circular transform. By setting `zero_pad_full_sig=True`, zeros are added at the end of the signal in an appropriate way such that the samples at the beginning and at the end of the original signal are not appearing in the same frame (i.e., the number of added zeros equals the window length minus one)." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "stft_params = {'hop': 1, 'n_bins': 4, 'win_name': 'hann', 'win_len': 4, 'param_constraint': 'fix'}\n", "stft_nopad = Stft(zero_pad_full_sig=False, **stft_params)\n", "print(stft_nopad)\n", "stft_pad = Stft(zero_pad_full_sig=True, **stft_params)\n", "print(stft_pad)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With the circular transform, the dirac at time $t=0$ spread at times $t=0$, $t=1$ and $t=15$ (i.e., at the last time step in the signal with length 16)" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X_nopad = stft_nopad.apply(x_nopad)\n", "print(X_nopad)\n", "_ = X_nopad.plot_spectrogram(dynrange=100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With additional zero-padding, the dirac at time $t=0$ does not spread at $t=15$ any more since the signal has been zero-padded to avoid circular effects (even if the transform is still circular). Energy is observed at time $t=19$, i.e. in the area where the signal has been extended." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X_pad = stft_pad.apply(x_pad)\n", "print(X_pad)\n", "_ = X_pad.plot_spectrogram(dynrange=100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Examples with diracs at boundaries\n", "This example illustrate how the first and last samples are neighbors in the case of a circular transform.\n", "The signal is now composed of a dirac at each boundary, i.e., at times $t=0$ and $t=15$, as well as two neighboring diracs at times $t=8$ and $t=9$ for control." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x_nopad = Waveform(np.zeros(signal_params_nopad['sig_len']), \n", " fs = signal_params_nopad['fs'])\n", "x_nopad[0] = x_nopad[-1] = x_nopad[8] = x_nopad[9] = 1\n", "print(x_nopad)\n", "x_nopad.plot()" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "x_pad = Waveform(np.zeros(signal_params_pad['sig_len']), \n", " fs = signal_params_pad['fs'])\n", "x_pad[0] = x_pad[-1] = x_pad[8] = x_pad[9] = 1\n", "print(x_pad)\n", "x_pad.plot()" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Without zero-padding, due to the circular transform, diracs influence each other and form a single area in the spectrogram, which is similar as the center area that contains two adjacent diracs." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "stft_nopad.apply(x_nopad).plot_spectrogram(dynrange=100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With additional zero-padding, the beginning and the end of the signal are separated with zeros so diracs are well resolved and do not appear as adjacent diracs." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "_ = stft_pad.apply(x_pad).plot_spectrogram(dynrange=100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "## Examples with a sinusoid\n", "The signal is now a sinusoid and the length of the signal is a multiple of the period." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "signal_params_nopad = {'sig_len': 32}\n", "signal_params_nopad['fs'] = signal_params_nopad['sig_len'] - 1\n", "signal_params_pad = {'sig_len': signal_params_nopad['sig_len'] + 1}\n", "signal_params_pad['fs'] = signal_params_pad['sig_len'] - 1\n", "f0 = 4 / signal_params_nopad['sig_len']\n", "x_nopad = Waveform(np.sin(2 * np.pi * f0 * np.arange(signal_params_nopad['sig_len'])), \n", " fs = signal_params_nopad['fs'])\n", "x_nopad.plot()\n", "f0_pad = 4 / signal_params_pad['sig_len']\n", "x_pad = Waveform(np.sin(2 * np.pi * f0_pad * np.arange(signal_params_pad['sig_len'])), \n", " fs = signal_params_pad['fs'])\n", "x_pad.plot(linestyle='--')" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "stft_params = {'hop': 1, 'n_bins': 16, 'win_name': 'hann', 'win_len': 16, 'param_constraint': 'fix'}\n", "stft_nopad = Stft(zero_pad_full_sig=False, **stft_params)\n", "print(stft_nopad)\n", "stft_pad = Stft(zero_pad_full_sig=True, **stft_params)\n", "print(stft_pad)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Periodic tranform: as the length of the signal is a multiple of the period, the circular transform coefficients are constant over time. " ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X_nopad = stft_nopad.apply(x_nopad)\n", "print(X_nopad)\n", "_ = X_nopad.plot_spectrogram(dynrange=100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "With additional zeros to avoid circular effects, transients appear at boundaries." ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X_pad = stft_pad.apply(x_pad)\n", "print(X_pad)\n", "_ = X_pad.plot_spectrogram(dynrange=100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Now, if the period is not a divisor of the length of the signal:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "signal_params_nopad = {'sig_len': 32}\n", "signal_params_nopad['fs'] = signal_params_nopad['sig_len'] - 1\n", "signal_params_pad = {'sig_len': signal_params_nopad['sig_len'] + 1}\n", "signal_params_pad['fs'] = signal_params_pad['sig_len'] - 1\n", "f0 = 8.5 / signal_params_nopad['sig_len']\n", "x_nopad = Waveform(np.sin(2 * np.pi * f0 * np.arange(signal_params_nopad['sig_len'])), \n", " fs = signal_params_nopad['fs'])\n", "x_nopad.plot()\n", "f0_pad = 8.5 / signal_params_pad['sig_len']\n", "x_pad = Waveform(np.sin(2 * np.pi * f0_pad * np.arange(signal_params_pad['sig_len'])), \n", " fs = signal_params_pad['fs'])\n", "x_pad.plot(linestyle='--')" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some boundary effects appear in the case without zero-padding due to the discontinuity between the end and the beginning of the signal:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X_nopad = stft_nopad.apply(x_nopad)\n", "print(X_nopad)\n", "_ = X_nopad.plot_spectrogram(dynrange=100)" ] }, { "cell_type": "markdown", "metadata": {}, "source": [ "Some boundary effects also appear in the case with zero-padding due to the discontinuity with the added zeros:" ] }, { "cell_type": "code", "execution_count": null, "metadata": {}, "outputs": [], "source": [ "X_pad = stft_pad.apply(x_pad)\n", "print(X_pad)\n", "_ = X_pad.plot_spectrogram(dynrange=100)" ] }, { "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" } }, "nbformat": 4, "nbformat_minor": 1 }