Voice Recognition with Machine Learning on Arduino Nano 33 BLE Sense

Exploring Advanced Word Classification Techniques in Embedded Systems

Jason J Pulikkottil
28 min readJan 6, 2024

This is a comprehensive and detailed post on voice recognition with machine learning on the Arduino Nano 33 BLE Sense. The post covers various aspects, including hardware and software requirements, capturing audio samples, training a machine learning model, and deploying it to Arduino.

Hardware and Software Requirements: You’ll need an Arduino Nano 33 BLE Sense, 0.96 Inch I2C/IIC 4-Pin OLED Display Module, Arduino IDE and Python installed on your computer, along with Python modules scikit-learn and micromlgen.

Pin Out Diagram
0.96 Inch I2C/IIC 4-Pin OLED Display Module

To install the software, open your terminal and install the libraries.

pip install -U scikit-learn
pip install -U micromlgen

Capturing Audio Samples: The tutorial instructs on how to capture audio samples of specific words using the Arduino board. It involves using the microphone on the Arduino Nano 33 BLE Sense, which utilizes pulse-density modulation, and recording short words like ‘yes’, ‘no’, ‘play’, ‘stop’. Variations in voice intensity and distance from the microphone are recommended for robust data collection. The collected data is then saved in CSV format.

To flash the code to your board, copy the provided code, open the Arduino IDE, and follow the on-screen instructions.

#include "Mic.h"
#define SAMPLES 64
#define GAIN (1.0f/50)
#define SOUND_THRESHOLD 2000

float features[SAMPLES];
Mic mic;

void setup() {
Serial.begin(115200);
PDM.onReceive(onAudio);
mic.begin();
delay(3000);
}

void loop() {
if (recordAudioSample()) {
for (int i = 0; i < SAMPLES; i++) {
Serial.print(features[i], 6);
Serial.print(i == SAMPLES - 1 ? '\n' : ',');
}

delay(1000);
}

delay(20);
}


void onAudio() {
mic.update();
}

bool recordAudioSample() {
if (mic.hasData() && mic.data() > SOUND_THRESHOLD) {

for (int i = 0; i < SAMPLES; i++) {
while (!mic.hasData())
delay(1);

features[i] = mic.pop() * GAIN;
}

return true;
}

return false;
}
// Mic.h

#include <PDM.h>
#include <arm_math.h>

#define MICROPHONE_BUFFER_SIZE_IN_WORDS (256U)
#define MICROPHONE_BUFFER_SIZE_IN_BYTES (MICROPHONE_BUFFER_SIZE_IN_WORDS * sizeof(int16_t))


class Mic {
public:

Mic() :
_ready(false) {

}

bool begin(uint8_t gain = 20) {
PDM.begin(1, 16000);
PDM.setGain(gain);

return true;
}

bool hasData() {
return _ready;
}

int16_t data() {
return _rms;
}

int16_t pop() {
int16_t rms = data();

reset();

return rms;
}

void update() {
int bytesAvailable = PDM.available();

if(bytesAvailable == MICROPHONE_BUFFER_SIZE_IN_BYTES) {
int16_t _buffer[MICROPHONE_BUFFER_SIZE_IN_WORDS];

_ready = true;
PDM.read(_buffer, bytesAvailable);
arm_rms_q15((q15_t*)_buffer, MICROPHONE_BUFFER_SIZE_IN_WORDS, (q15_t*)&_rms);
}
}

void reset() {
_ready = false;
}


protected:
int16_t _rms;
bool _ready;
};

Training the Machine Learning Model: Now train a classifier model using the collected data. The script uses the scikit-learn library and an SVM (Support Vector Machine) classifier, which showed the best accuracy in this case. The trained model is then exported as a plain C code using the micromlgen library.

ArduinoWordClassification
|-- train_classifier.py
|-- data/
|---- yes.csv
|---- no.csv
|---- play.csv
|---- any other .csv file you recorded
# file: train_classifier.py

import numpy as np
from os.path import basename
from glob import glob
from sklearn.svm import SVC
from micromlgen import port
from sklearn.model_selection import train_test_split

def load_features(folder):
dataset = None
classmap = {}
for class_idx, filename in enumerate(glob('%s/*.csv' % folder)):
class_name = basename(filename)[:-4]
classmap[class_idx] = class_name
samples = np.loadtxt(filename, dtype=float, delimiter=',')
labels = np.ones((len(samples), 1)) * class_idx
samples = np.hstack((samples, labels))
dataset = samples if dataset is None else np.vstack((dataset, samples))
return dataset, classmap

np.random.seed(0)
dataset, classmap = load_features('data')
X, y = dataset[:, :-1], dataset[:, -1]
# this line is for testing your accuracy only: once you're satisfied with the results, set test_size to 1
X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.2)

clf = SVC(kernel='poly', degree=2, gamma=0.1, C=100)
clf.fit(X_train, y_train)

print('Accuracy', clf.score(X_test, y_test))
print('Exported classifier to plain C')
print(port(clf, classmap=classmap))
// File: Classifier.h

#pragma once
namespace Eloquent {
namespace ML {
namespace Port {
class SVM {
public:
/**
* Predict class for features vector
*/
int predict(float *x) {
float kernels[35] = { 0 };
float decisions[6] = { 0 };
int votes[4] = { 0 };
kernels[0] = compute_kernel(x, 33.0 , 41.0 , 47.0 , 54.0 , 59.0 , 61.0 , 56.0 , 51.0 , 50.0 , 51.0 , 44.0 , 32.0 , 23.0 , 15.0 , 12.0 , 8.0 , 5.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 5.0 , 3.0 , 5.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 );
kernels[1] = compute_kernel(x, 40.0 , 50.0 , 51.0 , 60.0 , 56.0 , 57.0 , 58.0 , 53.0 , 50.0 , 45.0 , 42.0 , 34.0 , 23.0 , 16.0 , 10.0 , 7.0 , 3.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 14.0 , 3.0 , 8.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 5.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 5.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 3.0 );
kernels[2] = compute_kernel(x, 56.0 , 68.0 , 78.0 , 91.0 , 84.0 , 84.0 , 84.0 , 74.0 , 69.0 , 64.0 , 57.0 , 44.0 , 33.0 , 18.0 , 12.0 , 8.0 , 5.0 , 9.0 , 15.0 , 12.0 , 12.0 , 9.0 , 12.0 , 7.0 , 3.0 , 10.0 , 12.0 , 6.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 6.0 , 3.0 , 6.0 , 10.0 , 10.0 , 8.0 , 3.0 , 9.0 , 9.0 , 9.0 , 8.0 , 9.0 , 9.0 , 11.0 , 3.0 , 8.0 , 9.0 , 8.0 , 8.0 , 8.0 , 6.0 , 7.0 , 3.0 , 3.0 , 8.0 , 5.0 , 3.0 , 0.0 , 3.0 , 0.0 , 0.0 );

// ...many other kernels computations...

decisions[0] = 0.722587775297
+ kernels[1] * 3.35855e-07
+ kernels[2] * 1.64612e-07
+ kernels[4] * 6.00056e-07
+ kernels[5] * 3.5195e-08
+ kernels[7] * -4.2079e-08
+ kernels[8] * -4.2843e-08
+ kernels[9] * -9.994e-09
+ kernels[10] * -5.11065e-07
+ kernels[11] * -5.979e-09
+ kernels[12] * -4.4672e-08
+ kernels[13] * -1.5606e-08
+ kernels[14] * -1.2941e-08
+ kernels[15] * -2.18903e-07
+ kernels[17] * -2.31635e-07
;
decisions[1] = -1.658344586719
+ kernels[0] * 2.45018e-07
+ kernels[1] * 4.30223e-07
+ kernels[3] * 1.00277e-07
+ kernels[4] * 2.16524e-07
+ kernels[18] * -4.81187e-07
+ kernels[20] * -5.10856e-07
;
decisions[2] = -1.968607562265
+ kernels[0] * 3.001833e-06
+ kernels[3] * 4.5201e-08
+ kernels[4] * 1.54493e-06
+ kernels[5] * 2.81834e-07
+ kernels[25] * -5.93581e-07
+ kernels[26] * -2.89779e-07
+ kernels[27] * -1.73958e-06
+ kernels[28] * -1.09552e-07
+ kernels[30] * -3.09126e-07
+ kernels[31] * -1.294219e-06
+ kernels[32] * -5.37961e-07
;
decisions[3] = -0.720663029823
+ kernels[6] * 1.4362e-08
+ kernels[7] * 6.177e-09
+ kernels[9] * 1.25e-08
+ kernels[10] * 2.05478e-07
+ kernels[12] * 2.501e-08
+ kernels[15] * 4.363e-07
+ kernels[16] * 9.147e-09
+ kernels[18] * -1.82182e-07
+ kernels[20] * -4.93707e-07
+ kernels[21] * -3.3084e-08
;
decisions[4] = -1.605747746589
+ kernels[6] * 6.182e-09
+ kernels[7] * 1.3853e-08
+ kernels[8] * 2.12e-10
+ kernels[9] * 1.1243e-08
+ kernels[10] * 7.80681e-07
+ kernels[15] * 8.347e-07
+ kernels[17] * 1.64985e-07
+ kernels[23] * -4.25014e-07
+ kernels[25] * -1.134803e-06
+ kernels[34] * -2.52038e-07
;
decisions[5] = -0.934328303475
+ kernels[19] * 3.3529e-07
+ kernels[20] * 1.121946e-06
+ kernels[21] * 3.44683e-07
+ kernels[22] * -6.23056e-07
+ kernels[24] * -1.4612e-07
+ kernels[28] * -1.24025e-07
+ kernels[29] * -4.31701e-07
+ kernels[31] * -9.2146e-08
+ kernels[33] * -3.8487e-07
;
votes[decisions[0] > 0 ? 0 : 1] += 1;
votes[decisions[1] > 0 ? 0 : 2] += 1;
votes[decisions[2] > 0 ? 0 : 3] += 1;
votes[decisions[3] > 0 ? 1 : 2] += 1;
votes[decisions[4] > 0 ? 1 : 3] += 1;
votes[decisions[5] > 0 ? 2 : 3] += 1;
int val = votes[0];
int idx = 0;

for (int i = 1; i < 4; i++) {
if (votes[i] > val) {
val = votes[i];
idx = i;
}
}

return idx;
}

/**
* Convert class idx to readable name
*/
const char* predictLabel(float *x) {
switch (predict(x)) {
case 0:
return "no";
case 1:
return "stop";
case 2:
return "play";
case 3:
return "yes";
default:
return "we have a problem";
}
}

protected:

float compute_kernel(float *x, ...) {
va_list w;
va_start(w, 64);
float kernel = 0.0;

for (uint16_t i = 0; i < 64; i++) {
kernel += x[i] * va_arg(w, double);
}

return pow((0.1 * kernel) + 0.0, 2);
}
};
}
}
}

Deploying the Model to Arduino: The final step involves uploading the C code of the trained model to the Arduino Nano 33 BLE Sense. Once uploaded, the Arduino should be able to recognize and classify the words it was trained on in real-time.

#include <stdarg.h>
#include <SPI.h>
#include <Wire.h>
#include <Adafruit_GFX.h>
#include <Adafruit_SSD1306.h>
#include "Mic.h"
#include "Classifier.h"
#define OLED_RESET 4
#define SAMPLES 64
#define GAIN (1.0f/50)
#define SOUND_THRESHOLD 1000

Adafruit_SSD1306 display(OLED_RESET);


float features[SAMPLES];
Mic mic;
Eloquent::ML::Port::SVM clf;


void setup() {
display.begin(SSD1306_SWITCHCAPVCC, 0x3C);
display.clearDisplay();
Serial.begin(115200);
PDM.onReceive(onAudio);
mic.begin();
delay(3000);
}


void loop() {
display.clearDisplay();
display.setTextSize(2);
display.setTextColor(WHITE);
display.setCursor(0,0);
if (recordAudioSample()) {
Serial.println(clf.predictLabel(features));
display.println(clf.predictLabel(features));
display.display();
delay(1000);
}

delay(20);
}


/**
* PDM callback to update mic object
*/
void onAudio() {
mic.update();
}


/**
* Read given number of samples from mic
*/
bool recordAudioSample() {
if (mic.hasData() && mic.data() > SOUND_THRESHOLD) {

for (int i = 0; i < SAMPLES; i++) {
while (!mic.hasData())
delay(1);

features[i] = mic.pop() * GAIN;
}

return true;
}

return false;
}
//Classifier.h
#pragma once
namespace Eloquent {
namespace ML {
namespace Port {
class SVM {
public:
/**
* Predict class for features vector
*/
int predict(float *x) {
float kernels[35] = { 0 };
float decisions[6] = { 0 };
int votes[4] = { 0 };
kernels[0] = compute_kernel(x, 33.0 , 41.0 , 47.0 , 54.0 , 59.0 , 61.0 , 56.0 , 51.0 , 50.0 , 51.0 , 44.0 , 32.0 , 23.0 , 15.0 , 12.0 , 8.0 , 5.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 5.0 , 3.0 , 5.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 );
kernels[1] = compute_kernel(x, 40.0 , 50.0 , 51.0 , 60.0 , 56.0 , 57.0 , 58.0 , 53.0 , 50.0 , 45.0 , 42.0 , 34.0 , 23.0 , 16.0 , 10.0 , 7.0 , 3.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 14.0 , 3.0 , 8.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 5.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 5.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 3.0 );
kernels[2] = compute_kernel(x, 56.0 , 68.0 , 78.0 , 91.0 , 84.0 , 84.0 , 84.0 , 74.0 , 69.0 , 64.0 , 57.0 , 44.0 , 33.0 , 18.0 , 12.0 , 8.0 , 5.0 , 9.0 , 15.0 , 12.0 , 12.0 , 9.0 , 12.0 , 7.0 , 3.0 , 10.0 , 12.0 , 6.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 6.0 , 3.0 , 6.0 , 10.0 , 10.0 , 8.0 , 3.0 , 9.0 , 9.0 , 9.0 , 8.0 , 9.0 , 9.0 , 11.0 , 3.0 , 8.0 , 9.0 , 8.0 , 8.0 , 8.0 , 6.0 , 7.0 , 3.0 , 3.0 , 8.0 , 5.0 , 3.0 , 0.0 , 3.0 , 0.0 , 0.0 );
kernels[3] = compute_kernel(x, 33.0 , 18.0 , 26.0 , 39.0 , 46.0 , 60.0 , 66.0 , 72.0 , 82.0 , 76.0 , 82.0 , 77.0 , 78.0 , 79.0 , 76.0 , 73.0 , 63.0 , 41.0 , 33.0 , 21.0 , 13.0 , 7.0 , 3.0 , 10.0 , 3.0 , 5.0 , 6.0 , 21.0 , 21.0 , 14.0 , 5.0 , 8.0 , 5.0 , 5.0 , 0.0 , 8.0 , 8.0 , 3.0 , 0.0 , 3.0 , 3.0 , 5.0 , 0.0 , 3.0 , 8.0 , 7.0 , 6.0 , 7.0 , 8.0 , 9.0 , 9.0 , 8.0 , 8.0 , 7.0 , 17.0 , 3.0 , 3.0 , 6.0 , 6.0 , 5.0 , 3.0 , 6.0 , 6.0 , 3.0 );
kernels[4] = compute_kernel(x, 54.0 , 57.0 , 62.0 , 58.0 , 61.0 , 61.0 , 59.0 , 58.0 , 57.0 , 51.0 , 34.0 , 25.0 , 18.0 , 10.0 , 6.0 , 6.0 , 10.0 , 7.0 , 5.0 , 10.0 , 5.0 , 7.0 , 8.0 , 6.0 , 5.0 , 5.0 , 5.0 , 7.0 , 3.0 , 5.0 , 0.0 , 0.0 , 0.0 , 3.0 , 3.0 , 6.0 , 0.0 , 7.0 , 0.0 , 5.0 , 6.0 , 0.0 , 0.0 , 6.0 , 7.0 , 5.0 , 3.0 , 5.0 , 6.0 , 0.0 , 0.0 , 0.0 , 12.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 );
kernels[5] = compute_kernel(x, 49.0 , 58.0 , 68.0 , 69.0 , 72.0 , 72.0 , 75.0 , 76.0 , 73.0 , 59.0 , 59.0 , 36.0 , 19.0 , 12.0 , 12.0 , 17.0 , 12.0 , 21.0 , 9.0 , 6.0 , 8.0 , 6.0 , 7.0 , 15.0 , 14.0 , 14.0 , 10.0 , 8.0 , 5.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 7.0 , 10.0 , 7.0 , 6.0 , 8.0 , 12.0 , 13.0 , 15.0 , 11.0 , 16.0 , 15.0 , 13.0 , 7.0 , 6.0 , 12.0 , 5.0 , 8.0 , 8.0 , 12.0 , 8.0 , 0.0 , 3.0 , 7.0 , 10.0 , 9.0 , 8.0 , 5.0 );
kernels[6] = compute_kernel(x, 43.0 , 63.0 , 76.0 , 73.0 , 67.0 , 72.0 , 64.0 , 50.0 , 31.0 , 123.0 , 95.0 , 27.0 , 17.0 , 20.0 , 12.0 , 14.0 , 11.0 , 9.0 , 6.0 , 3.0 , 3.0 , 15.0 , 156.0 , 172.0 , 69.0 , 52.0 , 47.0 , 41.0 , 18.0 , 29.0 , 46.0 , 20.0 , 22.0 , 21.0 , 0.0 , 0.0 , 6.0 , 3.0 , 7.0 , 10.0 , 10.0 , 14.0 , 13.0 , 13.0 , 11.0 , 8.0 , 18.0 , 26.0 , 19.0 , 15.0 , 15.0 , 16.0 , 17.0 , 13.0 , 11.0 , 8.0 , 20.0 , 19.0 , 10.0 , 9.0 , 10.0 , 12.0 , 9.0 , 12.0 );
kernels[7] = compute_kernel(x, 66.0 , 85.0 , 105.0 , 116.0 , 118.0 , 104.0 , 102.0 , 81.0 , 58.0 , 129.0 , 222.0 , 48.0 , 80.0 , 70.0 , 50.0 , 40.0 , 19.0 , 11.0 , 3.0 , 0.0 , 0.0 , 0.0 , 7.0 , 5.0 , 15.0 , 16.0 , 9.0 , 5.0 , 25.0 , 29.0 , 43.0 , 32.0 , 28.0 , 31.0 , 21.0 , 8.0 , 0.0 , 9.0 , 8.0 , 3.0 , 3.0 , 0.0 , 0.0 , 7.0 , 11.0 , 9.0 , 26.0 , 16.0 , 13.0 , 9.0 , 20.0 , 16.0 , 16.0 , 26.0 , 18.0 , 10.0 , 7.0 , 12.0 , 10.0 , 8.0 , 7.0 , 17.0 , 15.0 , 7.0 );
kernels[8] = compute_kernel(x, 64.0 , 77.0 , 90.0 , 92.0 , 93.0 , 93.0 , 83.0 , 58.0 , 112.0 , 80.0 , 34.0 , 13.0 , 16.0 , 10.0 , 5.0 , 3.0 , 7.0 , 0.0 , 0.0 , 0.0 , 8.0 , 10.0 , 50.0 , 101.0 , 44.0 , 41.0 , 16.0 , 23.0 , 19.0 , 6.0 , 13.0 , 19.0 , 25.0 , 15.0 , 8.0 , 0.0 , 0.0 , 0.0 , 0.0 , 5.0 , 10.0 , 19.0 , 8.0 , 8.0 , 10.0 , 7.0 , 8.0 , 9.0 , 14.0 , 7.0 , 9.0 , 8.0 , 10.0 , 8.0 , 7.0 , 6.0 , 6.0 , 3.0 , 7.0 , 6.0 , 3.0 , 3.0 , 3.0 , 3.0 );
kernels[9] = compute_kernel(x, 33.0 , 28.0 , 20.0 , 9.0 , 5.0 , 7.0 , 7.0 , 13.0 , 130.0 , 183.0 , 212.0 , 197.0 , 190.0 , 167.0 , 151.0 , 110.0 , 83.0 , 54.0 , 67.0 , 20.0 , 23.0 , 24.0 , 16.0 , 12.0 , 7.0 , 0.0 , 3.0 , 9.0 , 0.0 , 3.0 , 5.0 , 10.0 , 79.0 , 109.0 , 80.0 , 75.0 , 38.0 , 38.0 , 29.0 , 26.0 , 29.0 , 27.0 , 26.0 , 27.0 , 22.0 , 22.0 , 15.0 , 6.0 , 0.0 , 3.0 , 12.0 , 18.0 , 21.0 , 24.0 , 27.0 , 27.0 , 25.0 , 26.0 , 25.0 , 25.0 , 27.0 , 25.0 , 22.0 , 19.0 );
kernels[10] = compute_kernel(x, 36.0 , 58.0 , 70.0 , 69.0 , 62.0 , 56.0 , 52.0 , 50.0 , 26.0 , 9.0 , 3.0 , 0.0 , 3.0 , 6.0 , 3.0 , 0.0 , 0.0 , 5.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 5.0 , 0.0 , 0.0 , 7.0 , 6.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 3.0 , 0.0 , 3.0 , 5.0 , 7.0 , 5.0 , 0.0 , 0.0 , 7.0 , 9.0 , 6.0 , 5.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 3.0 , 0.0 , 5.0 , 5.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 8.0 , 6.0 );
kernels[11] = compute_kernel(x, 99.0 , 122.0 , 127.0 , 115.0 , 110.0 , 101.0 , 88.0 , 64.0 , 51.0 , 186.0 , 73.0 , 16.0 , 25.0 , 26.0 , 22.0 , 18.0 , 12.0 , 9.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 21.0 , 14.0 , 3.0 , 11.0 , 19.0 , 34.0 , 31.0 , 33.0 , 18.0 , 15.0 , 9.0 , 19.0 , 19.0 , 16.0 , 6.0 , 0.0 , 0.0 , 0.0 , 7.0 , 12.0 , 9.0 , 10.0 , 12.0 , 14.0 , 12.0 , 13.0 , 10.0 , 10.0 , 12.0 , 9.0 , 13.0 , 13.0 , 14.0 , 8.0 , 11.0 , 8.0 , 6.0 , 3.0 , 7.0 , 3.0 , 5.0 );
kernels[12] = compute_kernel(x, 51.0 , 69.0 , 82.0 , 82.0 , 78.0 , 82.0 , 71.0 , 68.0 , 50.0 , 33.0 , 58.0 , 76.0 , 28.0 , 5.0 , 12.0 , 12.0 , 6.0 , 6.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 5.0 , 52.0 , 90.0 , 45.0 , 30.0 , 19.0 , 12.0 , 19.0 , 19.0 , 18.0 , 7.0 , 13.0 , 16.0 , 10.0 , 7.0 , 3.0 , 0.0 , 5.0 , 6.0 , 0.0 , 11.0 , 17.0 , 14.0 , 12.0 , 16.0 , 9.0 , 11.0 , 11.0 , 18.0 , 13.0 , 8.0 , 8.0 , 10.0 , 12.0 , 8.0 , 9.0 , 8.0 , 8.0 , 5.0 , 6.0 );
kernels[13] = compute_kernel(x, 55.0 , 102.0 , 134.0 , 149.0 , 145.0 , 149.0 , 148.0 , 127.0 , 94.0 , 64.0 , 108.0 , 94.0 , 37.0 , 15.0 , 22.0 , 17.0 , 17.0 , 14.0 , 13.0 , 0.0 , 8.0 , 14.0 , 9.0 , 0.0 , 6.0 , 3.0 , 7.0 , 5.0 , 6.0 , 5.0 , 5.0 , 12.0 , 8.0 , 0.0 , 10.0 , 14.0 , 8.0 , 9.0 , 0.0 , 3.0 , 3.0 , 0.0 , 5.0 , 3.0 , 8.0 , 8.0 , 3.0 , 3.0 , 3.0 , 3.0 , 8.0 , 3.0 , 5.0 , 0.0 , 0.0 , 0.0 , 12.0 , 3.0 , 0.0 , 7.0 , 5.0 , 3.0 , 0.0 , 0.0 );
kernels[14] = compute_kernel(x, 75.0 , 89.0 , 116.0 , 125.0 , 124.0 , 102.0 , 109.0 , 99.0 , 80.0 , 57.0 , 136.0 , 108.0 , 55.0 , 10.0 , 20.0 , 20.0 , 16.0 , 10.0 , 8.0 , 14.0 , 6.0 , 0.0 , 3.0 , 3.0 , 6.0 , 19.0 , 8.0 , 11.0 , 3.0 , 46.0 , 33.0 , 29.0 , 26.0 , 22.0 , 12.0 , 14.0 , 21.0 , 16.0 , 18.0 , 16.0 , 13.0 , 3.0 , 0.0 , 8.0 , 6.0 , 14.0 , 10.0 , 21.0 , 21.0 , 17.0 , 16.0 , 16.0 , 19.0 , 17.0 , 16.0 , 20.0 , 14.0 , 10.0 , 14.0 , 13.0 , 12.0 , 12.0 , 10.0 , 6.0 );
kernels[15] = compute_kernel(x, 43.0 , 57.0 , 63.0 , 60.0 , 64.0 , 57.0 , 55.0 , 35.0 , 18.0 , 14.0 , 13.0 , 5.0 , 3.0 , 10.0 , 5.0 , 3.0 , 3.0 , 0.0 , 7.0 , 3.0 , 5.0 , 5.0 , 0.0 , 23.0 , 8.0 , 3.0 , 3.0 , 17.0 , 6.0 , 13.0 , 10.0 , 5.0 , 0.0 , 10.0 , 7.0 , 9.0 , 8.0 , 13.0 , 6.0 , 7.0 , 5.0 , 6.0 , 3.0 , 3.0 , 5.0 , 8.0 , 3.0 , 3.0 , 5.0 , 5.0 , 5.0 , 7.0 , 8.0 , 6.0 , 6.0 , 7.0 , 6.0 , 6.0 , 5.0 , 5.0 , 5.0 , 5.0 , 5.0 , 3.0 );
kernels[16] = compute_kernel(x, 31.0 , 33.0 , 27.0 , 19.0 , 14.0 , 9.0 , 3.0 , 6.0 , 16.0 , 131.0 , 186.0 , 214.0 , 206.0 , 212.0 , 192.0 , 186.0 , 147.0 , 90.0 , 157.0 , 98.0 , 34.0 , 37.0 , 35.0 , 31.0 , 17.0 , 10.0 , 7.0 , 0.0 , 3.0 , 3.0 , 5.0 , 6.0 , 10.0 , 12.0 , 22.0 , 50.0 , 48.0 , 48.0 , 61.0 , 28.0 , 26.0 , 29.0 , 30.0 , 24.0 , 26.0 , 19.0 , 26.0 , 15.0 , 26.0 , 19.0 , 17.0 , 10.0 , 3.0 , 3.0 , 0.0 , 6.0 , 12.0 , 16.0 , 16.0 , 21.0 , 25.0 , 27.0 , 27.0 , 26.0 );
kernels[17] = compute_kernel(x, 50.0 , 70.0 , 80.0 , 83.0 , 79.0 , 73.0 , 80.0 , 74.0 , 54.0 , 34.0 , 16.0 , 7.0 , 3.0 , 3.0 , 3.0 , 3.0 , 6.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 5.0 , 3.0 , 10.0 , 3.0 , 7.0 , 5.0 , 0.0 , 3.0 , 3.0 , 3.0 , 3.0 , 0.0 , 5.0 , 6.0 , 0.0 , 0.0 , 3.0 , 3.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 7.0 , 3.0 , 0.0 , 3.0 , 0.0 );
kernels[18] = compute_kernel(x, 38.0 , 50.0 , 52.0 , 49.0 , 44.0 , 42.0 , 43.0 , 41.0 , 41.0 , 42.0 , 42.0 , 40.0 , 35.0 , 29.0 , 23.0 , 22.0 , 20.0 , 20.0 , 18.0 , 16.0 , 16.0 , 15.0 , 11.0 , 12.0 , 15.0 , 11.0 , 13.0 , 8.0 , 5.0 , 5.0 , 3.0 , 0.0 , 0.0 , 3.0 , 7.0 , 3.0 , 8.0 , 3.0 , 0.0 , 5.0 , 6.0 , 5.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 6.0 , 3.0 , 8.0 , 5.0 , 7.0 , 5.0 , 8.0 , 8.0 , 7.0 , 6.0 , 10.0 , 11.0 , 3.0 , 5.0 );
kernels[19] = compute_kernel(x, 33.0 , 37.0 , 34.0 , 30.0 , 25.0 , 22.0 , 37.0 , 44.0 , 40.0 , 36.0 , 33.0 , 29.0 , 27.0 , 26.0 , 28.0 , 28.0 , 28.0 , 25.0 , 20.0 , 16.0 , 14.0 , 13.0 , 12.0 , 11.0 , 10.0 , 10.0 , 10.0 , 7.0 , 6.0 , 6.0 , 6.0 , 6.0 , 5.0 , 0.0 , 5.0 , 5.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 );
kernels[20] = compute_kernel(x, 43.0 , 52.0 , 49.0 , 45.0 , 44.0 , 43.0 , 43.0 , 41.0 , 43.0 , 42.0 , 36.0 , 34.0 , 28.0 , 27.0 , 21.0 , 18.0 , 19.0 , 17.0 , 16.0 , 15.0 , 13.0 , 14.0 , 14.0 , 12.0 , 13.0 , 14.0 , 10.0 , 8.0 , 7.0 , 5.0 , 3.0 , 5.0 , 8.0 , 0.0 , 0.0 , 5.0 , 8.0 , 7.0 , 3.0 , 0.0 , 3.0 , 5.0 , 3.0 , 7.0 , 6.0 , 8.0 , 0.0 , 6.0 , 3.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 7.0 , 10.0 , 8.0 , 14.0 , 7.0 , 5.0 , 11.0 );
kernels[21] = compute_kernel(x, 33.0 , 28.0 , 26.0 , 21.0 , 22.0 , 31.0 , 38.0 , 35.0 , 33.0 , 32.0 , 30.0 , 28.0 , 25.0 , 28.0 , 29.0 , 30.0 , 27.0 , 25.0 , 20.0 , 16.0 , 16.0 , 15.0 , 15.0 , 13.0 , 11.0 , 10.0 , 9.0 , 8.0 , 5.0 , 6.0 , 5.0 , 0.0 , 9.0 , 12.0 , 9.0 , 12.0 , 12.0 , 9.0 , 8.0 , 13.0 , 12.0 , 10.0 , 13.0 , 7.0 , 10.0 , 16.0 , 10.0 , 16.0 , 6.0 , 0.0 , 0.0 , 8.0 , 0.0 , 6.0 , 10.0 , 8.0 , 11.0 , 10.0 , 5.0 , 8.0 , 9.0 , 8.0 , 6.0 , 6.0 );
kernels[22] = compute_kernel(x, 40.0 , 49.0 , 48.0 , 45.0 , 48.0 , 47.0 , 51.0 , 55.0 , 52.0 , 43.0 , 35.0 , 30.0 , 16.0 , 8.0 , 6.0 , 8.0 , 8.0 , 7.0 , 7.0 , 9.0 , 10.0 , 8.0 , 9.0 , 8.0 , 6.0 , 8.0 , 6.0 , 5.0 , 10.0 , 7.0 , 3.0 , 3.0 , 0.0 , 3.0 , 3.0 , 0.0 , 0.0 , 5.0 , 6.0 , 8.0 , 9.0 , 14.0 , 13.0 , 14.0 , 10.0 , 10.0 , 10.0 , 8.0 , 7.0 , 0.0 , 5.0 , 0.0 , 0.0 , 3.0 , 3.0 , 10.0 , 10.0 , 0.0 , 8.0 , 14.0 , 9.0 , 12.0 , 5.0 , 14.0 );
kernels[23] = compute_kernel(x, 37.0 , 42.0 , 57.0 , 68.0 , 69.0 , 75.0 , 74.0 , 67.0 , 51.0 , 38.0 , 26.0 , 13.0 , 6.0 , 13.0 , 15.0 , 14.0 , 11.0 , 10.0 , 8.0 , 12.0 , 9.0 , 8.0 , 5.0 , 8.0 , 13.0 , 8.0 , 3.0 , 3.0 , 0.0 , 0.0 , 9.0 , 9.0 , 5.0 , 7.0 , 6.0 , 3.0 , 3.0 , 5.0 , 5.0 , 7.0 , 3.0 , 6.0 , 3.0 , 6.0 , 3.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 5.0 , 0.0 , 0.0 , 3.0 , 0.0 );
kernels[24] = compute_kernel(x, 42.0 , 39.0 , 41.0 , 45.0 , 46.0 , 49.0 , 46.0 , 43.0 , 35.0 , 28.0 , 18.0 , 11.0 , 7.0 , 10.0 , 8.0 , 10.0 , 8.0 , 8.0 , 7.0 , 8.0 , 8.0 , 8.0 , 8.0 , 8.0 , 6.0 , 5.0 , 6.0 , 5.0 , 6.0 , 5.0 , 0.0 , 3.0 , 5.0 , 6.0 , 0.0 , 5.0 , 3.0 , 8.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 3.0 );
kernels[25] = compute_kernel(x, 45.0 , 43.0 , 45.0 , 48.0 , 56.0 , 54.0 , 54.0 , 44.0 , 35.0 , 25.0 , 19.0 , 8.0 , 6.0 , 5.0 , 6.0 , 5.0 , 5.0 , 6.0 , 5.0 , 6.0 , 6.0 , 6.0 , 5.0 , 5.0 , 3.0 , 3.0 , 5.0 , 5.0 , 6.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 7.0 , 9.0 , 5.0 , 5.0 , 0.0 , 0.0 , 0.0 , 5.0 , 3.0 , 3.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 5.0 , 6.0 , 5.0 , 0.0 , 0.0 );
kernels[26] = compute_kernel(x, 31.0 , 43.0 , 66.0 , 75.0 , 75.0 , 81.0 , 89.0 , 85.0 , 79.0 , 68.0 , 50.0 , 32.0 , 22.0 , 10.0 , 8.0 , 12.0 , 10.0 , 10.0 , 12.0 , 12.0 , 11.0 , 10.0 , 10.0 , 8.0 , 8.0 , 9.0 , 8.0 , 7.0 , 7.0 , 6.0 , 3.0 , 3.0 , 3.0 , 0.0 , 0.0 , 5.0 , 8.0 , 8.0 , 6.0 , 3.0 , 7.0 , 8.0 , 11.0 , 12.0 , 12.0 , 16.0 , 9.0 , 0.0 , 0.0 , 0.0 , 3.0 , 7.0 , 7.0 , 8.0 , 6.0 , 8.0 , 12.0 , 10.0 , 8.0 , 7.0 , 5.0 , 3.0 , 6.0 , 8.0 );
kernels[27] = compute_kernel(x, 33.0 , 40.0 , 41.0 , 41.0 , 43.0 , 48.0 , 49.0 , 49.0 , 47.0 , 36.0 , 27.0 , 18.0 , 9.0 , 3.0 , 5.0 , 3.0 , 5.0 , 5.0 , 5.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 3.0 , 0.0 , 3.0 , 3.0 , 7.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 );
kernels[28] = compute_kernel(x, 30.0 , 47.0 , 72.0 , 81.0 , 81.0 , 79.0 , 85.0 , 88.0 , 85.0 , 86.0 , 64.0 , 45.0 , 27.0 , 15.0 , 13.0 , 14.0 , 11.0 , 18.0 , 20.0 , 24.0 , 18.0 , 17.0 , 20.0 , 15.0 , 19.0 , 14.0 , 10.0 , 10.0 , 8.0 , 6.0 , 6.0 , 3.0 , 3.0 , 0.0 , 6.0 , 7.0 , 18.0 , 15.0 , 11.0 , 12.0 , 19.0 , 20.0 , 10.0 , 8.0 , 0.0 , 0.0 , 0.0 , 6.0 , 6.0 , 9.0 , 10.0 , 9.0 , 12.0 , 12.0 , 10.0 , 12.0 , 12.0 , 3.0 , 6.0 , 7.0 , 8.0 , 10.0 , 8.0 , 5.0 );
kernels[29] = compute_kernel(x, 33.0 , 31.0 , 31.0 , 33.0 , 36.0 , 36.0 , 36.0 , 32.0 , 25.0 , 19.0 , 12.0 , 5.0 , 5.0 , 10.0 , 6.0 , 6.0 , 8.0 , 6.0 , 7.0 , 6.0 , 6.0 , 6.0 , 11.0 , 6.0 , 6.0 , 6.0 , 5.0 , 3.0 , 3.0 , 0.0 , 0.0 , 6.0 , 3.0 , 5.0 , 3.0 , 10.0 , 5.0 , 6.0 , 9.0 , 3.0 , 7.0 , 6.0 , 6.0 , 8.0 , 7.0 , 0.0 , 6.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 6.0 , 6.0 , 0.0 , 5.0 , 3.0 , 3.0 , 5.0 , 8.0 , 7.0 , 0.0 );
kernels[30] = compute_kernel(x, 31.0 , 48.0 , 65.0 , 60.0 , 68.0 , 81.0 , 88.0 , 91.0 , 93.0 , 79.0 , 56.0 , 32.0 , 22.0 , 12.0 , 16.0 , 13.0 , 12.0 , 13.0 , 13.0 , 13.0 , 14.0 , 11.0 , 11.0 , 14.0 , 12.0 , 10.0 , 8.0 , 8.0 , 7.0 , 5.0 , 3.0 , 0.0 , 3.0 , 5.0 , 5.0 , 7.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 6.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 3.0 , 5.0 , 0.0 , 0.0 , 0.0 );
kernels[31] = compute_kernel(x, 34.0 , 47.0 , 50.0 , 51.0 , 60.0 , 67.0 , 65.0 , 63.0 , 54.0 , 42.0 , 30.0 , 19.0 , 25.0 , 22.0 , 28.0 , 7.0 , 6.0 , 5.0 , 7.0 , 7.0 , 5.0 , 8.0 , 6.0 , 3.0 , 3.0 , 3.0 , 6.0 , 7.0 , 3.0 , 0.0 , 0.0 , 0.0 , 3.0 , 5.0 , 5.0 , 3.0 , 5.0 , 3.0 , 3.0 , 3.0 , 0.0 , 6.0 , 3.0 , 0.0 , 0.0 , 5.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 5.0 );
kernels[32] = compute_kernel(x, 34.0 , 48.0 , 58.0 , 55.0 , 59.0 , 69.0 , 77.0 , 75.0 , 75.0 , 69.0 , 56.0 , 43.0 , 22.0 , 13.0 , 10.0 , 6.0 , 9.0 , 15.0 , 11.0 , 10.0 , 8.0 , 8.0 , 7.0 , 3.0 , 6.0 , 5.0 , 5.0 , 7.0 , 6.0 , 6.0 , 7.0 , 3.0 , 5.0 , 11.0 , 5.0 , 7.0 , 6.0 , 8.0 , 11.0 , 8.0 , 16.0 , 9.0 , 7.0 , 8.0 , 6.0 , 3.0 , 6.0 , 3.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 6.0 , 3.0 , 0.0 , 3.0 , 5.0 , 8.0 , 10.0 , 13.0 , 13.0 );
kernels[33] = compute_kernel(x, 32.0 , 31.0 , 33.0 , 33.0 , 35.0 , 37.0 , 34.0 , 28.0 , 25.0 , 15.0 , 10.0 , 5.0 , 6.0 , 5.0 , 7.0 , 8.0 , 6.0 , 6.0 , 7.0 , 8.0 , 5.0 , 6.0 , 5.0 , 7.0 , 6.0 , 5.0 , 3.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 3.0 , 0.0 , 0.0 , 5.0 , 3.0 , 0.0 , 3.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 , 0.0 );
kernels[34] = compute_kernel(x, 44.0 , 43.0 , 48.0 , 58.0 , 59.0 , 54.0 , 55.0 , 49.0 , 48.0 , 38.0 , 26.0 , 14.0 , 8.0 , 9.0 , 14.0 , 12.0 , 7.0 , 9.0 , 10.0 , 8.0 , 9.0 , 7.0 , 6.0 , 6.0 , 6.0 , 6.0 , 6.0 , 5.0 , 6.0 , 8.0 , 6.0 , 0.0 , 0.0 , 13.0 , 8.0 , 6.0 , 17.0 , 10.0 , 8.0 , 17.0 , 13.0 , 15.0 , 13.0 , 14.0 , 8.0 , 8.0 , 11.0 , 8.0 , 8.0 , 6.0 , 5.0 , 3.0 , 5.0 , 3.0 , 8.0 , 7.0 , 6.0 , 10.0 , 9.0 , 12.0 , 13.0 , 10.0 , 7.0 , 10.0 );
decisions[0] = 0.722587775297
+ kernels[1] * 3.35855e-07
+ kernels[2] * 1.64612e-07
+ kernels[4] * 6.00056e-07
+ kernels[5] * 3.5195e-08
+ kernels[7] * -4.2079e-08
+ kernels[8] * -4.2843e-08
+ kernels[9] * -9.994e-09
+ kernels[10] * -5.11065e-07
+ kernels[11] * -5.979e-09
+ kernels[12] * -4.4672e-08
+ kernels[13] * -1.5606e-08
+ kernels[14] * -1.2941e-08
+ kernels[15] * -2.18903e-07
+ kernels[17] * -2.31635e-07
;
decisions[1] = -1.658344586719
+ kernels[0] * 2.45018e-07
+ kernels[1] * 4.30223e-07
+ kernels[3] * 1.00277e-07
+ kernels[4] * 2.16524e-07
+ kernels[18] * -4.81187e-07
+ kernels[20] * -5.10856e-07
;
decisions[2] = -1.968607562265
+ kernels[0] * 3.001833e-06
+ kernels[3] * 4.5201e-08
+ kernels[4] * 1.54493e-06
+ kernels[5] * 2.81834e-07
+ kernels[25] * -5.93581e-07
+ kernels[26] * -2.89779e-07
+ kernels[27] * -1.73958e-06
+ kernels[28] * -1.09552e-07
+ kernels[30] * -3.09126e-07
+ kernels[31] * -1.294219e-06
+ kernels[32] * -5.37961e-07
;
decisions[3] = -0.720663029823
+ kernels[6] * 1.4362e-08
+ kernels[7] * 6.177e-09
+ kernels[9] * 1.25e-08
+ kernels[10] * 2.05478e-07
+ kernels[12] * 2.501e-08
+ kernels[15] * 4.363e-07
+ kernels[16] * 9.147e-09
+ kernels[18] * -1.82182e-07
+ kernels[20] * -4.93707e-07
+ kernels[21] * -3.3084e-08
;
decisions[4] = -1.605747746589
+ kernels[6] * 6.182e-09
+ kernels[7] * 1.3853e-08
+ kernels[8] * 2.12e-10
+ kernels[9] * 1.1243e-08
+ kernels[10] * 7.80681e-07
+ kernels[15] * 8.347e-07
+ kernels[17] * 1.64985e-07
+ kernels[23] * -4.25014e-07
+ kernels[25] * -1.134803e-06
+ kernels[34] * -2.52038e-07
;
decisions[5] = -0.934328303475
+ kernels[19] * 3.3529e-07
+ kernels[20] * 1.121946e-06
+ kernels[21] * 3.44683e-07
+ kernels[22] * -6.23056e-07
+ kernels[24] * -1.4612e-07
+ kernels[28] * -1.24025e-07
+ kernels[29] * -4.31701e-07
+ kernels[31] * -9.2146e-08
+ kernels[33] * -3.8487e-07
;
votes[decisions[0] > 0 ? 0 : 1] += 1;
votes[decisions[1] > 0 ? 0 : 2] += 1;
votes[decisions[2] > 0 ? 0 : 3] += 1;
votes[decisions[3] > 0 ? 1 : 2] += 1;
votes[decisions[4] > 0 ? 1 : 3] += 1;
votes[decisions[5] > 0 ? 2 : 3] += 1;
int val = votes[0];
int idx = 0;

for (int i = 1; i < 4; i++) {
if (votes[i] > val) {
val = votes[i];
idx = i;
}
}

return idx;
}

/**
* Convert class idx to readable name
*/
const char* predictLabel(float *x) {
switch (predict(x)) {
case 0:
return "no";
case 1:
return "stop";
case 2:
return "play";
case 3:
return "yes";
default:
return "Houston we have a problem";
}
}

protected:
/**
* Compute kernel between feature vector and support vector.
* Kernel type: poly
*/
float compute_kernel(float *x, ...) {
va_list w;
va_start(w, 64);
float kernel = 0.0;

for (uint16_t i = 0; i < 64; i++) {
kernel += x[i] * va_arg(w, double);
}

return pow((0.1 * kernel) + 0.0, 2);
}
};
}
}
}
//Mic.h
#include <PDM.h>
#include <arm_math.h>

#define MICROPHONE_BUFFER_SIZE_IN_WORDS (256U)
#define MICROPHONE_BUFFER_SIZE_IN_BYTES (MICROPHONE_BUFFER_SIZE_IN_WORDS * sizeof(int16_t))


class Mic {
public:

Mic() :
_ready(false) {

}

bool begin(uint8_t gain = 20) {
PDM.begin(1, 16000);
PDM.setGain(gain);

return true;
}

bool hasData() {
return _ready;
}

int16_t data() {
return _rms;
}

int16_t pop() {
int16_t rms = data();

reset();

return rms;
}

void update() {
int bytesAvailable = PDM.available();

if(bytesAvailable == MICROPHONE_BUFFER_SIZE_IN_BYTES) {
int16_t _buffer[MICROPHONE_BUFFER_SIZE_IN_WORDS];

_ready = true;
PDM.read(_buffer, bytesAvailable);
arm_rms_q15((q15_t*)_buffer, MICROPHONE_BUFFER_SIZE_IN_WORDS, (q15_t*)&_rms);
}
}

void reset() {
_ready = false;
}


protected:
int16_t _rms;
bool _ready;
};
Arduino IDE
Output

Your feedback on my post is highly valued, so don’t hesitate to share your thoughts and concerns in the comments.

If you appreciate my work and wish to show support, consider buying me a coffee.

Stay informed about my latest publications by subscribing for email updates.

For more insights, please consider following me.

--

--

Jason J Pulikkottil

Web Developer | Subject-Matter Expert | Digital Creator | Technology enthusiast | https://linktr.ee/pjjason