{"cells": [{"source": ["## Generating different colors of noise\n", "\n", "This notebook demonstrates how to generate different colors of noise. Different colors of noise are described here (with audio samples): https://en.wikipedia.org/wiki/Colors_of_noise .\n", "\n", "Some of the code below is heavily inspired by the noise generators in python-acoustics."], "metadata": {}, "cell_type": "markdown"}, {"execution_count": null, "metadata": {"collapsed": true}, "outputs": [], "cell_type": "code", "source": ["import numpy as np\n", "\n", "np.random.seed(1337)\n", "\n", "%matplotlib inline\n", "import matplotlib.pyplot as plt\n", "\n", "import scipy.signal"]}, {"execution_count": null, "metadata": {"collapsed": true}, "outputs": [], "cell_type": "code", "source": ["sample_rate = 16000\n", "samples_to_generate = 16000"]}, {"execution_count": null, "metadata": {"collapsed": true}, "outputs": [], "cell_type": "code", "source": ["def to_16bit(samples):\n", "    # assume +1 corresponds to +32767 and -1 corresponds to -32767\n", "    # (note that we don't use -32768)\n", "    # \n", "    # does not convert the samples to int16 for the moment\n", "    \n", "    return np.clip(32767 * samples, -32767, +32767)"]}, {"execution_count": null, "metadata": {"collapsed": true}, "outputs": [], "cell_type": "code", "source": ["def normalize(samples):\n", "    \"\"\"normalizes a sample to unit standard deviation (assuming the mean is zero)\"\"\"\n", "    std = samples.std()\n", "    if std > 0:\n", "        return samples / std\n", "    else:\n", "        return samples"]}, {"execution_count": null, "metadata": {"collapsed": true}, "outputs": [], "cell_type": "code", "source": ["def _gen_colored_noise(spectral_shape):\n", "    # helper function generating a noise spectrum\n", "    # and applying a shape to it\n", "    flat_spectrum = np.random.normal(size = samples_to_generate // 2 + 1) + \\\n", "            1j * np.random.normal(size = samples_to_generate // 2 + 1)\n", "\n", "    return normalize(np.fft.irfft( flat_spectrum * spectral_shape).real)\n", "        \n", "\n", "def gen_noise(color):\n", "    \n", "    assert samples_to_generate % 2 == 0\n", "    \n", "    if color == 'white':\n", "        # flat in frequency\n", "        \n", "        # note that this needs to be normalized because\n", "        # with std = 1 many samples will be outside +1/-1\n", "        return np.random.normal(size = samples_to_generate)\n", "    \n", "    spectrum_len = samples_to_generate // 2 + 1\n", "    \n", "    if color == 'pink':\n", "        return _gen_colored_noise(1. / (np.sqrt(np.arange(spectrum_len) + 1.)))\n", "        \n", "    elif color == 'blue':\n", "        return _gen_colored_noise(np.sqrt(np.arange(spectrum_len)))\n", "    \n", "    elif color == 'brown' or color == 'red':\n", "        return _gen_colored_noise(1. / (np.arange(spectrum_len) + 1))\n", "\n", "    elif color == 'violet' or color == 'purple':\n", "        return _gen_colored_noise(np.arange(spectrum_len))\n", "    \n", "    else:\n", "        raise Exception(\"unsupported noise color %s\" % color)"]}, {"source": ["generate an example for each of the supported colors and inspect it visually"], "metadata": {}, "cell_type": "markdown"}, {"execution_count": null, "metadata": {"scrolled": false}, "outputs": [], "cell_type": "code", "source": ["noise = {}\n", "\n", "for color in ('white',   # flat spectrum\n", "              'pink',    # -3dB (factor 0.5)  per octave / -10 dB (factor 0.1) per decade\n", "              'blue',    # +3dB (factor 2)    per octave / +10 dB (factor 10) per decade\n", "              'brown',   # -6dB (factor 0.25) per octave / -20 dB (factor 0.01) per decade\n", "              'violet'): # +6dB (factor 4)    per octave / +20 dB (factor 100) per decade\n", "    \n", "    noise[color] = to_16bit(gen_noise(color) / 4)\n", "    \n", "    plt.figure(figsize = (15,7))\n", "    \n", "    plt.subplot(1,2,1)\n", "    plt.plot(noise[color])\n", "    plt.grid()\n", "    plt.title(\"%s noise\" % color)\n", "    plt.ylabel('amplitude')\n", "    \n", "    # plot spectral power density\n", "    plt.subplot(1,2,2)\n", "    freqs, spec = scipy.signal.welch(noise[color], fs = sample_rate)\n", "    \n", "    # normalize to middle of spectrum\n", "    # freqs -= freqs[len(freqs) // 2]\n", "    \n", "    plt.loglog(freqs, spec)\n", "    plt.gca().minorticks_on()\n", "    plt.grid(True, which = 'both')\n", "    # plt.ylim(ymin = 0)\n", "    plt.xlabel('frequency [Hz]')\n", "    plt.ylabel('power spectral density')"]}, {"source": ["listen to the generated samples"], "metadata": {}, "cell_type": "markdown"}, {"execution_count": null, "metadata": {"collapsed": true}, "outputs": [], "cell_type": "code", "source": ["import IPython"]}, {"execution_count": null, "metadata": {"scrolled": false}, "outputs": [], "cell_type": "code", "source": ["IPython.display.Audio(noise['white'], rate = sample_rate)"]}, {"execution_count": null, "metadata": {}, "outputs": [], "cell_type": "code", "source": ["IPython.display.Audio(noise['pink'], rate = sample_rate)"]}, {"execution_count": null, "metadata": {}, "outputs": [], "cell_type": "code", "source": ["IPython.display.Audio(noise['blue'], rate = sample_rate)"]}, {"execution_count": null, "metadata": {}, "outputs": [], "cell_type": "code", "source": ["IPython.display.Audio(noise['brown'], rate = sample_rate)"]}, {"execution_count": null, "metadata": {}, "outputs": [], "cell_type": "code", "source": ["IPython.display.Audio(noise['violet'], rate = sample_rate)"]}, {"execution_count": null, "metadata": {"collapsed": true}, "outputs": [], "cell_type": "code", "source": []}], "nbformat_minor": 1, "metadata": {"language_info": {"codemirror_mode": {"version": 3, "name": "ipython"}, "file_extension": ".py", "name": "python", "version": "3.5.4", "pygments_lexer": "ipython3", "mimetype": "text/x-python", "nbconvert_exporter": "python"}, "kernelspec": {"language": "python", "name": "python3", "display_name": "Python 3"}}, "nbformat": 4}