{ "cells": [ { "cell_type": "markdown", "id": "241df33e", "metadata": {}, "source": [ "# Simple keyword spotting with CMSIS-DSP Python wrapper and Arduino" ] }, { "cell_type": "markdown", "id": "3652bb1c", "metadata": {}, "source": [ "The goal of this notebook is to demonstrate how to use the CMSIS-DSP Python wrapper on an example which is complex enough.\n", "\n", "It is not a state of the art keyword recognition system. The feature used for the machine learning is very simple and just able to recognize the \"Yes\" keyword.\n", "\n", "But it is a good start and enough to demonstrate lots of features of the Python wrapper like:\n", "\n", "* Testing the CMSIS-DSP algorithm directly in Python\n", "* Test of fixed point implementation\n", "* Implementation of the compute graph and streaming computation from the CMSIS-DSP Synchronous Data Flow framework\n", "* C++ code generation for the compute graph\n", "* Final implementation for Arduino Nano 33 BLE" ] }, { "cell_type": "markdown", "id": "23aa0adb", "metadata": {}, "source": [ "Several Python packages are required. If they are not already installed on you system, you can install them from the notebook by using:\n", "\n", "`!pip install packagename`\n", "\n", "The machine learning is using scikit-learn. For scientific computations, we are using SciPy, NumPy and Matplotlib.\n", "\n", "For reading wav files, the soundfile package is used.\n", "\n", "Other packages will be used below in the notebook and will have to be installed." ] }, { "cell_type": "code", "execution_count": 1, "id": "d8ef4050", "metadata": { "scrolled": true }, "outputs": [], "source": [ "import cmsisdsp as dsp\n", "import cmsisdsp.fixedpoint as fix\n", "import numpy as np\n", "import os.path\n", "import glob\n", "import pathlib\n", "import random\n", "import soundfile as sf\n", "import matplotlib.pyplot as plt\n", "from IPython.display import display,Audio,HTML\n", "import scipy.signal\n", "from numpy.lib.stride_tricks import sliding_window_view\n", "from scipy.signal.windows import hann\n", "from sklearn import svm\n", "from sklearn.metrics import confusion_matrix, ConfusionMatrixDisplay\n", "from sklearn.model_selection import GridSearchCV\n", "from sklearn.model_selection import RandomizedSearchCV\n", "from scipy.stats import uniform\n", "from sklearn.linear_model import LogisticRegression\n", "import pickle" ] }, { "cell_type": "markdown", "id": "5b7926c9", "metadata": {}, "source": [ "## The speech commands\n", "\n", "We are using the simplified speech commands from the TensorFlow Lite tutorial.\n", "\n", "Those commands can be downloaded from this link: \"http://storage.googleapis.com/download.tensorflow.org/data/mini_speech_commands.zip\"\n", "\n", "Once the zip has been uncompressed, you'll need to change the path of the folder below." ] }, { "cell_type": "markdown", "id": "352220f9", "metadata": {}, "source": [ "The below code is loading the list of commands available in the `mini_speech_commands` folder and it is describing the words we want to detect. Here we only want to detect the `Yes` keyword.\n", "\n", "You can add other keywords but the CMSIS-DSP implementation in this notebook is only supporting one keyword.\n", "Nevertheless, if you'd like to experiment with the training of the ML model and different features, then you can work with more commands." ] }, { "cell_type": "code", "execution_count": 2, "id": "3fb202b4", "metadata": {}, "outputs": [], "source": [ "MINISPEECH=\"mini_speech_commands\"\n", "commands=np.array([os.path.basename(f) for f in glob.glob(os.path.join(MINISPEECH,\"mini_speech_commands\",\"*\"))])\n", "commands=commands[commands != \"README.md\"]\n", "# Any other word will be recognized as unknown\n", "to_keep=['yes']" ] }, { "cell_type": "markdown", "id": "3bc4b610", "metadata": {}, "source": [ "The below code is generating a label ID for a command. The ID will be -1 for any command not in the `to_keep` list. Other ID will be the index of the keyword in this list." ] }, { "cell_type": "code", "execution_count": 3, "id": "9df05672", "metadata": {}, "outputs": [], "source": [ "UNKNOWN_CLASS = -1\n", "def get_label(name):\n", " return(pathlib.PurePath(name).parts[-2])\n", "def get_label_id(name):\n", " label=get_label(name)\n", " if label in to_keep:\n", " return(to_keep.index(label))\n", " else:\n", " return(UNKNOWN_CLASS)" ] }, { "cell_type": "markdown", "id": "7cf6b745", "metadata": {}, "source": [ "## The feature\n", "\n", "The feature is based on a simple zero crossing rate (zcr). We choose to only keep the increasing crossing. I don't think it is making a lot of differences for the final performance of the keyword recognition.\n", "\n", "The `zcr` function is computing the zcr for a window of samples." ] }, { "cell_type": "code", "execution_count": 4, "id": "f24e5b4c", "metadata": {}, "outputs": [], "source": [ "def zcr(w):\n", " w = w-np.mean(w)\n", " f=w[:-1]\n", " g=w[1:]\n", " k=np.count_nonzero(np.logical_and(f*g<0, g>f))\n", " return(1.0*k/len(f))\n", " " ] }, { "cell_type": "markdown", "id": "a218c0e5", "metadata": {}, "source": [ "The final feature is the zcr computed on a segment of 1 second and filtered. We are using a sliding window and using a Hann window." ] }, { "cell_type": "code", "execution_count": 6, "id": "4dc76d14", "metadata": {}, "outputs": [], "source": [ "def feature(data):\n", " samplerate=16000\n", " input_len = 16000\n", " \n", " # The speech pattern is padded to ensure it has a duration of 1 second\n", " \n", " waveform = data[:input_len]\n", " \n", " zero_padding = np.zeros(\n", " 16000 - waveform.shape[0],\n", " dtype=np.float32)\n", " \n", " \n", " signal = np.hstack([waveform, zero_padding])\n", " \n", " \n", " # We decompose the intput signal into overlapping window. And the signal in each window\n", " # is premultiplied by a Hann window of the right size.\n", " # Warning : if you change the window duration and audio offset, you'll need to change the value\n", " # in the scripts used for the scheduling of the compute graph later.\n", " winDuration=25e-3\n", " audioOffsetDuration=10e-3\n", " winLength=int(np.floor(samplerate*winDuration))\n", " audioOffset=int(np.floor(samplerate*audioOffsetDuration))\n", " overlap=winLength-audioOffset\n", " window=hann(winLength,sym=False)\n", " reta=[zcr(x*window) for x in sliding_window_view(signal,winLength)[::audioOffset,:]]\n", " \n", " # The final signal is filtered. We have tested several variations on the feature. This filtering is\n", " # improving the recognition\n", " reta=scipy.signal.lfilter(np.ones(10)/10.0,[1],reta)\n", " return(np.array(reta))" ] }, { "cell_type": "markdown", "id": "40b040df", "metadata": {}, "source": [ "## The patterns\n", "\n", "The below class is representing a Pattern. A pattern can either be a sound file from the TensorFlow Lite examples and in this case we compute the feature and the label id.\n", "\n", "The pattern can also be a random white noise. In that case, we also compute the feature and the class id is -1.\n", "\n", "Note that when you use the signal property, the speech patterns will return the content of the file but noise patterns will generate a random noise which will thus be different each time." ] }, { "cell_type": "code", "execution_count": 7, "id": "279b0999", "metadata": {}, "outputs": [], "source": [ "class Pattern:\n", " def __init__(self,p):\n", " global UNKNOWN_CLASS\n", " if isinstance(p, str):\n", " self._isFile=True \n", " self._filename=p\n", " self._label=get_label_id(p)\n", " \n", " data, samplerate = sf.read(self._filename)\n", " self._feature = feature(data)\n", " else:\n", " self._isFile=False\n", " self._noiseLevel=p\n", " self._label=UNKNOWN_CLASS\n", " \n", " noise=np.random.randn(16000)*p\n", " self._feature=feature(noise)\n", " \n", " @property\n", " def label(self):\n", " return(self._label)\n", " \n", " @property\n", " def feature(self):\n", " return(self._feature)\n", " \n", " \n", " # Only useful for plotting\n", " # The random pattern will be different each time\n", " @property\n", " def signal(self):\n", " if not self._isFile:\n", " return(np.random.randn(16000)*self._noiseLevel)\n", " else:\n", " data, samplerate = sf.read(self._filename)\n", " return(data)\n", " " ] }, { "cell_type": "markdown", "id": "099433f6", "metadata": {}, "source": [ "Following code is giving the number of speech samples for each keyword.\n", "It is assuming that all keywords contain the same number of samples." ] }, { "cell_type": "code", "execution_count": 8, "id": "79588da0", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "1000" ] }, "execution_count": 8, "metadata": {}, "output_type": "execute_result" } ], "source": [ "files_per_command=len(glob.glob(os.path.join(MINISPEECH,\"mini_speech_commands\",commands[0],\"*\")))\n", "files_per_command" ] }, { "cell_type": "markdown", "id": "bb329acb", "metadata": {}, "source": [ "The following code is generating the patterns used for the training of the ML model,.\n", "It is reading patterns for all the words we want to keep (from `to_keep` list) and it is aggregating all other keywords in the unknown class.\n", "\n", "It is also generating some random noise patterns.For the unknown class, the number of patterns will always be `files_per_command` but some patterns may be noise rather than sound files.\n", "\n", "There is some randomization of file names. So each time this code is executed, you'll get patterns in a different order and for the unknown class, which is containing more than `files_per_command`, you'll get a different subset of those patterns (thr subset will have the right length `files_per_command`).\n", "\n", "Finally the patterns are also randomized so that the split between training and test patterns will select different patterns each time this code is executed." ] }, { "cell_type": "code", "execution_count": 9, "id": "e4e8bf7d", "metadata": {}, "outputs": [], "source": [ "# Add patterns we want to detect\n", "filenames=[]\n", "for f in to_keep:\n", " filenames+=glob.glob(os.path.join(MINISPEECH,\"mini_speech_commands\",f,\"*\"))\n", "\n", " \n", "random.shuffle(filenames)\n", " \n", "# Add remaining patterns\n", "remaining_words=list(set(commands)-set(to_keep))\n", "nb_noise=0\n", "\n", "remaining=[]\n", "for f in remaining_words:\n", " remaining+=glob.glob(os.path.join(MINISPEECH,\"mini_speech_commands\",f,\"*\"))\n", " \n", "random.shuffle(remaining)\n", "\n", "\n", "filenames += remaining[0:files_per_command-nb_noise]\n", "\n", "patterns=[Pattern(x) for x in filenames]\n", "\n", "for i in range(nb_noise):\n", " patterns.append(Pattern(np.abs(np.random.rand(1)*0.05)[0]))\n", " \n", "random.shuffle(patterns)" ] }, { "cell_type": "markdown", "id": "cc8b0033", "metadata": {}, "source": [ "Below code is extracting the training and test patterns.\n", "This will be used later to generate the array used by scikit learn to train the model." ] }, { "cell_type": "code", "execution_count": 10, "id": "e9ebb293", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "2000\n" ] } ], "source": [ "print(len(patterns))\n", "patterns=np.array(patterns)\n", "\n", "nb_patterns = len(patterns)\n", "nb_train= int(np.floor(0.8 * nb_patterns))\n", "nb_tests=nb_patterns-nb_train\n", "\n", "train_patterns = patterns[:nb_train]\n", "test_patterns = patterns[-nb_tests:]" ] }, { "cell_type": "markdown", "id": "bab9b1d2", "metadata": {}, "source": [ "## Testing on a signal\n", "\n", "The following code is displaying a pattern as example." ] }, { "cell_type": "code", "execution_count": 11, "id": "b298cfea", "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "nbpat=50\n", "data = patterns[nbpat].signal\n", "samplerate=16000\n", "plt.plot(data)\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 12, "id": "bbdb9edd", "metadata": {}, "outputs": [ { "data": { "text/html": [ "\n", " \n", " " ], "text/plain": [ "" ] }, "execution_count": 12, "metadata": {}, "output_type": "execute_result" } ], "source": [ "audio=Audio(data=data,rate=samplerate,autoplay=False)\n", "audio" ] }, { "cell_type": "markdown", "id": "460afa2a", "metadata": {}, "source": [ "Simple function to display a spectrogram. It is adapted from a SciPy example." ] }, { "cell_type": "code", "execution_count": 13, "id": "8cd9c83f", "metadata": {}, "outputs": [], "source": [ "def get_spectrogram(waveform,fs):\n", " # Zero-padding for an audio waveform with less than 16,000 samples.\n", " input_len = 16000\n", " waveform = waveform[:input_len]\n", " zero_padding = np.zeros(\n", " 16000 - waveform.shape[0],\n", " dtype=np.float32)\n", " mmax=np.max(np.abs(waveform))\n", " \n", " equal_length = np.hstack([waveform, zero_padding])\n", " f, t, Zxx = scipy.signal.stft(equal_length, fs, nperseg=1000)\n", " plt.pcolormesh(t, f, np.abs(Zxx), vmin=0, vmax=mmax/100, shading='gouraud')\n", " plt.title('STFT Magnitude')\n", " plt.ylabel('Frequency [Hz]')\n", " plt.xlabel('Time [sec]')\n", " plt.show()" ] }, { "cell_type": "code", "execution_count": 14, "id": "92eca740", "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "get_spectrogram(data,16000)" ] }, { "cell_type": "markdown", "id": "03037e1b", "metadata": {}, "source": [ "Display of the feature to compare with the spectrogram." ] }, { "cell_type": "code", "execution_count": 15, "id": "c55f0d03", "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "feat=feature(data)\n", "plt.plot(feat)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "8b798aea", "metadata": {}, "source": [ "## Patterns for training\n", "\n", "Now we generate the arrays needed to train and test the model.\n", "We have an array of feature : X_array.\n", "An array of label ID : y\n", "\n", "and similar arrays for the tests." ] }, { "cell_type": "code", "execution_count": 16, "id": "647ecb32", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1600, 98)" ] }, "execution_count": 16, "metadata": {}, "output_type": "execute_result" } ], "source": [ "X=np.array([x.feature for x in train_patterns])\n", "X.shape" ] }, { "cell_type": "code", "execution_count": 17, "id": "2603ecb9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "(1600,)" ] }, "execution_count": 17, "metadata": {}, "output_type": "execute_result" } ], "source": [ "y=np.array([x.label for x in train_patterns])\n", "y.shape" ] }, { "cell_type": "code", "execution_count": 18, "id": "658b7553", "metadata": {}, "outputs": [], "source": [ "y_test = [x.label for x in test_patterns]\n", "X_test = [x.feature for x in test_patterns]" ] }, { "cell_type": "markdown", "id": "79909063", "metadata": {}, "source": [ "## Logistic Regression\n", "\n", "We have chosen to use a simple logistic regression. We are doing a randomized search on the hyperparameter space." ] }, { "cell_type": "code", "execution_count": 19, "id": "e1fdf0ef", "metadata": {}, "outputs": [], "source": [ "distributionsb = dict(C=uniform(loc=1, scale=1000)\n", " )\n", "reg = LogisticRegression(penalty=\"l1\", solver=\"saga\", tol=0.1)\n", "clfb=RandomizedSearchCV(reg, distributionsb,random_state=0,n_iter=50).fit(X, y)" ] }, { "cell_type": "markdown", "id": "bca2dabd", "metadata": {}, "source": [ "We are using the best estimator found during the randomized search:" ] }, { "cell_type": "code", "execution_count": 20, "id": "fddd7782", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "LogisticRegression(C=682.8202991034834, penalty='l1', solver='saga', tol=0.1)" ] }, "execution_count": 20, "metadata": {}, "output_type": "execute_result" } ], "source": [ "clfb.best_estimator_" ] }, { "cell_type": "markdown", "id": "6a7ffeb1", "metadata": {}, "source": [ "The confusion matrix is generated from the test patterns to check the behavior of the classifier:" ] }, { "cell_type": "code", "execution_count": 21, "id": "eb6facde", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 21, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "y_pred = clfb.predict(X_test)\n", "labels=[\"Unknown\"] + to_keep\n", "ConfusionMatrixDisplay.from_predictions(y_test, y_pred,display_labels=labels)" ] }, { "cell_type": "markdown", "id": "76b17c7d", "metadata": {}, "source": [ "We compute the final score. 0.8 is really the minimum acceptable value for this kind of demo.\n", "With the zcr feature, if you try to detect `Yes`, `No`, `Unknown`, you'll get a score of around 0.6 which is very bad." ] }, { "cell_type": "code", "execution_count": 22, "id": "de8460b1", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.83" ] }, "execution_count": 22, "metadata": {}, "output_type": "execute_result" } ], "source": [ "clfb.score(X_test, y_test)" ] }, { "cell_type": "markdown", "id": "9ba6739f", "metadata": {}, "source": [ "We can now save the model so that next time we want to play with the notebook and test the CMSIS-DSP implementation we do not have to retrain the model:" ] }, { "cell_type": "code", "execution_count": 23, "id": "ea4ae8f8", "metadata": {}, "outputs": [], "source": [ "with open(\"logistic.pickle\",\"wb\") as f:\n", " s = pickle.dump(clfb,f)" ] }, { "cell_type": "markdown", "id": "aab3aaf2", "metadata": {}, "source": [ "And we can reload the saved model:" ] }, { "cell_type": "code", "execution_count": 197, "id": "c4811945", "metadata": {}, "outputs": [], "source": [ "with open(\"logistic.pickle\",\"rb\") as f:\n", " clfb=pickle.load(f)" ] }, { "cell_type": "markdown", "id": "a9c1ef1b", "metadata": {}, "source": [ "## Reference implementation with Matrix" ] }, { "cell_type": "markdown", "id": "ef865bc5", "metadata": {}, "source": [ "This is the reference implementation which will be used to build the CMSIS-DSP implementation. We are no more using the scikit-learn predict function instead we are using an implementation of predict using linear algebra. It should give the same results." ] }, { "cell_type": "code", "execution_count": 24, "id": "f6e861cf", "metadata": {}, "outputs": [], "source": [ "def predict(feat):\n", " coef=clfb.best_estimator_.coef_\n", " intercept=clfb.best_estimator_.intercept_\n", " \n", " res=np.dot(coef,feat) + intercept\n", " \n", " if res<0:\n", " return(-1)\n", " else:\n", " return(0)" ] }, { "cell_type": "markdown", "id": "918afd57", "metadata": {}, "source": [ "And like in the code above with scikit-learn, we are checking the result with the confusion matrix and the score. It should give the same results:" ] }, { "cell_type": "code", "execution_count": 25, "id": "66e69345", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 25, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "y_pred_ref = [predict(x) for x in X_test]\n", "labels=[\"Unknown\"] + to_keep\n", "ConfusionMatrixDisplay.from_predictions(y_test, y_pred_ref,display_labels=labels)" ] }, { "cell_type": "code", "execution_count": 26, "id": "887d714a", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.83" ] }, "execution_count": 26, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.count_nonzero(np.equal(y_test,y_pred_ref))/len(y_test)" ] }, { "cell_type": "markdown", "id": "6bbd0d3b", "metadata": {}, "source": [ "## CMSIS-DSP implementation\n", "\n", "Now we are ready to implement the code using CMSIS-DSP API. Once we have a running implementation in Python, writing the C code will be easy since the API is the same.\n", "\n", "We are testing 3 implementations here : F32, Q31 and Q15.\n", "At the end, we will check that Q15 is giving good enough results and thus can be implemented in C for the Arduino." ] }, { "cell_type": "markdown", "id": "a801479c", "metadata": {}, "source": [ "### F32 Implementation\n", "\n", "It will be very similar to the implemenattion above with matrix but will instead use the CMSIS-DSP API." ] }, { "cell_type": "code", "execution_count": 27, "id": "d861ee1c", "metadata": {}, "outputs": [], "source": [ "coef_f32=clfb.best_estimator_.coef_\n", "intercept_f32=clfb.best_estimator_.intercept_" ] }, { "cell_type": "code", "execution_count": 28, "id": "1e50c5b1", "metadata": {}, "outputs": [], "source": [ "def dsp_zcr(w):\n", " m = dsp.arm_mean_f32(w)\n", " m = -m\n", " w = dsp.arm_offset_f32(w,m)\n", " f=w[:-1]\n", " g=w[1:]\n", " k=np.count_nonzero(np.logical_and(f*g<0, g>f))\n", " return(1.0*k/len(f))" ] }, { "cell_type": "markdown", "id": "fa0b092d", "metadata": {}, "source": [ "For the FIR, CMSIS-DSP is using a FIR instance structure and thus we need to define it" ] }, { "cell_type": "code", "execution_count": 29, "id": "3313b384", "metadata": {}, "outputs": [], "source": [ "firf32 = dsp.arm_fir_instance_f32()" ] }, { "cell_type": "code", "execution_count": 30, "id": "480631ce", "metadata": {}, "outputs": [], "source": [ "def dsp_feature(data):\n", " samplerate=16000\n", " input_len = 16000\n", " \n", " waveform = data[:input_len]\n", " \n", " zero_padding = np.zeros(\n", " 16000 - waveform.shape[0],\n", " dtype=np.float32)\n", " \n", " \n", " signal = np.hstack([waveform, zero_padding])\n", " \n", " \n", " winDuration=25e-3\n", " audioOffsetDuration=10e-3\n", " winLength=int(np.floor(samplerate*winDuration))\n", " audioOffset=int(np.floor(samplerate*audioOffsetDuration))\n", " overlap=winLength -audioOffset\n", " window=hann(winLength,sym=False)\n", " reta=[dsp_zcr(dsp.arm_mult_f32(x,window)) for x in sliding_window_view(signal,winLength)[::audioOffset,:]]\n", " \n", " # Reset state and filter\n", " # We want to start with a clean filter each time we filter a new feature.\n", " # So the filter state is reset each time.\n", " blockSize=98\n", " numTaps=10\n", " stateLength = numTaps + blockSize - 1\n", " dsp.arm_fir_init_f32(firf32,10,np.ones(10)/10.0,np.zeros(stateLength))\n", " reta=dsp.arm_fir_f32(firf32,reta)\n", " return(np.array(reta))" ] }, { "cell_type": "markdown", "id": "4d683590", "metadata": {}, "source": [ "Let's check that the feature is giving the same result as the reference implemenattion using linear algebra." ] }, { "cell_type": "code", "execution_count": 31, "id": "1b926a1a", "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "feat=dsp_feature(data)\n", "plt.plot(feat)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "f894f1f0", "metadata": {}, "source": [ "The feature code is working, so now we can implement the predict:" ] }, { "cell_type": "code", "execution_count": 32, "id": "a67a5b5b", "metadata": {}, "outputs": [], "source": [ "def dsp_predict(feat):\n", " \n", " res=dsp.arm_dot_prod_f32(coef_f32,feat)\n", " res = res + intercept_f32\n", " \n", " if res[0]<0:\n", " return(-1)\n", " else:\n", " return(0)" ] }, { "cell_type": "markdown", "id": "fccb1c17", "metadata": {}, "source": [ "And finally we can check the CMSIS-DSP behavior of the test patterns:" ] }, { "cell_type": "code", "execution_count": 33, "id": "84bac863", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 33, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "y_pred_ref = [dsp_predict(dsp_feature(x.signal)) for x in test_patterns]\n", "labels=[\"Unknown\"] + to_keep\n", "ConfusionMatrixDisplay.from_predictions(y_test, y_pred_ref,display_labels=labels)" ] }, { "cell_type": "code", "execution_count": 34, "id": "bf0a23d9", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.83" ] }, "execution_count": 34, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.count_nonzero(np.equal(y_test,y_pred_ref))/len(y_test)" ] }, { "cell_type": "markdown", "id": "0a80b698", "metadata": {}, "source": [ "We are getting very similar results to the reference implementation. Now let's explore fixed point." ] }, { "cell_type": "markdown", "id": "f3bcc892", "metadata": {}, "source": [ "### Q31 implementation\n", "\n", "First thing to do is to convert the F32 values of the ML mode into Q31.\n", "But we need values in [-1,1]. So we rescale those values and keep track of the shift required to restore the original value.\n", "\n", "Then, we convert those rescaled values to Q31." ] }, { "cell_type": "code", "execution_count": 35, "id": "beb7e364", "metadata": {}, "outputs": [], "source": [ "scaled_coef=clfb.best_estimator_.coef_ \n", "coef_shift=0\n", "while np.max(np.abs(scaled_coef)) > 1:\n", " scaled_coef = scaled_coef / 2.0 \n", " coef_shift = coef_shift + 1\n", "\n", "coef_q31=fix.toQ31(scaled_coef)\n", "\n", "scaled_intercept = clfb.best_estimator_.intercept_ \n", "intercept_shift = 0\n", "while np.abs(scaled_intercept) > 1:\n", " scaled_intercept = scaled_intercept / 2.0 \n", " intercept_shift = intercept_shift + 1\n", " \n", "intercept_q31=fix.toQ31(scaled_intercept)" ] }, { "cell_type": "markdown", "id": "ed1cbb2c", "metadata": {}, "source": [ "Now we can implement the zcr and feature in Q31." ] }, { "cell_type": "code", "execution_count": 36, "id": "7a64829c", "metadata": {}, "outputs": [], "source": [ "def dsp_zcr_q31(w):\n", " m = dsp.arm_mean_q31(w)\n", " # Negate can saturate so we use CMSIS-DSP function which is working on array (and we have a scalar)\n", " m = dsp.arm_negate_q31(np.array([m]))[0]\n", " w = dsp.arm_offset_q31(w,m)\n", " \n", " f=w[:-1]\n", " g=w[1:]\n", " k=np.count_nonzero(np.logical_and(np.logical_or(np.logical_and(f>0,g<0), np.logical_and(f<0,g>0)),g>f))\n", " \n", " # k < len(f) so shift should be 0 except when k == len(f)\n", " # When k==len(f) normally quotient is 0x40000000 and shift 1 and we convert\n", " # this to 0x7FFFFFF and shift 0\n", " status,quotient,shift_val=dsp.arm_divide_q31(k,len(f))\n", " if shift_val==1:\n", " return(dsp.arm_shift_q31(np.array([quotient]),shift)[0])\n", " else:\n", " return(quotient)" ] }, { "cell_type": "code", "execution_count": 37, "id": "2aac9a63", "metadata": {}, "outputs": [], "source": [ "firq31 = dsp.arm_fir_instance_q31()" ] }, { "cell_type": "code", "execution_count": 38, "id": "a65003af", "metadata": {}, "outputs": [], "source": [ "def dsp_feature_q31(data):\n", " samplerate=16000\n", " input_len = 16000\n", " \n", " waveform = data[:input_len]\n", " \n", " zero_padding = np.zeros(\n", " 16000 - waveform.shape[0],\n", " dtype=np.int32)\n", " \n", " \n", " signal = np.hstack([waveform, zero_padding])\n", " \n", " \n", " winDuration=25e-3\n", " audioOffsetDuration=10e-3\n", " winLength=int(np.floor(samplerate*winDuration))\n", " audioOffset=int(np.floor(samplerate*audioOffsetDuration))\n", " overlap=winLength-audioOffset\n", " \n", " window=fix.toQ31(hann(winLength,sym=False))\n", " reta=[dsp_zcr_q31(dsp.arm_mult_q31(x,window)) for x in sliding_window_view(signal,winLength)[::audioOffset,:]]\n", " \n", " # Reset state and filter\n", " blockSize=98\n", " numTaps=10\n", " stateLength = numTaps + blockSize - 1\n", " dsp.arm_fir_init_q31(firq31,10,fix.toQ31(np.ones(10)/10.0),np.zeros(stateLength,dtype=np.int32))\n", " reta=dsp.arm_fir_q31(firq31,reta)\n", " return(np.array(reta))" ] }, { "cell_type": "markdown", "id": "e63b0ceb", "metadata": {}, "source": [ "Let's check the feature on the data to compare with the F32 version and check it is working:" ] }, { "cell_type": "code", "execution_count": 39, "id": "d59c2442", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAX4AAAD4CAYAAADrRI2NAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAssUlEQVR4nO3deXxU5b3H8c8ve0L2kASyQNi3AAFDELBuoGCrotRW3LfWbt4u3traa1/2XrvZ2lq1LtWqdbmlitaFa60oW0VBSMJO2JIAWUjIvpP9uX/MhIYYYIBJzsyc3/v1youZM2dmfpMTvjl5nuc8jxhjUEopZR9+VheglFJqcGnwK6WUzWjwK6WUzWjwK6WUzWjwK6WUzQRYXUBfQ4cONWlpaVaXoZRSXiU3N7fKGBPvyr4eF/xpaWnk5ORYXYZSSnkVETns6r7a1KOUUjajwa+UUjajwa+UUjajwa+UUjajwa+UUjajwa+UUjajwa+UUjbjceP4lVK+q7vbkF/ZxOaDNYQG+nP5lEQiQgKtLst2NPiVUgOquqmNNXsrWLO3gs8Kq6lt6Tj+WMg7flw2eRhZo2JpaeukobWDpOhQbswagYhYWLVv0+BXSrmVMYYDFU2s2nOU1Xsq2FJUizEwLDKE+ZMSyRoVS1ZaLNXN7by9tYT3dpTxf9uPACACxkBooD9LZqZY/El8l3jaClyZmZlGp2xQyjut3VvBQ+/lcbCqGYCpyVHMn5TAgkmJTEmK7Pcsvr2zm+rmNiJDAgkJ9Ocrf9rAwapmVt17EXHhwYP9EbyWiOQaYzJd2VfP+JVS56y+pYOH3svj71tKGJcQzi+vTWf+xESGRYWc9rlBAX4Mjwo9fv/hL0/jS0+s5xf/2MMfrs8YwKrtS4NfKXVOdpbU87VXsqlqaueeS8byH/PHEhzgf9avNz4xgm9dNIYn1uRzzYxkLhrv0oST6gzocE6l1FnLO9LAzS9sIsDPj3e+PY8fLpxwTqHf4zuXjmVM/BAeeHsnzW2dbqhU9abBr5Q6K/vKG7n5hU0MCfLntbvPZ2pKlNteOzjAn4e/PI3SumP86v09bntd5aDBr5Q6Y4erm7np+c8I8BOWff18UmPD3P4es9Ji+foXRvPXTUWs3Vfh9te3Mw1+pdQZ+8NH+znW3sWyr59P2tAhA/Y+9142ngmJEfzozR3UNrcP2PvYjUvBLyKLRGSfiOSLyP39PH6viOSJyA4RWS0iI3s91iUi25xfK9xZvFJq8B1taOW9HWV8dVYqYxPCB/S9QgL9efT66dS1tPPTd3bhacPPvdVpg19E/IGngCuAycANIjK5z25bgUxjzDTgTeC3vR47ZozJcH5d7aa6lVIWeXXjYbqM4fa5aYPyflOSovj+gvH8Y2cZa/Zqk487uHLGnwXkG2MKjTHtwGvA4t47GGPWGmNanHc/A/SSO6V8UGtHF8s2F7FgUiIj4wauiaevb1w4muToUJ77uHDQ3tOXuRL8yUBxr/slzm0ncxfwz173Q0QkR0Q+E5FrzrxEpZSneHdbKTXN7dwxL21Q3zfA34/b56ax6WANO0vqB/W9fZFbO3dF5GYgE3ik1+aRzsuIbwQeE5Ex/Tzvbucvh5zKykp3lqSUchNjDH/59BATh0UwZ3TcoL//9VmphAcH8PwnetZ/rlwJ/lIgtdf9FOe2E4jIAuAB4GpjTFvPdmNMqfPfQmAdMKPvc40xzxljMo0xmfHxepWeUp5oY0E1e8sbuXPeKEtmzowMCWTprFTe21HGkbpjg/7+vsSV4M8GxonIKBEJApYCJ4zOEZEZwLM4Qr+i1/YYEQl23h4KzAPy3FW8UmpwdHcbfvfhPoaGB3F1RpJlddzubGJ6ecMhy2rwBacNfmNMJ3APsBLYAyw3xuwWkYdEpGeUziNAOPBGn2Gbk4AcEdkOrAUeNsZo8CvlZZbnFLOlqI4fL5pISOC5T8lwtlJiwrgifRjLNhfRpFM5nDWXJmkzxrwPvN9n24O9bi84yfM2AFPPpUCllLVqmtt5+IO9ZKXFct151g/Y+/oXRvPejjLeyCnmjnmjrC7HK+mVu0qpU/r1+3toau3kF9eme8SqWNNTo5meGs1fNxXpBV1nSYNfKXVS2YdqeCO3hK99YTTjEyOsLue4m2aPIL+iiexDtVaX4pU0+JVSJ/X4qgMMjwrhu/PHWl3KCa6alkRESAB/3XTY6lK8kga/UqpfrR1dbD5Uw5emDicsyLPWbAoN8mfJjGT+ubOcGp287Yxp8Cul+rXlcC3tnd3MHTv4F2u54sbZI2nv6ubvuSVWl+J1NPiVUv36tKAKfz9hVlqs1aX0a8KwCDJHxrBss3bynikNfqVUvzYUVDM9JYqIkECrSzmpm84fwcGqZjYWVFtdilfR4FdKfU5jawc7SuqZO2ao1aWc0hXpw4kOC+S17OLT76yO0+BXSn3O5oM1dHUb5o7xzPb9HiGB/lw5bTgf5pXrlbxnQINfKfU5GwqqCQrwY+bIGKtLOa1rZyTT2tHNyl3lVpfiNTT4lVKfs6GgmsyRMZbOy+OqmSNiGBEbxttbPzdpsDoJDX6l1AlqmtvZU9bg8c08PUSEa2Yk82lBFUcbWq0uxyto8CulTtAzQmaOh3fs9nZNRhLGwIptR6wuxSto8CulTrChoIohQf5MS4myuhSXjY4PZ3pqtDb3uEiDXyl1go2F1WSNiiXQ37viYcmMZPLKGthX3mh1KR7Pu46sUmpA1TS3U1jZzKxRnnm17qlcOW04/n7CW1t1CofT0eBXSh235bBjmuPzRnj+MM6+4sKDuWRCPG9tKaWjq9vqcjyaBr9S6rjcoloC/ITpqdFWl3JWbpw9gsrGNlblHbW6FI+mwa+UOi73cC1TkqO8Yvx+fy4an0BydCjLNhdZXYpH0+BXSgHQ0dXN9uI6r2zm6eHvJyydlcr6A1Ucqmq2uhyPpcGvlAIg70gDbZ3dnOcF0zScyldnpeLvJ/wtW8/6T0aDXykFOJp5AGaOjLa2kHOUGBnCZZMSeSOnhLbOLqvL8Uga/EopwNGxmxwdyvCoUKtLOWc3zh5BTXM7K3drJ29/NPiVUhhjyD1U6xWzcbrigrFDGREbxt82aXNPfzT4lVIcqW+lvKGV80ZEW12KW/j5CYvSh5HrXDdYnUiDXyl1vH3/vJHed8XuyWSkRtPe1c3e8garS/E4GvxKKbYcriU00J9JwyOsLsVteiaZ215cZ20hHkiDXylF7uFaMlKjCfCyidlOJTk6lKHhQWwvqbe6FI/jO0dZKXVWWju6yCtr8PphnH2JCNNTovWMvx8uBb+ILBKRfSKSLyL39/P4vSKSJyI7RGS1iIzs9dhtInLA+XWbO4tXSp27vLIGuroNU5OjrS7F7aalRJNf2aQLsfdx2uAXEX/gKeAKYDJwg4hM7rPbViDTGDMNeBP4rfO5scDPgNlAFvAzEfGN8WJK+YhdpY6mkKletPCKq6anRmEM7NTmnhO4csafBeQbYwqNMe3Aa8Di3jsYY9YaY1qcdz8DUpy3FwIfGWNqjDG1wEfAIveUrpRyh50l9cQOCSIpKsTqUtxueko0ANtL6iytw9O4EvzJQHGv+yXObSdzF/DPM3muiNwtIjkiklNZWelCSUopd9lZWs/U5ChExOpS3C5mSBAjYsO0nb8Pt3buisjNQCbwyJk8zxjznDEm0xiTGR8f786SlFKn0NrRxYGKJqYm+14zT4/pqdrB25crwV8KpPa6n+LcdgIRWQA8AFxtjGk7k+cqpazR07Gb7svBnxLFkfpWKhpbrS7FY7gS/NnAOBEZJSJBwFJgRe8dRGQG8CyO0K/o9dBK4HIRiXF26l7u3KaU8gC+3LHbo2c1sR3F2sHb47TBb4zpBO7BEdh7gOXGmN0i8pCIXO3c7REgHHhDRLaJyArnc2uAn+P45ZENPOTcppTyAL7csdtjSlIk/n6iHby9BLiykzHmfeD9Ptse7HV7wSme+yLw4tkWqJQaODtL60n30Y7dHmFBAYxPjGCbtvMfp1fuKmVT/+7YjbS6lAE3PSWKHSX1GGOsLsUjaPArZVN7jl+x67vt+z3Sk6OoP9ZBSe0xq0vxCBr8StnUTmfHri+P6OkxJcnxV83uIzpFM2jwK2VbPR27ydHev9Ti6UwcFomfQN4RHdkDGvxK2ZYdOnZ7hAb5MyY+XM/4nTT4lbIhO3Xs9picFKnB76TBr5QN5dmoY7fHlKRIyhtaqW5qO/3OPk6DXykb2lZUB0BGqn1mSZ+S5Pgll1emZ/0a/ErZ0PaSOhIjgxnmw1fs9jV5uI7s6aHBr5QNbSuuI8M5h41dxDinptDg1+BXynZqm9s5XN1yfPIyO5mcFMVuHdKpwa+U3fRMVma3M35wdPAerGqmpd3ea/Bq8CtlM9uK6xDBViN6ekxJisQY2FPWaHUpltLgV8pmthfXMTY+nIiQQKtLGXRTnL/s7H4Frwa/UjZijGF7Sb0tm3kAkqJCiAoNtH0Hrwa/UjZSXHOMmuZ2W3bsAogIU/QKXg1+pexkm407dntMSYpk39FGOrq6rS7FMhr8StnI9uI6ggP8mDAswupSLDMlKYr2zm4KKpusLsUyGvxK2ci24jrSk6MI9Lfvf/3JPXPzl9q3uce+R18pm+no6mZXqX07dnuMHjqE4AA/W7fza/ArZRP7yhtp6+y2bcdujwB/PyYOjySvzL5DOjX4lbKJnEM1AMwcEW1tIR5gSlIkeUcabLv4uga/Ujax+VANydGhpMSEWV2K5aYkRdLQ2mnbxdc1+JWyAWMMmw/WMivNPvPvn8q/p2i2Z3OPBr9SNnCwqpmqpjayRsVZXYpH+Pfi6/bs4NXgV8oGsp3t+1mj9IwfdPF1DX6lbGDTwRpihwQxJj7c6lI8hp2nbtDgV8oGsg/VMCstBhGxuhSPMSUpyraLr2vwK+XjyuqPUVxzTNv3++i5gteOi6+7FPwiskhE9olIvojc38/jF4rIFhHpFJHr+jzWJSLbnF8r3FW4Uso1mw862/fTYi2uxLNMSbLv4usBp9tBRPyBp4DLgBIgW0RWGGPyeu1WBNwO/LCflzhmjMk491KVUmdj88EawoMDmDTcvhOz9Sc6LIjk6FAN/pPIAvKNMYUAIvIasBg4HvzGmEPOx+w7z6lSHir7UA0zR8YQYOOJ2U5mclKkLcfyu/KTkAwU97pf4tzmqhARyRGRz0Tkmv52EJG7nfvkVFZWnsFLK6VOpba5nf1Hm8jSC7f61bP4enObvRZfH4xTgJHGmEzgRuAxERnTdwdjzHPGmExjTGZ8fPwglKSUPWw+Pn5fO3b7M3m4Y/H1veX2au5xJfhLgdRe91Oc21xijCl1/lsIrANmnEF9Sqlz8PH+SsKC/JmeGmV1KR5paorj+7LLZnPzuxL82cA4ERklIkHAUsCl0TkiEiMiwc7bQ4F59OobUEoNHGMMa/ZWcMHYoQQH+FtdjkcaFhnC0PBgdpTYq53/tMFvjOkE7gFWAnuA5caY3SLykIhcDSAis0SkBPgK8KyI7HY+fRKQIyLbgbXAw31GAymlBsje8kbK6luZPynB6lI8logwNTmSnaV1VpcyqFwZ1YMx5n3g/T7bHux1OxtHE1Df520App5jjUqps7BmbwUAl0zQ4D+VqSnR/Gt/JS3tnYQFuRSJXk/Hdynlo1bvOcrU5CgSIkOsLsWjTUuOotvYa6ZODX6lfFBNcztbi+u4dKKe7Z9OTwevndr5NfiV8kHr9lVgDNq+74LEyBASIoLZWarBr5TyYqv3VhAfEUx6kg7jdMW0lCgNfqWU9+ro6ubjfZVcOiEBPz+dhtkVU5OjKahsoskmV/Bq8CvlY3IO1dLY1sml2szjsqkpjit4d9vkrF+DXykfs3rPUYL8/bhg7FCrS/Ea6cmOJjG7NPdo8CvlQ4wxrMwrZ97YOIYE22NMujskRIQwPCpEg18p5X3yyhoorjnGovRhVpfiddKTo9hpkyGdGvxK+ZCVu8rxE1gwKdHqUrzOtOQoCquaaWjtsLqUAafBr5QPWbn7KLPSYokLD7a6FK/TcyHXbhvM1KnBr5SPOFjVzL6jjdrMc5ampUQDsKWo1tpCBoEGv1I+YuXucgAun6LBfzZihwQxITGCzwqrrS5lwGnwK+UjPthVzrSUKJKjQ60uxWvNGRNH9qEa2jt9e/lwDX6lfEB5fSvbiutYqGf75+T80XG0dnSzrbjO6lIGlAa/Uj7gwzxHM48G/7k5f3QsIrCxwLebezT4lfIBH+UdZUz8EMYmhFtdileLDgti8vBINhZWWV3KgNLgV8rLtbR3sqmwRufed5M5o+PYUlRHa0eX1aUMGA1+pbzcxoJq2ru6uViXWHSLOWPiaO/sZsth3x3WqcGvlJdbu6+CsCB/MtNirC7FJ2SNisXfT9jow8M6NfiV8mLGGNbtq2TumKEEB/hbXY5PiAgJJD05yqc7eDX4lfJiBZXNlNQe4+IJ8VaX4lPmjI5je0kdLe2+uTCLBr9SXmzdvgoADX43mzMmjo4uQ84h32zn1+BXyov9a38lYxPCSYkJs7oUnzIrLYYAH27n1+BXykv1DOO8eLye7btbWFAA6clR5OoZv1LKk+gwzoF13sgYtpfU+eS8PRr8SnmpnmGcs0bpMM6BkDkyhrbObnYd8b1VuTT4lfJCOoxz4J3nvC7CF5t7NPiV8kIFlU2U1B7jkonavj9QEiJCGBEbRs7hGqtLcTuXgl9EFonIPhHJF5H7+3n8QhHZIiKdInJdn8duE5EDzq/b3FW4Una2Zq9jGOcl2r4/oDJHxpB7uBZjjNWluNVpg19E/IGngCuAycANIjK5z25FwO3Asj7PjQV+BswGsoCfiYg2SCp1jtburWTisAiSdNGVAXVeWgxVTe0crm6xuhS3cuWMPwvIN8YUGmPagdeAxb13MMYcMsbsAPp2fy8EPjLG1BhjaoGPgEVuqFsp22po7SD7UI2O5hkEmSNjAcjxsQnbXAn+ZKC41/0S5zZXuPRcEblbRHJEJKeystLFl1bKnj49UEVnt9FpmAfBuIRwIkMCyPWxdn6P6Nw1xjxnjMk0xmTGx2tnlVKnsmZvBZEhAcwcEW11KT7Pz0+YOTLG56ZucCX4S4HUXvdTnNtccS7PVUr10d1tWLe/kgvHxxPg7xHnbT4vc2QMByqaqGtpt7oUt3HlJycbGCcio0QkCFgKrHDx9VcCl4tIjLNT93LnNqXUWcgra6CysU1H8wyi85zt/FuKfOes/7TBb4zpBO7BEdh7gOXGmN0i8pCIXA0gIrNEpAT4CvCsiOx2PrcG+DmOXx7ZwEPObUqps7BmbwUicJHOxjloMlKjCfATn2ruCXBlJ2PM+8D7fbY92Ot2No5mnP6e+yLw4jnUqJRyWruvgmkp0QwND7a6FNsIDfJnSlKkT43s0UZCpbxEfUsH24vrdDZOC2SmxbK92HcmbNPgV8pLbDpYTbeBuWPirC7Fdmal+daEbRr8SnmJjYXVBAf4kaHDOAddTwdvziHf6KLU4FfKS2wsqCYzLUZn47RAfEQwaXFhZPtIB68Gv1JeoLqpjb3ljcwdM9TqUmwrMy3WZyZs0+BXJ7V2XwVffmYDb28tobvb+3/Yvdmmg44mhvNHa/u+VTJHxlDT3E5hVbPVpZwzDX7Vr5xDNXzrf3PZVVrPD17fzlVPfsL6AzqPklU2FlQTFuTPtJQoq0uxrcw032nn1+BXn7OnrIE7X8omKSqUT358KY8vzaD+WAe3vLCZ17OLrC7PljYWVjMrLZZAnabBMmPihxATFugT7fz6U6ROUFzTwq0vbiYsKIBXvzab+IhgFmcks/o/L+KCsUN58N3d7ClrsLpMW6loaCW/okmHcVpMRI6383s7DX51XHtnN9/6ay7tnd28elcWyb0W+QgO8OexpRlEhQbynb9uoamt08JK7WVjYTUAczT4LZc5MoaDVc1UNrZZXco50eBXx/3+w33sKm3gt9dNY1xixOceHxoezBM3zOBQdTP/9dZOnxjd4A0+K6wmIiSAKUnavm+1nnZ+b5+fX4NfAfDJgSqe/biQm2aPYOGUYSfd7/zRcdx72XhWbD/CW1t0hu3BsKGgmtmjYvH3E6tLsb305EiCA/y8fsI2DX5FdVMbP1i+jbEJ4fz0S32XU/68b188lozUaB7+YK82+Qyw3UfqOVzdouP3PURwgD/TU6PZ7OUjezT4ba6upZ27X82lvqWDJ5bOIDTo9FeF+vkJD141mcrGNp5Zlz8IVZ6otaOLktoW6o91+Pz1BX/4aD+RIQF8+bx+J79VFpg3Zig7S+upafbehVlcmpZZ+aay+mPc+sJmDle38PjSDCYnRbr83JkjYrgmI4k/rz/I0lkjSI0NG5D6gvz9iHNOQVx/rINXNhzihU8PUtfSAYAIJEQEk5kWy+xRscwdE8fYhM/3T3ijLUW1rNpTwX0LJxAVGmh1Ocrpognx/GHVftYfqGRxhqvLj3sWDX6byq9o5NYXNtPQ2slLd846q6aEHy2ayAe7y3n4g708deNMt9W2q7SeJ9fk88HucsAR7OMTI9heXEdjWycLJiUwf1IizW2dNLR2cri6mc0Ha/jHjjLAMfLi1rlpXJE+zKvHvT/64X7ihgRx+9w0q0tRvUxNjiImLJB/7dfgV16kuqmNm5/fTGe34bW7zyc9+exGiyRFh/KNC8fw+OoD3Dy7+pyHG9Y2t3Pfm9tZtaeCiJAA7rlkLNFhgeSVNbCvvJGLJybwrYvG9PuXiTGGktpjrNxdzqufHea7f9vK0PBg5o2NI2uU46+BMfHhiHhHB+nGgmo+ya/ip1+axJBg/W/qSfz9hC+Mi+fj/VV0dxv8vLDTXX+ibKa72/CD5dupaWnnrW/NPevQ7/HNi8bw1tYS7n4lh+duzTzr8K9sbOOWFzZRWNXMfQsncMuckUSGuN68ISKkxobxtS+M5s55o/jXgUr+nlvChoJq3t12BIDk6FDmO/9amDM6jqAAz/xroL2zm99/uI/EyGBuPn+k1eWoflw0Pp4V24+QV9Zwzv+HrKDBbzPP/KuAj/dX8otr0t3yAxsa5M/rd8/hthc3c9uLm3l8aQZXTB1+Rq9RXt/KTc9/RmndMV68bRYXjDu3ESx+fsIlExK4ZEICxhgOV7ewsbCa1XsqWJ5TzCsbDxMTFshV05O4ZkYyM1KjB/Qvgbe3lrD54OlHgbS0d7GvvJGCyiY6ugy/uCadkECdgtkTfWG842f04wOVXhn84mkX4WRmZpqcnByry/BJmwqrueHPn/GlaUk8sTTDrWFX19LOXS/nsKWolqumJRE7JIjI0EDGxA9hwaTEfpsrjDFsKKjmv97eSVVjG3+5I4usUbFuq6k/rR1drD9QxbvbSvko7yhtnd0szkjisevd+/3o8eSaA/zuw/3EhAWetr8hKMCPcQnhTBweyfSUaBZOSfSapik7+uLj64kICeD1b8yxuhQARCTXGJPpyr56xm8TRdUtfGfZVtLihvDrJVPdHijRYUH8712zeeDtnWw6WEPDsQ4anWP8QwP9WZQ+jPmTEhy/EEICKatv5el1+WwtqiMxMphXvzabmSNi3FpTf0IC/blsciKXTU6kobWDP60r4Ol1BYyJD+e788e57X2MMTz60X7+uCafa2ck88h10wjw4o5m9XkXTYjnzx8X0tjaQcQZNEt6Ag1+G6hobOXmFzbR2d3Nc7eeR/gAdRaGBvnz6PUZx+93dRu2FNXy1pZS/rHjCG9vPfFK35SYUH55bTrXnZdiyapSkSGB3LdwAuUNrTz60X7GJYSfcTNVf7q6Db96fw8vfHKQpbNS+dW1U72yA1Cd2kXj43lmXQEbCqpPebW7J9Lg93H1xzq49YXNVDW1sezr5w/qGHd/P2FWWiyz0mL576snk1/RRGNrJw3HOvD3Ey4cH2/5cEsR4VfXTuVQVTP3Lt9OamzYObXZ1ja3893XtrL+QBW3z03jwSsna+j7qJkjYggPDuBf+ys1+JXn2FVaz0/f2UVBZRMv3j6LjNRoy2oJDvD32EnGQgL9efaWTBY/+Qk3Pb+Jx5ZmcMmEhDN+nZ0l9Xzzf3OpbGzj10umckPWiAGoVnmKoAA/5o6JY93eCq8b1qmNjj5oS1Etd76UzZV//ISCiiaeWDqDL4yLt7osjxYfEcxrd88hKTqUO1/K5rFV+12eDuJYexePrNzLkmc+xRjDG9+co6FvE4vSh3GkvtXr5u7RM34fs2L7Eb77t63EhAXyw8vHc8ucNL3c30Uj4sJ461tzeeDtnTy26gCfHKhi8YxkFkxKYHhU6Of2N8awcvdRfv5eHqV1x1gyI5mfXjmZ2CFBFlSvrHBF+nB+9u5ulmcXe9V6yDqc04dsK67j+mc3Mj0lmr/cMUuv+DxLxhiWbS7izx8Xcqi6BYDJwyNZMDmRBZMSGDV0CO9sLeXljYfJr2hiQmIEDy2ewmwv+o+v3Oe/3t7JW1tK2PzAgjO66NDdzmQ4pwa/jyivb+XqJz8hKMCPd78z7/jEZursGWMoqGxm9Z6jrNpzlNzDtXQbx8RwxsC0lChunZPG4owkyzuplXW2F9ex+KlP+eW16dw027orrXUcvwfp7jYcbWztt6nAXVo7urj71Rya2zp55a65GvpuIiKMTQhnbEI437hoDDXN7azbV8G+8kYWpQ8jY4Cv+FXeYVpKFBMSI1ieXWxp8J8Jl05TRGSRiOwTkXwRub+fx4NF5HXn45tEJM25PU1EjonINufXn9xcv6W6uw1dp+gAPNbuCOQ5v17DV/+0kX/sKKOjq9vtdTy9Np8dJfU8tnQGE4e5PrWyOjOxQ4JYMjOFn3xxEjNGxGjoK8BxgvDVWalsL6lnb3mD1eW45LRn/CLiDzwFXAaUANkissIYk9drt7uAWmPMWBFZCvwGuN75WIExJsO9ZVuvvbOba576lP1HGxkeHUJSVCgZqdHcNHskI+LCqGtp52sv55BbVMsNWal8kl/Fd5ZtIT4imAvGDiVrVCxzRseRNnTIOdVRXt/Kc+sLuXLacC6bnOimT6eUOhPXzkjm4X/uYXl2CQ9edfpV7KzmSlNPFpBvjCkEEJHXgMVA7+BfDPy38/abwJPi46dDz39SSF5ZAzdkpdLS3kVJ7TGe/+Qgz60v5NIJCRTVtHC4uoWnbpzJF6cOp6vbsG5fBW9tKWX9gcrjV7E+eeMMrpyWdNZ1PPrRPrq6DT9aONFdH00pdYZihwRx+eRhvL21hPuvmOixM7/2cCX4k4HiXvdLgNkn28cY0yki9UDPEIdRIrIVaAB+aoxZ3/cNRORu4G6AESM8f/xzcU0LT6w+wOWTE/n1kmnHt5fXt7JscxHLNhXR1tHFy3dmHZ+m2N9PmD8pkfmTEjHGcLCqmXuWbeW3H+xj4ZSzWzBkb3kDb+SWcNe8UYyIc/8KWEop1y2Zmcw/dpaxoaCKi8/iAsDBNNC/lsqAEcaYGcC9wDIR+VwjtDHmOWNMpjEmMz7e8y80+p//240g/OzqKSdsHxYVwr2XjWfD/Zfy6U8uPenc9CLC6Phw7ls4gaKaFt7IKTmrOn79/l4iggO459KxZ/V8pZT7zBs7lCFB/qx0rhznyVwJ/lIgtdf9FOe2fvcRkQAgCqg2xrQZY6oBjDG5QAEw/lyLttKHu8tZtaeC7y8YR3J0/yN1ggL8XBrPe/GEeM4bGcMf1xygtaPL5RqMMSzbVMS/9lfyH5eOIzpMLxhSymohgf5cMjGBj/KOnnLQhydwJfizgXEiMkpEgoClwIo++6wAbnPevg5YY4wxIhLv7BxGREYD44BC95Q++LYU1fLTd3YxITGCOy8Ydc6vJyL85+XjKatv5a+bilx6zoGjjdzw58/4r7d3ct7IGG6d6x3Dx5Syg4VThlHV1E7u4VqrSzml0wa/MaYTuAdYCewBlhtjdovIQyJytXO3F4A4EcnH0aTTM+TzQmCHiGzD0en7TWOMd01qgWOa3afW5vOVP20kKMCPx5ZmuO2CnbljhjJvbBzPrMun2Tl//cks21TEFY+vZ09ZI7+8Np3l35hjyXTGSqn+XTIxgSB/P49v7tErd0/jWHsXX3slm0/zq7ly2nB+tWSq2y/L3lJUy5KnNzAyLozLJiWyYHIis9Ji8e81219+RRNffGI9WWmxPL40Qy/SUspD3flSNvvKG/nkx5cM6rUeZ3LlrmePOfIAv/lgL5/mV/Pwkqn88YYZAzIXx8wRMTy+NIORcUN4ZeNhlj73GTc9/xlNzr8AuroN9725nbAgfx69frqGvlIebNGUYZTWHWP3Ec+9mEuD/xTWH6jkpQ2HuGNeGkuzRgzob+/FGcm8cmcWWx68jJ8vnkL2oVpufWETDa0d/OXTg2wtquO/r5pCQkTIgNWglDp38ycl4Cd4dHOPBv9J1Ld0cN8bOxgTP4QfLxq8i6PCgwO4ZU4aT904g52l9Vz/7Gc8snIfCyYlsjjj7C/0UkoNjrjwYLJGxfLBLg1+r/Pgil1UNrXxh+szCAkc/A7URenDefaW8yiobCI4wI9fXZuuc8Mo5SUWTRnGgYomjz3r19k5e2nv7Oafu8p4ZeNhcg/X8v0F45iWEm1ZPZdOTOSdb88DICFSm3iU8hbXzkhheU4J33g1l+/NH8f35o/zqKUZNfiddpXWc8dL2VQ2tjFq6BB+dtVkbjnf+jHyk5N0tk2lvE1UWCBvfXsuD7y9i8dXH2B7SR0/X5xOauyJU6scqTtGWJD/oF+EqcHv9PS6fDq6unnpjllcOC7eo347K6W8T0igP7/7yjRmjIjmf/5vNxc+spb5ExO5afYISmpbeGtrKVuL6ggK8OPq6UncPjeN9OSoQalNgx+oamrjo7yj3DYnzeMnV1JKeQ8R4ebzR3LpxASWbSrib5uLWLXnKAATh0Xw40UTHb8EtpTyZm4JF46P5+U7Zg14f54GP/D33BI6ugxLs1JPv7NSSp2hpOhQfrhwAv8xfywf768iKTqEKUn/Prv/0aKJ/D23hPau7kEZxGH74DfG8Hp2MbPSYhibEGF1OUopHxYc4N/vgklRoYFumf/LVbYfzrnpYA2FVc0sneX56wAopZQ72D74X9tcRERIAF+cOtzqUpRSalDYOvjrWtp5f1c5185IJjRIZ7lUStmDrYP/+fUHae/s5vpZ2qmrlLIP2wb/H1cf4Mm1+VyTkXRC77pSSvk6243qMcbw+w/38+TafJbMSOa31007/ZOUUsqH2C74H1vlONO/ISuVX14zVa/QVUrZjq2C/9P8Kp5Yc4Avz0zhV9dO1dkulVK2ZJs2/uqmNn7w+jZGDx3CL67RKY6VUvZlizN+Yww//vsO6lo6eOmOLB26qZSyNZ8/4+/qNjy9roBVeyq4/4qJOs2xUsr2fPaMv6OrmxXbjvDUunwKK5tZMCmBO+alWV2WUkpZzieDv7WjiyVPbyCvrIGJwyJ48sYZXJE+XNv1lVIKHw3+p9cVkFfWwO+/Mp0lM5M18JVSqhefC/7Cyib+tK6AxRlJfPm8FKvLUUopj+NTnbvGGB58dzfBgX488KVJVpejlFIeyaeCf8X2I3ySX8V9CyeQEBFidTlKKeWRfCb4G1o7+MU/9jAtJYqbZo+0uhyllPJYLgW/iCwSkX0iki8i9/fzeLCIvO58fJOIpPV67CfO7ftEZKEbaz9Ba0cXGanR/OKadPx1/h2llDqp03buiog/8BRwGVACZIvICmNMXq/d7gJqjTFjRWQp8BvgehGZDCwFpgBJwCoRGW+M6XL3B0mICOHPt2a6+2WVUsrnuHLGnwXkG2MKjTHtwGvA4j77LAZedt5+E5gvjjGUi4HXjDFtxpiDQL7z9ZRSSlnEleBPBop73S9xbut3H2NMJ1APxLn4XKWUUoPIIzp3ReRuEckRkZzKykqry1FKKZ/mSvCXAr0XpU1xbut3HxEJAKKAahefizHmOWNMpjEmMz4+3vXqlVJKnTFXgj8bGCcio0QkCEdn7Yo++6wAbnPevg5YY4wxzu1LnaN+RgHjgM3uKV0ppdTZOO2oHmNMp4jcA6wE/IEXjTG7ReQhIMcYswJ4AXhVRPKBGhy/HHDutxzIAzqB7wzEiB6llFKuE8eJuefIzMw0OTk5VpehlFJeRURyjTEujWn3iM5dpZRSg8fjzvhFpBI4fA4vMRSoclM53sSunxv0s+tnt5eTfe6RxhiXRsd4XPCfKxHJcfXPHV9i188N+tn1s9uLOz63NvUopZTNaPArpZTN+GLwP2d1ARax6+cG/ex2ZdfPfs6f2+fa+JVSSp2aL57xK6WUOgUNfqWUshmfCf7TrRLmS0QkVUTWikieiOwWke85t8eKyEcicsD5b4zVtQ4EEfEXka0i8p7z/ijnym/5zpXggqyucSCISLSIvCkie0Vkj4jMsdEx/4HzZ32XiPxNREJ89biLyIsiUiEiu3pt6/c4i8MTzu/BDhGZ6cp7+ETw91ol7ApgMnCDc/UvX9UJ/KcxZjJwPvAd5+e9H1htjBkHrHbe90XfA/b0uv8b4A/GmLFALY4V4XzR48AHxpiJwHQc3wOfP+Yikgx8F8g0xqTjmDOsZ6U/XzzuLwGL+mw72XG+Asfkl+OAu4FnXHkDnwh+XFslzGcYY8qMMVuctxtxBEAyJ66E9jJwjSUFDiARSQG+BDzvvC/ApThWfgPf/dxRwIU4JkTEGNNujKnDBsfcKQAIdU77HgaU4aPH3RjzMY7JLns72XFeDLxiHD4DokVk+Onew1eC37YrfTkXtp8BbAISjTFlzofKgUSr6hpAjwE/Arqd9+OAOufKb+C7x34UUAn8xdnM9byIDMEGx9wYUwr8DijCEfj1QC72OO49Tnaczyr7fCX4bUlEwoG/A983xjT0fsy5HoJPjdUVkSuBCmNMrtW1WCAAmAk8Y4yZATTTp1nHF485gLM9ezGOX35JwBA+3xRiG+44zr4S/C6t9OVLRCQQR+j/1RjzlnPz0Z4/85z/VlhV3wCZB1wtIodwNOddiqPdO9rZBAC+e+xLgBJjzCbn/Tdx/CLw9WMOsAA4aIypNMZ0AG/h+Fmww3HvcbLjfFbZ5yvB78oqYT7D2a79ArDHGPNor4d6r4R2G/DuYNc2kIwxPzHGpBhj0nAc4zXGmJuAtThWfgMf/NwAxphyoFhEJjg3zcexwJFPH3OnIuB8EQlz/uz3fHafP+69nOw4rwBudY7uOR+o79UkdHLGGJ/4Ar4I7AcKgAesrmeAP+sFOP7U2wFsc359EUd792rgALAKiLW61gH8HlwMvOe8PRrHkp75wBtAsNX1DdBnzgBynMf9HSDGLscc+B9gL7ALeBUI9tXjDvwNR19GB46/9O462XEGBMeIxgJgJ46RT6d9D52yQSmlbMZXmnqUUkq5SINfKaVsRoNfKaVsRoNfKaVsRoNfKaVsRoNfKaVsRoNfKaVs5v8BT24M5NwPm1oAAAAASUVORK5CYII=\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "feat=fix.Q31toF32(dsp_feature_q31(fix.toQ31(data)))\n", "plt.plot(feat)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "ccd39f92", "metadata": {}, "source": [ "The Q31 feature is very similar to the F32 one so now we can implement the predict:" ] }, { "cell_type": "code", "execution_count": 40, "id": "0df93150", "metadata": {}, "outputs": [], "source": [ "def dsp_predict_q31(feat):\n", " \n", " res=dsp.arm_dot_prod_q31(coef_q31,feat)\n", " \n", " # Before adding the res and the intercept we need to ensure they are in the same Qx.x format\n", " # The scaling applied to the coefs and to the intercept is different so we need to scale\n", " # the intercept to take this into account\n", " scaled=dsp.arm_shift_q31(np.array([intercept_q31]),intercept_shift-coef_shift)[0]\n", " # Because dot prod output is in Q16.48\n", " # and ret is on 64 bits\n", " scaled = np.int64(scaled) << 17 \n", " \n", " res = res + scaled\n", " \n", " \n", " \n", " if res<0:\n", " return(-1)\n", " else:\n", " return(0)" ] }, { "cell_type": "markdown", "id": "8691cb89", "metadata": {}, "source": [ "Now we can check the Q31 implementation on the test patterns:" ] }, { "cell_type": "code", "execution_count": 41, "id": "7f8787ac", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 41, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "y_pred_ref = [dsp_predict_q31(dsp_feature_q31(fix.toQ31(x.signal))) for x in test_patterns]\n", "labels=[\"Unknown\"] + to_keep\n", "ConfusionMatrixDisplay.from_predictions(y_test, y_pred_ref,display_labels=labels)" ] }, { "cell_type": "code", "execution_count": 42, "id": "500da0b5", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.8225" ] }, "execution_count": 42, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.count_nonzero(np.equal(y_test,y_pred_ref))/len(y_test)" ] }, { "cell_type": "markdown", "id": "e4cb5d66", "metadata": {}, "source": [ "The score is as good as the F32 implementation." ] }, { "cell_type": "markdown", "id": "22e5033e", "metadata": {}, "source": [ "### Q15 Implementation\n", "\n", "It is the same as Q31 but using Q15 functions." ] }, { "cell_type": "code", "execution_count": 43, "id": "cf7674a2", "metadata": {}, "outputs": [], "source": [ "scaled_coef=clfb.best_estimator_.coef_ \n", "coef_shift=0\n", "while np.max(np.abs(scaled_coef)) > 1:\n", " scaled_coef = scaled_coef / 2.0 \n", " coef_shift = coef_shift + 1\n", "\n", "coef_q15=fix.toQ15(scaled_coef)\n", "\n", "scaled_intercept = clfb.best_estimator_.intercept_ \n", "intercept_shift = 0\n", "while np.abs(scaled_intercept) > 1:\n", " scaled_intercept = scaled_intercept / 2.0 \n", " intercept_shift = intercept_shift + 1\n", " \n", "intercept_q15=fix.toQ15(scaled_intercept)" ] }, { "cell_type": "code", "execution_count": 44, "id": "3e2258ca", "metadata": {}, "outputs": [], "source": [ "def dsp_zcr_q15(w):\n", " m = dsp.arm_mean_q15(w)\n", " # Negate can saturate so we use CMSIS-DSP function which is working on array (and we have a scalar)\n", " m = dsp.arm_negate_q15(np.array([m]))[0]\n", " w = dsp.arm_offset_q15(w,m)\n", " \n", " f=w[:-1]\n", " g=w[1:]\n", " k=np.count_nonzero(np.logical_and(np.logical_or(np.logical_and(f>0,g<0), np.logical_and(f<0,g>0)),g>f))\n", " \n", " # k < len(f) so shift should be 0 except when k == len(f)\n", " # When k==len(f) normally quotient is 0x4000 and shift 1 and we convert\n", " # this to 0x7FFF and shift 0\n", " status,quotient,shift_val=dsp.arm_divide_q15(k,len(f))\n", " if shift_val==1:\n", " return(dsp.arm_shift_q15(np.array([quotient]),shift)[0])\n", " else:\n", " return(quotient)" ] }, { "cell_type": "code", "execution_count": 45, "id": "345c8f73", "metadata": {}, "outputs": [], "source": [ "firq15 = dsp.arm_fir_instance_q15()" ] }, { "cell_type": "code", "execution_count": 46, "id": "6a974f45", "metadata": {}, "outputs": [], "source": [ "def dsp_feature_q15(data):\n", " samplerate=16000\n", " input_len = 16000\n", " \n", " waveform = data[:input_len]\n", " \n", " zero_padding = np.zeros(\n", " 16000 - waveform.shape[0],\n", " dtype=np.int16)\n", " \n", " \n", " signal = np.hstack([waveform, zero_padding])\n", " \n", " \n", " winDuration=25e-3\n", " audioOffsetDuration=10e-3\n", " winLength=int(np.floor(samplerate*winDuration))\n", " audioOffset=int(np.floor(samplerate*audioOffsetDuration))\n", " overlap=winLength - audioOffset\n", " \n", " window=fix.toQ15(hann(winLength,sym=False))\n", " reta=[dsp_zcr_q15(dsp.arm_mult_q15(x,window)) for x in sliding_window_view(signal,winLength)[::audioOffset,:]]\n", " \n", " # Reset state and filter\n", " blockSize=98\n", " numTaps=10\n", " stateLength = numTaps + blockSize - 1\n", " dsp.arm_fir_init_q15(firq15,10,fix.toQ15(np.ones(10)/10.0),np.zeros(stateLength,dtype=np.int16))\n", " reta=dsp.arm_fir_q15(firq15,reta)\n", " return(np.array(reta))" ] }, { "cell_type": "code", "execution_count": 47, "id": "18a33368", "metadata": {}, "outputs": [ { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "feat=fix.Q15toF32(dsp_feature_q15(fix.toQ15(data)))\n", "plt.plot(feat)\n", "plt.show()" ] }, { "cell_type": "code", "execution_count": 48, "id": "9ad998ad", "metadata": {}, "outputs": [], "source": [ "def dsp_predict_q15(feat):\n", " \n", " res=dsp.arm_dot_prod_q15(coef_q15,feat)\n", " \n", " scaled=dsp.arm_shift_q15(np.array([intercept_q15]),intercept_shift-coef_shift)[0]\n", " # Because dot prod output is in Q34.30\n", " # and ret is on 64 bits\n", " scaled = np.int64(scaled) << 15 \n", " \n", " res = res + scaled\n", " \n", " \n", " \n", " if res<0:\n", " return(-1)\n", " else:\n", " return(0)" ] }, { "cell_type": "code", "execution_count": 49, "id": "501be275", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "" ] }, "execution_count": 49, "metadata": {}, "output_type": "execute_result" }, { "data": { "image/png": "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\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "y_pred_ref = [dsp_predict_q15(dsp_feature_q15(fix.toQ15(x.signal))) for x in test_patterns]\n", "labels=[\"Unknown\"] + to_keep\n", "ConfusionMatrixDisplay.from_predictions(y_test, y_pred_ref,display_labels=labels)" ] }, { "cell_type": "code", "execution_count": 50, "id": "511f5d36", "metadata": {}, "outputs": [ { "data": { "text/plain": [ "0.8175" ] }, "execution_count": 50, "metadata": {}, "output_type": "execute_result" } ], "source": [ "np.count_nonzero(np.equal(y_test,y_pred_ref))/len(y_test)" ] }, { "cell_type": "markdown", "id": "7c1ce084", "metadata": {}, "source": [ "Q15 version is as good as other versions so we are selecting this implementation to run on the Arduino (once it has been converted to C)." ] }, { "cell_type": "markdown", "id": "5c3fed6a", "metadata": {}, "source": [ "## Synchronous Data Flow\n", "\n", "We are receiving stream of samples but our functions are using buffers.\n", "We have sliding windows which make it more difficult to connect those functions together : we need FIFOs.\n", "\n", "So we are going to use the CMSIS-DSP Synchronous Data Flow framework to describe the compute graph, compute the FIFO lengths and generate a static schedule implementing the streaming computation." ] }, { "cell_type": "code", "execution_count": 51, "id": "e17fecbb", "metadata": {}, "outputs": [], "source": [ "from cmsisdsp.sdf.scheduler import *" ] }, { "cell_type": "markdown", "id": "b273e79c", "metadata": {}, "source": [ "To describe our compute graph, we need to describe the nodes which are used in this graph.\n", "Each node is described by its inputs and outputs. For each IO, we define the data type and the number of samples read or written on the IO.\n", "\n", "We need the following nodes in our system:\n", "* A source to get audio samples from the Arduino PDM driver\n", "* A Sink to generate the messages on the Arduino serial port\n", "* A feature node to compute the feature for a given window (and pre-multipliying with the Hann window)\n", "* A FIR node which is filtering all the features for one second of signal\n", "* A KWS node which is doing the logistic regression\n", "\n", "In addition to that we need sliding windows:\n", "* Like in the Python code above we need a sliding window for audio\n", "* After each recognition attempt on a segment of 1 second, we want to slide the recognition window by 0.5 seconds. It can be implemented with a sliding window on the features before the FIR" ] }, { "cell_type": "code", "execution_count": 52, "id": "6dad5c54", "metadata": {}, "outputs": [], "source": [ "class Source(GenericSource):\n", " def __init__(self,name,inLength):\n", " GenericSource.__init__(self,name)\n", " q15Type=CType(Q15)\n", " self.addOutput(\"o\",q15Type,inLength)\n", "\n", " @property\n", " def typeName(self):\n", " return \"Source\"\n", " \n", "class Sink(GenericSink):\n", " def __init__(self,name,outLength):\n", " GenericSink.__init__(self,name)\n", " q15Type=CType(Q15)\n", " self.addInput(\"i\",q15Type,outLength)\n", "\n", " @property\n", " def typeName(self):\n", " return \"Sink\"\n", " \n", "class Feature(GenericNode):\n", " def __init__(self,name,inLength):\n", " GenericNode.__init__(self,name)\n", "\n", " q15Type=CType(Q15)\n", " self.addInput(\"i\",q15Type,inLength)\n", " self.addOutput(\"o\",q15Type,1)\n", "\n", " @property\n", " def typeName(self):\n", " return \"Feature\"\n", " \n", "class FIR(GenericNode):\n", " def __init__(self,name,inLength,outLength):\n", " GenericNode.__init__(self,name)\n", "\n", " q15Type=CType(Q15)\n", " self.addInput(\"i\",q15Type,inLength)\n", " self.addOutput(\"o\",q15Type,outLength)\n", "\n", " @property\n", " def typeName(self):\n", " return \"FIR\"\n", " \n", "class KWS(GenericNode):\n", " def __init__(self,name,inLength):\n", " GenericNode.__init__(self,name)\n", "\n", " q15Type=CType(Q15)\n", " self.addInput(\"i\",q15Type,inLength)\n", " self.addOutput(\"o\",q15Type,1)\n", "\n", " @property\n", " def typeName(self):\n", " return \"KWS\"" ] }, { "cell_type": "markdown", "id": "a07cf93a", "metadata": {}, "source": [ "We need some parameters. Those parameters need to be coherent with the values defined in the features in the above code.\n", "AUDIO_INTERRUPT_LENGTH is the audio length generated by the source. But it is not the audio length generated by th PDM driver on Arduino. The Arduino implementation of the Source is doing the adaptation as we will see below." ] }, { "cell_type": "code", "execution_count": 53, "id": "c37f2dbe", "metadata": {}, "outputs": [], "source": [ "q15Type=CType(Q15)\n", "FS=16000\n", "winDuration=25e-3\n", "audioOffsetDuration=10e-3\n", "winLength=int(np.floor(FS*winDuration))\n", "audio_input_length=int(np.floor(FS*audioOffsetDuration))\n", "AUDIO_INTERRUPT_LENGTH = audio_input_length" ] }, { "cell_type": "markdown", "id": "aa4ed03b", "metadata": {}, "source": [ "Below function is :\n", "* Defining the compute graph by connecting all the nodes\n", "* Generating a Python implementation of the compute graph and its scheduling\n", "* Generating a C++ implementation of the compute graph and its scheduling\n", "* Generating a graphviz description of the graph\n", "\n", "The feature length is hardcoded. So if the sliding window parameters are changed, you'll need to change the values for the FEATURE_LENGTH and FEATURE_OVERLAP." ] }, { "cell_type": "code", "execution_count": 54, "id": "055749cc", "metadata": {}, "outputs": [], "source": [ "def gen_sched(python_code=True):\n", " src=Source(\"src\",AUDIO_INTERRUPT_LENGTH)\n", " # For Python code, the input is a numpy array which is passed\n", " # as argument of the node\n", " if python_code:\n", " src.addVariableArg(\"input_array\")\n", " sink=Sink(\"sink\",1)\n", "\n", " feature=Feature(\"feature\",winLength)\n", " feature.addVariableArg(\"window\")\n", "\n", " sliding_audio=SlidingBuffer(\"audioWin\",q15Type,winLength,winLength-audio_input_length)\n", "\n", "\n", " FEATURE_LENGTH=98 # for one second\n", " FEATURE_OVERLAP = 49 # We slide feature by 0.5 second\n", " sliding_feature=SlidingBuffer(\"featureWin\",q15Type,FEATURE_LENGTH,FEATURE_OVERLAP)\n", " kws=KWS(\"kws\",FEATURE_LENGTH)\n", " # Parameters of the ML model used by the node.\n", " kws.addVariableArg(\"coef_q15\")\n", " kws.addVariableArg(\"coef_shift\")\n", " kws.addVariableArg(\"intercept_q15\")\n", " kws.addVariableArg(\"intercept_shift\")\n", "\n", " fir=FIR(\"fir\",FEATURE_LENGTH,FEATURE_LENGTH)\n", "\n", "\n", "\n", " # Description of the compute graph\n", " g = Graph()\n", "\n", " g.connect(src.o, sliding_audio.i)\n", " g.connect(sliding_audio.o, feature.i)\n", " g.connect(feature.o, sliding_feature.i)\n", " g.connect(sliding_feature.o, fir.i)\n", " g.connect(fir.o, kws.i)\n", " g.connect(kws.o, sink.i)\n", "\n", " \n", " # For Python we run for only around 13 seconds of input signal.\n", " # Without this, it would run forever.\n", " conf=Configuration()\n", " if python_code:\n", " conf.debugLimit=13\n", " \n", " # We compute the scheduling\n", " sched = g.computeSchedule(conf)\n", "\n", " print(\"Schedule length = %d\" % sched.scheduleLength)\n", " print(\"Memory usage %d bytes\" % sched.memory)\n", "\n", " # We generate the scheduling code for a Python and C++ implementations\n", " if python_code:\n", " conf.pyOptionalArgs=\"input_array,window,coef_q15,coef_shift,intercept_q15,intercept_shift\"\n", " sched.pythoncode(\".\",config=conf)\n", " with open(\"test.dot\",\"w\") as f:\n", " sched.graphviz(f)\n", " else:\n", " conf.cOptionalArgs=\"\"\"const q15_t *window,\n", " const q15_t *coef_q15,\n", " const int coef_shift,\n", " const q15_t intercept_q15,\n", " const int intercept_shift\"\"\"\n", " conf.memoryOptimization=True\n", " # When schedule is long\n", " conf.codeArray=True\n", " sched.ccode(\"kws\",config=conf)\n", " with open(\"kws/test.dot\",\"w\") as f:\n", " sched.graphviz(f)" ] }, { "cell_type": "markdown", "id": "8b80da54", "metadata": {}, "source": [ "Next line is generating `sched.py` which is the Python implementation of the compute graph and its static scheduling. This file is describing the FIFOs connecting the nodes and describing how the nodes are scheduled.\n", "\n", "You still need to provide an implementation of the nodes. It is available in `appnodes.py` and it is nearly a copy/paste of the Q15 implementation above.\n", "\n", "But it is simpler because the sliding window and the static schedule ensure that each node is run only when enough data is available. So a big part of the control logic has been removed from the nodes.\n", "\n", "`sched.py` is long because the static schedule is long and there are lots of function calls.. When we generate the C++ implementation, we are using an option which is using an array to describe the static schedule. It makes the C++ code much shorter. But having the sequence of function calls can be useful for debugging." ] }, { "cell_type": "code", "execution_count": 55, "id": "b87a56ec", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Schedule length = 151\n", "Memory usage 1612 bytes\n" ] } ], "source": [ "gen_sched(True)" ] }, { "cell_type": "markdown", "id": "f283fc12", "metadata": {}, "source": [ "Next line is generating the C++ schedule that we will need for the Arduino implementation : `kws/scheduler.cpp`" ] }, { "cell_type": "code", "execution_count": 56, "id": "4875861f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Schedule length = 151\n", "Memory usage 1612 bytes\n" ] } ], "source": [ "gen_sched(False)" ] }, { "cell_type": "markdown", "id": "d8cc15da", "metadata": {}, "source": [ "Now we'd like to test the Q15 classifier and the static schedule on a real patterns.\n", "We are using the `Yes/No` pattern from our `VHT-SystemModeling` example.\n", "Below code is loading the pattern into a NumPy array." ] }, { "cell_type": "code", "execution_count": 57, "id": "6f50ba6f", "metadata": {}, "outputs": [], "source": [ "from urllib.request import urlopen\n", "import io\n", "import soundfile as sf" ] }, { "cell_type": "code", "execution_count": 58, "id": "47083054", "metadata": {}, "outputs": [], "source": [ "test_pattern_url=\"https://github.com/ARM-software/VHT-SystemModeling/blob/main/EchoCanceller/sounds/yesno.wav?raw=true\"\n", "f = urlopen(test_pattern_url)\n", "filedata = f.read()\n", "data, samplerate = sf.read(io.BytesIO(filedata))\n", "if len(data.shape)>1:\n", " data=data[:,0]" ] }, { "cell_type": "markdown", "id": "c63c7749", "metadata": {}, "source": [ "Let's plot the signal to check we have the right one:" ] }, { "cell_type": "code", "execution_count": 59, "id": "188670c1", "metadata": {}, "outputs": [ { "data": { "image/png": "iVBORw0KGgoAAAANSUhEUgAAAXwAAAD4CAYAAADvsV2wAAAAOXRFWHRTb2Z0d2FyZQBNYXRwbG90bGliIHZlcnNpb24zLjUuMSwgaHR0cHM6Ly9tYXRwbG90bGliLm9yZy/YYfK9AAAACXBIWXMAAAsTAAALEwEAmpwYAAAnKklEQVR4nO3deZgU1bk/8O/LHhBkR2QbUFzQyNYiqGhUVPRGcBeTGLyJYqLemOsvycVw4zVuMWrM/eXRGx1jIpob15gwBhQRcQdkQFABkWFEGWQZBgEBBYZ57x9dQ2q6q9dazpmu7+d5eOiurq7zdk33W6dOnTpHVBVERFT6WpgOgIiIosGET0QUE0z4REQxwYRPRBQTTPhERDHRynQAmXTv3l3LyspMh0FE1KwsXrx4i6r28HrN2oRfVlaGyspK02EQETUrIvJJptfYpENEFBNM+EREMcGET0QUE0z4REQxwYRPRBQTTPhERDHBhE9EFBNM+Aa9uXoL1m/70nQYROTThxt3oHLtVtNh5MSEb8jWXXvxnUcW4rR7XjUdiqcfPfEuBk+bZTqM0Pzs2WV4+PVq02FEYmF1HX76zDJw7ovwjP/vN3Dxg/NRt3OP6VCyYsI35PTfvAoA2Lu/wWwgHhoaFBXLPsO+/aWbIJ6urMEds1biq337TYcSusvKF+CZxTXYumuv6VBK3oyln5kOISsmfEO27d5nOoSMnn/P7i+tX+5a2LJ128wFEgH3Ae2tNXUGI4mHW/+xwnQIWTHhW2BhtV0/xE/rdh94XLX5C4ORhGN/wz/PXC4rX2AwkvBV1+468PhHT7xrMBKyARO+BabPX2s6hIzG3fe66RCIKCCBJHwRGS8iq0SkSkSmZljnUhFZISLLReQvQZRL4RAxHQERhcH38Mgi0hLAAwDOBFADYJGIVKjqCtc6gwHcBOAkVf1cRHr6LZeIcuPBm9yCqOGPAlClqtWquhfAkwAmpqxzNYAHVPVzAFDVzQGUSyGRUs8SJf7xiDIJIuH3AbDO9bzGWeZ2BIAjROQtEVkgIuO9NiQiU0SkUkQqa2trAwiteWD3aCKKQlQXbVsBGAzgGwAuB/CwiHROXUlVy1U1oaqJHj08Z+giogKU+skaFSaIhL8eQD/X877OMrcaABWquk9VPwbwEZIHAKLICdt0KKaCSPiLAAwWkYEi0gbAJAAVKev8HcnaPUSkO5JNPPG4r52IyBK+E76q1gO4HsBsACsBPK2qy0XkVhGZ4Kw2G0CdiKwAMA/AT1XVrruN6AA2A5QOns2Qm+9umQCgqrMAzEpZdrPrsQK40flHKWy7aLug2v5R/4iocLzTltKs2rjDdAih4hkMxRUTPlEJ48GN3JjwiYhiggmfiCgmmPAtoLDsqm2Ji1MrR5w+K+XGhE9UwrZ/ae9EO6XCPb8CAKunkmTCpzR76u2bdpGK8/AbvL8xbGtqd5oOIW9M+Baot2zuWJunXwzCorW8z4DCY+M81Y2Y8C0w90OOFh2l1BvL9ln8Aw1aavMDBe/v76YOJWYPJnyKvVJO+KlDK5TyZ7XFzPc3mg4hIyZ8IqIAfbm33nQIGTHhExEFyOJOOkz4RDb/QP3i0ArRs/nrxIRPVMJSE34pH9xMaU7HVCZ8ih3WeilMvPGKiIzgBCjkFkjCF5HxIrJKRKpEZGqW9S4SERWRRBDlEhUjNQnaWx8LHsdtCp/Ne9h3wheRlgAeAHAOgCEALheRIR7rdQRwA4CFfsskIrKVxS06gdTwRwGoUtVqVd0L4EkAEz3Wuw3ArwF8FUCZRJQPXrQNXXPapUEk/D4A1rme1zjLDhCREQD6qerMbBsSkSkiUikilbW1tQGERkQULZsPAKFftBWRFgDuA/D/cq2rquWqmlDVRI8ePcIOjWKKvXQoSM3p6xREwl8PoJ/reV9nWaOOAI4F8KqIrAUwGkAFL9ySLWzuRudX3c49TZ6X7ic1Z7/Gazz8RQAGi8hAEWkDYBKAisYXVXW7qnZX1TJVLQOwAMAEVa0MoGyiglU3o/HL/UodGZSC9/DrHzd5bnG+95/wVbUewPUAZgNYCeBpVV0uIreKyAS/2ycK2rxV8b0+ZHPts7lat3V3k+c2d31tFcRGVHUWgFkpy27OsO43giiTiIgKwzttKfbsrY8FL06f1RSbT6KY8IlixOZkROFjwiciCpDNB1UmfKI4sTgZNVepF2lt3sVM+BR7NtfIqPnZuP1L0yFkxIRPOe34ap/pEEK1dN020yFQM5ZaYfh8t72/FyZ8A7bt3ms6hILs31/aVeC99Q2mQ4jMvFWbTYdQcio/+dx0CHljwjfgrao60yGQy1OLPjUdQmQ2f8HBauOMCZ9ib+eeetMhEEWCCZ9yKu0GHV60DZuqckgHSzDhkxU+3rLLWFKIstSrplfi0bc+zr1iSKKe43ZN7U4MvGkWEre/HGm5bg0Niq/27TdWvk2Y8A3geOxN3faPFTjt3lfx2PxPzAQQUcav39+Al1duwi3Pr4imQAv8yTm41e0y11Fh0M9n4ahfvGisfJsw4RvAs9umHnkzmRSee3d9jjXD0RDRH+Telz6KpByb7PiS10dswoRPRj2/7LN/PinhJp37X1mNB19bE0FJ2T27uCayst5YXYsK9983Yh9v2YWyqVlnVY0dJnzKaX9DOClxf4Pi3554N5RtFyKKawe21O5XbfoisrKueOSdyMryLn+h0fJtFEjCF5HxIrJKRKpEZKrH6zeKyAoReU9E5orIgCDKba682vD31Nt7UentNVtC2e6XllxI273XjjgoWFtSpnekABK+iLQE8ACAcwAMAXC5iAxJWe1dAAlVPQ7AswDu9ltuqRn6y5dMh5DRbf9YUdLd6j7cGF2tl6Jj8itr6+8liBr+KABVqlqtqnsBPAlgonsFVZ2nqo3zgC1AcqJzcvlqn72392/ZuRdr63bnXrFAqU1FX3xl7gJfnO5AfeXDTaZDiMSelCEzlnwa3RAID71eHVlZhQgi4fcBsM71vMZZlsn3Abzg9YKITBGRShGprK0t3XlHw2oTD0Km/sph9CR9pnJdk+fVW3aFUEp+nnpnXe6VArRvv7kDfNVmM5O4m76j+cL/eTuysp43eLE6m0gv2orIdwAkANzj9bqqlqtqQlUTPXr0iDK0SN370irTIWS0YXt0Nd3bZ66MrCyTKtduTVu2zeIRFYPgNcLqsghHJW2wuFJlUhCTmK8H0M/1vK+zrAkRGQdgGoBTVTXWV1M+CaF5hOx18YPz05alTppRao67Jf2aVJTN2qZHsLS0CT+QGv4iAINFZKCItAEwCUCFewURGQ7gIQATVJXjsxIWWzak7D/e22A6hMiYGg46yoPcpQ+lH2SjtGLDDqPlZ+I74atqPYDrAcwGsBLA06q6XERuFZEJzmr3ADgIwDMislREKjJsLtY2RticksmHGb6oQd80dNX0RYFuz6+w+qd/mulszmANMOx7AjL1ULG11hsngbThq+osVT1CVQ9T1TucZTeraoXzeJyq9lLVYc6/Cdm3GE8vfmC+lpmpXf3JRcFe1LR5VqAg/VfFB57Lo8h967eZmWpv3VZ7p/iLO95pa5Gaz/lDCdvmHdGeRZm8XrPWUK+n59/z7qHCCr55TPgWqbegZ0Gpj+S5LuKDqsmupqaaUO6Z7d0LbXdE3TI/NrjPbceEbxEb7s4znfB3xWT2qfdrtodeRlSjgObrP/76XiTlrLLkzunPDQ4JnQkTvkXeWWu+50q2CTKCOiCZnIwi2wFtxWfR9ayYPn9t6GVkS/gmKhc7IrqT2pb7XIbfNsd0CGmY8C2ycsMO3PDku9gUcTuzW4ssCXFjQHF53ZTTyGSd9OrHKiMrK4p8my3hX/T7t1H7RWneDmPqTuLmgAnfMjOWfoY7DN6B+unWzBcZx/zqlUB6frz4wcaMr5ls1jLVqyUs2cZnWvLpNhx/h7lpB+PilorlpkNoggnfQnNWmBvcKtd145PuesV3Ge9+us33NsJy0e+jGW/lzapwhpx2s60NP44efXut6RCaYMK30Jf79mPGUjPT/eXDby+IbLX4l5aHe7DLdU06yDuATV+Ez6fT1yUPRjegWFyZ/h64MeFb6smIR28sxGn3vurr/dm+/m+FNNlKIU781dxAtmP6d57PPQeLLOgoUOoue2iB6RAOYMIPSf3+Bvxu7mrs3ltcz4SabeHesLOmdifqfMwI5Gc0wtc/yjL0dUBJcsbS9XjcoydMeR7jlH8W0BAXCz9OHyUzSiZGIzXZ4SBM//NqFUZ5XPPIZ6jzd9ZuLToPBI0JPyTPLVmP++Z8hN/OKW7ckrBvTz/jN69h7N3zin7/a9mSdg7ZhlUIapKKG55cil/MSL9g9kKWC8ZuQVxHeX/9tqyv//HNj32XEYQge7WsKdEeMne/uAqbPXo15dv0OuxWO7poMuGHZMuu5JcjddYdGzTWwvzM5Zrp9nm/1tbtxi/+7j3+TL6CaDMNootmrsrfrf9Y4buMIFzzeHDdUXN937/1sNnmjbKpMwOdiGVXnr8hUyOUpmLCD8ndLyZv/nhj9ZaiE1BYF3tOuNN/G/VzS8K7qPz4gk98vf/qxxYHFIk/UbXh729QfFq323OilXysqQ1uKIJcTTpvr6kLrKxiFdqU+Zmru27qiLazmtmw2kz4Idji+kJ9vGUXBt40q6hpDS+PoDZUNnUmtn9Z3MiVNvU+cHt55T+bY8qmzsTv5q42EscnddGM6XLYz2fhlHvm4eIH56Nqs9lhBbp2aGO0/DBsdQ2RMPpXc5sMi3Hy4O55b2dPvbk7zBsx4Yfgp88sS1v2p7cKb69dUL018Plvv/Q4BR36y/TZifLhtyYelfuKvI4y4f43fZWbz5DSQSfocfe9XtT7fvVCMBd4/yuPG41qPg+vQ8KG7bmvfV33lyUFbTP1ZsTzXN+Lvy6pyXs7R/7niwWVG4ZAEr6IjBeRVSJSJSJTPV5vKyJPOa8vFJGyIMq1wdJ127Cguulp6rxV6Rc0b5+5Eg0NWvCgWfl8gQvxWYbtZRvuIJObPS6KBqVs6kzUBzjRdzF30b5Xsz30s5hx972OnXvqAy1nfhHNJg+9lrv3Uj7ymRP55F/P86x4BGFffe79+MH6HXingB5UPTq2TVvW2LRTHWBzWBTE7xdNRFoC+AjAmQBqkJzy8HJVXeFa51oAx6nqD0RkEoALVPWybNtNJBJaWRnd2CbFKps603QIRFRixgzqhiemjC7qvSKyWFUTXq8FMYn5KABVqlrtFPYkgIkA3F0QJgK4xXn8LID7RUQ0hOrTrj31GHv3PJx2ZE8kyro0ec2rNK95Nr3XSxdkDZSIqNH86nAubgeR8PsAcDdW1gA4IdM6qlovItsBdAPQ5LZKEZkCYAoA9O/fv6hgdu2px9Zde/HXJTUFta8REZW6IBJ+YFS1HEA5kGzSKWYbPTu1w9PXjEHPjm3RrnXLtNe9xkPPOL6K57r/XPjVvv2+bl4iIopSEAl/PYB+rud9nWVe69SISCsABwMIrUPuqIFdw9o0EVHo/nJVaiNJMIJI+IsADBaRgUgm9kkAvpWyTgWAyQDmA7gYwCthtN+b8OZ/nIbWLVugV6d2B5ZlupC79q5/Qd3OPRh5e/7jkK+581y0zDYrSYH27W/A4GkveMYGFHYR+uxjeuGhKzyvDWWVTxn3f2s4vnncoQVvW1Ux8KZZacuL+Xzu9xUj37L8lOFVTvWd56JFC4n0s2aKJcyyvCz+5PO8hriuuuMctGqZXyfFzV98hVF3NL1Z0cT3KQi+u2Wqaj2A6wHMBrASwNOqulxEbhWRCc5qjwDoJiJVAG4EkNZ1s7nq26V9k2QPAM9ff3Laek9fMwYA0O2g9C5e2QSZ7AGgtceXfHj/zkVt67eXDfMXTBbFJHsAEI82u+nfG1XUts4fVlwMhVh9xzmBbu+vPxyDFkV8Z6rvPDeQ8kfk8V2q/M9xgZTlZeSALjnXufeSoXknewDo2bFdxtfatsp/O8P6dc573bAE0g9fVWep6hGqepiq3uEsu1lVK5zHX6nqJap6uKqOauzRU6q+3vfgJs/vvWRoUc1Mb089PaiQMjr9qJ7427UnFfXedq3Sr5HY4L5Lhx54/MINY3HqET2K2o7fA9pFI/rmXMfrAFysow7piJEDimvOLOYg4eX60w/PuU73Ais9QcvnoJTNGtfBcUC39nm/7+/XFfc7CxLvtA3J7ecfe+DxxSNz//C9HNr5a0GF08TLN5564PEfrzy+qG2MO7pnYEki1ZJfnOnr/Re6Eu2gHh2K3o7X2UIhzhvaO+vr3QIehuCFG8YW9b5Caqm5DO+Xu4Zt2qAeBxX93nsvGdrkrPuEgd2CCCkyTPgh+c7oAbh14jGY8++nmA4lzeE9D8J9lw7FjWceUfQ2Tjws/zFECtUmgAQ0pHcnAECLIpO2V7NcoXI1x511TC/fZQDA1/skzyhTD1CnH9Uzr/c//v3gLhDuK9F7U+64IFmBS6Q0GeW7j23pSGJVt8xS890xZUW/t/FHHJYL82huyOSqkwdi8ollwQWTokMb/01Ff77qBKzcsCOtyeRHpx+O371SlfP9qc1yxWiZ42Dz7+OKP+C6/fn7J2Ctx0Btpwzujlc+3Jzz/UEmoy9yDD1890XHBVZWlL59wgBcfnz/tLPafNvlG6/hmcaEb6nn/81/DTMsV58yKPCLyW5+m1KA5KiNJx2efhZycPvczSgXDO/ju/xkWa2zvt7pa9lfL6Scoe07py3PpxvclFMGBRJDow5tsqcU0zXdH5x6WNHv9WrCzOcM8rgAKg9BYZOOhcYWMOSqCQ0+e9RmOw2+cEQwyTaTfA4ljc1Bfh1zaPYfuteNgUHK58/Uv2v+Fx3z0e2g7AfUsu7FX1MJwk/PPjLQ7UkeGXTq+KMCLdMPJnwL/f9Jw02HkNXBPmum534988XM48vCrQHmqpCNO7oXrhgzINQYbHHtNw7DpYl+uVcsQJC9jsIQ9Jlprma7Ef0740SPM01T2KRjmeW/PBsd2tr7ZwnixpHDsvSc8Xv2kEuun/sfJhd+I5mtcu3Jn1lU82yucjXpPFdkl+ew2H04jqEAmq9DMzSgtsjh/TN33Qv7/usgrg80F21axuezuh0dUJNcPlo0swzazMItfTYPONGzU+Y7DoPSsV24ZzdfC6AHUBDGDAq//7bpG5xMGTmgc2RlFdvt1xQmfMtYnO8jORidV+SQCvnqaElz2SWJ4rvF5su279J5Q8MfqgIApowtvidOoZjwyZdWIXZ3zIfXdG6NgmrSySasu3cb2fL7jOLgaeps8XsnDfRcHvb1mUbt20Z3Fmf451owJnyL3DrxmNC76uWS7ft73Wm5x0mxX7S/0Lsu/Lrn8iiSn9dsbo3C7Pr77dEZJi+K6AAUZVNWtmtCC39+RmRx5IsJ3yJRXmzK5IrRmbskBln77p6jv3ZYstXwy68YGXh5mbo9jj/2kMDLKkR5EcNa5+uwDGPVhHmzno1SR9G1ARO+RVLH6TDhhAguJgLAo/9a3JDFfh2S5Ud41jHBJ+FMB8mO7YK5yzabbBUIExevf3TG4MjLdMvWHTgumPAtYnOXwXsuDnYMlMN7Fj9ioR9DLRiTPCqZatqmhN0Dy+2qk9OvI9h2EdsEXwlfRLqKyBwRWe38n1ZFFZFhIjJfRJaLyHsicpmfMilcmY45xY4pn4npaxWprjk12DFl3I46pGNo2y5G2MNXAMC3TsjQjh+Raf9ydNqyKC9ihz34YbH81vCnApirqoMBzIX3TFa7AXxXVY8BMB7Af4tIZ5/lUkgynWOE8VuxacygrnkMqlasYmfcCsvQvp1DL+MO13wQJnidLUc5q6qt1yv8JvyJAKY7j6cDOD91BVX9SFVXO48/A7AZQLDVRQpd14An6wCAOy/w7sFiQuccI1v6YdvFu8uOD3b8HC82NE+mjnq6P8KEb8HH9+Q34fdS1Q3O440Ass7oICKjALQBsMZnuSUnijsvi1V+xchQBsXqF/BIjX5cMjL8JGgLU81p7SO+UJx6naghwrlZov6s+cp5FUVEXgbg1X1hmvuJqqqIZDyEikhvAI8DmKyqnrteRKYAmAIA/fubbQOM2hNTRpsOIdbCvuGLoumZlE2Y12lS/fbSYZGVVYicCV9VM04xLyKbRKS3qm5wErrn9Doi0gnATADTVHVBlrLKAZQDQCKR4EV1A7xORfmHoObo0M5Nm9JGZBm0L2hRjDtVDL/n6RUAJjuPJwOYkbqCiLQB8DcAj6nqsz7LIwNsHtCNKJPzh4XfG6m58Zvw7wJwpoisBjDOeQ4RSYjIH5x1LgVwCoArRWSp82+Yz3IpUuFl/DPynAS6uVv+y7Nx0znxGn/+xR+PNTo2lIig+s5zjZVvI18JX1XrVPUMVR2squNUdauzvFJVr3Ie/1lVW6vqMNe/pQHETqGI9gf6yJXHH+jjX8rD+XZo2wqXBDy7lO2OOqQTqgwnXPe1maCmrmzO7BgrlqzhVSELu0nnvKGH4rWPavGnK48PtyDDurRvjStPLItkaGSbJAZ0wYUjzH3mF388FnU79/LCPJjwjSjr1h5r63abDsOT1005YTfhXzyyL844qie6hNDX3yYiglsmHGM6jMg9+8MTjZZ/1CGs2TfiWDoGPGJxTdZULajUkz2RDZjwDbBtUKtcSr2XzpG97BrrJkzZJrih4hxkySxq+WDCp5xMjV0fFdvGugnTlSeWmQ6h5DSngygTPuUU1Rj5pvTq1Hx+sH592/AolqUodfays4ZkHWHGKCZ8IiIfUps8bR0pE2DCJyKKDSZ8IiIfUieLt7mTAxM+EVFMMOETEflgc40+FRM+UYx0aEZ9xpurAd3smdgnFRM+UYyEMXNZ3KXW8BsHA7QR//pERAGyuYWHCZ+IKCaY8ImIfFCNSbdMEekqInNEZLXzf8ZJI0Wkk4jUiMj9fsokIrKJxfk9jd8a/lQAc1V1MIC5zvNMbgPwus/yiIisYnONPpXfhD8RwHTn8XQA53utJCIjAfQC8JLP8oiIrJJ2p63FdX6/Cb+Xqm5wHm9EMqk3ISItAPwGwE9ybUxEpohIpYhU1tbW+gyNiIjcct6FISIvAzjE46Vp7ieqqiLidWi7FsAsVa0RyT6KnKqWAygHgEQiYe9hkogoA5ubeHImfFUdl+k1EdkkIr1VdYOI9Aaw2WO1MQDGisi1AA4C0EZEdqpqtvZ+IiIKmN/7rCsATAZwl/P/jNQVVPXbjY9F5EoACSZ7IioVqTV6iyv4vtvw7wJwpoisBjDOeQ4RSYjIH/wGR0REwfFVw1fVOgBneCyvBHCVx/JHATzqp0wiIpvYXKNPxTttiYh8SGvSsfiqLRM+EZEv9ib4VEz4FHu5ugsTlQomfCIiHyxuwUnDhE9E5ENqvrc5/zPhExH5YPNF2lRM+EREPqSle4vzPxM+EVFMMOETEfnQshn18mLCJyphX+9zsOkQSt4tE45p8ryUx8MnanaO7t3JdAhUQrod1MZ0CHljwqfY6dah+fxAqfmxudMOEz4RUUww4RMRBYg1fCIiMs5XwheRriIyR0RWO/93ybBefxF5SURWisgKESnzUy6RH2Xd25sOgcgIvzX8qQDmqupgAHOd514eA3CPqh4NYBS8574lisTkMWWmQ4jM+GMPMR1CyevUrnWT5xa36PhO+BMBTHceTwdwfuoKIjIEQCtVnQMAqrpTVXf7LJeoaHEaDvnUI3qYDqHkHduM7nXwm/B7qeoG5/FGAL081jkCwDYReU5E3hWRe0SkpdfGRGSKiFSKSGVtba3P0KhY5w871HQIRM2WzYOp5ZzTVkReBuB1XjjN/URVVUS8PmkrAGMBDAfwKYCnAFwJ4JHUFVW1HEA5ACQSCXv3Wolr1bLUr+Xzq0XxlDPhq+q4TK+JyCYR6a2qG0SkN7zb5msALFXVauc9fwcwGh4Jn4ioubO5OuG3KlcBYLLzeDKAGR7rLALQWUQaGxNPB7DCZ7lERFQgvwn/LgBnishqAOOc5xCRhIj8AQBUdT+AnwCYKyLvAxAAD/ssl4iICpSzSScbVa0DcIbH8koAV7mezwFwnJ+yiIiaA4uv2fJOWyKiuGDCJyIK0KAeHUyHkBETvgUmHd/PdAhNxOe2JKLgHdGro+kQMmLCpzQxuhGVKFaY8ImIYoIJn4goJpjwiYhiggmfiCgmmPCJiGKCCZ+IKCaY8ImIYoIJn9KI69arVi3YKZ+oVDDhW+AYi6dIW/DztLHxSso3j+ttOgSiyDDhW+A7J/Q3HUJGLUr8ttshh3YyHUJkJnLqythjwrdAnCbVJnMSZV1Nh0CG+Ur4ItJVROaIyGrn/y4Z1rtbRJaLyEoR+Z0wwxERRc5vDX8qgLmqOhjAXOd5EyJyIoCTkJwA5VgAxwM41We5FCJ1zcqpNs/mQDkN7G7vUL0UPb8JfyKA6c7j6QDO91hHAbQD0AZAWwCtAWzyWS6FqFXL0m7pa9mitD+fW4e2rkntePCOPb/f/F6qusF5vBFAr9QVVHU+gHkANjj/ZqvqSq+NicgUEakUkcra2lqfoVGxrh47yHQIoXLXepkDKU5yzmkrIi8DOMTjpWnuJ6qqIpL28xGRwwEcDaCvs2iOiIxV1TdS11XVcgDlAJBIJPhTNKR9m5amQyCiEORM+Ko6LtNrIrJJRHqr6gYR6Q1gs8dqFwBYoKo7nfe8AGAMgLSET0RE4fHbpFMBYLLzeDKAGR7rfArgVBFpJSKtkbxg69mkQ/bhaRZR6fCb8O8CcKaIrAYwznkOEUmIyB+cdZ4FsAbA+wCWAVimqs/7LJeIiAqUs0knG1WtA5B2772qVgK4ynm8H8A1fsohIiL/4tM/jchDnO4ziM8npUyY8ImIYoIJn7Iq9QpwqX8+tzh9VvLGhE9EFBNM+EREMcGET0QUE0z4FGt9unzNdAiROenw7qZDKHlXjx1oOoSsmPApqzYlPnLm+GO9hokqTRwqOXxH97Z7BrXS/jWTbwe3b206hFC1axWfgeI4H334Olv+e2HCp1hrEaMsyInmwnfakT1Nh5AVE75h3Q9qYzoEIgqI7QdVJnwiophgwjfkO6P7AwAuO76f4Uio1PXr+jV8/2S7e49QNHyNlknFu23isbjmlMPQ18JugY0npX062xdbUH50+uE4yvIeFUF542enmw6BLMGEb4iIoF/X9qbD8NSjY1v89Owj8c3jepsOJTQ3nnWk6RCohMy47iTsqW8wHUZOTPiURkRw3WmHmw6DqNkY2q+z6RDy4qsNX0QuEZHlItIgIoks640XkVUiUiUiU/2USURExfF70fYDABcCeD3TCiLSEsADAM4BMATA5SIyxGe5RERUIL9THK4EcvY9HQWgSlWrnXWfBDARwAo/ZRMRUWGi6JbZB8A61/MaZ1kaEZkiIpUiUllbWxtBaERE8ZGzhi8iLwPwGmFqmqrOCDIYVS0HUA4AiUSC8/MQEQUoZ8JX1XE+y1gPwH13UV9nGRERRSiKJp1FAAaLyEARaQNgEoCKCMolIiIXv90yLxCRGgBjAMwUkdnO8kNFZBYAqGo9gOsBzAawEsDTqrrcX9hERFQoUUunsheRWgCf+NhEdwBbAgonTIwzWIwzeM0lVsaZNEBVe3i9YG3C90tEKlU1481gtmCcwWKcwWsusTLO3DhaJhFRTDDhExHFRCkn/HLTAeSJcQaLcQavucTKOHMo2TZ8IiJqqpRr+ERE5MKET0QUEyWX8E2MvS8i/URknoiscOYHuMFZfouIrBeRpc6/c13vucmJcZWInJ0rfudO5YXO8qecu5aLiXWtiLzvxFPpLOsqInNEZLXzfxdnuYjI75wy3xOREa7tTHbWXy0ik13LRzrbr3Lem3Uo1QwxHunaZ0tFZIeI/NiW/SkifxSRzSLygWtZ6PswUxkFxnmPiHzoxPI3EensLC8TkS9d+/bBYuPJ9pkLiDP0v7WItHWeVzmvlxUR51OuGNeKyFLT+zMrVS2ZfwBaAlgDYBCANgCWARgSQbm9AYxwHncE8BGSY//fAuAnHusPcWJrC2CgE3PLbPEDeBrAJOfxgwB+WGSsawF0T1l2N4CpzuOpAH7tPD4XwAtITnM7GsBCZ3lXANXO/12cx12c195x1hXnvecE8DfdCGCALfsTwCkARgD4IMp9mKmMAuM8C0Ar5/GvXXGWuddL2U5B8WT6zAXGGfrfGsC1AB50Hk8C8FShcaa8/hsAN5ven9n+lVoN/8DY+6q6F0Dj2PuhUtUNqrrEefwFkkNIeA4B7ZgI4ElV3aOqHwOoQjJ2z/idGsDpAJ513j8dwPkBfoSJzjZTtz0RwGOatABAZxHpDeBsAHNUdauqfg5gDoDxzmudVHWBJr+pjwUQ5xkA1qhqtruuI92fqvo6gK0eMYS9DzOVkXecqvqSJoc7AYAFSA5mmFGR8WT6zHnHmUWQf2t3/M8COKOxtl1onM77LgXwRLbgo9if2ZRaws977P2wOKeFwwEsdBZd75yG/dF1Cp4pzkzLuwHY5vqh+vlcCuAlEVksIlOcZb1UdYPzeCOAXkXG2cd5nLrcj0lo+iOybX82imIfZiqjWN9DsubYaKCIvCsir4nIWFf8hcYT1O8w7L/1gfc4r2931i/GWACbVHW1a5lt+7PkEr5RInIQgL8C+LGq7gDwewCHARgGYAOSp3ymnayqI5CccvI6ETnF/aJT67Cir67T1joBwDPOIhv3Z5oo9qHfMkRkGoB6AP/rLNoAoL+qDgdwI4C/iEinqOLx0Cz+1i6Xo2nFxLb9CaD0Er6xsfdFpDWSyf5/VfU5AFDVTaq6X1UbADyM5GlntjgzLa9D8jSuVcrygqnqeuf/zQD+5sS0qfEU0fl/c5FxrkfTJgK/+/8cAEtUdZMTs3X70yWKfZipjIKIyJUAvgng205igdNEUuc8Xoxke/gRRcbj+3cY0d/6wHuc1w921i+I894LATzlit+q/dmo1BK+kbH3nfa7RwCsVNX7XMvd7WwXIDnpO5yYJjm9BAYCGIzkhRzP+J0f5TwAFzvvnwyg4NnGRKSDiHRsfIzkBbwPnHgae4m4t10B4LtOL4HRALY7p5yzAZwlIl2cU+2zAMx2XtshIqOdffLdYuJ0aVJrsm1/pohiH2YqI28iMh7AzwBMUNXdruU9RKSl83gQkvuwush4Mn3mQuKM4m/tjv9iAK80HgALNA7Ah6p6oKnGtv15QOpV3Ob+D8kr2h8heUSdFlGZJyN5+vUegKXOv3MBPA7gfWd5BYDervdMc2JcBVdPlkzxI9n74B0kL1I9A6BtEXEOQrL3wjIAyxu3j2S75VwAqwG8DKCrs1wAPODE8j6AhGtb33NiqQLwr67lCSR/nGsA3A/nbu4iYu2AZG3rYNcyK/YnkgehDQD2Idme+v0o9mGmMgqMswrJ9uDG72ljL5WLnO/EUgBLAJxXbDzZPnMBcYb+twbQznle5bw+qNA4neWPAvhByrrG9me2fxxagYgoJkqtSYeIiDJgwiciigkmfCKimGDCJyKKCSZ8IqKYYMInIooJJnwiopj4PytiTMTJt9YFAAAAAElFTkSuQmCC\n", "text/plain": [ "
" ] }, "metadata": { "needs_background": "light" }, "output_type": "display_data" } ], "source": [ "plt.plot(data)\n", "plt.show()" ] }, { "cell_type": "markdown", "id": "3409e71e", "metadata": {}, "source": [ "Now we can run our static schedule on this file.\n", "The reload function are needed when debugging (or implementing) the `appnodes.py`. Without this, the package would not be reloaded in the notebook.\n", "\n", "This code needs some variables evaluated in the Q15 estimator code above." ] }, { "cell_type": "code", "execution_count": 60, "id": "a3a624a0", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Yes\n", "Unknown\n", "Yes\n", "Yes\n", "Yes\n", "Unknown\n", "Yes\n", "Yes\n", "Unknown\n", "Yes\n", "Unknown\n", "Yes\n", "Unknown\n" ] } ], "source": [ "import sched as s \n", "from importlib import reload\n", "import appnodes \n", "\n", "appnodes= reload(appnodes)\n", "\n", "s = reload(s)\n", "\n", "dataQ15=fix.toQ15(data)\n", "windowQ15=fix.toQ15(hann(winLength,sym=False))\n", "\n", "nb,error = s.scheduler(dataQ15,windowQ15,coef_q15,coef_shift,intercept_q15,intercept_shift)" ] }, { "cell_type": "markdown", "id": "65d58b64", "metadata": {}, "source": [ "The code is working. We are getting more printed `Yes` than `Yes` in the pattern because we are sliding by 0.5 second between each recognition and the same word can be recognized several time.\n", "\n", "Now we are ready to implement the same on an Arduino.\n", "First we need to generate the parameters of the model. If you have saved the model, you can reload it with the code below:" ] }, { "cell_type": "code", "execution_count": 61, "id": "ee7c58d5", "metadata": {}, "outputs": [], "source": [ "with open(\"logistic.pickle\",\"rb\") as f:\n", " clfb=pickle.load(f)" ] }, { "cell_type": "markdown", "id": "e600613d", "metadata": {}, "source": [ "Once the model is loaded, we extract the values and convert them to Q15:" ] }, { "cell_type": "code", "execution_count": 62, "id": "cc3999d3", "metadata": {}, "outputs": [], "source": [ "scaled_coef=clfb.best_estimator_.coef_ \n", "coef_shift=0\n", "while np.max(np.abs(scaled_coef)) > 1:\n", " scaled_coef = scaled_coef / 2.0 \n", " coef_shift = coef_shift + 1\n", "\n", "coef_q15=fix.toQ15(scaled_coef)\n", "\n", "scaled_intercept = clfb.best_estimator_.intercept_ \n", "intercept_shift = 0\n", "while np.abs(scaled_intercept) > 1:\n", " scaled_intercept = scaled_intercept / 2.0 \n", " intercept_shift = intercept_shift + 1\n", " \n", "intercept_q15=fix.toQ15(scaled_intercept)" ] }, { "cell_type": "markdown", "id": "d35d8b49", "metadata": {}, "source": [ "Now we need to generate C arrays for the ML model parameters. Those parameters are generated into `kws/coef.cpp`" ] }, { "cell_type": "code", "execution_count": 63, "id": "65618fee", "metadata": {}, "outputs": [], "source": [ "def carray(a):\n", " s=\"{\"\n", " k=0 \n", " for x in a:\n", " s = s + (\"%d,\" % (x,))\n", " k = k + 1 \n", " if k == 10:\n", " k=0;\n", " s = s + \"\\n\"\n", " s = s + \"}\"\n", " return(s)\n", "\n", "ccode=\"\"\"#include \"arm_math.h\"\n", "#include \"coef.h\"\n", "\n", "\n", "const q15_t fir_coefs[NUMTAPS]=%s;\n", "\n", "\n", "const q15_t coef_q15[%d]=%s;\n", "\n", "const q15_t intercept_q15 = %d;\n", "const int coef_shift=%d;\n", "const int intercept_shift=%d;\n", " \n", "const q15_t window[%d]=%s;\n", "\"\"\"\n", "\n", "def gen_coef_code():\n", " fir_coef = carray(fix.toQ15(np.ones(10)/10.0))\n", " winq15=carray(fix.toQ15(hann(winLength,sym=False)))\n", " res = ccode % (fir_coef,\n", " len(coef_q15[0]),\n", " carray(coef_q15[0]),\n", " intercept_q15,\n", " coef_shift,\n", " intercept_shift,\n", " winLength,\n", " winq15\n", " )\n", " \n", " with open(os.path.join(\"kws\",\"coef.cpp\"),\"w\") as f:\n", " print(res,file=f)\n", " " ] }, { "cell_type": "markdown", "id": "742406d2", "metadata": {}, "source": [ "Generation of the coef code:" ] }, { "cell_type": "code", "execution_count": 64, "id": "2ee643d7", "metadata": {}, "outputs": [], "source": [ "gen_coef_code()" ] }, { "cell_type": "markdown", "id": "fd7763f7", "metadata": {}, "source": [ "The implementation of the nodes is in `kws/AppNodes.h`. It is very similar to the `appnodes.py` but using the CMSIS-DSP C API.\n", "\n", "The C++ template are used only to minimize the overhead at runtime.\n" ] }, { "cell_type": "markdown", "id": "6c92158e", "metadata": {}, "source": [ "## Arduino" ] }, { "cell_type": "markdown", "id": "0e419afd", "metadata": {}, "source": [ "You need to have the arduino command line tools installed. And they need to be in your `PATH` so that the notebook can find the tool.\n", "We are using the Arduino Nano 33 BLE" ] }, { "cell_type": "markdown", "id": "02896ac3", "metadata": {}, "source": [ "### Building and upload" ] }, { "cell_type": "code", "execution_count": 73, "id": "41e89b2f", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Port Protocol Type Board Name FQBN Core \n", "COM3 serial Serial Port Unknown \n", "COM6 serial Serial Port (USB) Arduino Nano 33 BLE arduino:mbed_nano:nano33ble arduino:mbed_nano\n", "\n" ] } ], "source": [ "!arduino-cli board list" ] }, { "cell_type": "code", "execution_count": 74, "id": "b44dbf60", "metadata": {}, "outputs": [ { "name": "stderr", "output_type": "stream", "text": [ "Config file already exists, use --overwrite to discard the existing one.\n" ] } ], "source": [ "!arduino-cli config init" ] }, { "cell_type": "code", "execution_count": 75, "id": "06b3c20e", "metadata": { "scrolled": true }, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Downloading Arduino_CMSIS-DSP@5.7.0...\n", "Arduino_CMSIS-DSP@5.7.0 already downloaded\n", "Installing Arduino_CMSIS-DSP@5.7.0...\n", "Already installed Arduino_CMSIS-DSP@5.7.0\n" ] } ], "source": [ "!arduino-cli lib install Arduino_CMSIS-DSP" ] }, { "cell_type": "markdown", "id": "5f5909ca", "metadata": {}, "source": [ "The first time the below command is executed, it will take a __very__ long time. The full CMSIS-DSP library has to be rebuilt for the Arduino." ] }, { "cell_type": "code", "execution_count": 65, "id": "0ea363fc", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Sketch uses 98272 bytes (9%) of program storage space. Maximum is 983040 bytes.\n", "Global variables use 46760 bytes (17%) of dynamic memory, leaving 215384 bytes for local variables. Maximum is 262144 bytes.\n", "\n" ] } ], "source": [ "!arduino-cli compile -b arduino:mbed_nano:nano33ble kws" ] }, { "cell_type": "code", "execution_count": 66, "id": "bd13af3d", "metadata": {}, "outputs": [ { "name": "stdout", "output_type": "stream", "text": [ "Device : nRF52840-QIAA\n", "Version : Arduino Bootloader (SAM-BA extended) 2.0 [Arduino:IKXYZ]\n", "Address : 0x0\n", "Pages : 256\n", "Page Size : 4096 bytes\n", "Total Size : 1024KB\n", "Planes : 1\n", "Lock Regions : 0\n", "Locked : none\n", "Security : false\n", "Erase flash\n", "\n", "Done in 0.001 seconds\n", "Write 98972 bytes to flash (25 pages)\n", "\n", "[ ] 0% (0/25 pages)\n", "[= ] 4% (1/25 pages)\n", "[== ] 8% (2/25 pages)\n", "[=== ] 12% (3/25 pages)\n", "[==== ] 16% (4/25 pages)\n", "[====== ] 20% (5/25 pages)\n", "[======= ] 24% (6/25 pages)\n", "[======== ] 28% (7/25 pages)\n", "[========= ] 32% (8/25 pages)\n", "[========== ] 36% (9/25 pages)\n", "[============ ] 40% (10/25 pages)\n", "[============= ] 44% (11/25 pages)\n", "[============== ] 48% (12/25 pages)\n", "[=============== ] 52% (13/25 pages)\n", "[================ ] 56% (14/25 pages)\n", "[================== ] 60% (15/25 pages)\n", "[=================== ] 64% (16/25 pages)\n", "[==================== ] 68% (17/25 pages)\n", "[===================== ] 72% (18/25 pages)\n", "[====================== ] 76% (19/25 pages)\n", "[======================== ] 80% (20/25 pages)\n", "[========================= ] 84% (21/25 pages)\n", "[========================== ] 88% (22/25 pages)\n", "[=========================== ] 92% (23/25 pages)\n", "[============================ ] 96% (24/25 pages)\n", "[==============================] 100% (25/25 pages)\n", "Done in 4.110 seconds\n" ] } ], "source": [ "!arduino-cli upload -b arduino:mbed_nano:nano33ble -p COM5 kws" ] }, { "cell_type": "markdown", "id": "20eab198", "metadata": {}, "source": [ "### Testing\n", "\n", "Below code is connecting to the Arduino board an displaying the output in a cell.\n", "If you say `Yes` loudly enough (so not too far from the board) and if you don't have too much background noise in your room, then it should work.\n", "\n", "You need to install the `pyserial` python package" ] }, { "cell_type": "code", "execution_count": 67, "id": "5a36492a", "metadata": {}, "outputs": [], "source": [ "import serial\n", "import ipywidgets as widgets\n", "import time\n", "import threading" ] }, { "cell_type": "code", "execution_count": 68, "id": "7d55a8ed", "metadata": {}, "outputs": [], "source": [ "STOPSERIAL=False \n", "def stop_action(btn):\n", " global STOPSERIAL\n", " STOPSERIAL=True\n", " \n", "out = widgets.Output(layout={'border': '1px solid black','height':'40px'})\n", "button = widgets.Button(\n", " description='Stop',\n", " disabled=False,\n", " button_style='', # 'success', 'info', 'warning', 'danger' or ''\n", " tooltip='Click me'\n", ")\n", "button.on_click(stop_action)" ] }, { "cell_type": "code", "execution_count": 69, "id": "ecabec72", "metadata": {}, "outputs": [ { "data": { "application/vnd.jupyter.widget-view+json": { "model_id": "1d06ab7d3efa41c38f51d9e9b626b40e", "version_major": 2, "version_minor": 0 }, "text/plain": [ "VBox(children=(Output(layout=Layout(border='1px solid black', height='40px')), Button(description='Stop', styl…" ] }, "metadata": {}, "output_type": "display_data" } ], "source": [ "out.clear_output()\n", "display(widgets.VBox([out,button]))\n", "\n", "STOPSERIAL = False\n", "\n", "def get_serial():\n", " try:\n", " with serial.Serial('COM6', 115200, timeout=1) as ser: \n", " ser.reset_input_buffer()\n", " global STOPSERIAL\n", " while not STOPSERIAL:\n", " data=ser.readline()\n", " if (len(data)>0):\n", " with out:\n", " out.clear_output()\n", " res=data.decode('ascii').rstrip()\n", " if res==\"Yes\":\n", " display(HTML(\"

YES

\"))\n", " else:\n", " print(res)\n", " with out:\n", " out.clear_output()\n", " print(\"Communication closed\")\n", " except Exception as inst:\n", " with out:\n", " out.clear_output()\n", " print(inst)\n", " \n", "t = threading.Thread(target=get_serial)\n", "t.start()\n" ] } ], "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 }