code wiki / (root) / nx_signal_compensator.nx

nx_signal_compensator.nx source

↩ module page · 182 lines · 10318 B

1// nx_signal_compensator.nx -- meta-level inverse-response DSP correction. 2// 3// module: nishi-core.perception.signal_compensator 4// depends: nishi-core.perception.profile + nishi-core.perception.transducer_characterizer + 5// nishi-core.io.syscalls 6// disk_kb: 5 7// capability: PERCEPTION 8// wired_status: PARTIAL_WIRED 9// 10// MISSING_CAPABILITIES: 11// - RESPONSE_CURVE_LOAD (deserialize stored response from provenance store; 12// queued, depends on nx_provenance_curve_store) 13// - INVERSE_RESPONSE_COMPUTE (regularized inverse, handles unstable nulls 14// in driver response per Kirkeby & Nelson 1999; queued, depends on 15// nx_fft + Tikhonov regularization) 16// - TEMPORAL_FILTER_DESIGN (FIR or minimum-phase IIR from inverse curve) 17// - SPATIAL_FILTER_DESIGN (gamma LUT / color matrix for visual transducers) 18// - REAL_TIME_APPLY_TEMPORAL (convolution at render time for audio + vibration) 19// - REAL_TIME_APPLY_SPATIAL (LUT lookup at render time for visual) 20// 21// license_tier: PUBLIC_NISHI_SUBSTRATE 22// genealogy_id: feedback-substrate-primitives-meta-not-one-off_2026 + 23// feedback-substrate-does-heavy-lifting-user-is-partner-not-gate_2026 + 24// feedback-multi-species-perceptual-substrate-not-anthropocentric_2026 + 25// kirkeby_nelson_1999_inverse_filter_regularization + 26// mourjopoulos_1994_digital_equalization_room_response + 27// poynton_2003_gamma_correction + 28// feedback-build-intelligence-never-strip-features 29// 30// Per cardinal [[feedback-substrate-primitives-meta-not-one-off]]: 31// THIS primitive applies inverse-response compensation to ANY signal chain — 32// not just audio rigs. Originally scoped as "rig_compensator" during dog 33// perceptual test bring-up, promoted to meta-level when reuse across 34// products surfaced. 35// 36// Reuse set served by this single primitive: 37// - Audio pre-correction (dog perceptual test, dog toy, vet stethoscope, 38// working-dog trainer, conservation recorder, beekeeping sensor) 39// - Display gamma + gamut correction (Nishi /video output to species-aware 40// displays) 41// - Vibration linearization (haptic motor in dog toy + other haptic outputs) 42// - Hydrophone pressure-response correction (aquaculture) 43// - Camera + photodiode response linearization (visual input) 44// - Thermal sensor calibration correction (vet diagnostics) 45// - Composite chain compensation when multiple transducers in series 46// 47// User invocation: implicit -- nx_audio_render / nx_video_render / 48// nx_haptic_render automatically invoke nx_signal_compensator_apply if a 49// valid response curve exists for the configured transducer. No user knob. 50// 51// THIS IS A PARTIAL_WIRED STUB. Sealed enums + function signatures + the 52// honest-verdict gate are wired now. Downstream callers can compose against 53// the stable interface; substrate returns DEPENDENCY_MISSING until the 54// FFT + regularizer + filter-design layer lands. 55 56import "nx_syscalls.nx" 57import "nx_perceptual_profile.nx" 58import "nx_transducer_characterizer.nx" 59 60// ===== Signal domain sealed enum (meta — covers full reuse set) === 61 62const NX_SIG_DOMAIN_TEMPORAL_AUDIO: i64 = 1 // time-domain audio 63const NX_SIG_DOMAIN_TEMPORAL_VIBRATION: i64 = 2 // haptic, accel 64const NX_SIG_DOMAIN_TEMPORAL_SCALAR: i64 = 3 // single-channel scalar (thermal, pressure) 65const NX_SIG_DOMAIN_TEMPORAL_MULTICHANNEL: i64 = 4 // N-channel sensor array 66const NX_SIG_DOMAIN_SPATIAL_VISUAL: i64 = 5 // image, display pixels 67const NX_SIG_DOMAIN_SPATIO_TEMPORAL_VIDEO: i64 = 6 // frame sequence 68 69func nx_sig_domain_name(d: i64) -> *u8 { 70 if d == NX_SIG_DOMAIN_TEMPORAL_AUDIO { return "TEMPORAL_AUDIO" } 71 if d == NX_SIG_DOMAIN_TEMPORAL_VIBRATION { return "TEMPORAL_VIBRATION" } 72 if d == NX_SIG_DOMAIN_TEMPORAL_SCALAR { return "TEMPORAL_SCALAR" } 73 if d == NX_SIG_DOMAIN_TEMPORAL_MULTICHANNEL { return "TEMPORAL_MULTICHANNEL" } 74 if d == NX_SIG_DOMAIN_SPATIAL_VISUAL { return "SPATIAL_VISUAL" } 75 if d == NX_SIG_DOMAIN_SPATIO_TEMPORAL_VIDEO { return "SPATIO_TEMPORAL_VIDEO" } 76 return "UNKNOWN_DOMAIN" 77} 78 79// ===== Compensation strategy sealed enum ========================== 80// 81// Different strategies trade latency, artifacts, stability per domain. 82// Substrate picks domain-appropriate default; caller can override. 83 84const NX_SIG_COMP_NONE: i64 = 0 // disabled; pass-through 85const NX_SIG_COMP_MINIMUM_PHASE_IIR: i64 = 1 // audio default, low-latency 86const NX_SIG_COMP_LINEAR_PHASE_FIR: i64 = 2 // audio phase-preserving 87const NX_SIG_COMP_REGULARIZED_INVERSE: i64 = 3 // Kirkeby-Nelson 1999 for 88 // noisy / peaky response 89const NX_SIG_COMP_PARAMETRIC_EQ: i64 = 4 // biquad chain, lowest CPU 90const NX_SIG_COMP_GAMMA_LUT_1D: i64 = 5 // visual: per-channel gamma 91const NX_SIG_COMP_COLOR_MATRIX_3X3: i64 = 6 // visual: cross-channel gamut 92const NX_SIG_COMP_3D_LUT: i64 = 7 // visual: full color transform 93const NX_SIG_COMP_TIME_DELAY: i64 = 8 // scalar: response-time 94 // correction 95const NX_SIG_COMP_POLYNOMIAL_LINEARIZE: i64 = 9 // scalar: nonlinear sensor 96 // correction 97 98func nx_sig_comp_strategy_name(s: i64) -> *u8 { 99 if s == NX_SIG_COMP_NONE { return "NONE" } 100 if s == NX_SIG_COMP_MINIMUM_PHASE_IIR { return "MINIMUM_PHASE_IIR" } 101 if s == NX_SIG_COMP_LINEAR_PHASE_FIR { return "LINEAR_PHASE_FIR" } 102 if s == NX_SIG_COMP_REGULARIZED_INVERSE { return "REGULARIZED_INVERSE" } 103 if s == NX_SIG_COMP_PARAMETRIC_EQ { return "PARAMETRIC_EQ" } 104 if s == NX_SIG_COMP_GAMMA_LUT_1D { return "GAMMA_LUT_1D" } 105 if s == NX_SIG_COMP_COLOR_MATRIX_3X3 { return "COLOR_MATRIX_3X3" } 106 if s == NX_SIG_COMP_3D_LUT { return "3D_LUT" } 107 if s == NX_SIG_COMP_TIME_DELAY { return "TIME_DELAY" } 108 if s == NX_SIG_COMP_POLYNOMIAL_LINEARIZE { return "POLYNOMIAL_LINEARIZE" } 109 return "UNKNOWN_STRATEGY" 110} 111 112// ===== Application verdicts ======================================= 113 114const NX_SIG_COMP_APPLIED: i64 = 0 115const NX_SIG_COMP_NOT_APPLIED_NO_CURVE: i64 = 1 // no response curve loaded 116const NX_SIG_COMP_NOT_APPLIED_STALE_CURVE: i64 = 2 // curve > 90 days old 117const NX_SIG_COMP_NOT_APPLIED_INSTABILITY: i64 = 3 // inverse would exceed headroom 118const NX_SIG_COMP_NOT_APPLIED_DOMAIN_MISMATCH: i64 = 4 // wrong strategy for domain 119const NX_SIG_COMP_NOT_APPLIED_DEPENDENCY_MISSING: i64 = 5 // PARTIAL_WIRED default 120 121func nx_sig_comp_verdict_name(v: i64) -> *u8 { 122 if v == NX_SIG_COMP_APPLIED { return "APPLIED" } 123 if v == NX_SIG_COMP_NOT_APPLIED_NO_CURVE { return "NOT_APPLIED_NO_CURVE" } 124 if v == NX_SIG_COMP_NOT_APPLIED_STALE_CURVE { return "NOT_APPLIED_STALE_CURVE" } 125 if v == NX_SIG_COMP_NOT_APPLIED_INSTABILITY { return "NOT_APPLIED_INSTABILITY" } 126 if v == NX_SIG_COMP_NOT_APPLIED_DOMAIN_MISMATCH { return "NOT_APPLIED_DOMAIN_MISMATCH" } 127 if v == NX_SIG_COMP_NOT_APPLIED_DEPENDENCY_MISSING { return "NOT_APPLIED_DEPENDENCY_MISSING" } 128 return "UNKNOWN_COMP_VERDICT" 129} 130 131// ===== Top-level entry stubs ====================================== 132 133// nx_signal_compensator_apply -- called by nx_audio_render / nx_video_render 134// / nx_haptic_render automatically. Given samples + transducer name + 135// signal domain + strategy, applies inverse-response correction in place. 136 137func nx_signal_compensator_apply(samples_ptr: *u8, samples_len: i64, 138 txr_name_ptr: *u8, txr_name_len: i64, 139 domain: i64, strategy: i64) -> i64 { 140 if samples_len <= 0 { return NX_SIG_COMP_NOT_APPLIED_NO_CURVE } 141 if txr_name_len <= 0 { return NX_SIG_COMP_NOT_APPLIED_NO_CURVE } 142 if domain < NX_SIG_DOMAIN_TEMPORAL_AUDIO { return NX_SIG_COMP_NOT_APPLIED_DOMAIN_MISMATCH } 143 if domain > NX_SIG_DOMAIN_SPATIO_TEMPORAL_VIDEO { return NX_SIG_COMP_NOT_APPLIED_DOMAIN_MISMATCH } 144 if strategy < NX_SIG_COMP_NONE { return NX_SIG_COMP_NOT_APPLIED_DEPENDENCY_MISSING } 145 if strategy > NX_SIG_COMP_POLYNOMIAL_LINEARIZE { return NX_SIG_COMP_NOT_APPLIED_DEPENDENCY_MISSING } 146 if strategy == NX_SIG_COMP_NONE { return NX_SIG_COMP_APPLIED } // honest no-op 147 // PARTIAL_WIRED: dependencies not yet landed. 148 return NX_SIG_COMP_NOT_APPLIED_DEPENDENCY_MISSING 149} 150 151// nx_signal_compensator_default_strategy_for_domain -- substrate picks 152// domain-appropriate default; caller can override. 153 154func nx_signal_compensator_default_strategy_for_domain(domain: i64) -> i64 { 155 if domain == NX_SIG_DOMAIN_TEMPORAL_AUDIO { return NX_SIG_COMP_MINIMUM_PHASE_IIR } 156 if domain == NX_SIG_DOMAIN_TEMPORAL_VIBRATION { return NX_SIG_COMP_PARAMETRIC_EQ } 157 if domain == NX_SIG_DOMAIN_TEMPORAL_SCALAR { return NX_SIG_COMP_POLYNOMIAL_LINEARIZE } 158 if domain == NX_SIG_DOMAIN_TEMPORAL_MULTICHANNEL { return NX_SIG_COMP_MINIMUM_PHASE_IIR } 159 if domain == NX_SIG_DOMAIN_SPATIAL_VISUAL { return NX_SIG_COMP_GAMMA_LUT_1D } 160 if domain == NX_SIG_DOMAIN_SPATIO_TEMPORAL_VIDEO { return NX_SIG_COMP_GAMMA_LUT_1D } 161 return NX_SIG_COMP_NONE 162} 163 164// nx_signal_compensator_disable -- explicitly turn off compensation for 165// diagnostic purposes (compare compensated vs uncompensated rendering). 166 167func nx_signal_compensator_disable(txr_name_ptr: *u8, txr_name_len: i64) -> i64 { 168 if txr_name_len <= 0 { return 0 } 169 return 1 170} 171 172// nx_signal_compensator_get_post_correction_flatness_dB10 -- inspector 173// that reports predicted post-correction flatness in dB×10 (e.g., 18 174// means ± 1.8 dB). Audio + vibration only; visual domain reports 175// delta-E instead, separate inspector. 176 177func nx_signal_compensator_get_post_correction_flatness_dB10(txr_name_ptr: *u8, 178 txr_name_len: i64) -> i64 { 179 if txr_name_len <= 0 { return -1 } 180 // PARTIAL_WIRED: depends on response load + inverse compute. 181 return -1 182}