Skip to content

Feature/nrf edgeai 3.0.0+new model observabilities - #145

Open
rrusak wants to merge 9 commits into
mainfrom
feature/nrf_edgeai_3.0.0_obsv
Open

rrusak wants to merge 9 commits into
mainfrom
feature/nrf_edgeai_3.0.0_obsv

Conversation

@rrusak

@rrusak rrusak commented Aug 18, 2026

Copy link
Copy Markdown
Member

This pull request refactors includes a nrf_edgeai 3.0.0 and enhances the observability configuration and implementation for the wakeword and keyword spotting models in the ww_kws application. The changes introduce more granular control over which models have observability enabled, centralize observability handling, and update documentation and configuration files accordingly. Additionally, several generated model files are updated to support new feature scaling interfaces.

Key changes include:

New nrf_edgeai version

Update nrf_edgeai to 3.0.0 version

Observability configuration and implementation

  • Split the monolithic CONFIG_MODELS_OBSERVABILITY Kconfig option into two separate options: CONFIG_MODELS_OBSERVABILITY_WW (for the wakeword model) and CONFIG_MODELS_OBSERVABILITY_KWS (for the keyword spotting model), allowing independent enabling of observability for each model. An umbrella CONFIG_MODELS_OBSERVABILITY is now auto-selected if either is enabled.
  • Updated observability.conf to enable only the wakeword observability by default and added detailed comments about configuration and memory usage. All built-in metrics are now enabled for both models, with configurable histogram bin numbers and other metric parameters.
  • Refactored src/kws/kws.c to use the new model_obsv shared module for observability, removing direct metric and Memfault context management from the model file. Observability is now conditionally compiled only if CONFIG_MODELS_OBSERVABILITY_KWS is enabled. [1] [2] [3] [4]
  • Updated CMake configuration to include the model_obsv.c source file only when observability is enabled.

Documentation updates

  • Revised the README.rst to reflect the new observability configuration, clarifying how to enable observability for each model and describing the centralized role of the model_obsv.c module. [1] [2]

Model interface updates

rrusak added 4 commits August 4, 2026 13:33
Update nrf_edgeai

Signed-off-by: Raman Rusak <raman.rusak@nordicsemi.no>
Replicate the full observability metric set into ww_kws.  Observability is selectable per model via CONFIG_MODELS_OBSERVABILITY_WW / _KWS (either, or both)

Signed-off-by: Raman Rusak <raman.rusak@nordicsemi.no>
Update nrf_edgeai internal state handling, make all models compatible with 3.0.0 version

Signed-off-by: Raman Rusak <raman.rusak@nordicsemi.no>
Added Release v3.0.0 (17 August 2026)

Signed-off-by: Raman Rusak <raman.rusak@nordicsemi.no>
@rrusak
rrusak requested review from Szynkaa, annwoj, grochu and mbarchie and a lite review from Copilot August 18, 2026 16:21
@rrusak
rrusak requested a review from a team as a code owner August 18, 2026 16:21
@github-actions github-actions Bot added the doc-required PR must not be merged without tech writer approval. label Aug 18, 2026
@rrusak
rrusak removed the request for review from Copilot August 18, 2026 16:21
@github-actions

Copy link
Copy Markdown

You can find the documentation preview for this PR here.

{
const char* p_solution_id; /**< Solution ID string */
nrf_edgeai_rt_version_t version; /**< Solution runtime version */
/**< Solution ID string */

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

don't use inline docs marking for non-inline docs
same below

*
* Declare one static instance per model and pass it to @ref model_obsv_init.
*/
struct model_obsv {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

this increase memory usage for not used storage in wakeword and create need for synthesized [1 - p, p] vector, I see it was done for code deduplication, but I think it hides how to configure observability in clients application

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @Szynkaa comment - this code deduplication comes with big cost in memory and I guess it's not how users would exactly use it in their apps. It's better for us, who are testing observability feature.

I think metrics should be enabled per-model and sized appropriately. One alternative idea would be some config array, so that model_obsv_init() could iterate over it and register them for specific models? I think buffers could be also statically allocated based on some config, but it would require use of some X-macro probably - which would increase complexity and reduce readability of sample application.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not addressed

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Work in progress

Comment thread applications/ww_kws/Kconfig
.interfaces.input_init = NN_INPUT_INIT_INTERFACE,
.interfaces.feed_inputs = NN_INPUT_FEED_INTERFACE,
.interfaces.process_features = NN_PROCESS_FEATURES_INTERFACE,
.interfaces.scale_features = NN_SCALE_FEATURES_INTERFACE,

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

whitespace formatting is updated model files is inconsistent (tabs vs spaces)

Comment thread applications/ww_kws/src/kws/kws.c Outdated
Comment on lines +55 to +59
/* Mel feature vector length produced by the model DSP front end. Sizes the
* FEATURES-stream metric storage; validated at runtime against
* nrf_edgeai_dsp_features_ctx()->overall_num.
*/
#define KWS_NUM_FEATURES 40

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is the comment correct? I couldn't find any runtime check against overall_num. Same for WW.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Yeah it is inside nrf_edgeai runtime library .... :) I'll remove this comment

Comment on lines +182 to +185
err = nrf_edgeai_process_features(kws_model);
if (err == NRF_EDGEAI_ERR_INPROGRESS) {
/* Feature window not complete yet. */
return -EBUSY;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is NRF_EDGEAI_ERR_INPROGRESS expected to be returned when window is not full? Or NRF_EDGEAI_ERR_WRONG_STATE - as I understand it from description of nrf_edgeai_process_features().

I have the same doubt about nrf_edgeai_run_inference() looking at its description.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For ww/kws we have internal 3x40 discrete mel features window, each nrf_edgeai_process_features computes 1x40 mel vector, so we will return NRF_EDGEAI_ERR_INPROGRESS if 3x40 has not yet been collected

# above the default. If RAM is tight, lower the *_BIN_NUM values above.
CONFIG_NRF_EDGEAI_OBSV_MEMFAULT_AUTO_COLLECT=y
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=4096
CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE=12288

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With only WW observability enabled in this .conf file, there's no need to set CONFIG_NRF_EDGEAI_OBSV_MEMFAULT_MAX_CONTEXTS to 2 and increase CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE that much.

I get it's to make it easier to play with enabling/disabling WW/KWS observability, without needing to tweak other options. However, in this case, IMO it would be better to deliver this sample with observability enabled for both models by default.

@rrusak rrusak Aug 19, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

or make it conditional?

config SYSTEM_WORKQUEUE_STACK_SIZE
	default 12288 if MODELS_OBSERVABILITY_WW && MODELS_OBSERVABILITY_KWS 
	default 8192  if MODELS_OBSERVABILITY_KWS                            
	default 4096  if MODELS_OBSERVABILITY_WW  

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It would work, but I'm not convinced that the same approach as for CONFIG_NRF_EDGEAI_OBSV_MEMFAULT_MAX_CONTEXTS is the best one.

With your proposal SYSTEM_WORKQUEUE_STACK_SIZE would be hidden in Kconfig and pretending to depend just from observability. However, it's a shared, global resource, so the correct size is the max of everyone's needs, not just the observability. If we compute it purely from MODELS_OBSERVABILITY_WW/_KWS, that's an implicit claim that these are the only two things that matter for this stack. A developer re-using this sample naturally reads observability.conf and tunes what's there and an explicit CONFIG_SYSTEM_WORKQUEUE_STACK_SIZE keeps that setting visible for them to bump

Comment thread applications/ww_kws/README.rst Outdated

The application provides predefined :file:`observability.conf` configuration file for enabling observability.
This file enables the ``CONFIG_MODELS_OBSERVABILITY`` Kconfig option, Bluetooth LE, Memfault Diagnostic Service and required dependencies to provide observability for bundled models.
This file enables observability for both bundled models (``CONFIG_MODELS_OBSERVABILITY_WW`` and ``CONFIG_MODELS_OBSERVABILITY_KWS``), Bluetooth LE, Memfault Diagnostic Service and required dependencies. Enable only one of the two options to observe just the wakeword or just the keyword spotting model.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This doesn't match what's in observability.conf - only WW is enabled. Plus new sentence should go into new line.

Suggested change
This file enables observability for both bundled models (``CONFIG_MODELS_OBSERVABILITY_WW`` and ``CONFIG_MODELS_OBSERVABILITY_KWS``), Bluetooth LE, Memfault Diagnostic Service and required dependencies. Enable only one of the two options to observe just the wakeword or just the keyword spotting model.
This file enables observability for both bundled models (``CONFIG_MODELS_OBSERVABILITY_WW`` and ``CONFIG_MODELS_OBSERVABILITY_KWS``), Bluetooth LE, Memfault Diagnostic Service and required dependencies.
Enable only one of the two options to observe just the wakeword or just the keyword spotting model.

depends on NRF_EDGEAI_OBSV_METRIC_TRANSITION_MATRIX || APP_MODE_WW_ONLY
depends on NRF_EDGEAI_OBSV_MEMFAULT_MAX_CONTEXTS >= 2 || !APP_MODE_WW_GATED_KWS
depends on APP_MODE_WW_GATED_KWS || APP_MODE_KWS_ONLY
depends on NRF_EDGEAI_OBSV_MEMFAULT_MAX_CONTEXTS >= 2 || !MODELS_OBSERVABILITY_WW

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Doesn't MODELS_OBSERVABILITY_WW need similar dependency on number of contexts?

@rrusak rrusak Aug 19, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

The KWS guard MAX_CONTEXTS >= 2 || !MODELS_OBSERVABILITY_WW is that condition written from KWS's side. Because it's a dependency of KWS, it's evaluated whenever KWS would be y:

If KWS=y, then (>=2 || !WW) must hold - NOT(WW && KWS && <2).
If KWS=n, the illegal combo can't exist (it needs KWS).

So the state WW && KWS && MAX_CONTEXTS<2 is unreachable with the guard on KWS alone. Why we need to check NRF_EDGEAI_OBSV_MEMFAULT_MAX_CONTEXTS in WW?

Maybe better to add to Kconfig something like:

config NRF_EDGEAI_OBSV_MEMFAULT_MAX_CONTEXTS
	default 2 if MODELS_OBSERVABILITY_WW && MODELS_OBSERVABILITY_KWS
	default 1 if MODELS_OBSERVABILITY

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree the current one guards against misconfiguration from logical point of view and the other check would be redundant. But it doesn't seem intuitive from UX point of view - misconfiguration of contexts always pops up as KWS failure.

I think your Kconfig fix is fine.

*
* Declare one static instance per model and pass it to @ref model_obsv_init.
*/
struct model_obsv {

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I agree with @Szynkaa comment - this code deduplication comes with big cost in memory and I guess it's not how users would exactly use it in their apps. It's better for us, who are testing observability feature.

I think metrics should be enabled per-model and sized appropriately. One alternative idea would be some config array, so that model_obsv_init() could iterate over it and register them for specific models? I think buffers could be also statically allocated based on some config, but it would require use of some X-macro probably - which would increase complexity and reduce readability of sample application.

Comment thread applications/ww_kws/README.rst Outdated
Comment on lines +44 to +45
Enable ``CONFIG_MODELS_OBSERVABILITY_WW``, ``CONFIG_MODELS_OBSERVABILITY_KWS``, or both to wire metrics into the wakeword model, the keyword spotting model, or both.
The shared :file:`src/obsv/model_obsv.c` module owns each model's observability context, registers every enabled built-in metric, and binds the Memfault transport; the model files (:file:`src/ww/wakeword.c` and :file:`src/kws/kws.c`) only feed samples to it.

@annwoj annwoj Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Enable ``CONFIG_MODELS_OBSERVABILITY_WW``, ``CONFIG_MODELS_OBSERVABILITY_KWS``, or both to wire metrics into the wakeword model, the keyword spotting model, or both.
The shared :file:`src/obsv/model_obsv.c` module owns each model's observability context, registers every enabled built-in metric, and binds the Memfault transport; the model files (:file:`src/ww/wakeword.c` and :file:`src/kws/kws.c`) only feed samples to it.
Enable metrics for each model independently (either option, or both):
* ``CONFIG_MODELS_OBSERVABILITY_WW`` - Wakeword model
* ``CONFIG_MODELS_OBSERVABILITY_KWS`` - Keyword spotting model
The :file:`src/obsv/model_obsv.c` module does all the observability work.
For each enabled model, it owns the observability context, registers the built-in metrics selected in :file:`observability.conf`, and binds the Memfault transport.
The model files (:file:`src/ww/wakeword.c` and :file:`src/kws/kws.c`) only feed samples to this module.
Because both models use the same metric set, the single output of the wakeword model is expanded into a synthetic two-class ``[1 - p, p]`` distribution before the probability metrics are updated.

Comment thread applications/ww_kws/README.rst Outdated
Comment on lines +47 to +48
Both models register the same metric set: whichever built-in metrics are enabled at build time (see :file:`observability.conf`).
The wakeword model has a single output, so it is expanded into a synthetic two-class ``[1 - p, p]`` distribution before the probability metrics, which lets the same set apply to it as to the multi-class keyword spotting model.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
Both models register the same metric set: whichever built-in metrics are enabled at build time (see :file:`observability.conf`).
The wakeword model has a single output, so it is expanded into a synthetic two-class ``[1 - p, p]`` distribution before the probability metrics, which lets the same set apply to it as to the multi-class keyword spotting model.

Comment thread doc/libraries/nrf_edgeai_changelog.rst Outdated
Comment on lines +12 to +54
Release v3.0.0 (17 August 2026)
*******************************

This release is tagged as ``NRF-EDGEAI-RELEASE-3.0.0`` (internal release commit ``6dfb365bca9400f463b8c16773887b6d6fa39550``).

This is a major release.
The runtime major version was raised from 2 to 3, which makes it incompatible with solutions generated for the 2.x runtime.

* Breaking changes:

* Runtime version raised to 3.0.0. :c:func:`nrf_edgeai_is_runtime_compatible` compares the major version of the runtime library against the solution, so a model generated for a 2.x runtime now causes :c:func:`nrf_edgeai_init` to fail with ``NRF_EDGEAI_ERR_INCOMPATIBLE``. Regenerate the solution with Nordic Edge AI Lab 3.0.0.
* Feature processing was split into two separate pipeline stages: DSP feature extraction and feature scaling. The runtime interface structure ``nrf_edgeai_interfaces_t`` gained a new mandatory ``scale_features`` member (``nrf_edgeai_iface_scale_features_t``), which every solution context must populate.
* The combined ``nrf_edgeai_process_features_<mode>_<input>_<output>`` interface family was removed and replaced:

* ``process_features`` now provides DSP extraction only — ``nrf_edgeai_process_features_dsp_i8()``, ``nrf_edgeai_process_features_dsp_i16()``, ``nrf_edgeai_process_features_dsp_f32()``, and ``nrf_edgeai_process_features_empty()``.
* Scaling moved to the new ``nrf_edgeai_scale_features_*`` family declared in ``nrf_edgeai_scale_features.h``.
* Scaling mode prefixes were renamed: ``scale_vector_*`` is now ``input_vector_*``, and ``scale_window_*`` is now ``input_window_*``.
* The ``nrf_edgeai_t`` runtime context gained a ``state`` member, changing the structure layout. Applications and generated solutions must be recompiled against the new headers.

* Added:

* The public :c:func:`nrf_edgeai_process_features` API, allowing DSP feature extraction to be triggered independently of model inference.
* Runtime state tracking via ``nrf_edgeai_state_t``, with state bit definitions (``NRF_EDGEAI_STATE_RT_INITIALIZED``, ``NRF_EDGEAI_STATE_RT_INPUTS_COLLECTED``, ``NRF_EDGEAI_STATE_RT_FEATURES_PROCESSED``, ``NRF_EDGEAI_STATE_RT_INFERENCE_COMPLETED``) and composite readiness masks. The runtime now validates its state on entry to the input, feature processing, and inference stages.
* Two error codes for state violations: ``NRF_EDGEAI_ERR_UNINITIALIZED`` (-8) and ``NRF_EDGEAI_ERR_WRONG_STATE`` (-9).
* :c:func:`nrf_edgeai_dsp_features_ctx` to obtain read-only access to the DSP feature extraction context, so computed features can be used from the application.

* :c:func:`nrf_edgeai_run_inference` keeps the previous single-call workflow working. If features have not been processed yet, it invokes :c:func:`nrf_edgeai_process_features` internally and propagates its status code unchanged.


* Fixed:

* :c:func:`nrf_edgeai_feed_inputs` now rejects calls on a context that was never successfully initialized, returning ``NRF_EDGEAI_ERR_UNINITIALIZED`` instead of forwarding the data to an uninitialized input window context.

Known issues
============

There are no critical known issues identified for this release.

Compatibility
=============

* Nordic Edge AI Lab solutions version: 3.0.0
* Axon driver version: 1.3.0 - 1.5.0

@annwoj annwoj Aug 19, 2026

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Maybe instead of "breaking changes" we should change it into "migration notes"? something we usually do in ncs.

Suggested change
Release v3.0.0 (17 August 2026)
*******************************
This release is tagged as ``NRF-EDGEAI-RELEASE-3.0.0`` (internal release commit ``6dfb365bca9400f463b8c16773887b6d6fa39550``).
This is a major release.
The runtime major version was raised from 2 to 3, which makes it incompatible with solutions generated for the 2.x runtime.
* Breaking changes:
* Runtime version raised to 3.0.0. :c:func:`nrf_edgeai_is_runtime_compatible` compares the major version of the runtime library against the solution, so a model generated for a 2.x runtime now causes :c:func:`nrf_edgeai_init` to fail with ``NRF_EDGEAI_ERR_INCOMPATIBLE``. Regenerate the solution with Nordic Edge AI Lab 3.0.0.
* Feature processing was split into two separate pipeline stages: DSP feature extraction and feature scaling. The runtime interface structure ``nrf_edgeai_interfaces_t`` gained a new mandatory ``scale_features`` member (``nrf_edgeai_iface_scale_features_t``), which every solution context must populate.
* The combined ``nrf_edgeai_process_features_<mode>_<input>_<output>`` interface family was removed and replaced:
* ``process_features`` now provides DSP extraction only — ``nrf_edgeai_process_features_dsp_i8()``, ``nrf_edgeai_process_features_dsp_i16()``, ``nrf_edgeai_process_features_dsp_f32()``, and ``nrf_edgeai_process_features_empty()``.
* Scaling moved to the new ``nrf_edgeai_scale_features_*`` family declared in ``nrf_edgeai_scale_features.h``.
* Scaling mode prefixes were renamed: ``scale_vector_*`` is now ``input_vector_*``, and ``scale_window_*`` is now ``input_window_*``.
* The ``nrf_edgeai_t`` runtime context gained a ``state`` member, changing the structure layout. Applications and generated solutions must be recompiled against the new headers.
* Added:
* The public :c:func:`nrf_edgeai_process_features` API, allowing DSP feature extraction to be triggered independently of model inference.
* Runtime state tracking via ``nrf_edgeai_state_t``, with state bit definitions (``NRF_EDGEAI_STATE_RT_INITIALIZED``, ``NRF_EDGEAI_STATE_RT_INPUTS_COLLECTED``, ``NRF_EDGEAI_STATE_RT_FEATURES_PROCESSED``, ``NRF_EDGEAI_STATE_RT_INFERENCE_COMPLETED``) and composite readiness masks. The runtime now validates its state on entry to the input, feature processing, and inference stages.
* Two error codes for state violations: ``NRF_EDGEAI_ERR_UNINITIALIZED`` (-8) and ``NRF_EDGEAI_ERR_WRONG_STATE`` (-9).
* :c:func:`nrf_edgeai_dsp_features_ctx` to obtain read-only access to the DSP feature extraction context, so computed features can be used from the application.
* :c:func:`nrf_edgeai_run_inference` keeps the previous single-call workflow working. If features have not been processed yet, it invokes :c:func:`nrf_edgeai_process_features` internally and propagates its status code unchanged.
* Fixed:
* :c:func:`nrf_edgeai_feed_inputs` now rejects calls on a context that was never successfully initialized, returning ``NRF_EDGEAI_ERR_UNINITIALIZED`` instead of forwarding the data to an uninitialized input window context.
Known issues
============
There are no critical known issues identified for this release.
Compatibility
=============
* Nordic Edge AI Lab solutions version: 3.0.0
* Axon driver version: 1.3.0 - 1.5.0
Release v3.0.0 (17 August 2026)
*******************************
This release is tagged as ``NRF-EDGEAI-RELEASE-3.0.0`` (internal release commit ``6dfb365bca9400f463b8c16773887b6d6fa39550``).
This is a major release.
The runtime major version was raised from 2 to 3, which makes it incompatible with solutions generated for the v2.x runtime.
* This release contains the following breaking changes:
* Solutions and applications built for the 2.x runtime do not work with this release.
Retrain your model and export a new solution with Nordic Edge AI Lab 3.0.0.
:c:func:`nrf_edgeai_is_runtime_compatible` compares the major version of the runtime library against the solution, so a solution created for a 2.x runtime causes :c:func:`nrf_edgeai_init` to fail with ``NRF_EDGEAI_ERR_INCOMPATIBLE``.
* Feature processing is now split into two separate pipeline stages: DSP feature extraction and feature scaling.
The ``nrf_edgeai_interfaces_t`` runtime interface structure gained a new mandatory ``scale_features`` member of type ``nrf_edgeai_iface_scale_features_t``, which every solution context must provide.
Solutions exported with Nordic Edge AI Lab 3.0.0 populate this member automatically.
* The combined ``nrf_edgeai_process_features_<mode>_<input>_<output>`` interface family was removed and replaced by the following:
* ``process_features``, which now provides DSP extraction only, through ``nrf_edgeai_process_features_dsp_i8()``, ``nrf_edgeai_process_features_dsp_i16()``, ``nrf_edgeai_process_features_dsp_f32()``, and ``nrf_edgeai_process_features_empty()``.
* The new ``nrf_edgeai_scale_features_*`` family declared in :file:`nrf_edgeai_scale_features.h`, which handles scaling.
* Renamed scaling mode prefixes, where ``scale_vector_*`` is now ``input_vector_*``, and ``scale_window_*`` is now ``input_window_*``.
* The ``nrf_edgeai_t`` runtime context gained a ``state`` member, which changes the structure layout.
Applications and exported solutions must be recompiled against the 3.0.0 headers.
* Added:
* The public :c:func:`nrf_edgeai_process_features` API, allowing DSP feature extraction to be triggered independently of model inference.
* Runtime state tracking through ``nrf_edgeai_state_t``, with composite readiness masks and the following state bit definitions:
* ``NRF_EDGEAI_STATE_RT_INITIALIZED``
* ``NRF_EDGEAI_STATE_RT_INPUTS_COLLECTED``
* ``NRF_EDGEAI_STATE_RT_FEATURES_PROCESSED``
* ``NRF_EDGEAI_STATE_RT_INFERENCE_COMPLETED``
The runtime now validates its state on entry to the input, feature processing, and inference stages.
* Two error codes for state violations: ``NRF_EDGEAI_ERR_UNINITIALIZED`` (-8) and ``NRF_EDGEAI_ERR_WRONG_STATE`` (-9).
* :c:func:`nrf_edgeai_dsp_features_ctx` to obtain read-only access to the DSP feature extraction context, so computed features can be used from the application.
* Updated:
* Feature processing was split into two separate pipeline stages: DSP feature extraction and feature scaling.
* :c:func:`nrf_edgeai_run_inference` keeps the previous single-call workflow working.
If features have not been processed yet, it invokes :c:func:`nrf_edgeai_process_features` internally and propagates its status code unchanged.
* Fixed:
* :c:func:`nrf_edgeai_feed_inputs` now rejects calls on a context that was never successfully initialized, returning ``NRF_EDGEAI_ERR_UNINITIALIZED`` instead of forwarding the data to an uninitialized input window context.
Known issues
============
There are no critical known issues identified for this release.
Compatibility
=============
* Nordic Edge AI Lab solutions version: 3.0.0
* Axon driver version: 1.3.0 to 1.5.0

@rrusak rrusak Aug 20, 2026

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Currently, there is no "regenerate solution" option in Nordic Edge AI Lab; the only way is for the user to retrain everything from scratch.
Is it even necessary to write this migration if the add-on is still in the experimental phase? I wouldn't want the user to manually edit the model's internal context.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Got it - thought we actually do have migration steps and this is the desired solution.
But in this case it's as you mention, we don't need the migration steps.
I updated the edit - please check

@grochu grochu modified the milestones: v2.3.0, v3.0.0 Aug 20, 2026
rrusak added 2 commits August 20, 2026 15:10
fix whitespaces and comments

Signed-off-by: Raman Rusak <raman.rusak@nordicsemi.no>
…f_edgeai 3.0.0 changelog

Derive class/context sizing from WW/KWS; set the shared workqueue stack explicitly.

Signed-off-by: Raman Rusak <raman.rusak@nordicsemi.no>

@Szynkaa Szynkaa left a comment

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

the commits needs squashing

  • lib update with models alignment
  • (optional) separate lib changelog update
  • observability update in KWS

Comment thread applications/ww_kws/Kconfig Outdated
Comment on lines +106 to +108
config NRF_EDGEAI_OBSV_MAX_CLASSES
default 12 if MODELS_OBSERVABILITY_KWS
default 2 if MODELS_OBSERVABILITY_WW

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think this should stay in .conf. Value depends not only on which models have observability enabled (y in .conf already), but also on the model itself

Comment thread applications/ww_kws/observability.conf Outdated
Comment on lines +46 to +52
# System workqueue stack — a SHARED, global stack (Memfault packetizer, logging,
# BLE, ...), so it is set explicitly here rather than derived; its correct size is
# the max over all its users. This value covers the observability encode buffer for
# the default scope (both models = 2 contexts x 12 classes) plus headroom. Lower it
# to ~8192 for the keyword model only or ~4096 for the wakeword model only; raise it
# if you add other workqueue-heavy work. The observability Memfault library
# BUILD_ASSERTs its own floor, so an under-sized value fails the build.

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

brieffer, no need to comment about deriving size from other kconfigs

*
* Declare one static instance per model and pass it to @ref model_obsv_init.
*/
struct model_obsv {

Copy link
Copy Markdown
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

not addressed

Comment on lines +19 to +21
* This release contains the following breaking changes:
* Solutions and applications built for the 2.x runtime do not work with this release.
Retrain your model and export a new solution with Nordic Edge AI Lab 3.0.0.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* This release contains the following breaking changes:
* Solutions and applications built for the 2.x runtime do not work with this release.
Retrain your model and export a new solution with Nordic Edge AI Lab 3.0.0.
* This release contains the following breaking changes:
* Solutions and applications built for the 2.x runtime do not work with this release.
Retrain your model and export a new solution with Nordic Edge AI Lab 3.0.0.

* This release contains the following breaking changes:
* Solutions and applications built for the 2.x runtime do not work with this release.
Retrain your model and export a new solution with Nordic Edge AI Lab 3.0.0.
:c:func:`nrf_edgeai_is_runtime_compatible` compares the major version of the runtime library against the solution, so a solution created for a 2.x runtime causes :c:func:`nrf_edgeai_init` to fail with ``NRF_EDGEAI_ERR_INCOMPATIBLE``.

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I think the indent here should be aligned with what's above(?) Won't render correctly otherwise

* Two error codes for state violations: ``NRF_EDGEAI_ERR_UNINITIALIZED`` (-8) and ``NRF_EDGEAI_ERR_WRONG_STATE`` (-9).
* :c:func:`nrf_edgeai_dsp_features_ctx` to obtain read-only access to the DSP feature extraction context, so computed features can be used from the application.

* Updated:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Updated:
* Updated:

* :c:func:`nrf_edgeai_run_inference` keeps the previous single-call workflow working.
If features have not been processed yet, it invokes :c:func:`nrf_edgeai_process_features` internally and propagates its status code unchanged.

* Fixed:

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Suggested change
* Fixed:
* Fixed:

Replace the shared model_obsv module with per-model ww_obsv.c and kws_obsv.c, sizing metric storage per model and saving 1840 bytes. Set MAX_CLASSES and MEMFAULT_MAX_CONTEXTS in observability.conf.

Signed-off-by: Raman Rusak <raman.rusak@nordicsemi.no>
changelog fixes

Signed-off-by: Raman Rusak <raman.rusak@nordicsemi.no>
* extra DSP work.
*/
err = nrf_edgeai_process_features(ww_model);
if (err == NRF_EDGEAI_ERR_INPROGRESS) {

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't the NRF_EDGEAI_ERR_WRONG_STATE code be checked for a case that feature window is not complete yet? API doc: https://github.com/nrfconnect/sdk-edge-ai/pull/145/changes#diff-601d8fd4bb578bb6f2198666ccbc9bf852a2010da7e785f5acdbc8ef4cb014f2R75 - or maybe the header requires alignment?

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

but this statement will show if window was incomplete when calling this function
else if (err) {
LOG_ERR("Failed to process features (err %d)", err);
return -EPERM;
}

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

That's right, maybe just the comment below is misleading.

Comment thread applications/ww_kws/observability.conf Outdated
CONFIG_NRF_EDGEAI_OBSV_MEMFAULT_MAX_CONTEXTS=2

# All built-in metrics, applied to both models (the wakeword model's single output
# is expanded to a synthetic 2-class distribution in wakeword.c). Histograms at 16

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Now it's done in ww_obsv.c not in wakeword.c - maybe remove the source file name from the comment?


void kws_obsv_update_features(const float *feats, uint16_t n)
{
int err = nrf_edgeai_obsv_update_features(&ctx, feats, n);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Shouldn't n be checked against KWS_OBSV_FEATURES?


void ww_obsv_update_features(const float *feats, uint16_t n)
{
int err = nrf_edgeai_obsv_update_features(&ctx, feats, n);

Copy link
Copy Markdown
Collaborator

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

As https://github.com/nrfconnect/sdk-edge-ai/pull/145/changes#r3958873402, shouldn't n be checked against WW_OBSV_FEATURES?

validate feature count in kws_obsv and ww_obsv update functions

Signed-off-by: Raman Rusak <raman.rusak@nordicsemi.no>
@rrusak
rrusak requested a review from a team as a code owner September 10, 2026 13:21

@mbarchie mbarchie left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

a few compliance checks failing + history of commits need to be cleaned up before merging


#include <nrf_edgeai/nrf_edgeai.h>

/** @brief Create the observability context and metrics for the wakeword model. */

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

No param/return in doxygen for functions in ww_obsv.h and kws_obsv.h

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

doc-required PR must not be merged without tech writer approval.

Projects

None yet

Development

Successfully merging this pull request may close these issues.

5 participants