Any number of Raw Sensor continuous example

I have the raw sensor Arduino example running for different number of sensors from the DOCS here and my Github is here.

I see that the above example is fairly close to the motion standard example, meaning the continuous motion example should be fairly close to a continuous raw sensor example, just wondering if anyone has made a raw sensor continuous example that is easy to switch the number of raw sensors from say 3 to any number between 1 and 10?

I will try to work on a solution, but if anyone has already done it that would be nice.

Here is the continuous motion example:


/* Edge Impulse Arduino examples
 * Copyright (c) 2021 EdgeImpulse Inc.
 *
 * Permission is hereby granted, free of charge, to any person obtaining a copy
 * of this software and associated documentation files (the "Software"), to deal
 * in the Software without restriction, including without limitation the rights
 * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
 * copies of the Software, and to permit persons to whom the Software is
 * furnished to do so, subject to the following conditions:
 *
 * The above copyright notice and this permission notice shall be included in
 * all copies or substantial portions of the Software.
 *
 * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
 * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
 * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
 * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
 * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
 * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
 * SOFTWARE.
 */

/* Includes ---------------------------------------------------------------- */
#include <ei-proximity-v04_inferencing.h>
#include <Arduino_LSM9DS1.h>

/* Constant defines -------------------------------------------------------- */
#define CONVERT_G_TO_MS2    9.80665f
#define MAX_ACCEPTED_RANGE  2.0f        // starting 03/2022, models are generated setting range to +-2, but this example use Arudino library which set range to +-4g. If you are using an older model, ignore this value and use 4.0f instead

/*
 ** NOTE: If you run into TFLite arena allocation issue.
 **
 ** This may be due to may dynamic memory fragmentation.
 ** Try defining "-DEI_CLASSIFIER_ALLOCATION_STATIC" in boards.local.txt (create
 ** if it doesn't exist) and copy this file to
 ** `<ARDUINO_CORE_INSTALL_PATH>/arduino/hardware/<mbed_core>/<core_version>/`.
 **
 ** See
 ** (https://support.arduino.cc/hc/en-us/articles/360012076960-Where-are-the-installed-cores-located-)
 ** to find where Arduino installs cores on your machine.
 **
 ** If the problem persists then there's not enough memory for this model and application.
 */

/* Private variables ------------------------------------------------------- */
static bool debug_nn = false; // Set this to true to see e.g. features generated from the raw signal
static uint32_t run_inference_every_ms = 200;
static rtos::Thread inference_thread(osPriorityLow);
static float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 };
static float inference_buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE];

/* Forward declaration */
void run_inference_background();

/**
* @brief      Arduino setup function
*/
void setup()
{
    // put your setup code here, to run once:
    Serial.begin(115200);
    Serial.println("Edge Impulse Inferencing Demo");

    if (!IMU.begin()) {
        ei_printf("Failed to initialize IMU!\r\n");
    }
    else {
        ei_printf("IMU initialized\r\n");
    }

    if (EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME != 3) {
        ei_printf("ERR: EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME should be equal to 3 (the 3 sensor axes)\n");
        return;
    }

    inference_thread.start(mbed::callback(&run_inference_background));
}

/**
 * @brief Return the sign of the number
 * 
 * @param number 
 * @return int 1 if positive (or 0) -1 if negative
 */
float ei_get_sign(float number) {
    return (number >= 0.0) ? 1.0 : -1.0;
}

/**
 * @brief      Run inferencing in the background.
 */
void run_inference_background()
{
    // wait until we have a full buffer
    delay((EI_CLASSIFIER_INTERVAL_MS * EI_CLASSIFIER_RAW_SAMPLE_COUNT) + 100);

    // This is a structure that smoothens the output result
    // With the default settings 70% of readings should be the same before classifying.
    ei_classifier_smooth_t smooth;
    ei_classifier_smooth_init(&smooth, 10 /* no. of readings */, 7 /* min. readings the same */, 0.8 /* min. confidence */, 0.3 /* max anomaly */);

    while (1) {
        // copy the buffer
        memcpy(inference_buffer, buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE * sizeof(float));

        // Turn the raw buffer in a signal which we can the classify
        signal_t signal;
        int err = numpy::signal_from_buffer(inference_buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal);
        if (err != 0) {
            ei_printf("Failed to create signal from buffer (%d)\n", err);
            return;
        }

        // Run the classifier
        ei_impulse_result_t result = { 0 };

        err = run_classifier(&signal, &result, debug_nn);
        if (err != EI_IMPULSE_OK) {
            ei_printf("ERR: Failed to run classifier (%d)\n", err);
            return;
        }

        // print the predictions
        ei_printf("Predictions ");
        ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
            result.timing.dsp, result.timing.classification, result.timing.anomaly);
        ei_printf(": ");

        // ei_classifier_smooth_update yields the predicted label
        const char *prediction = ei_classifier_smooth_update(&smooth, &result);
        ei_printf("%s ", prediction);
        // print the cumulative results
        ei_printf(" [ ");
        for (size_t ix = 0; ix < smooth.count_size; ix++) {
            ei_printf("%u", smooth.count[ix]);
            if (ix != smooth.count_size + 1) {
                ei_printf(", ");
            }
            else {
              ei_printf(" ");
            }
        }
        ei_printf("]\n");

        delay(run_inference_every_ms);
    }

    ei_classifier_smooth_free(&smooth);
}

/**
* @brief      Get data and run inferencing
*
* @param[in]  debug  Get debug info if true
*/
void loop()
{
    while (1) {
        // Determine the next tick (and then sleep later)
        uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000);

        // roll the buffer -3 points so we can overwrite the last one
        numpy::roll(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, -3);

        // read to the end of the buffer
        IMU.readAcceleration(
            buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - 3],
            buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - 2],
            buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - 1]
        );

        for (int i = 0; i < 3; i++) {
            if (fabs(buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - 3 + i]) > MAX_ACCEPTED_RANGE) {
                buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - 3 + i] = ei_get_sign(buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - 3 + i]) * MAX_ACCEPTED_RANGE;
            }
        }

        buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - 3] *= CONVERT_G_TO_MS2;
        buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - 2] *= CONVERT_G_TO_MS2;
        buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - 1] *= CONVERT_G_TO_MS2;

        // and wait for next tick
        uint64_t time_to_wait = next_tick - micros();
        delay((int)floor((float)time_to_wait / 1000.0f));
        delayMicroseconds(time_to_wait % 1000);
    }
}

#if !defined(EI_CLASSIFIER_SENSOR) || EI_CLASSIFIER_SENSOR != EI_CLASSIFIER_SENSOR_ACCELEROMETER
#error "Invalid model for current sensor"
#endif

.
.

.

and here is the DOCS arduino classify example linked to above


// Include the Arduino library here (something like your_project_inference.h) 
// In the Arduino IDE see **File > Examples > Your project name - Edge Impulse > Static buffer** to get the exact name
#include <your_project_inference.h>
#include <Arduino_LSM9DS1.h>

#define CONVERT_G_TO_MS2    9.80665f
#define FREQUENCY_HZ        EI_CLASSIFIER_FREQUENCY
#define INTERVAL_MS         (1000 / (FREQUENCY_HZ + 1))

static unsigned long last_interval_ms = 0;
// to classify 1 frame of data you need EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE values
float features[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE];
// keep track of where we are in the feature array
size_t feature_ix = 0;

void setup() {
    Serial.begin(115200);
    Serial.println("Started");

    if (!IMU.begin()) {
        Serial.println("Failed to initialize IMU!");
        while (1);
    }
}

void loop() {
    float x, y, z;

    if (millis() > last_interval_ms + INTERVAL_MS) {
        last_interval_ms = millis();

        // read sensor data in exactly the same way as in the Data Forwarder example
        IMU.readAcceleration(x, y, z);

        // fill the features buffer
        features[feature_ix++] = x * CONVERT_G_TO_MS2;
        features[feature_ix++] = y * CONVERT_G_TO_MS2;
        features[feature_ix++] = z * CONVERT_G_TO_MS2;

        // features buffer full? then classify!
        if (feature_ix == EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE) {
            ei_impulse_result_t result;

            // create signal from features frame
            signal_t signal;
            numpy::signal_from_buffer(features, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal);

            // run classifier
            EI_IMPULSE_ERROR res = run_classifier(&signal, &result, false);
            ei_printf("run_classifier returned: %d\n", res);
            if (res != 0) return;

            // print predictions
            ei_printf("Predictions (DSP: %d ms., Classification: %d ms., Anomaly: %d ms.): \n",
                result.timing.dsp, result.timing.classification, result.timing.anomaly);

            // print the predictions
            for (size_t ix = 0; ix < EI_CLASSIFIER_LABEL_COUNT; ix++) {
                ei_printf("%s:\t%.5f\n", result.classification[ix].label, result.classification[ix].value);
            }
        #if EI_CLASSIFIER_HAS_ANOMALY == 1
            ei_printf("anomaly:\t%.3f\n", result.anomaly);
        #endif

            // reset features frame
            feature_ix = 0;
        }
    }
}

void ei_printf(const char *format, ...) {
    static char print_buf[1024] = { 0 };

    va_list args;
    va_start(args, format);
    int r = vsnprintf(print_buf, sizeof(print_buf), format, args);
    va_end(args);

    if (r > 0) {
        Serial.write(print_buf);
    }
}

@shawn_edgeimpulse

This might be easier than I originally thought, except does anyone know what these lines in the continuous motion analysis does (see code 2 above) and if it is needed for a generic 1-10 raw data continuous analysis. It looks like it formats the acceleration data to always be between -2.00 and 2.00?

I think I can just ditch it, any suggestions why to keep it?


#define MAX_ACCEPTED_RANGE  2.0f        // starting 03/2022, models are generated setting range to +-2, but this example use Arudino library which set range to +-4g. If you are using an older model, ignore this value and use 4.0f instead




float ei_get_sign(float number) {
    return (number >= 0.0) ? 1.0 : -1.0;
}

// Then in the main loop


        for (int i = 0; i < 3; i++) {
            if (fabs(buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - 3 + i]) > MAX_ACCEPTED_RANGE) {
                buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - 3 + i] = ei_get_sign(buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - 3 + i]) * MAX_ACCEPTED_RANGE;
            }
        }

Hi @Rocksetta,

The best example I can think of for seeing out run_classifier_continuous() works for generic sensor data is linked from this API page: https://docs.edgeimpulse.com/reference/c++-inference-sdk-library/functions/run_classifier_continuous

Thanks @shawn_edgeimpulse I am starting to understand. The sound example is going to be too hard to convert to a generic multi-raw sample continuous example. The motion continuous example above is easier and I almost have it working but it does not have the moving average filter (MAF) which seems like an important feature.

My working draft for a single raw sample “proximity on the Nano33BleSense” is here

The above code compiles but the Nano33 loses it’s Serial port, which kind of means it crashed.

Time to ask the big guns, any chance @janjongboom or one of the other Code Gods can have a quick look.

The plan is to convert the motion continuous example but with moving average filter MAF for any number of raw samples I am starting with 1 raw sense: “proximity” but will move to code including many others sensors as soon as it is working.

Oops, my attempt works, totally my mistake. I never started the Gesture library

if (!APDS.begin()){}

So now I just need to include some kind of MAF (moving average filter). The concept is fairly easy. One buffer feeds to the classifier. The other buffer takes chunks of the raw sensor data. Then those chunks are copied into the first buffer.

Just more confusing with sound analysis. Should be easier using raw sensor data like proximity. Should be fairly easy to do. Jump in anyone who knows what they are doing.

another oops. I am confusing MAF with double buffering.

I need to first get double buffering working.

This is kind of what I want

Having nothing really to work with, I made a test program. It doesn’t actually seem that hard to do the issue is to keep track of the insertion point.

Using this code I can add 1,2,3 to a bigger buffer and can do it moving the numbers up or down the sequence.

#define EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE 12
#define EI_SLICE EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE/4
static float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE/4] = { 1, 2, 3 };
static float inference_buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = {12,11,10,9,8,7,6,5,4,3,2,1};
                                                                   
int myPosition = 0;


void setup() {
    Serial.begin(115200);
    delay(5000);
    for (int i=0; i < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; i++) {
      Serial.print(inference_buffer[i]);
      Serial.print(", ");
    }
    Serial.println();
    for (int j=0; j < EI_SLICE; j++) {
      Serial.print(buffer[j]);
      Serial.print(", ");
    }
    Serial.println();




  for (int x=0;  x <= EI_SLICE; x++){

    memcpy(inference_buffer+myPosition, buffer, sizeof(buffer) );
    
    for (int m=0; m < EI_SLICE; m++) {
      Serial.print(buffer[m]);
      Serial.print(", ");
    }
    Serial.println();
      
    for (int k=0; k < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; k++) {
      Serial.print(inference_buffer[k]);
      Serial.print(", ");
    }

    Serial.println();
    myPosition += EI_SLICE;
  }

  Serial.println("-------------------------");
  inference_buffer[0] = 5;
  inference_buffer[1] = 5;
  inference_buffer[2] = 5;
  inference_buffer[3] = 5;
  inference_buffer[4] = 5;
  inference_buffer[5] = 5;
  inference_buffer[6] = 5;
  inference_buffer[7] = 5;
  inference_buffer[8] = 5;
  inference_buffer[9] = 5;
  inference_buffer[10] = 5;
  inference_buffer[11] = 5;
  
  for (int z=0; z < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; z++) {
     Serial.print(inference_buffer[z]);
     Serial.print(", ");
  }
  Serial.println();
  myPosition -= EI_SLICE;
  
  
  
  for (int y=EI_SLICE;  y >= 0; y--){

    memcpy(inference_buffer+myPosition, buffer, sizeof(buffer) );
    
    for (int p=0; p < EI_SLICE; p++) {
      Serial.print(buffer[p]);
      Serial.print(", ");
    }
    Serial.println();
      
    for (int q=0; q < EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE; q++) {
      Serial.print(inference_buffer[q]);
      Serial.print(", ");
    }

    Serial.println();
    myPosition -= EI_SLICE;
  }




    
}

void loop() {


}

.
.

and my output proves it works
.
.

12.00, 11.00, 10.00, 9.00, 8.00, 7.00, 6.00, 5.00, 4.00, 3.00, 2.00, 1.00, 
1.00, 2.00, 3.00, 
1.00, 2.00, 3.00, 
1.00, 2.00, 3.00, 9.00, 8.00, 7.00, 6.00, 5.00, 4.00, 3.00, 2.00, 1.00, 
1.00, 2.00, 3.00, 
1.00, 2.00, 3.00, 1.00, 2.00, 3.00, 6.00, 5.00, 4.00, 3.00, 2.00, 1.00, 
1.00, 2.00, 3.00, 
1.00, 2.00, 3.00, 1.00, 2.00, 3.00, 1.00, 2.00, 3.00, 3.00, 2.00, 1.00, 
1.00, 2.00, 3.00, 
1.00, 2.00, 3.00, 1.00, 2.00, 3.00, 1.00, 2.00, 3.00, 1.00, 2.00, 3.00, 
-------------------------
5.00, 5.00, 5.00, 5.00, 5.00, 5.00, 5.00, 5.00, 5.00, 5.00, 5.00, 5.00, 
1.00, 2.00, 3.00, 
5.00, 5.00, 5.00, 5.00, 5.00, 5.00, 5.00, 5.00, 5.00, 1.00, 2.00, 3.00, 
1.00, 2.00, 3.00, 
5.00, 5.00, 5.00, 5.00, 5.00, 5.00, 1.00, 2.00, 3.00, 1.00, 2.00, 3.00, 
1.00, 2.00, 3.00, 
5.00, 5.00, 5.00, 1.00, 2.00, 3.00, 1.00, 2.00, 3.00, 1.00, 2.00, 3.00, 
1.00, 2.00, 3.00, 
1.00, 2.00, 3.00, 1.00, 2.00, 3.00, 1.00, 2.00, 3.00, 1.00, 2.00, 3.00, 


So I just have to somehow insert this into my continuous sensor code, the only problem is, what if my main buffer length is not divisible evenly by the smaller buffer? Any suggestions?

When I use the data forwarder it does tell me my length of the data input. I can probably adjust my sample size until the maximum data input is an even number, but since I can’t force that I need some backup. The issue is going to be EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE What if it can’t be evenly divided by the smaller buffer size?

Should I just add zeros to the end if needed, or is it better not to touch whatever the original data was? any suggestions?

.

.

.

A few minutes later…

Making the large buffer slightly bigger is easy.

Just ignoring the last few items of a non-divisible buffer is probably the safest. I tried adding data beyond the buffer size using memcpy and it crashes the code. The extra code needed to wrap the smaller buffer around the bigger buffer is not worth it for my simple example.

If anyone is interested in the code. All this rough coding is in my maker100 ml-kit-nano-33-ble-sense-examples folder here

Well here is the code for a double-buffer using the Nano33BleSense proximity regression model of punching speeds (no units) . Not sure if it is accurate but it does seem to work. I even managed to hack together something to deal with the end of the main buffer not being completely divisible by the slices.

I also just moved the double buffer data manually instead of using the very cool numpy::roll that the accelerometer continuous code uses.

numpy::roll(buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, -3);

The following code could probably be made more efficient, but at least it seems to work. I just now have to figure out how to easily add more sensors.


/* Includes ---------------------------------------------------------------- */
//This is your RAW regression model made using EdgeImpulse.com
#include <ei-proximity-v04_inferencing.h>
//#include <Arduino_LSM9DS1.h>
#include <Arduino_APDS9960.h>
/* Constant defines -------------------------------------------------------- */
//#define CONVERT_G_TO_MS2    9.80665f
//#define MAX_ACCEPTED_RANGE  2.0f        // starting 03/2022, models are generated setting range to +-2, but this example use Arudino library which set range to +-4g. If you are using an older model, ignore this value and use 4.0f instead
#define MAX_ACCEPTED_RANGE  255.0f       

// force a slice width by setting a specific value
#define EI_SLICE EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE/EI_CLASSIFIER_SLICES_PER_MODEL_WINDOW
//#define EI_SLICE 5  // this was just for testing


int mySizeCalculation;
int myDoublePosition = -1;
int myDoubleCapture;
int myMainPosition;
long myCounter = 0;
int proximity, gesture, colourR, colourG, colourB;

/*
 ** NOTE: If you run into TFLite arena allocation issue.
 **
 ** This may be due to may dynamic memory fragmentation.
 ** Try defining "-DEI_CLASSIFIER_ALLOCATION_STATIC" in boards.local.txt (create
 ** if it doesn't exist) and copy this file to
 ** `<ARDUINO_CORE_INSTALL_PATH>/arduino/hardware/<mbed_core>/<core_version>/`.
 **
 ** See
 ** (https://support.arduino.cc/hc/en-us/articles/360012076960-Where-are-the-installed-cores-located-)
 ** to find where Arduino installs cores on your machine.
 **
 ** If the problem persists then there's not enough memory for this model and application.
 */

/* Private variables ------------------------------------------------------- */
static bool debug_nn = true;  //false; // Set this to true to see e.g. features generated from the raw signal
static uint32_t run_inference_every_ms = 200;
static rtos::Thread inference_thread(osPriorityLow);
static float buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE] = { 0 };
static float inference_buffer[EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE];
static float doubleBuffer[EI_SLICE] = { 1, 2, 3 };

float myGenericFloat = 239.00;
int mySize = sizeof(myGenericFloat); 

/* Forward declaration */
void run_inference_background();

/**
* @brief      Arduino setup function
*/
void setup()
{
    // put your setup code here, to run once:
    Serial.begin(115200);
   // Serial.println("Edge Impulse Inferencing Demo");


  APDS.setGestureSensitivity(70);  // 0 to 100
  if (!APDS.begin())
  {
    Serial.println("Error initializing APDS9960 sensor.");
    /* Hacky way of stopping program executation in event of failure. */
    while(1);
  }
  /* As per Arduino_APDS9960.h, 0=100%, 1=150%, 2=200%, 3=300%. Obviously more
   * boost results in more power consumption. */
  APDS.setLEDBoost(3);    
    
   

    inference_thread.start(mbed::callback(&run_inference_background));
}

/**
 * @brief Return the sign of the number
 * 
 * @param number 
 * @return int 1 if positive (or 0) -1 if negative
 */
float ei_get_sign(float number) {
    return (number >= 0.0) ? 1.0 : -1.0;
}

/**
 * @brief      Run inferencing in the background.
 */
void run_inference_background()
{
    // wait until we have a full buffer
    delay((EI_CLASSIFIER_INTERVAL_MS * EI_CLASSIFIER_RAW_SAMPLE_COUNT) + 100);

    // This is a structure that smoothens the output result
    // With the default settings 70% of readings should be the same before classifying.
    ei_classifier_smooth_t smooth;
    ei_classifier_smooth_init(&smooth, 10 /* no. of readings */, 7 /* min. readings the same */, 0.8 /* min. confidence */, 0.3 /* max anomaly */);

    while (1) {


      
        // copy the buffer
        memcpy(inference_buffer, buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE * sizeof(float));

        // Turn the raw buffer in a signal which we can the classify
        signal_t signal;
        int err = numpy::signal_from_buffer(inference_buffer, EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE, &signal);
        if (err != 0) {
            ei_printf("Failed to create signal from buffer (%d)\n", err);
            return;
        }

        // Run the classifier
        ei_impulse_result_t result = { 0 };

        err = run_classifier(&signal, &result, debug_nn);
        if (err != EI_IMPULSE_OK) {
            ei_printf("ERR: Failed to run classifier (%d)\n", err);
            return;
        }

        // print the predictions
        ei_printf("Predictions ");
        ei_printf("(DSP: %d ms., Classification: %d ms., Anomaly: %d ms.)",
            result.timing.dsp, result.timing.classification, result.timing.anomaly);
        ei_printf(": ");

        // ei_classifier_smooth_update yields the predicted label
        const char *prediction = ei_classifier_smooth_update(&smooth, &result);
        ei_printf("%s \n", prediction);
        ei_printf("float size %i", mySize);
        ei_printf(", EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE %i", EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE);
        ei_printf(", EI_SLICE %i", EI_SLICE);
        ei_printf(", myDoublePosition %i \n", myDoublePosition);
        ei_printf(", myCounter %i", myCounter);
        ei_printf(", myMainPosition from myDoubleCapture %i", myDoubleCapture);
        ei_printf(", mySizeCalculation %i", mySizeCalculation);




        
        // print the cumulative results
        ei_printf(" [ ");
        for (size_t ix = 0; ix < smooth.count_size; ix++) {
            ei_printf("%u", smooth.count[ix]);
            if (ix != smooth.count_size + 1) {
                ei_printf(", ");
            }
            else {
              ei_printf(" ");
            }
        }
        ei_printf("]\n");

        delay(run_inference_every_ms);
    }

    ei_classifier_smooth_free(&smooth);
}

/**
* @brief      Get data and run inferencing
*
* @param[in]  debug  Get debug info if true
*/
void loop()
{
    while (1) {


               myDoublePosition +=1;
          // If double Buffer finished then update buffer
          if (myDoublePosition > EI_SLICE) { 
             myDoublePosition = -1;
             memcpy(buffer+myMainPosition, doubleBuffer, sizeof(doubleBuffer) ); 
             myMainPosition += EI_SLICE-1;

             // If near the end of the main buffer and a few spots left, calculate the size and fill those few spots
             if (myMainPosition > (EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - EI_SLICE) ) {  
                myDoubleCapture = myMainPosition;
                mySizeCalculation = mySize * (EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE - myMainPosition); // -1);  // try -1 to see if last is zero
                memcpy(buffer+myMainPosition, doubleBuffer, mySizeCalculation ); 
                myMainPosition = 0;
               // it should really also send a classification then except that is on another thread
             }  
          } else {
                 if (APDS.proximityAvailable()){
                     proximity = 240 +(APDS.readProximity()*-1); 
                     myCounter +=1;  // just testing if the doubleBuffer gets updated
                 } 
                 // update the value using the old value if a new reading is not available!
                 doubleBuffer[myDoublePosition] = proximity * 1.0f; //myCounter;  
            }
        // Determine the next tick (and then sleep later)
        uint64_t next_tick = micros() + (EI_CLASSIFIER_INTERVAL_MS * 1000);


        // and wait for next tick
        uint64_t time_to_wait = next_tick - micros();
        delay((int)floor((float)time_to_wait / 1000.0f));
        delayMicroseconds(time_to_wait % 1000);
    }
}


2 Likes