Skip to content

Commit

Permalink
Deploying to gh-pages from @ 20f2599 🚀
Browse files Browse the repository at this point in the history
  • Loading branch information
github-actions[bot] committed Oct 2, 2024
0 parents commit 80170c1
Show file tree
Hide file tree
Showing 137 changed files with 22,215 additions and 0 deletions.
2 changes: 2 additions & 0 deletions .gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
# macOS
.DS_Store
Empty file added .nojekyll
Empty file.
113 changes: 113 additions & 0 deletions _downloads/0d95c47479bb83aaf162357584d36ccd/30_apply_a_window.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,113 @@
"""
==============
Apply a window
==============
.. include:: ../../links.inc
In signal processing and statistics, a window function (also known as an
apodization function or tapering function) is a mathematical function that is
zero-valued outside of some chosen interval, normally symmetric around the
middle of the interval, usually near a maximum in the middle, and usually
tapering away from the middle. Mathematically, when another function or
waveform/data-sequence is "multiplied" by a window function, the product is
also zero-valued outside the interval: all that is left is the part where they
overlap, the "view through the window".
Source: `Wikipedia <https://en.wikipedia.org/wiki/Window_function>`_
A sound waveform might have an abrupt onset or offset. It is often preferred to
apply a window to ramp up and ramp down the volume.
"""

# %%

# sphinx_gallery_thumbnail_number = 3

import numpy as np
from matplotlib import pyplot as plt
from scipy.signal.windows import tukey

from stimuli.audio import Tone

# %%
#
# In this tutorial, we will create a pure tone auditory stimuli and apply a
# window with a linear ramp-up and a linear ramp-down to smooth the onset and
# offset.

# %%
# Create a pure tone
# ------------------
#
# To create the stimuli, we create a :class:`~stimuli.audio.Tone` object with
# a given volume and frequency.

sound = Tone(frequency=200, volume=10, duration=0.1)

# %%
# By default, a generated signal will have a rectangular window applied. A
# recctangular window is equal to 0 outside of the signal definition range, and
# to 1 inside. We can plot the waveform of one of the channels:

# draw the waveform
_, ax = sound.plot()
ax.set_title("Waveform - Rectangular window")

# overlay a rectangular window
# note: for demonstration purposes, we make the window 20% longer than the
# signal by extending it by 10% before and after the signal.
extension = int(0.1 * sound.times.size)
window = np.zeros(extension + sound.times.size + extension)
window[extension + 1 : extension + sound.times.size] = 1 / sound.volume
# determine the timestamps associated to each sample in the window (ms)
window_times = np.arange(0, 1 / sound.sample_rate * window.size, 1 / sound.sample_rate)
window_times -= extension / sound.sample_rate
# draw the window
ax.plot(window_times, window, color="crimson")
plt.show()

# %%
# Create a different window
# -------------------------
#
# For this tutorial, we will define a window with a ramp from ``0`` to ``1``
# during the first 10% of the total duration, and a ramp from ``1`` to ``0``
# during the last 10% of the total duration. A correctly defined window is a
# 1D `~numpy.array` with the same number of samples as the sound.

window = np.ones(sound.times.size)
n_samples_ramp = int(0.1 * sound.times.size)
ramp = np.linspace(start=0, stop=1, num=n_samples_ramp)
window[:n_samples_ramp] = ramp
window[-n_samples_ramp:] = ramp[::-1]

# %%
# Change the window
# -----------------
#
# We can change the applied window by setting the property ``window``.

sound.window = window

# draw the modified sound and the window
_, ax = sound.plot()
ax.set_title("Waveform - Ramp onset/offset window")
ax.plot(sound.times, window / sound.volume, color="crimson") # overlay the window
plt.show()

# %%
# Scipy windows
# -------------
#
# `scipy`_ has many windows implemented in :mod:`scipy.signal.windows`. For instance
# we can use a Tukey window with the function `~scipy.signal.windows.tukey`.

window = tukey(sound.times.size)
sound.window = window

# draw the modified sound and the window
_, ax = sound.plot()
ax.set_title("Waveform - Tukey window")
ax.plot(sound.times, window / sound.volume, color="crimson") # overlay the window
plt.show()
Original file line number Diff line number Diff line change
@@ -0,0 +1,61 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Synchronize sound and trigger\n\nOften, a trigger must be emitted simultenously with a sound onset, with as little delay\nand jitter as possible. With ``stimuli``, similarly to ``psychtoolbox``, the key concept\nis to schedule the sound.\n\nFirst, let's have a look at our default device latency.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import sounddevice as sd\n\nfrom stimuli.audio import SoundAM\nfrom stimuli.time import sleep\nfrom stimuli.triggers import MockTrigger\n\nidx = sd.default.device[\"output\"]\nprint(f\"Low-latency (s): {sd.query_devices()[idx]['default_low_output_latency']}\")"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"Next, we can schedule a sound with the argument ``when`` which will use the clock\nprovided in the argument ``clock`` to schedule the sound. Then, we wait for this\nduration to elapse before sending the trigger.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"trigger = MockTrigger() # replace with your trigger object\nsound = SoundAM(\n frequency_carrier=1000,\n frequency_modulation=40,\n method=\"dsbsc\",\n volume=10,\n duration=1,\n)\nsound.play(when=0.5, blocking=False)\nsleep(0.5)\ntrigger.signal(1)"
]
}
],
"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.11.10"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
140 changes: 140 additions & 0 deletions _downloads/5cd9f36d95a835433df7ed54eca518a8/30_apply_a_window.ipynb
Original file line number Diff line number Diff line change
@@ -0,0 +1,140 @@
{
"cells": [
{
"cell_type": "markdown",
"metadata": {},
"source": [
"\n# Apply a window\n\n.. include:: ../../links.inc\n\nIn signal processing and statistics, a window function (also known as an\napodization function or tapering function) is a mathematical function that is\nzero-valued outside of some chosen interval, normally symmetric around the\nmiddle of the interval, usually near a maximum in the middle, and usually\ntapering away from the middle. Mathematically, when another function or\nwaveform/data-sequence is \"multiplied\" by a window function, the product is\nalso zero-valued outside the interval: all that is left is the part where they\noverlap, the \"view through the window\".\n\nSource: [Wikipedia](https://en.wikipedia.org/wiki/Window_function)\n\nA sound waveform might have an abrupt onset or offset. It is often preferred to\napply a window to ramp up and ramp down the volume.\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"import numpy as np\nfrom matplotlib import pyplot as plt\nfrom scipy.signal.windows import tukey\n\nfrom stimuli.audio import Tone"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"In this tutorial, we will create a pure tone auditory stimuli and apply a\nwindow with a linear ramp-up and a linear ramp-down to smooth the onset and\noffset.\n\n"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Create a pure tone\n\nTo create the stimuli, we create a :class:`~stimuli.audio.Tone` object with\na given volume and frequency.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"sound = Tone(frequency=200, volume=10, duration=0.1)"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"By default, a generated signal will have a rectangular window applied. A\nrecctangular window is equal to 0 outside of the signal definition range, and\nto 1 inside. We can plot the waveform of one of the channels:\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"# draw the waveform\n_, ax = sound.plot()\nax.set_title(\"Waveform - Rectangular window\")\n\n# overlay a rectangular window\n# note: for demonstration purposes, we make the window 20% longer than the\n# signal by extending it by 10% before and after the signal.\nextension = int(0.1 * sound.times.size)\nwindow = np.zeros(extension + sound.times.size + extension)\nwindow[extension + 1 : extension + sound.times.size] = 1 / sound.volume\n# determine the timestamps associated to each sample in the window (ms)\nwindow_times = np.arange(0, 1 / sound.sample_rate * window.size, 1 / sound.sample_rate)\nwindow_times -= extension / sound.sample_rate\n# draw the window\nax.plot(window_times, window, color=\"crimson\")\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Create a different window\n\nFor this tutorial, we will define a window with a ramp from ``0`` to ``1``\nduring the first 10% of the total duration, and a ramp from ``1`` to ``0``\nduring the last 10% of the total duration. A correctly defined window is a\n1D `~numpy.array` with the same number of samples as the sound.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"window = np.ones(sound.times.size)\nn_samples_ramp = int(0.1 * sound.times.size)\nramp = np.linspace(start=0, stop=1, num=n_samples_ramp)\nwindow[:n_samples_ramp] = ramp\nwindow[-n_samples_ramp:] = ramp[::-1]"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Change the window\n\nWe can change the applied window by setting the property ``window``.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"sound.window = window\n\n# draw the modified sound and the window\n_, ax = sound.plot()\nax.set_title(\"Waveform - Ramp onset/offset window\")\nax.plot(sound.times, window / sound.volume, color=\"crimson\") # overlay the window\nplt.show()"
]
},
{
"cell_type": "markdown",
"metadata": {},
"source": [
"## Scipy windows\n\n`scipy`_ has many windows implemented in :mod:`scipy.signal.windows`. For instance\nwe can use a Tukey window with the function `~scipy.signal.windows.tukey`.\n\n"
]
},
{
"cell_type": "code",
"execution_count": null,
"metadata": {
"collapsed": false
},
"outputs": [],
"source": [
"window = tukey(sound.times.size)\nsound.window = window\n\n# draw the modified sound and the window\n_, ax = sound.plot()\nax.set_title(\"Waveform - Tukey window\")\nax.plot(sound.times, window / sound.volume, color=\"crimson\") # overlay the window\nplt.show()"
]
}
],
"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.11.10"
}
},
"nbformat": 4,
"nbformat_minor": 0
}
Loading

0 comments on commit 80170c1

Please sign in to comment.