code wiki / _hdl_build / nx_aec.nx
nx_aec.nx
buildroot/runtime/_hdl_build/nx_aec.nx
about
nx_aec.nx -- R4a: sovereign Acoustic Echo Canceller. The reserved-but-empty nx_aec slot in
nx_audio_session, now built. Adaptive FIR (NLMS) in INTEGER fixed-point (NO-FLOAT doctrine):
it learns the echo path (speaker->room->mic) from the far-end reference and subtracts the
predicted echo from the mic signal, so the far end doesn't hear itself.
y[n] = (sum_k w[k]*x[n-k]) >> Qw (predicted echo from far-end reference x)
e[n] = d[n] - y[n] (mic d minus predicted echo = the cleaned output)
w[k] += mu * e[n] * x[n-k] / (||x||^2 + eps) (NLMS update, normalized step)
MEASURED metric = ERLE (Echo Return Loss Enhancement) = echo power BEFORE / AFTER cancel.
Negative controls: (T2) adaptation OFF -> e==d -> no cancellation (the filter is load-bearing);
(T3) DOUBLE-TALK -- with the converged filter frozen, near-end speech must SURVIVE while the
echo is removed (a broken AEC would crush the near-end too); (T4) ERLE improves over time (it LEARNS).
main() is the SELF-VALIDATING GATE. Evidence -> knowledge/status/aec.log.
license_tier: ORIGINAL
dependencies 1 imports · 2 importers
imports: nx_syscalls.nx
imported by: nx_aec_dtd_gate.nxnx_aec_gate.nx
call flow from main pre-order; caps 40 nodes / depth 6 declared; ↻ = already shown
structs
| none |
consts
| 18 | const AEC_MAGIC_12000: i64 = 12000 |
| 19 | const AEC_MAGIC_2000: i64 = 2000 |
| 20 | const AEC_MAGIC_13579: i64 = 13579 |
| 21 | const AEC_MAGIC_1103515245: i64 = 1103515245 |
| 22 | const AEC_MAGIC_12345: i64 = 12345 |
| 23 | const AEC_MAGIC_16001: i64 = 16001 |
| 24 | const AEC_MAGIC_8000: i64 = 8000 |
| 25 | const AEC_MAGIC_24680: i64 = 24680 |
| 26 | const AEC_MAGIC_12001: i64 = 12001 |
| 27 | const AEC_MAGIC_6000: i64 = 6000 |
| 28 | const AEC_MAGIC_26214: i64 = 26214 |
| 29 | const AEC_MAGIC_16384: i64 = 16384 |
| 30 | const AEC_MAGIC_9830: i64 = 9830 |
| 31 | const AEC_MAGIC_6554: i64 = 6554 |
| 32 | const AEC_MAGIC_3277: i64 = 3277 |
| 33 | const AEC_MAGIC_1966: i64 = 1966 |
| 35 | const AEC_LOG: *u8 = "knowledge/status/aec.log" |
| 36 | const QW: i64 = 16 // filter coeff fixed-point |
| 37 | const MU_NUM: i64 = 1 |
| 38 | const MU_DEN: i64 = 2 // mu = 0.5 (stable) |
| 39 | const EPS: i64 = 256 |
functions
| 41 | func aw(fd: i64, s: *u8) -> i64 { var n: i64=0; while s[n]!=(0 as u8){n=n+1} sys_write(fd,s,n); return 0 } |
| 42 | func awn(fd: i64, v: i64) -> i64 { let bb: *u8=sys_mmap(28); var m: i64=v; if m<0{m=0-m;sys_write(fd,"-" as *u8,1)} let t: *u8=sys_mmap(28); var k: i64=0; if m==0{t[0]=48 as u8;k=1} while m>0{t[k]=(48+(m%10)) as u8;m=m/10;k=k+1} var i: i64=0; while i<k{bb[i]=t[k-1-i];i=i+1} sys_write(fd,bb,k); return 0 } |
| 45 | func aec_run(w: *i64, x: *i64, d: *i64, e: *i64, T: i64, L: i64, adapt: i64) -> i64 |
| 71 | func powwin(a: *i64, start: i64, n: i64) -> i64 { var s: i64=0; var i: i64=start; while i < start+n { s = s + a[i]*a[i]; i=i+1 } return s } called by 1: main |
| 73 | func powdiff(a: *i64, b: *i64, start: i64, n: i64) -> i64 { var s: i64=0; var i: i64=start; while i < start+n { let dd: i64=a[i]-b[i]; s = s + dd*dd; i=i+1 } return s } called by 1: main |
| 75 | func erle_db(ratio: i64) -> i64 called by 1: main |
| 87 | func aec_run_dtd(w: *i64, x: *i64, d: *i64, e: *i64, T: i64, L: i64, dtd_thresh_q8: i64, hang: i64) -> i64 |
| 112 | func main() -> i64 |