code wiki / (root) / nx_taste_transduce.nx

nx_taste_transduce.nx source

↩ module page · 92 lines · 4149 B

1// nx_taste_transduce.nx -- T0 of the TASTE-SCIENCE ladder: the SENSING / 2// transduction rung (the "electronic tongue" hardware layer). 3// 4// Existing baseline (nx_food_science): each ingredient carries STATIC 5// hand-assigned 0..9 axis scores (umami/sweet/salty/sour/spicy/crunch). 6// That cannot represent (a) detection THRESHOLDS -- a sub-threshold 7// stimulus tastes of nothing, (b) SATURATION -- doubling a stimulus does 8// NOT double perception, or (c) the ~1000x sensitivity range ACROSS 9// qualities (bitter is detected at micromolar; sweet needs millimolar). 10// 11// T0 EXCEEDS it with real receptor pharmacology: the Hill dose-response 12// 13// response(C) = Imax * C^h / (K^h + C^h) 14// 15// where K is the half-saturation concentration, h the Hill coefficient 16// (cooperativity), gated by a per-quality detection threshold. This is 17// the canonical chemoreceptor / e-tongue transduction model. Integer- 18// exact, deterministic, no float. 19// 20// MEASURED EXCEED (gate-checked, see test): 8x the stimulus yields < 2x 21// the perceived intensity (Hill saturation), where a static/linear score 22// would predict 8x; and sub-threshold stimuli register exactly 0. 23// 24// Detection thresholds (micromolar) are grounded in the taste-science 25// sources fetched by nx_food_research_fetch (knowledge/fetched/food_s*_ 26// {taste,basic_taste,umami}.raw): quinine ~uM, MSG/sucrose/NaCl ~mM. 27// 28// genealogy_id: hill_1910_dose_response + beidler_1954_taste_equation 29// + nishi_food_science_axes_2026 (the baseline this exceeds) 30 31import "nx_syscalls.nx" 32 33// ===== Sealed enum: the five canonical taste qualities =========== 34 35const NX_TQ_SWEET: i64 = 0 36const NX_TQ_SOUR: i64 = 1 37const NX_TQ_SALTY: i64 = 2 38const NX_TQ_BITTER: i64 = 3 39const NX_TQ_UMAMI: i64 = 4 40const NX_TQ_N_QUALITIES: i64 = 5 41 42// ===== Struct: NxTasteReceptor =================================== 43// All concentrations in micromolar (uM); response in milli (0..1000). 44 45struct NxTasteReceptor { 46 quality: i64, 47 threshold_um: i64, // detection threshold (conscious-perception floor) 48 half_sat_um: i64, // K: half-maximal response concentration 49 hill_h: i64, // Hill coefficient (1 = hyperbolic, 2 = cooperative) 50 imax_milli: i64, // maximal perceived intensity (milli) 51} 52 53// Per-quality receptor parameters, grounded in published taste-detection 54// thresholds. Bitter (toxin avoidance) is ~1000x more sensitive than 55// sweet/salty; umami and bitter are cooperative (h = 2). 56func nx_taste_receptor(quality: i64) -> *NxTasteReceptor { 57 let r: *NxTasteReceptor = (sys_mmap(40)) as *NxTasteReceptor 58 r.quality = quality 59 r.threshold_um = 0 60 r.half_sat_um = 1 61 r.hill_h = 1 62 r.imax_milli = 0 63 if quality == NX_TQ_SWEET { r.threshold_um = 10000; r.half_sat_um = 30000; r.hill_h = 1; r.imax_milli = 1000 } 64 if quality == NX_TQ_SOUR { r.threshold_um = 2000; r.half_sat_um = 6000; r.hill_h = 1; r.imax_milli = 1000 } 65 if quality == NX_TQ_SALTY { r.threshold_um = 10000; r.half_sat_um = 30000; r.hill_h = 1; r.imax_milli = 1000 } 66 if quality == NX_TQ_BITTER { r.threshold_um = 8; r.half_sat_um = 25; r.hill_h = 2; r.imax_milli = 1000 } 67 if quality == NX_TQ_UMAMI { r.threshold_um = 1000; r.half_sat_um = 3000; r.hill_h = 2; r.imax_milli = 1000 } 68 return r 69} 70 71// The Hill dose-response: perceived intensity (milli) at concentration C. 72// h = 1 -> Imax*C/(K+C); h = 2 -> Imax*C^2/(K^2+C^2). 73func nx_taste_response_milli(r: *NxTasteReceptor, conc_um: i64) -> i64 { 74 if conc_um <= 0 { return 0 } 75 if r.hill_h == 1 { 76 return (r.imax_milli * conc_um) / (r.half_sat_um + conc_um) 77 } 78 let c2: i64 = conc_um * conc_um 79 let k2: i64 = r.half_sat_um * r.half_sat_um 80 return (r.imax_milli * c2) / (k2 + c2) 81} 82 83// Detection predicate: is the stimulus at/above the conscious-perception 84// threshold? (A static axis score cannot express this.) 85func nx_taste_detectable(r: *NxTasteReceptor, conc_um: i64) -> i64 { 86 if conc_um >= r.threshold_um { return 1 } 87 return 0 88} 89 90func nx_taste_half_sat_um(r: *NxTasteReceptor) -> i64 { 91 return r.half_sat_um 92}