/* adn426.h --------------------------------------------------------------- */
#ifndef ADN426_H_
#define ADN426_H_
#include <stdint.h>
#include <stddef.h>
#ifdef __cplusplus
extern "C"
#endif
/* Opaque context – allocate on the stack or static storage */
typedef struct ADN426_Context ADN426_Context;
/* Create a context; `window_sz` is the number of samples used for statistics.
Must be a power of two (e.g., 64, 128, 256). */
ADN426_Context *adn426_create(uint16_t window_sz);
/* Destroy a context allocated with `adn426_create`. */
void adn426_destroy(ADN426_Context *ctx);
/* Process a single sample (float) and obtain the normalized output. */
static inline float adn426_process(ADN426_Context *ctx, float sample);
/* Optional: retrieve the current scale factor for diagnostics. */
float adn426_get_scale(const ADN426_Context *ctx);
/* Optional: reset statistics without reallocating the context. */
void adn426_reset(ADN426_Context *ctx);
#ifdef __cplusplus
#endif
#endif /* ADN426_H_ */
/* adn426.c --------------------------------------------------------------- */
#include "adn426.h"
#include <math.h>
/* Internal structure – hidden from the user */
struct ADN426_Context
uint16_t win_mask; /* (window_sz - 1) for fast modulo */
uint16_t count; /* Samples processed so far */
float mean; /* Running mean (Welford) */
float M2; /* Sum of squares of differences */
float scale; /* Current scale factor */
float lut[256]; /* 256‑entry lookup table (auto‑tuned)*/
;
/* --------------------------------------------------------------------- */
ADN426_Context *adn426_create(uint16_t window_sz)
/* window_sz must be a power of two – fast check */
if ((window_sz == 0)
/* --------------------------------------------------------------------- */
void adn426_destroy(ADN426_Context *ctx)
free(ctx);
/* --------------------------------------------------------------------- */
static inline float adn426_process(ADN426_Context *ctx, float sample)
/* ---- 1️⃣ Update running statistics (Welford) -------------------- */
uint16_t n = ++ctx->count;
float delta = sample - ctx->mean;
ctx->mean += delta / n;
float delta2 = sample - ctx->mean;
ctx->M2 += delta * delta2; /* M2 = Σ (x - mean)² */
/* ---- 2️⃣ Compute variance & effective range ---------------------- */
float var = (n > 1) ? ctx->M2 / (n - 1) : 0.0f;
float sigma = sqrtf(var);
float range = 3.0f * sigma; /* k = 3 (≈99.7% of normal data) */
/* ---- 3️⃣ Select scale factor from LUT (branch‑free) ------------- */
/* Map `range` to an 8‑bit index: 0 → 0.0, 255 → max_range (configurable) */
uint8_t idx = (uint8_t)(range * (255.0f / 10.0f)); /* assuming max_range ≈10 */
ctx->scale = ctx->lut[idx];
/* ---- 4️⃣ Normalization (FMA if available) ------------------------ */
#if defined(__FMA__)
/* --------------------------------------------------------------------- */
float adn426_get_scale(const ADN426_Context *ctx)
return ctx->scale;
/* --------------------------------------------------------------------- */
void adn426_reset(ADN426_Context *ctx)
ctx->count = 0;
ctx->mean = 0.0f;
ctx->M2 = 0.0f;
ctx->scale = 1.0f;
All steps are branch‑free (except the optional table‑maintenance path) to guarantee deterministic execution.
5G mmWave base stations require deterministic sub-microsecond response times. The ADN426 C Exclusive’s isolated clock domains prevent cross-talk between hundreds of simultaneous user sessions. adn426 c exclusive