Generating Raw features for static_buffer script

Hello,
I have been collecting custom data from the data forwarder off the Nano 33 BLE Sense. The data is imported perfectly, trained, classified and processed on the Dashboard. Thereafter, I want to deploy this model to the board for continuous data processing without establishing connection to the Dashboard. Since custom data import does not support direct deployement with the board, I have gone ahead and used the Static_buffer script from the EI library for compiling the sketch. This script requires the Raw features from the data collected off the dashboard. This becomes a sedate task for continuous classification. Is there a way to create a script which produces the raw features deployed to the board from the data collected for continuous processing?

Reference:

#include <apple-rgb-classification_inference.h>

static const float features[] = {
    // copy raw features here (for example from the 'Live 
classification' page)
    // see https://docs.edgeimpulse.com/docs/running- 
your-impulse-arduino
};

Any idea @janjongboom @aureleq

Thanks,
Dhruv

1 Like

@dhruvsheth See https://docs.edgeimpulse.com/docs/running-your-impulse-locally-1#signal-layout-for-time-series-data

If you got data from the data forwarder then something like this would work:

// this holds all features (allocate it once :-))
float *features = (float*)malloc(EI_CLASSIFIER_DSP_INPUT_FRAME_SIZE * sizeof(float));
if (!features) {
    Serial.println("Failed to allocate features array");
    return;
}

// loop frame by frame
for (size_t ix = 0; ix < EI_CLASSIFIER_RAW_SAMPLE_COUNT; ix += EI_CLASSIFIER_RAW_SAMPLES_PER_FRAME) {
    // read data from your sensor
    features[ix + 0] = sensor_axis_1;
    features[ix + 1] = sensor_axis_2;
    delay(EI_CLASSIFIER_INTERVAL_MS); // sleep for a little bit
}

And done.

1 Like

Thanks for the script
I understood how you are taking in the data from the sensors, but I fail to figure out the variable embedded in the features part:

static const float features[] = {

};

Here’s the data forwarder code for reference:

#include <Arduino_LPS22HB.h>
#include <Arduino_HTS221.h>

#define FREQUENCY_HZ        50
#define INTERVAL_MS         (1000 / (FREQUENCY_HZ + 1))

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

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

void loop() {
    static unsigned long last_interval_ms = 0;

    if (millis() > last_interval_ms + INTERVAL_MS) {
        last_interval_ms = millis();
        
        float t = HTS.readTemperature();
        float h = HTS.readHumidity();
        float p = BARO.readPressure();
        
        Serial.print(t);
        Serial.print('\t');
        Serial.print(h);
        Serial.print('\t');
        Serial.println(p * 0.3);        
    
    }
}
1 Like

Hi @dhruvsheth

Try this:

// 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 loop() {
    static unsigned long last_interval_ms = 0;

    if (millis() > last_interval_ms + INTERVAL_MS) {
        last_interval_ms = millis();
        
        float t = HTS.readTemperature();
        float h = HTS.readHumidity();
        float p = BARO.readPressure();

        // keep filling the features array until it's full
        features[feature_ix++] = t;
        features[feature_ix++] = h;
        features[feature_ix++] = p * 0.3;

        // full frame of data?
        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);
            printf("run_classifier returned: %d\n", res);
            if (res != 0) return;

            // print predictions
            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++) {
                printf("%s:\t%.5f\n", result.classification[ix].label, result.classification[ix].value);
            }
        #if EI_CLASSIFIER_HAS_ANOMALY == 1
            printf("anomaly:\t%.3f\n", result.anomaly);
        #endif

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

I’m using the Arduino Web Editor and it the script generates the following error

Using library Wire in folder: /home/builder/.arduino15/packages/arduino/hardware/mbed/1.3.1/libraries/Wire (legacy)

Using library arduino_hts221_1_0_0 at version 1.0.0 in folder: /home/builder/opt/libraries/latest/arduino_hts221_1_0_0

../../core/core_arduino_mbed_nano33ble_962bb9ec2777bc9b98acba3af0ef33ef.a(main.cpp.o): In function `main':

/home/builder/.arduino15/packages/arduino/hardware/mbed/1.3.1/cores/arduino/main.cpp:44: undefined reference to `setup'

collect2: error: ld returned 1 exit status

exit status 1

What probably might be an issue here?
Thanks!

@dhruvsheth you’ll still need the setup code and the other parts of your original sketch.

1 Like

Oh right, I have just included the libraries. Thanks

Hi, sorry to interrupt again.
The script compiles to the board, but after that, the board gets disconnected and is unable to be located on the serial port, as well as through arduino-cli board list . The orange LED on the board blinks in a random fashion. The board can be located once reset again.
Acknowlege your time, Thanks

Here’s the script:

Arduino Create/Editor redirect

Hey @dhruvsheth you’re missing:

    HTS.begin();
    BARO.begin();

In setup() (really annoying that they don’t handle this better).

1 Like

I don’t know how I’m missing the details of the script :sweat_smile:. Thanks a lot for pointing that out! =)
Dhruv

1 Like

@dhruvsheth We’ve now added examples on how to go from Data forwarder => Classifying data on Arduino, Mbed OS and Zephyr here: https://docs.edgeimpulse.com/docs/cli-data-forwarder#classifying-data hope this helps people in the future!

1 Like

Thanks a ton, the resource would be useful further =)

Everything works just fine, until I unplug and plug the Nano 33 ble back in right the next time after compilation. It gave perfect results on the serial monitor right after it had been compiled.

The second time it gives this -


    run_classifier returned: 0
    Predictions (DSP: 12 ms., Classification: 183484 ms., Anomaly: 6 ms.): 
    anomaly:	1000.000
    run_classifier returned: 0
    Predictions (DSP: 12 ms., Classification: 183484 ms., Anomaly: 6 ms.): 
    anomaly:	1000.000
    run_classifier returned: 0
    Predictions (DSP: 12 ms., Classification: 183484 ms., Anomaly: 6 ms.): 
    anomaly:	1000.000

Output generated from -


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

Update: Works now, maybe a glitch

1 Like