nx_transducer_characterizer.nx source
↩ module page · 212 lines · 11940 B
1// nx_transducer_characterizer.nx -- meta-level instrument characterization.
2//
3// module: nishi-core.perception.transducer_characterizer
4// depends: nishi-core.perception.profile + nishi-core.io.syscalls
5// disk_kb: 6
6// capability: PERCEPTION
7// wired_status: PARTIAL_WIRED
8//
9// MISSING_CAPABILITIES:
10// - STIMULUS_GENERATION (log-swept-sine, MLS, calibrated reference;
11// queued, depends on nx_synthesis_engine landing)
12// - FFT_RESPONSE_COMPUTE (FFT + cross-spectrum / auto-spectrum for
13// time-domain transducers; queued, depends on nx_fft landing)
14// - SPATIAL_RESPONSE_COMPUTE (gamma curves, gamut measurement,
15// spatial-frequency response for visual transducers)
16// - CALIBRATION_REFERENCE_APPLY (load stored reference-transducer
17// calibration and apply offset before response computation)
18// - PROVENANCE_STORE_WRITE (persist measured curve to provenance
19// curve store)
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// farina_2000_swept_sine_room_acoustics_aes +
26// schroeder_1979_mls_measurement +
27// poynton_2003_digital_video_image_systems +
28// feedback-end-to-end-bit-traceability-architecture
29//
30// Per cardinals [[feedback-substrate-primitives-meta-not-one-off]] and
31// [[feedback-substrate-does-heavy-lifting-user-is-partner-not-gate]]:
32// THIS primitive characterizes ANY transducer chain — audio output (DAC +
33// amp + speaker), audio input (mic + preamp + ADC), haptic motor, camera
34// sensor, accelerometer, display, thermocouple, gas/scent sensor, hydrophone,
35// even composite multi-stage chains. Originally scoped to a "rig" during
36// dog perceptual test bring-up, then promoted to meta-level when the user
37// surfaced reuse across products.
38//
39// Reuse set served by this single primitive:
40// - Dog perceptual test rig (first use, audio output FRF)
41// - Prey-spec dog toy production line (each shipped toy characterized)
42// - Livestock acoustic welfare sensors (audio input FRF)
43// - Conservation acoustic recorders (audio input + filter chain)
44// - Veterinary diagnostic stethoscopes (audio input low-frequency)
45// - Working-dog training devices (audio output FRF)
46// - Beekeeping hive sensors (vibration input)
47// - Aquaculture hydrophones (audio input + pressure-equivalent)
48// - Nishi /video pipeline (camera + display + mic + speaker)
49// - Nishi field-recording sensor suite
50// - nishi-silicon test bench when silicon ships
51//
52// User invocation (substrate hides product-domain specifics):
53// nishi transducer-characterize <transducer_name> --kind <KIND> --stim <STIM>
54//
55// THIS IS A PARTIAL_WIRED STUB. Sealed enums + function signatures + the
56// honest-verdict gate are wired so downstream callers can compose against
57// stable shapes while the FFT + stimulus generator + persistence layer lands.
58
59import "nx_syscalls.nx"
60import "nx_perceptual_profile.nx"
61
62// ===== Transducer kind sealed enum (meta — covers full reuse set) =
63
64const NX_TXR_KIND_AUDIO_OUTPUT: i64 = 1 // DAC + amp + speaker chain
65const NX_TXR_KIND_AUDIO_INPUT: i64 = 2 // mic + preamp + ADC chain
66const NX_TXR_KIND_VIBRATION_OUTPUT: i64 = 3 // haptic motor, LRA, ERM
67const NX_TXR_KIND_VIBRATION_INPUT: i64 = 4 // accelerometer, geophone
68const NX_TXR_KIND_VISUAL_OUTPUT: i64 = 5 // display, LED matrix, projector
69const NX_TXR_KIND_VISUAL_INPUT: i64 = 6 // camera sensor, photodiode array
70const NX_TXR_KIND_THERMAL_OUTPUT: i64 = 7 // Peltier, resistive heater
71const NX_TXR_KIND_THERMAL_INPUT: i64 = 8 // thermocouple, IR sensor, RTD
72const NX_TXR_KIND_PRESSURE_INPUT: i64 = 9 // pressure sensor, hydrophone
73const NX_TXR_KIND_CHEMICAL_INPUT: i64 = 10 // gas / scent / volatile sensor
74const NX_TXR_KIND_CHEMICAL_OUTPUT: i64 = 11 // scent cartridge dispense
75const NX_TXR_KIND_ELECTRICAL_LOOPBACK: i64 = 12 // pure electrical, no air gap
76const NX_TXR_KIND_ROOM_ACOUSTIC: i64 = 13 // room itself as transducer
77 // (reverb characterization)
78const NX_TXR_KIND_COMPOSITE_CHAIN: i64 = 14 // multi-stage, user-defined
79
80func nx_txr_kind_name(k: i64) -> *u8 {
81 if k == NX_TXR_KIND_AUDIO_OUTPUT { return "AUDIO_OUTPUT" }
82 if k == NX_TXR_KIND_AUDIO_INPUT { return "AUDIO_INPUT" }
83 if k == NX_TXR_KIND_VIBRATION_OUTPUT { return "VIBRATION_OUTPUT" }
84 if k == NX_TXR_KIND_VIBRATION_INPUT { return "VIBRATION_INPUT" }
85 if k == NX_TXR_KIND_VISUAL_OUTPUT { return "VISUAL_OUTPUT" }
86 if k == NX_TXR_KIND_VISUAL_INPUT { return "VISUAL_INPUT" }
87 if k == NX_TXR_KIND_THERMAL_OUTPUT { return "THERMAL_OUTPUT" }
88 if k == NX_TXR_KIND_THERMAL_INPUT { return "THERMAL_INPUT" }
89 if k == NX_TXR_KIND_PRESSURE_INPUT { return "PRESSURE_INPUT" }
90 if k == NX_TXR_KIND_CHEMICAL_INPUT { return "CHEMICAL_INPUT" }
91 if k == NX_TXR_KIND_CHEMICAL_OUTPUT { return "CHEMICAL_OUTPUT" }
92 if k == NX_TXR_KIND_ELECTRICAL_LOOPBACK { return "ELECTRICAL_LOOPBACK" }
93 if k == NX_TXR_KIND_ROOM_ACOUSTIC { return "ROOM_ACOUSTIC" }
94 if k == NX_TXR_KIND_COMPOSITE_CHAIN { return "COMPOSITE_CHAIN" }
95 return "UNKNOWN_KIND"
96}
97
98// ===== Stimulus type sealed enum ==================================
99//
100// Different transducer kinds accept different stimuli; substrate selects
101// appropriate stimulus generator per kind, but caller can override.
102
103const NX_TXR_STIM_LOG_SWEPT_SINE: i64 = 1 // audio + vibration default
104const NX_TXR_STIM_LIN_SWEPT_SINE: i64 = 2
105const NX_TXR_STIM_MLS: i64 = 3 // Schroeder 1979
106const NX_TXR_STIM_PINK_NOISE: i64 = 4
107const NX_TXR_STIM_WHITE_NOISE: i64 = 5
108const NX_TXR_STIM_TONE_BURST: i64 = 6
109const NX_TXR_STIM_KNOWN_REFERENCE: i64 = 7 // bit-identical reference signal
110const NX_TXR_STIM_TEST_PATTERN: i64 = 8 // visual transducer: gradient,
111 // color bars, checkerboard, etc.
112const NX_TXR_STIM_STEP_RESPONSE: i64 = 9 // thermal default
113const NX_TXR_STIM_GAS_BOLUS: i64 = 10 // chemical: known
114 // concentration injection
115const NX_TXR_STIM_PRESSURE_RAMP: i64 = 11 // pressure transducer
116
117func nx_txr_stim_name(s: i64) -> *u8 {
118 if s == NX_TXR_STIM_LOG_SWEPT_SINE { return "LOG_SWEPT_SINE" }
119 if s == NX_TXR_STIM_LIN_SWEPT_SINE { return "LIN_SWEPT_SINE" }
120 if s == NX_TXR_STIM_MLS { return "MLS" }
121 if s == NX_TXR_STIM_PINK_NOISE { return "PINK_NOISE" }
122 if s == NX_TXR_STIM_WHITE_NOISE { return "WHITE_NOISE" }
123 if s == NX_TXR_STIM_TONE_BURST { return "TONE_BURST" }
124 if s == NX_TXR_STIM_KNOWN_REFERENCE { return "KNOWN_REFERENCE" }
125 if s == NX_TXR_STIM_TEST_PATTERN { return "TEST_PATTERN" }
126 if s == NX_TXR_STIM_STEP_RESPONSE { return "STEP_RESPONSE" }
127 if s == NX_TXR_STIM_GAS_BOLUS { return "GAS_BOLUS" }
128 if s == NX_TXR_STIM_PRESSURE_RAMP { return "PRESSURE_RAMP" }
129 return "UNKNOWN_STIM"
130}
131
132// ===== Characterization verdicts ==================================
133
134const NX_TXR_VERDICT_PASS: i64 = 0
135const NX_TXR_VERDICT_MARGINAL: i64 = 1 // measurable but compensable
136const NX_TXR_VERDICT_FAIL_REPAIRABLE: i64 = 2 // diagnostic emitted a fix
137const NX_TXR_VERDICT_FAIL_UNRECOVERABLE: i64 = 3 // transducer physically broken
138const NX_TXR_VERDICT_REFERENCE_MISSING: i64 = 4 // no calibrated reference loaded
139const NX_TXR_VERDICT_DEPENDENCY_MISSING: i64 = 5 // PARTIAL_WIRED default
140
141func nx_txr_verdict_name(v: i64) -> *u8 {
142 if v == NX_TXR_VERDICT_PASS { return "PASS" }
143 if v == NX_TXR_VERDICT_MARGINAL { return "MARGINAL" }
144 if v == NX_TXR_VERDICT_FAIL_REPAIRABLE { return "FAIL_REPAIRABLE" }
145 if v == NX_TXR_VERDICT_FAIL_UNRECOVERABLE { return "FAIL_UNRECOVERABLE" }
146 if v == NX_TXR_VERDICT_REFERENCE_MISSING { return "REFERENCE_MISSING" }
147 if v == NX_TXR_VERDICT_DEPENDENCY_MISSING { return "DEPENDENCY_MISSING" }
148 return "UNKNOWN_VERDICT"
149}
150
151// ===== Top-level entry stubs ======================================
152
153// nx_transducer_characterize -- drive a stimulus through the named transducer
154// and return a verdict. Full implementation persists measured response
155// curve + diagnostics to nx_provenance_curve_store. Stub returns
156// DEPENDENCY_MISSING until supporting layer lands.
157
158func nx_transducer_characterize(name_ptr: *u8, name_len: i64,
159 kind: i64, stimulus: i64,
160 range_lo: i64, range_hi: i64) -> i64 {
161 if name_len <= 0 { return NX_TXR_VERDICT_FAIL_UNRECOVERABLE }
162 if kind < NX_TXR_KIND_AUDIO_OUTPUT { return NX_TXR_VERDICT_FAIL_UNRECOVERABLE }
163 if kind > NX_TXR_KIND_COMPOSITE_CHAIN { return NX_TXR_VERDICT_FAIL_UNRECOVERABLE }
164 if stimulus < NX_TXR_STIM_LOG_SWEPT_SINE { return NX_TXR_VERDICT_FAIL_UNRECOVERABLE }
165 if stimulus > NX_TXR_STIM_PRESSURE_RAMP { return NX_TXR_VERDICT_FAIL_UNRECOVERABLE }
166 if range_lo < 0 { return NX_TXR_VERDICT_FAIL_UNRECOVERABLE }
167 if range_hi <= range_lo { return NX_TXR_VERDICT_FAIL_UNRECOVERABLE }
168 // PARTIAL_WIRED: dependencies not yet landed.
169 return NX_TXR_VERDICT_DEPENDENCY_MISSING
170}
171
172// nx_transducer_apply_reference_calibration -- load a stored calibration
173// curve for the reference transducer (e.g., the verification mic that
174// characterizes the speaker; or the calibrated gray-card that
175// characterizes the camera).
176
177func nx_transducer_apply_reference_calibration(ref_name_ptr: *u8,
178 ref_name_len: i64) -> i64 {
179 if ref_name_len <= 0 { return 0 }
180 return 0
181}
182
183// nx_transducer_get_last_verdict -- inspector for the most recent
184// characterization run. nx_signal_compensator queries this before
185// applying compensation.
186
187func nx_transducer_get_last_verdict(name_ptr: *u8, name_len: i64) -> i64 {
188 if name_len <= 0 { return NX_TXR_VERDICT_REFERENCE_MISSING }
189 return NX_TXR_VERDICT_REFERENCE_MISSING
190}
191
192// nx_transducer_default_stimulus_for_kind -- helper picking the
193// substrate-recommended stimulus for a given transducer kind.
194// User can override at call time.
195
196func nx_transducer_default_stimulus_for_kind(kind: i64) -> i64 {
197 if kind == NX_TXR_KIND_AUDIO_OUTPUT { return NX_TXR_STIM_LOG_SWEPT_SINE }
198 if kind == NX_TXR_KIND_AUDIO_INPUT { return NX_TXR_STIM_LOG_SWEPT_SINE }
199 if kind == NX_TXR_KIND_VIBRATION_OUTPUT { return NX_TXR_STIM_LOG_SWEPT_SINE }
200 if kind == NX_TXR_KIND_VIBRATION_INPUT { return NX_TXR_STIM_LOG_SWEPT_SINE }
201 if kind == NX_TXR_KIND_VISUAL_OUTPUT { return NX_TXR_STIM_TEST_PATTERN }
202 if kind == NX_TXR_KIND_VISUAL_INPUT { return NX_TXR_STIM_TEST_PATTERN }
203 if kind == NX_TXR_KIND_THERMAL_OUTPUT { return NX_TXR_STIM_STEP_RESPONSE }
204 if kind == NX_TXR_KIND_THERMAL_INPUT { return NX_TXR_STIM_STEP_RESPONSE }
205 if kind == NX_TXR_KIND_PRESSURE_INPUT { return NX_TXR_STIM_PRESSURE_RAMP }
206 if kind == NX_TXR_KIND_CHEMICAL_INPUT { return NX_TXR_STIM_GAS_BOLUS }
207 if kind == NX_TXR_KIND_CHEMICAL_OUTPUT { return NX_TXR_STIM_GAS_BOLUS }
208 if kind == NX_TXR_KIND_ELECTRICAL_LOOPBACK { return NX_TXR_STIM_LOG_SWEPT_SINE }
209 if kind == NX_TXR_KIND_ROOM_ACOUSTIC { return NX_TXR_STIM_MLS }
210 if kind == NX_TXR_KIND_COMPOSITE_CHAIN { return NX_TXR_STIM_LOG_SWEPT_SINE }
211 return NX_TXR_STIM_LOG_SWEPT_SINE
212}