Opensource ML embedded evaluation kit

Change-Id: I12e807f19f5cacad7cef82572b6dd48252fd61fd
diff --git a/tests/use_case/kws_asr/Wav2LetterPreprocessingTest.cc b/tests/use_case/kws_asr/Wav2LetterPreprocessingTest.cc
new file mode 100644
index 0000000..e71366a
--- /dev/null
+++ b/tests/use_case/kws_asr/Wav2LetterPreprocessingTest.cc
@@ -0,0 +1,152 @@
+/*
+ * Copyright (c) 2021 Arm Limited. All rights reserved.
+ * SPDX-License-Identifier: Apache-2.0
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *     http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, software
+ * distributed under the License is distributed on an "AS IS" BASIS,
+ * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
+ * See the License for the specific language governing permissions and
+ * limitations under the License.
+ */
+#include "Wav2LetterPreprocess.hpp"
+
+#include <algorithm>
+#include <catch.hpp>
+#include <limits>
+
+constexpr uint32_t numMfccFeatures = 13;
+constexpr uint32_t numMfccVectors  = 10;
+
+/* Test vector output: generated using test-asr-preprocessing.py. */
+int8_t expectedResult[numMfccVectors][numMfccFeatures*3] = {
+    /* Feature vec 0. */
+    -32,   4,  -9,  -8, -10, -10, -11, -11, -11, -11, -12, -11, -11,    /* MFCCs.   */
+    -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,    /* Delta 1. */
+    -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,    /* Delta 2. */
+
+    /* Feature vec 1. */
+    -31,   4,  -9,  -8, -10, -10, -11, -11, -11, -11, -12, -11, -11,
+    -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+    -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
+
+    /* Feature vec 2. */
+    -31,   4,  -9,  -9, -10, -10, -11, -11, -11, -11, -12, -12, -12,
+    -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+    -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
+
+    /* Feature vec 3. */
+    -31,   4,  -9,  -9, -10, -10, -11, -11, -11, -11, -11, -12, -12,
+    -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+    -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
+
+    /* Feature vec 4 : this should have valid delta 1 and delta 2. */
+    -31,   4,  -9,  -9, -10, -10, -11, -11, -11, -11, -11, -12, -12,
+    -38, -29,  -9,   1,  -2,  -7,  -8,  -8, -12, -16, -14,  -5,   5,
+    -68, -50, -13,   5,   0,  -9,  -9,  -8, -13, -20, -19,  -3,  15,
+
+    /* Feature vec 5 : this should have valid delta 1 and delta 2. */
+    -31,   4,  -9,  -8, -10, -10, -11, -11, -11, -11, -11, -12, -12,
+    -62, -45, -11,   5,   0,  -8,  -9,  -8, -12, -19, -17,  -3,  13,
+    -27, -22, -13,  -9, -11, -12, -12, -11, -11, -13, -13, -10,  -6,
+
+    /* Feature vec 6. */
+    -31,   4,  -9,  -8, -10, -10, -11, -11, -11, -11, -12, -11, -11,
+    -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+    -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
+
+    /* Feature vec 7. */
+    -32,   4,  -9,  -8, -10, -10, -11, -11, -11, -12, -12, -11, -11,
+    -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+    -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
+
+    /* Feature vec 8. */
+    -32,   4,  -9,  -8, -10, -10, -11, -11, -11, -12, -12, -11, -11,
+    -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+    -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10,
+
+    /* Feature vec 9. */
+    -31,   4,  -9,  -8, -10, -10, -11, -11, -11, -11, -12, -11, -11,
+    -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11, -11,
+    -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10, -10
+};
+
+void PopulateTestWavVector(std::vector<int16_t>& vec)
+{
+    constexpr int int16max = std::numeric_limits<int16_t>::max();
+    int val = 0;
+    for (size_t i = 0; i < vec.size(); ++i, ++val) {
+
+        /* We want a differential filter response from both - order 1
+         * and 2 => Don't have a linear signal here - we use a signal
+         * using squares for example. Alternate sign flips might work
+         * just as well and will be computationally less work! */
+        int valsq = val * val;
+        if (valsq > int16max) {
+            val = 0;
+            valsq = 0;
+        }
+        vec[i] = valsq;
+    }
+}
+
+TEST_CASE("Preprocessing calculation INT8")
+{
+    /* Initialise the HAL and platform. */
+    hal_platform    platform;
+    data_acq_module data_acq;
+    data_psn_module data_psn;
+    platform_timer  timer;
+    hal_init(&platform, &data_acq, &data_psn, &timer);
+    hal_platform_init(&platform);
+
+    /* Constants. */
+    const uint32_t  windowLen       = 512;
+    const uint32_t  windowStride    = 160;
+    const int       dimArray[]      = {3, 1, numMfccFeatures * 3, numMfccVectors};
+    const float     quantScale      = 0.1410219967365265;
+    const int       quantOffset     = -11;
+
+    /* Test wav memory. */
+    std::vector <int16_t> testWav((windowStride * numMfccVectors) +
+                                  (windowLen - windowStride));
+
+    /* Populate with dummy input. */
+    PopulateTestWavVector(testWav);
+
+    /* Allocate mem for tensor. */
+    std::vector<int8_t> tensorVec(dimArray[1]*dimArray[2]*dimArray[3]);
+
+    /* Initialise dimensions and the test tensor. */
+    TfLiteIntArray* dims= tflite::testing::IntArrayFromInts(dimArray);
+    TfLiteTensor tensor = tflite::testing::CreateQuantizedTensor(
+        tensorVec.data(), dims, quantScale, quantOffset, "preprocessedInput");
+
+    /* Initialise pre-processing module. */
+    arm::app::audio::asr::Preprocess prep{
+        numMfccFeatures, windowLen, windowStride, numMfccVectors};
+
+    /* Invoke pre-processing. */
+    REQUIRE(prep.Invoke(testWav.data(), testWav.size(), &tensor));
+
+    /* Wrap the tensor with a std::vector for ease. */
+    int8_t * tensorData = tflite::GetTensorData<int8_t>(&tensor);
+    std::vector <int8_t> vecResults =
+        std::vector<int8_t>(tensorData, tensorData + tensor.bytes);
+
+    /* Check sizes. */
+    REQUIRE(vecResults.size() == sizeof(expectedResult));
+
+    /* Check that the elements have been calculated correctly. */
+    for (uint32_t j = 0; j < numMfccVectors; ++j) {
+        for (uint32_t i = 0; i < numMfccFeatures * 3; ++i) {
+            size_t tensorIdx = (j * numMfccFeatures * 3) + i;
+            CHECK(vecResults[tensorIdx] == expectedResult[j][i]);
+        }
+    }
+}