{
    "nbformat": 4,
    "nbformat_minor": 5,
    "metadata": {
        "kernelspec": {
            "display_name": "Python",
            "language": "python",
            "name": "python"
        },
        "language_info": {
            "name": "python"
        }
    },
    "cells": [
        {
            "id": "bd4627bb",
            "cell_type": "markdown",
            "source": "<div class='alert alert-warning'>\n\nSciPy's interactive examples with Jupyterlite are experimental and may not always work as expected. Execution of cells containing imports may result in large downloads (up to 60MB of content for the first import from SciPy). Load times when importing from SciPy may take roughly 10-20 seconds. If you notice any problems, feel free to open an [issue](https://github.com/scipy/scipy/issues/new/choose).\n\n</div>",
            "metadata": {}
        },
        {
            "id": "db6e9e8f",
            "cell_type": "markdown",
            "source": "We will use the Kaiser window method to design a lowpass FIR filter\nfor a signal that is sampled at 1000 Hz.\n\nWe want at least 65 dB rejection in the stop band, and in the pass\nband the gain should vary no more than 0.5%.\n\nWe want a cutoff frequency of 175 Hz, with a transition between the\npass band and the stop band of 24 Hz. That is, in the band [0, 163],\nthe gain varies no more than 0.5%, and in the band [187, 500], the\nsignal is attenuated by at least 65 dB.\n",
            "metadata": {}
        },
        {
            "id": "0875a669",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "import numpy as np\nfrom scipy.signal import kaiserord, firwin, freqz\nimport matplotlib.pyplot as plt\nfs = 1000.0\ncutoff = 175\nwidth = 24",
            "outputs": []
        },
        {
            "id": "685fdaf5",
            "cell_type": "markdown",
            "source": "The Kaiser method accepts just a single parameter to control the pass\nband ripple and the stop band rejection, so we use the more restrictive\nof the two. In this case, the pass band ripple is 0.005, or 46.02 dB,\nso we will use 65 dB as the design parameter.\n\nUse `kaiserord` to determine the length of the filter and the\nparameter for the Kaiser window.\n",
            "metadata": {}
        },
        {
            "id": "a8456699",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "numtaps, beta = kaiserord(65, width/(0.5*fs))\nnumtaps",
            "outputs": [
                {
                    "output_type": "execute_result",
                    "metadata": {},
                    "data": {
                        "text/plain": "167"
                    },
                    "execution_count": null
                }
            ]
        },
        {
            "id": "97897fca",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "beta",
            "outputs": [
                {
                    "output_type": "execute_result",
                    "metadata": {},
                    "data": {
                        "text/plain": "6.20426"
                    },
                    "execution_count": null
                }
            ]
        },
        {
            "id": "92b06748",
            "cell_type": "markdown",
            "source": "Use `firwin` to create the FIR filter.\n",
            "metadata": {}
        },
        {
            "id": "5550a2fb",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "taps = firwin(numtaps, cutoff, window=('kaiser', beta),\n              scale=False, fs=fs)",
            "outputs": []
        },
        {
            "id": "fdac0fb1",
            "cell_type": "markdown",
            "source": "Compute the frequency response of the filter.  ``w`` is the array of\nfrequencies, and ``h`` is the corresponding complex array of frequency\nresponses.\n",
            "metadata": {}
        },
        {
            "id": "e7a0572e",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "w, h = freqz(taps, worN=8000)\nw *= 0.5*fs/np.pi  # Convert w to Hz.",
            "outputs": []
        },
        {
            "id": "d260fb56",
            "cell_type": "markdown",
            "source": "Compute the deviation of the magnitude of the filter's response from\nthat of the ideal lowpass filter. Values in the transition region are\nset to ``nan``, so they won't appear in the plot.\n",
            "metadata": {}
        },
        {
            "id": "06463058",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "ideal = w < cutoff  # The \"ideal\" frequency response.\ndeviation = np.abs(np.abs(h) - ideal)\ndeviation[(w > cutoff - 0.5*width) & (w < cutoff + 0.5*width)] = np.nan",
            "outputs": []
        },
        {
            "id": "a3d24add",
            "cell_type": "markdown",
            "source": "Plot the deviation. A close look at the left end of the stop band shows\nthat the requirement for 65 dB attenuation is violated in the first lobe\nby about 0.125 dB. This is not unusual for the Kaiser window method.\n",
            "metadata": {}
        },
        {
            "id": "54e4c9b7",
            "cell_type": "code",
            "metadata": {},
            "execution_count": null,
            "source": "plt.plot(w, 20*np.log10(np.abs(deviation)))\nplt.xlim(0, 0.5*fs)\nplt.ylim(-90, -60)\nplt.grid(alpha=0.25)\nplt.axhline(-65, color='r', ls='--', alpha=0.3)\nplt.xlabel('Frequency (Hz)')\nplt.ylabel('Deviation from ideal (dB)')\nplt.title('Lowpass Filter Frequency Response')\nplt.show()",
            "outputs": []
        }
    ]
}