{
 "cells": [
  {
   "cell_type": "markdown",
   "id": "32645dea",
   "metadata": {},
   "source": [
    "# CMSIS-DSP Python package example"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "adbbe2cc",
   "metadata": {},
   "source": [
    "## Installing and importing the needed packages"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "22230ac8",
   "metadata": {},
   "source": [
    "The following command may take some time to execute : the full cmsisdsp library is built."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 1,
   "id": "e684be27",
   "metadata": {
    "scrolled": false
   },
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "Requirement already satisfied: cmsisdsp in c:\\benchresults\\pythonwrappertests\\testenv\\lib\\site-packages (1.2.1)\n",
      "Requirement already satisfied: numpy>=1.19 in c:\\benchresults\\pythonwrappertests\\testenv\\lib\\site-packages (from cmsisdsp) (1.22.2)\n",
      "Requirement already satisfied: jinja2>=3.0 in c:\\benchresults\\pythonwrappertests\\testenv\\lib\\site-packages (from cmsisdsp) (3.0.3)\n",
      "Requirement already satisfied: networkx>=2.5 in c:\\benchresults\\pythonwrappertests\\testenv\\lib\\site-packages (from cmsisdsp) (2.6.3)\n",
      "Requirement already satisfied: sympy>=1.6 in c:\\benchresults\\pythonwrappertests\\testenv\\lib\\site-packages (from cmsisdsp) (1.9)\n",
      "Requirement already satisfied: MarkupSafe>=2.0 in c:\\benchresults\\pythonwrappertests\\testenv\\lib\\site-packages (from jinja2>=3.0->cmsisdsp) (2.1.0)\n",
      "Requirement already satisfied: mpmath>=0.19 in c:\\benchresults\\pythonwrappertests\\testenv\\lib\\site-packages (from sympy>=1.6->cmsisdsp) (1.2.1)\n"
     ]
    }
   ],
   "source": [
    "!pip install cmsisdsp"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 36,
   "id": "19c6b88c",
   "metadata": {},
   "outputs": [],
   "source": [
    "import numpy as np\n",
    "import cmsisdsp as dsp\n",
    "import cmsisdsp.fixedpoint as f"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 11,
   "id": "13c4c9c5",
   "metadata": {},
   "outputs": [],
   "source": [
    "import matplotlib.pyplot as plt\n",
    "from ipywidgets import interact, interactive, fixed, interact_manual,FloatSlider\n",
    "import ipywidgets as widgets"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a5e787dc",
   "metadata": {},
   "source": [
    "## Creating the signal"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "b9135875",
   "metadata": {},
   "source": [
    "### Conversion functions to use CMSIS-DSP FFTs with complex numbers"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "0c645caa",
   "metadata": {},
   "source": [
    "CMSIS-DSP FFTs are processing  array of complex numbers which are represented in memory asan array of floats. There is no specific data types for complex numbers.\n",
    "The Python array is containing complex numbers. They need to be replaced by a sequence of real numbers.\n",
    "The two functions below are doing those conversions."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 21,
   "id": "79d91f10",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Array of complex numbers as an array of real numbers\n",
    "def imToReal1D(a):\n",
    "    ar=np.zeros(np.array(a.shape) * 2)\n",
    "    ar[0::2]=a.real\n",
    "    ar[1::2]=a.imag\n",
    "    return(ar)\n",
    "\n",
    "# Array of real numbers as an array of complex numbers\n",
    "def realToIm1D(ar):\n",
    "    return(ar[0::2] + 1j * ar[1::2])"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 5,
   "id": "57740f0a",
   "metadata": {},
   "outputs": [],
   "source": [
    "nb = 512\n",
    "signal = None"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "a703fc4c",
   "metadata": {},
   "source": [
    "You can play with the slider to change the frequency of the signal.\n",
    "Don't forget to reconvert the signal to a Q15 format if you want to test the Q15 FFT."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 18,
   "id": "51cf9d5c",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "application/vnd.jupyter.widget-view+json": {
       "model_id": "6623baf5822e42bd8fe58dfc2b417dd7",
       "version_major": 2,
       "version_minor": 0
      },
      "text/plain": [
       "interactive(children=(FloatSlider(value=100.0, continuous_update=False, description='f', max=150.0, min=10.0, …"
      ]
     },
     "metadata": {},
     "output_type": "display_data"
    }
   ],
   "source": [
    "@interact(f=FloatSlider(100,min=10,max=150,step=20,continuous_update=False))\n",
    "def gen_signal(f=100):\n",
    "    global signal\n",
    "    global nb\n",
    "    signal = np.sin(2 * np.pi * np.arange(nb)*f / nb) + 0.1*np.random.randn(nb)\n",
    "    plt.plot(signal)\n",
    "    plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "8a959962",
   "metadata": {},
   "source": [
    "## Using the F32 CMSIS-DSP FFT"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "d5689ee9",
   "metadata": {},
   "source": [
    "The `arm_cfft_instance_f32` is created and initialized."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 19,
   "id": "54ecc9ae",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n"
     ]
    }
   ],
   "source": [
    "# CMSIS-DSP FFT F32 initialization\n",
    "cfftf32=dsp.arm_cfft_instance_f32()\n",
    "status=dsp.arm_cfft_init_f32(cfftf32,nb)\n",
    "print(status)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "14d1ed0a",
   "metadata": {},
   "source": [
    "The log magnitude of the FFT is computed and siplayed."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 37,
   "id": "5a8d4c77",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 29772 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Re-evaluate this each time you change the signal\n",
    "signalR = imToReal1D(signal)\n",
    "resultR = dsp.arm_cfft_f32(cfftf32,signalR,0,1)\n",
    "resultI = realToIm1D(resultR)\n",
    "mag=20 * np.log10(np.abs(resultI))\n",
    "\n",
    "plt.plot(mag[1:nb//2])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "42eb3a5e",
   "metadata": {},
   "source": [
    "## Using the Q15 CMSIS-DSP FFT"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "4b757402",
   "metadata": {},
   "source": [
    "The signal must be converted to Q15 each time it is changed with the slider above."
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 38,
   "id": "c2a9e191",
   "metadata": {},
   "outputs": [],
   "source": [
    "# Convert the signal to Q15 and viewed as a real array\n",
    "signalR = imToReal1D(signal)\n",
    "signalRQ15 = f.toQ15(signalR)"
   ]
  },
  {
   "cell_type": "markdown",
   "id": "2652245c",
   "metadata": {},
   "source": [
    "The `arm_cfft_instance_q15` is created and initialized"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 25,
   "id": "8943c69c",
   "metadata": {},
   "outputs": [
    {
     "name": "stdout",
     "output_type": "stream",
     "text": [
      "0\n"
     ]
    }
   ],
   "source": [
    "# Initialize the Q15 CFFT\n",
    "cfftq15 = dsp.arm_cfft_instance_q15()\n",
    "status = dsp.arm_cfft_init_q15(cfftq15,nb)\n",
    "print(status)"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": 39,
   "id": "21e39fca",
   "metadata": {},
   "outputs": [
    {
     "data": {
      "image/png": "[encoded data, 28400 characters]\n",
      "text/plain": [
       "<Figure size 432x288 with 1 Axes>"
      ]
     },
     "metadata": {
      "needs_background": "light"
     },
     "output_type": "display_data"
    }
   ],
   "source": [
    "# Compute the Q15 CFFT and convert back to float and complex array\n",
    "resultR = dsp.arm_cfft_q15(cfftq15,signalRQ15,0,1)\n",
    "resultR = f.Q15toF32(resultR)\n",
    "resultI = realToIm1D(resultR)*nb\n",
    "\n",
    "mag = 20 * np.log10(np.abs(resultI))\n",
    "plt.plot(mag[1:nb//2])\n",
    "plt.show()"
   ]
  },
  {
   "cell_type": "code",
   "execution_count": null,
   "id": "1aac0ecd",
   "metadata": {},
   "outputs": [],
   "source": []
  }
 ],
 "metadata": {
  "kernelspec": {
   "display_name": "Python 3 (ipykernel)",
   "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.10.0"
  }
 },
 "nbformat": 4,
 "nbformat_minor": 5
}
