NanoEdge AI Library for anomaly detection (AD)

1. What is NanoEdge AI Library for anomaly detection?

NanoEdge™ AI Library is an Artificial Intelligence (AI) static library for embedded C software running on Arm® Cortex® microcontrollers.

A NanoEdge AI Library is compiled in the last step of any NanoEdge AI Studio project.

The goal of Anomaly detection libraries is to distinguish normal and abnormal behavior defined during its training in NanoEdge AI Studio. A library contains everything needed to be embedded on a microcontroller:

  • The AI model and its hyperparameters
  • The preprocessing of the signals

Few files are given to make a use of it:

  • libneai.a contains the ML model as an obfuscated static library
  • NanoEdgeAI.h contains the variables and functions declaration

1.1. Embedded learning

Anomaly detection libraries have the particularity to be retrainable directly on a microcontroller. It is the only kind of library able to do so in NanoEdge AI Studio.

Compared to other kinds of libraries, Anomaly detection libraries need to be retrained before being used. You can do it in three different ways:

  • Deploy the model and initialize without pretrained knowledge (neai_anomalydetection_init(false)), then collect and learn new signals directly on the microcontroller before doing detection.
  • Deploy the model and initialize with pretrained knowledge (neai_anomalydetection_init(true)). Use the pretrained benchmark knowledge and then do detection.
  • Deploy the model and initialize with pretrained knowledge (neai_anomalydetection_init(true)), but also collect new signals and call neai_anomalydetection_learn() to enrich the knowledge before doing detection.

If you use the pretrained knowledge from the benchmark, you don't exploit the advantages of anomaly detection. If you decide to retrain the model with new signals, you should get a model that is more specifically made for its final environment and thus should give better results.

2. Install / Getting started

The main functions available via the library are:

init() run first before learning/detecting, or to reset the knowledge of the library/emulator
learn() start a number of learning iterations (to establish an initial knowledge, or enrich an existing one)
detect() start a number of detection iterations (inference), once a minimum knowledge base has been established
Important

When building a smart device, the final features heavily depend on the way those functions are called. It is entirely up to the developer to design relevant learning and detection strategies, depending on the project specificities and constraints.

For example for a hypothetical machine, one possible strategy is to:

  1. initialize the model
  2. establish an initial knowledge base by calling learn() every minute for 24 hours on that machine
  3. switch to the inference mode by calling detect() 10 times every hour (and averaging the returned scores), each day
  4. blink a LED and ring alarms whenever detect() returns any anomaly (average score < 90%)
  5. run another learning cycle to enrich the existing knowledge, if the temperature rises above 60°C (and the machine is still OK)
  6. send a daily report (average number of anomalies per hour, with date, time, and machine ID for instance) using Bluetooth® or LoRa®.

In summary, those smart functions can be triggered by external data (for example from sensors, buttons, to account for and adapt to environment changes).
The scores returned by the smart functions can trigger all kinds of behaviors on your device.
The possibilities are endless.

2.1. How to get an AI library

  • In NanoEdge AI Studio, after obtaining a library, click Compile (on the "Deployment" screen, which follows the "Benchmark" and "Validation" screens)

The .zip file obtained contains:

  • the static precompiled NanoEdge AI library file libneai.a
  • the NanoEdge AI header file NanoEdgeAI.h
  • the NanoEdge AI Emulators (both Windows® and Linux® versions)
  • some library metadata information in metadata.json

To use it, simply add libneai.a and NanoEdgeAI.h to your project. Then, link the library for the compilation in your IDE. For example in STM32CubeIDE, go to Project -> Properties -> C/C++ Build -> Settings -> MCU GCC Linker -> Libraries. Add "neai" in the Libraries section and the libneai.a' path in the Library search path section. Click Apply and Close.

2.2. NanoEdge AI Library functions

Most NanoEdge AI function return the status of the library in the following enum, neai_state:

enum neai_state {
    NEAI_OK = 0,
    NEAI_ERROR = 1,
    NEAI_NOT_INITIALIZED = 2,
    NEAI_INVALID_PARAM = 3,
    NEAI_NOT_SUPPORTED = 4,
    NEAI_LEARNING_DONE = 5,
    NEAI_LEARNING_IN_PROGRESS = 6
};

Here are the possible statuses:

NEAI_OK: library working as expected
NEAI_ERROR: internal error with the library
NEAI_NOT_INITIALIZED: learn or detect functions were called without running the init function first; initialize your library.
NEAI_INVALID_PARAM: neai function was called with one or more incorrect or missing parameters.
NEAI_NOT_SUPPORTED: board not supported
NEAI_LEARNING_DONE: minimum number of learning iterations reached
NEAI_LEARNING_IN_PROGRESS: fail-safe to prevent insufficient number of learning iterations; run more iterations.

2.2.1. Initialization

enum neai_state neai_anomalydetection_init(bool use_pretrained);

Initialization can be run at the beginning to initialize the model and/or later to initialize a new model and reset all knowledge.

Specify at initialization whether to use a pretrained model or perform on-device learning:

  • neai_anomalydetection_init(true) - Use embedded pretrained model (see below, no learning phase required)
  • neai_anomalydetection_init(false) - Perform on-device learning using neai_anomalydetection_learn()

Returns the neai_state enum (NEAI_OK == 0, in case of success).

2.2.2. Using embedded pretrained model

The main advantage of anomaly detection libraries is that they can be re-trained directly on the edge. By default, if you use the library on a microcontroller, the model must be retrained to better fit the data in its real environment. The training knowledge acquired during the benchmark (corresponding to the training data of the project) is automatically embedded in the library. It is up to you to either included it, or start from scratch; use the boolean argument use_pretrained to do so.

2.2.3. Learning

enum neai_state neai_anomalydetection_learn(float data_input[]);

This function is used to learn patterns in your data. It can be used at any time, in the beginning to build the original knowledge base of the AI model, but also later, as an additional learning phase to complement the existing knowledge.

  • Input:
float data_input[], the length of the data is NEAI_INPUT_SIGNAL_LENGTH * NEAI_INPUT_AXIS_NUMBER.
  • Output:
the neai_state enum (NEAI_LEARNING_DONE or NEAI_LEARNING_IN_PROGRESS).
Information

The learning function can be called:

  1. initially, before any inference, to establish some reference knowledge base
  2. subsequently, whenever needed, to complete the existing knowledge and enrich it (for example, to take into account some new nominal environment conditions)
Warning

NanoEdge AI Library uses float data types instead of int. If you are using int data types, convert (cast) them into float.

2.2.4. Detection

enum neai_state neai_anomalydetection_detect(float data_input[], uint8_t *similarity);

This function returns returns a similarity percentage, measure of the mathematical distance between the incoming signal and the existing knowledge, learned by the library.

  • Input:
float data_input[], the length of the data is NEAI_INPUT_SIGNAL_LENGTH * NEAI_INPUT_AXIS_NUMBER.
uint8_t *similarity, the variable that contains the similarity score returned by the function.
  • Output:
The percentage of similarity [0-100] between the new signal and learned patterns ("100" means completely similar, and "0" completely dissimilar).
The neai_state enum.
Information
  • The uint8_t *similarity variable must be defined prior to calling the detection function, and pointed to using &similarity when passed as an argument (see code example below).
  • The recommended threshold percentage is 90. Values under this threshold reveal a behavior that differs from the usual behavior learned by the AI model. This threshold can be defined by the user, depending on the final application sensitivity requirements.

2.3. Backing up and restoring the library knowledge

When using NanoEdge AI Library, knowledge is created on the go: after each learning iteration, the machine learning model gets incrementally richer.

For performance reasons, this knowledge lives in the microcontroller RAM. Since RAM is volatile, it is lost at every power cycle. To keep it, copy it to a non-volatile memory (internal flash, EEPROM, backup RAM, and so on) and restore it at the next boot.

Two functions are provided for that purpose:

enum neai_state neai_anomalydetection_get_knowledge(void **knowledge_ptr, size_t *knowledge_size);
enum neai_state neai_anomalydetection_set_knowledge(const void *knowledge_ptr, size_t knowledge_size);
Information

These functions are available for anomaly detection libraries only. The other library types do not learn on the device, so their state never changes after init(): there is nothing to persist.

2.3.1. Three values, three owners

Every save and restore sequence juggles three values that appear next to each other in the same few lines of code. They have different owners and different lifetimes, and only one of them is an address that you choose.

Value What it is Who owns it Lifetime
knowledge_ptr RAM address of the live knowledge, inside the library the library the address is fixed for the whole program run, but its content changes at every learn()
knowledge_size size of the knowledge, in bytes the library, fixed when it was generated identical at every boot of the same firmware; the library never stores it for you
NVM address where you decide to put the bytes: flash sector base, EEPROM offset, and so on your application yours alone; the library never sees it

Two consequences are worth remembering:

  • neai_anomalydetection_get_knowledge() copies nothing. It hands you the address of the buffer that the library is using right now, plus its size. Moving the bytes to and from the non-volatile memory is entirely your job: the library is not linked against any storage driver.
  • The NVM address never appears in the API. Neither function takes nor returns a flash address. set_knowledge() reads from whatever address you give it, be it RAM or memory-mapped flash.

2.3.2. Reading the knowledge

enum neai_state neai_anomalydetection_get_knowledge(void **knowledge_ptr, size_t *knowledge_size);

Both parameters are output parameters: the library writes into them, it does not write into a buffer of yours. Passing your flash address as the first argument is a category error, that direction is the job of set_knowledge().

The address returned points inside the library context, which is in static storage: it is the same address at every call and stays valid for the whole program run. What changes is its content, because every learn() and every set_knowledge() rewrites it in place. The pointer is therefore a window on live state, not a snapshot: copy the bytes out before resuming the learning.

Calling this function right after init() is the supported way to discover knowledge_size at boot, before you know whether there is anything to restore. The content is meaningless at that point, but the size is already final.

  • Output:
void **knowledge_ptr, receives the RAM address of the knowledge.
size_t *knowledge_size, receives the size of the knowledge in bytes.
The neai_state enum:
Return code Meaning
NEAI_OK Pointer and size written.
NEAI_NOT_INITIALIZED init() has not been called.
NEAI_INVALID_PARAM knowledge_ptr or knowledge_size is NULL.

2.3.3. Restoring the knowledge

enum neai_state neai_anomalydetection_set_knowledge(const void *knowledge_ptr, size_t knowledge_size);

Copies knowledge_size bytes from knowledge_ptr into the library, overwriting the current knowledge. The source can be any readable address: a RAM buffer, or directly a memory-mapped flash address.

Only the size is validated. There is no magic word, no CRC and no model identity check: integrity and versioning are your responsibility.

  • Input:
const void *knowledge_ptr, the address of the saved bytes.
size_t knowledge_size, their size, which must match the value returned by get_knowledge().
  • Output:
The neai_state enum:
Return code Meaning
NEAI_OK Knowledge restored.
NEAI_NOT_INITIALIZED init() has not been called.
NEAI_INVALID_PARAM knowledge_ptr is NULL, or knowledge_size differs from the size of this library's knowledge.

2.3.4. Saving to non-volatile memory

void save_knowledge(void)
{
    void *kn_ptr;
    size_t kn_size;

    if (neai_anomalydetection_get_knowledge(&kn_ptr, &kn_size) != NEAI_OK) {
        return;
    }

    /* Your driver. It reads kn_size bytes starting at kn_ptr and puts them
     * wherever you decided. On STM32 internal flash: erase the sector first,
     * then program the bytes with HAL_FLASH_Program(). */
    my_nvm_write_knowledge(kn_ptr, kn_size);
}
  • Never store kn_ptr itself. It is a RAM address of the current run; after a reset it means nothing. Store the bytes it points to, and store kn_size next to them if you want to validate the record later.
  • Do not let learn() run during the write. kn_ptr points to live state: a learn() called from an interrupt halfway through the flash write produces a torn record, which still passes the size check when restored.
  • Keep the blob 4-byte aligned in NVM if your flash is programmed by words. A header made of two 32-bit words preserves that alignment naturally.

The choice of the flash sector is yours. Take care not to overwrite the .data or .text sections, as this leads to a hard fault. The sectors available on the NUCLEO-F401RE development board are:

2.3.5. Restoring at boot

A restore always follows the same shape: init() first, because the model must exist before it can be overwritten, then get_knowledge() to learn this library's size, then a size-checked set_knowledge().

Variant A: memory-mapped NVM (internal flash), no intermediate buffer

#define NVM_BASE_ADDR   0x08010000U   /* your sector base */
#define NVM_HEADER_LEN  8U            /* your header: magic + size */

struct nvm_header { uint32_t magic; uint32_t size; };   /* your record, your layout */

neai_anomalydetection_init(false);

void *kn_ptr;
size_t kn_size;
neai_anomalydetection_get_knowledge(&kn_ptr, &kn_size);   /* size of this library */

const struct nvm_header *hdr = (const struct nvm_header *) NVM_BASE_ADDR;
if (hdr->magic == NVM_MAGIC && hdr->size == kn_size) {
    const void *blob = (const void *) (NVM_BASE_ADDR + NVM_HEADER_LEN);
    neai_anomalydetection_set_knowledge(blob, kn_size);   /* reads straight from flash */
}

The STM32 internal flash is readable with normal load instructions, so set_knowledge() can copy from it directly: no intermediate buffer, no extra RAM.

Warning

The blob is stored at NVM_BASE_ADDR + NVM_HEADER_LEN, not at NVM_BASE_ADDR. If you pass the base address, the call still returns NEAI_OK, because you passed the right size and the size is the only thing that the library checks, but the model is loaded with bytes shifted by the header length and detect() then returns meaningless scores. A result of "NEAI_OK but nonsense scores" almost always means a wrong source offset.

Variant B: serial NVM (SPI flash, I²C EEPROM), with an intermediate buffer

/* Ceiling chosen by the application, sized from a real measurement:
 * print kn_size once during bring-up rather than guessing a value. */
#define NVM_MAX_KNOWLEDGE 16384
static uint8_t scratch[NVM_MAX_KNOWLEDGE];

neai_anomalydetection_init(false);

void *kn_ptr;
size_t kn_size;
neai_anomalydetection_get_knowledge(&kn_ptr, &kn_size);

if (kn_size > sizeof(scratch)) {
    /* Refuse rather than overflow. Reaching this means the library grew:
     * increase NVM_MAX_KNOWLEDGE and rebuild. */
} else if (my_nvm_read_knowledge(scratch, kn_size)) {
    neai_anomalydetection_set_knowledge(scratch, kn_size);
}

The intermediate buffer exists only because the medium is not memory-mapped. Its size is a ceiling that you choose; kn_size is the actual number of bytes and the only value to pass to the API.

Once the knowledge is restored, you can switch to the detection mode directly, without running a new learning phase.

2.3.6. Troubleshooting

Symptom Cause
set_knowledge() returns NEAI_INVALID_PARAM at every boot The stored record comes from a library generated with different settings, so its size differs. Version your NVM records by firmware revision.
set_knowledge() returns NEAI_OK but detect() scores are meaningless The source address is off by the header length, or the record comes from another library that happens to have the same knowledge size. Only the size is checked.
set_knowledge() returns NEAI_NOT_INITIALIZED init() was not called first. A restore never replaces the initialization, it follows it.
The restore worked on the bench and fails in the field The record was saved while learn() was still running (torn write), or it was truncated by an intermediate buffer smaller than kn_size.
get_knowledge() does not fill my buffer It is not supposed to. Both parameters are output parameters: the library returns its own address and size, and the copy is yours to make.
The knowledge size changed between two firmware versions Expected: the size is fixed when the library is generated. Store it in your NVM header and compare it before restoring.

2.3.7. Limitations

  • The size is fixed by the library. It depends on the model and the hyperparameters chosen by NanoEdge AI Studio and frozen when the library was generated. If you regenerate a library with different settings, the records saved by the previous firmware are rejected with NEAI_INVALID_PARAM. Treat the knowledge as an opaque blob, versioned by your firmware revision.
  • Not portable across architectures. Structure padding and float endianness depend on the target. Saving on one architecture and restoring on another is not supported.
  • The blob contains the complete learning state. Both detect() and learn() read everything they need from the restored knowledge, so a save, restore and continue-learning sequence produces exactly the same knowledge as an uninterrupted learning session, and the same detection scores.
  • The library never accesses the non-volatile memory. Wear leveling, write throttling, atomic swap, CRC and recovery from a corrupted record are your application's responsibility.
  • No concurrency guarantee. get_knowledge() hands out a pointer to live state and the library does no locking. Serialize your saves against learn() yourself.

2.3.8. Frequently asked questions

Do I need an intermediate buffer to restore?
Only if your non-volatile memory is not memory-mapped. On the STM32 internal flash, pass the address of the stored blob straight to set_knowledge() and save the RAM.

Can I write to flash directly from the pointer returned by get_knowledge()?
Yes, that is the intended save path. The pointer is a valid source for memcpy() or for a flash programming routine. Just make sure that no learn() runs concurrently.

Can I call get_knowledge() in the middle of a learning phase?
Yes. The bytes reflect the current learning state. Detection scores computed after restoring them match the scores computed without the save and restore round trip, bit for bit.

Do I need init(true) before set_knowledge()?
No. init(false) is enough, since set_knowledge() overwrites the knowledge regardless of how init() was called. init(true) works equally well, the pretrained knowledge is simply overwritten.

How big is the knowledge?
Call get_knowledge() once after init() and read knowledge_size. The value is constant for a given library. Depending on the model and the signal length, it ranges from a few hundred bytes to a few tens of kilobytes.

What happens if I restore a record saved by another library?
set_knowledge() validates the size only. If the size matches by coincidence and the bytes are unrelated, the behavior is undefined: meaningless scores, without any crash. Always pair a saved record with a firmware version tag in your non-volatile memory.

2.4. Example "Hello World!"

Header file: NanoEdgeAI.h

Example of NanoEdge AI Library header file:

This snippet is provided AS IS, and by taking it, you agree to be bound to the license terms that can be found here for the component: Application.


/* =============
Copyright (c) 2026, STMicroelectronics

All rights reserved.

Redistribution and use in source and binary forms, with or without modification, are permitted 
provided that the following conditions are met:

* Redistributions of source code must retain the above copyright notice, this list of conditions 
  and the following disclaimer.

* Redistributions in binary form must reproduce the above copyright notice, this list of
  conditions and the following disclaimer in the documentation and/or other materials provided 
  with the distribution.

* Neither the name of the copyright holders nor the names of its contributors may be used to 
  endorse or promote products derived from this software without specific prior written 
  permission.

*THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR 
 IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY 
 AND FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER / 
 OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR 
 CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR 
 SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY 
 THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR 
 OTHERWISE) ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE 
 POSSIBILITY OF SUCH DAMAGE.*
*/


#ifndef NANOEDGEAI_H
#define NANOEDGEAI_H

#include <stdint.h>
#include <stdbool.h>

/* NEAI ID */
#define NEAI_ID "None"

/* Input signal configuration */
#define NEAI_INPUT_SIGNAL_LENGTH 256
#define NEAI_INPUT_AXIS_NUMBER 3

/* NEAI State Enum */
enum neai_state {
    NEAI_OK = 0,
    NEAI_ERROR = 1,
    NEAI_NOT_INITIALIZED = 2,
    NEAI_INVALID_PARAM = 3,
    NEAI_NOT_SUPPORTED = 4,
    NEAI_LEARNING_DONE = 5,
    NEAI_LEARNING_IN_PROGRESS = 6
};


#ifdef __cplusplus
extern "C" {
#endif

/* ===== Anomaly Detection API ===== */
/**
 * @brief  Must be called at the beginning to initialize the anomaly detection model.
 * @param  use_pretrained [in]  Set to true to use a pretrained model, false to start learning
 *                              from scratch (pretrained model comes from NanoEdge AI Studio
 *                              and is embedded in the library).
 * @return NEAI_OK on success, error code otherwise.
 */
enum neai_state neai_anomalydetection_init(bool use_pretrained);

/**
 * @brief  Learn patterns from a new input sample.
 *         It can be called at any time after initialization.
 *         At the beginning, multiple calls to build the knowledge base of the model.
 *         Later as an additional learning step to complement the knowledge base.
 * @param  in [in]  Pointer to the input signal array
 *                  (size NEAI_INPUT_SIGNAL_LENGTH * NEAI_INPUT_AXIS_NUMBER).
 * @return NEAI_LEARNING_DONE when minimum learning calls are reached.
 *         NEAI_LEARNING_IN_PROGRESS if more learning calls are needed.
 *         Error code otherwise.
 */
enum neai_state neai_anomalydetection_learn(float *in);

/**
 * @brief  Perform anomaly detection on a new input sample by returning a similarity percentage.
 *         The mathematical distance between the incoming sample and the learned patterns.
 * @param  in         [in]   Pointer to the input signal array
 *                           (size NEAI_INPUT_SIGNAL_LENGTH * NEAI_INPUT_AXIS_NUMBER).
 * @param  similarity [out]  Pointer to the similarity percentage [0-100]
 *                           (100 means completely similar, 0 means completely different).
 * @return NEAI_OK on success.
 *         NEAI_LEARNING_IN_PROGRESS if the model needs more learning calls (minimum learning
 *                                   calls not reached).
 *         Error code otherwise.
 */
enum neai_state neai_anomalydetection_detect(float *in, uint8_t *similarity);

/* ===== Common getter functions ===== */
/**
 * @brief  Get the NEAI identifier.
 * @return Pointer to a string containing the NEAI ID.
 */
char* neai_get_id(void);

/**
 * @brief  Get the input signal size (number of samples per axis).
 * @return Input signal size.
 */
int neai_get_input_signal_size(void);

/**
 * @brief  Get the number of input axes/channels.
 * @return Number of input axes.
 */
int neai_get_axis_number(void);


#ifdef __cplusplus
}
#endif

#endif /* NANOEDGEAI_H */


/* =============
Declarations to add to your main program to use the NanoEdge AI library.
You may copy-paste them directly or rename variables as needed.
WARNING: Respect the structures, types, and buffer sizes; only variable names may be changed.

enum neai_state state;   // Captures return states from NEAI functions
bool use_pretrained = false;   // Init function parameter: true = use pretrained model, false = learn from scratch
uint8_t similarity;   // Similarity percentage returned by detect function
float input_signal[NEAI_INPUT_SIGNAL_LENGTH * NEAI_INPUT_AXIS_NUMBER];   // Input signal buffer
============= */

Main program: main.c
This program must be completed by the user (depending for instance on the applications or the desired features).

Information

The example below also shows how to restore knowledge at boot and save it after learning. These two blocks are optional — they are only needed if the application wants the learned knowledge to survive a power cycle, and require a user-supplied NVM driver (see Backing up and restoring the library knowledge). If persistence is not needed, simply omit the NVM hook declarations and both OPTIONAL blocks below.

This snippet is provided AS IS, and by taking it, you agree to be bound to the license terms that can be found here for the component: Application.


/**
  **************************************************************************
  * Demo: NanoEdge AI process to include in main program body
  *
  * @note  This program must be completed and customized by the user
  **************************************************************************
  */

/* Includes --------------------------------------------------------------------*/
#include "NanoEdgeAI.h"
#include <stdbool.h>
#include <stddef.h>
/* Number of samples for learning: set by user ---------------------------------*/
#define LEARNING_ITERATIONS replace_learning_samples
float input_signal[NEAI_INPUT_SIGNAL_LENGTH * NEAI_INPUT_AXIS_NUMBER]; // Buffer of input values

/* Private function prototypes defined by user ---------------------------------*/
/*
 * @brief Collect data process
 *
 * This function is defined by user, depends on applications and sensors
 *
 * @param input_signal: [in, out] buffer of sample values
 * @retval None
 * @note   If NEAI_INPUT_AXIS_NUMBER = 3 (cf NanoEdgeAI.h), the buffer must be
 *         ordered as follow:
 *         [x0 y0 z0 x1 y1 z1 ... xn yn zn], where xi, yi and zi
 *         are the values for x, y and z axes, n is equal to
 *         NEAI_INPUT_SIGNAL_LENGTH (cf NanoEdgeAI.h)
 */
void fill_buffer(float *input_signal)
{
    /* USER BEGIN */
    /* USER END */
}

/* OPTIONAL: user-supplied NVM driver, only needed if the application wants the
 * learned knowledge to survive a power cycle. Implementation depends on the
 * target (internal Flash, external EEPROM, backup RAM, ...). The NEAI library
 * never touches NVM itself. Skip these declarations if persistence is not used.
 */
extern bool my_nvm_has_saved_knowledge(void);
extern void my_nvm_read_knowledge(void *dst, size_t size);
extern void my_nvm_write_knowledge(const void *src, size_t size);

/* -----------------------------------------------------------------------------*/
int main(void)
{
    /* Initialization ------------------------------------------------------------*/
    bool use_pretrained = false; // true to use the pretrained model, false to start learning from scratch
    enum neai_state error_code = neai_anomalydetection_init(use_pretrained);
    uint8_t similarity = 0;

    if (error_code != NEAI_OK) {
        /* Check the returned error code (cf NanoEdgeAI.h). */
    }

    /* OPTIONAL: restore previously saved knowledge, if any ----------------------
     * Remove this block if knowledge persistence across power cycles is not used.
     */
    if (my_nvm_has_saved_knowledge()) {
        void *kn_ptr;
        size_t kn_size;
        /* Called for the size only: kn_ptr is the library's own buffer. */
        neai_anomalydetection_get_knowledge(&kn_ptr, &kn_size);

        /* Ceiling chosen by the application; print kn_size once during
         * bring-up to size it. On memory-mapped Flash this buffer is not
         * needed at all: pass the stored address to set_knowledge() directly.
         */
        static uint8_t scratch[16384];
        if (kn_size <= sizeof(scratch)) {
            my_nvm_read_knowledge(scratch, kn_size);
            neai_anomalydetection_set_knowledge(scratch, kn_size);
        }
    }

    /* Learning process ----------------------------------------------------------*/
    for (uint16_t iteration = 0 ; iteration < LEARNING_ITERATIONS ; iteration++) {
        fill_buffer(input_signal);
        neai_anomalydetection_learn(input_signal);
    }

    /* OPTIONAL: persist the freshly learned knowledge to NVM --------------------
     * Remove this block if knowledge persistence across power cycles is not used.
     */
    {
        void *kn_ptr;
        size_t kn_size;
        if (neai_anomalydetection_get_knowledge(&kn_ptr, &kn_size) == NEAI_OK) {
            my_nvm_write_knowledge(kn_ptr, kn_size);
        }
    }

    /* Detection process ---------------------------------------------------------*/
    while (1) {
        fill_buffer(input_signal);
        neai_anomalydetection_detect(input_signal, &similarity);
        /* USER BEGIN */
    /*
    * e.g.: Trigger functions depending on similarity
    * (blink LED, ring alarm, etc.).
    */
        /* USER END */
    }
}

3. Resources

Documentation
All NanoEdge AI Studio documentation is available here.

Tutorials
Step-by-step tutorials to use NanoEdge AI Studio to build a smart device from A to Z.