eml-stdlib 0.4.0__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (185) hide show
  1. eml_stdlib/__init__.py +81 -0
  2. eml_stdlib/ballistics/air_density.eml +73 -0
  3. eml_stdlib/ballistics/ballistic_solver.eml +102 -0
  4. eml_stdlib/ballistics/coriolis.eml +60 -0
  5. eml_stdlib/ballistics/drag.eml +44 -0
  6. eml_stdlib/ballistics/gravity.eml +52 -0
  7. eml_stdlib/ballistics/muzzle_velocity.eml +42 -0
  8. eml_stdlib/ballistics/spin_drift.eml +60 -0
  9. eml_stdlib/ballistics/time_of_flight.eml +79 -0
  10. eml_stdlib/ballistics/wind.eml +58 -0
  11. eml_stdlib/biology/abilities/ballistic_armor.eml +61 -0
  12. eml_stdlib/biology/abilities/bite_force.eml +48 -0
  13. eml_stdlib/biology/abilities/chromatophore.eml +50 -0
  14. eml_stdlib/biology/abilities/discharge.eml +45 -0
  15. eml_stdlib/biology/abilities/elastic_energy.eml +42 -0
  16. eml_stdlib/biology/abilities/locomotion.eml +50 -0
  17. eml_stdlib/biology/abilities/muscle_power.eml +47 -0
  18. eml_stdlib/biology/abilities/sprint.eml +36 -0
  19. eml_stdlib/biology/abilities/texture_match.eml +49 -0
  20. eml_stdlib/biology/abilities/toxin.eml +44 -0
  21. eml_stdlib/biology/cone_l.eml +36 -0
  22. eml_stdlib/biology/cone_s.eml +32 -0
  23. eml_stdlib/biology/cryptochrome.eml +44 -0
  24. eml_stdlib/biology/geomagnetic_field.eml +32 -0
  25. eml_stdlib/biology/goldman_equation.eml +41 -0
  26. eml_stdlib/biology/hill_equation.eml +65 -0
  27. eml_stdlib/biology/hodgkin_huxley.eml +108 -0
  28. eml_stdlib/biology/michaelis_menten.eml +65 -0
  29. eml_stdlib/biology/plume_diffusion.eml +47 -0
  30. eml_stdlib/biology/receptor_binding.eml +35 -0
  31. eml_stdlib/biology/rod_sensitivity.eml +38 -0
  32. eml_stdlib/biology/tapetum.eml +70 -0
  33. eml_stdlib/carriers/acoustic_cloak.eml +56 -0
  34. eml_stdlib/carriers/ferron_emission.eml +55 -0
  35. eml_stdlib/carriers/ferron_logic.eml +45 -0
  36. eml_stdlib/carriers/ferron_propagation.eml +69 -0
  37. eml_stdlib/carriers/mach_zehnder.eml +52 -0
  38. eml_stdlib/carriers/magnon_dispersion.eml +57 -0
  39. eml_stdlib/carriers/magnon_logic.eml +45 -0
  40. eml_stdlib/carriers/optical_neuron.eml +55 -0
  41. eml_stdlib/carriers/phonon_bandgap.eml +54 -0
  42. eml_stdlib/carriers/ring_resonator.eml +48 -0
  43. eml_stdlib/carriers/spin_torque.eml +61 -0
  44. eml_stdlib/carriers/thermal_rectifier.eml +63 -0
  45. eml_stdlib/catalog.json +4209 -0
  46. eml_stdlib/circuits/buck_converter.eml +74 -0
  47. eml_stdlib/circuits/cmos_inverter.eml +75 -0
  48. eml_stdlib/circuits/h_bridge.eml +69 -0
  49. eml_stdlib/circuits/ldo.eml +66 -0
  50. eml_stdlib/circuits/mosfet_iv.eml +59 -0
  51. eml_stdlib/circuits/pll_loop.eml +63 -0
  52. eml_stdlib/circuits/rc_filter.eml +98 -0
  53. eml_stdlib/circuits/voltage_divider.eml +68 -0
  54. eml_stdlib/control/bangbang.eml +34 -0
  55. eml_stdlib/control/deadband.eml +28 -0
  56. eml_stdlib/control/hysteresis.eml +28 -0
  57. eml_stdlib/control/kalman_1d.eml +53 -0
  58. eml_stdlib/control/lqr_1d.eml +47 -0
  59. eml_stdlib/control/pid.eml +38 -0
  60. eml_stdlib/gaming/animation/bounce.eml +39 -0
  61. eml_stdlib/gaming/animation/ease_in.eml +27 -0
  62. eml_stdlib/gaming/animation/ease_in_out.eml +29 -0
  63. eml_stdlib/gaming/animation/ease_out.eml +27 -0
  64. eml_stdlib/gaming/animation/ik_2bone.eml +57 -0
  65. eml_stdlib/gaming/animation/spring.eml +39 -0
  66. eml_stdlib/gaming/audio/distance_attenuation.eml +50 -0
  67. eml_stdlib/gaming/audio/doppler.eml +39 -0
  68. eml_stdlib/gaming/audio/lowpass_audio.eml +32 -0
  69. eml_stdlib/gaming/audio/reverb_delay.eml +41 -0
  70. eml_stdlib/gaming/camera/dof_blur.eml +30 -0
  71. eml_stdlib/gaming/camera/fov_projection.eml +47 -0
  72. eml_stdlib/gaming/camera/orbit.eml +48 -0
  73. eml_stdlib/gaming/camera/shake.eml +20 -0
  74. eml_stdlib/gaming/lighting/ambient_occlusion.eml +40 -0
  75. eml_stdlib/gaming/lighting/area_light.eml +50 -0
  76. eml_stdlib/gaming/lighting/fog_exp.eml +28 -0
  77. eml_stdlib/gaming/lighting/fog_exp2.eml +30 -0
  78. eml_stdlib/gaming/lighting/point_light.eml +33 -0
  79. eml_stdlib/gaming/lighting/spot_light.eml +43 -0
  80. eml_stdlib/gaming/noise/fbm.eml +65 -0
  81. eml_stdlib/gaming/noise/perlin_2d.eml +65 -0
  82. eml_stdlib/gaming/noise/perlin_3d.eml +63 -0
  83. eml_stdlib/gaming/noise/simplex_2d.eml +67 -0
  84. eml_stdlib/gaming/noise/turbulence.eml +46 -0
  85. eml_stdlib/gaming/noise/value_noise.eml +45 -0
  86. eml_stdlib/gaming/noise/voronoi_2d.eml +83 -0
  87. eml_stdlib/gaming/noise/white_noise.eml +47 -0
  88. eml_stdlib/gaming/noise/worley.eml +79 -0
  89. eml_stdlib/gaming/particles/drag.eml +30 -0
  90. eml_stdlib/gaming/particles/emitter_radial.eml +35 -0
  91. eml_stdlib/gaming/particles/fade.eml +36 -0
  92. eml_stdlib/gaming/particles/gravity_particle.eml +32 -0
  93. eml_stdlib/gaming/particles/size_over_life.eml +28 -0
  94. eml_stdlib/gaming/physics/aabb_overlap.eml +38 -0
  95. eml_stdlib/gaming/physics/buoyancy.eml +43 -0
  96. eml_stdlib/gaming/physics/circle_collision.eml +46 -0
  97. eml_stdlib/gaming/physics/impulse_resolve.eml +39 -0
  98. eml_stdlib/gaming/physics/rigid_body_2d.eml +61 -0
  99. eml_stdlib/gaming/physics/spring_damper.eml +30 -0
  100. eml_stdlib/gaming/physics/verlet.eml +29 -0
  101. eml_stdlib/gaming/shading/fresnel.eml +57 -0
  102. eml_stdlib/gaming/shading/matcap.eml +34 -0
  103. eml_stdlib/gaming/shading/pbr_diffuse.eml +41 -0
  104. eml_stdlib/gaming/shading/pbr_specular.eml +75 -0
  105. eml_stdlib/gaming/shading/subsurface.eml +52 -0
  106. eml_stdlib/gaming/shading/toon.eml +30 -0
  107. eml_stdlib/gaming/terrain/biome_select.eml +41 -0
  108. eml_stdlib/gaming/terrain/cliff_detect.eml +35 -0
  109. eml_stdlib/gaming/terrain/erosion_hydraulic.eml +57 -0
  110. eml_stdlib/gaming/terrain/erosion_thermal.eml +44 -0
  111. eml_stdlib/gaming/terrain/heightmap.eml +33 -0
  112. eml_stdlib/gaming/textures/brick.eml +27 -0
  113. eml_stdlib/gaming/textures/caustics.eml +25 -0
  114. eml_stdlib/gaming/textures/checkerboard.eml +27 -0
  115. eml_stdlib/gaming/textures/fire.eml +26 -0
  116. eml_stdlib/gaming/textures/marble.eml +24 -0
  117. eml_stdlib/gaming/textures/rust.eml +23 -0
  118. eml_stdlib/gaming/textures/water_surface.eml +49 -0
  119. eml_stdlib/gaming/textures/wood.eml +41 -0
  120. eml_stdlib/math/abs.eml +45 -0
  121. eml_stdlib/math/atan.eml +32 -0
  122. eml_stdlib/math/atan2.eml +61 -0
  123. eml_stdlib/math/bessel_j0.eml +65 -0
  124. eml_stdlib/math/cos.eml +42 -0
  125. eml_stdlib/math/cosh.eml +24 -0
  126. eml_stdlib/math/erf.eml +66 -0
  127. eml_stdlib/math/exp.eml +49 -0
  128. eml_stdlib/math/gamma.eml +55 -0
  129. eml_stdlib/math/gaussian.eml +18 -0
  130. eml_stdlib/math/log.eml +59 -0
  131. eml_stdlib/math/pow.eml +51 -0
  132. eml_stdlib/math/relu.eml +63 -0
  133. eml_stdlib/math/sigmoid.eml +21 -0
  134. eml_stdlib/math/sin.eml +37 -0
  135. eml_stdlib/math/sinh.eml +24 -0
  136. eml_stdlib/math/softmax.eml +87 -0
  137. eml_stdlib/math/sqrt.eml +46 -0
  138. eml_stdlib/math/tan.eml +36 -0
  139. eml_stdlib/math/tanh.eml +54 -0
  140. eml_stdlib/ml/attention.eml +70 -0
  141. eml_stdlib/ml/cross_entropy.eml +85 -0
  142. eml_stdlib/ml/gelu.eml +51 -0
  143. eml_stdlib/ml/layernorm.eml +49 -0
  144. eml_stdlib/ml/leaky_relu.eml +51 -0
  145. eml_stdlib/ml/relu.eml +63 -0
  146. eml_stdlib/ml/rotary_embed.eml +64 -0
  147. eml_stdlib/ml/silu.eml +40 -0
  148. eml_stdlib/ml/softmax.eml +87 -0
  149. eml_stdlib/physics/coulomb.eml +48 -0
  150. eml_stdlib/physics/damped_oscillator.eml +20 -0
  151. eml_stdlib/physics/diffusion.eml +45 -0
  152. eml_stdlib/physics/gravity.eml +60 -0
  153. eml_stdlib/physics/hooke.eml +56 -0
  154. eml_stdlib/physics/navier_stokes_1d.eml +57 -0
  155. eml_stdlib/physics/planck_radiation.eml +77 -0
  156. eml_stdlib/physics/stefan_boltzmann.eml +75 -0
  157. eml_stdlib/physics/wave_propagation.eml +52 -0
  158. eml_stdlib/quantum/cnot.eml +72 -0
  159. eml_stdlib/quantum/grover_oracle.eml +69 -0
  160. eml_stdlib/quantum/hadamard.eml +73 -0
  161. eml_stdlib/quantum/pauli_x.eml +29 -0
  162. eml_stdlib/quantum/pauli_z.eml +29 -0
  163. eml_stdlib/quantum/phase_gate.eml +76 -0
  164. eml_stdlib/quantum/rotation_rz.eml +92 -0
  165. eml_stdlib/sensors/accelerometer.eml +59 -0
  166. eml_stdlib/sensors/hall_effect.eml +42 -0
  167. eml_stdlib/sensors/photodetector.eml +58 -0
  168. eml_stdlib/sensors/rtd.eml +57 -0
  169. eml_stdlib/sensors/strain_gauge.eml +63 -0
  170. eml_stdlib/sensors/thermistor.eml +71 -0
  171. eml_stdlib/signal/bandpass.eml +39 -0
  172. eml_stdlib/signal/chirp.eml +42 -0
  173. eml_stdlib/signal/dft_single.eml +30 -0
  174. eml_stdlib/signal/fft_butterfly.eml +36 -0
  175. eml_stdlib/signal/highpass.eml +45 -0
  176. eml_stdlib/signal/lowpass.eml +49 -0
  177. eml_stdlib/signal/matched_filter.eml +48 -0
  178. eml_stdlib/signal/notch_filter.eml +47 -0
  179. eml_stdlib/signal/window_hamming.eml +47 -0
  180. eml_stdlib/signal/window_hann.eml +50 -0
  181. eml_stdlib-0.4.0.dist-info/METADATA +453 -0
  182. eml_stdlib-0.4.0.dist-info/RECORD +185 -0
  183. eml_stdlib-0.4.0.dist-info/WHEEL +5 -0
  184. eml_stdlib-0.4.0.dist-info/licenses/LICENSE +21 -0
  185. eml_stdlib-0.4.0.dist-info/top_level.txt +1 -0
@@ -0,0 +1,74 @@
1
+ // buck_converter.eml -- step-down DC-DC buck converter (CCM).
2
+ //
3
+ // In continuous-conduction mode the steady-state output voltage is
4
+ //
5
+ // V_out = duty * V_in
6
+ //
7
+ // Output ripple is set by the inductor and output cap:
8
+ //
9
+ // delta_I_L = (V_in - V_out) * duty / (L * f_sw)
10
+ // delta_V_out = delta_I_L / (8 * Cout * f_sw)
11
+ //
12
+ // The LC corner sets the closed-loop bandwidth (~1/10 of f_sw).
13
+
14
+ module buck_converter;
15
+
16
+ @spice_voltage(name = "Vin", a = "vin", b = "0", value = 12.0)
17
+ @spice_inductor(name = "L1", a = "sw", b = "out", value = 22.0e-6)
18
+ @spice_capacitor(name = "Cout", a = "out", b = "0", value = 47.0e-6)
19
+ @spice_resistor(name = "Rload", a = "out", b = "0", value = 5.0)
20
+ fn circuit() -> Real
21
+ where chain_order <= 0
22
+ {
23
+ 0.0
24
+ }
25
+
26
+ // ── Mathematical certificates ─────────────────────────────────
27
+
28
+ @verify(lean, theorem = "buck_output_voltage_below_input")
29
+ fn output_voltage(duty: Real, v_in: Real) -> Real
30
+ where chain_order <= 0,
31
+ domain: v_in > 0.0
32
+ requires (duty >= 0.0)
33
+ requires (duty <= 1.0)
34
+ ensures (result >= 0.0)
35
+ ensures (result <= v_in)
36
+ {
37
+ duty * v_in
38
+ }
39
+
40
+ // Inductor ripple current.
41
+ @verify(lean, theorem = "buck_inductor_ripple_nonneg")
42
+ fn inductor_ripple(v_in: Real, v_out: Real, duty: Real,
43
+ inductance: Real, f_sw: Real) -> Real
44
+ where chain_order <= 0,
45
+ domain: inductance > 0.0 && f_sw > 0.0 && v_in >= v_out
46
+ requires (duty >= 0.0)
47
+ requires (duty <= 1.0)
48
+ ensures (result >= 0.0)
49
+ {
50
+ (v_in - v_out) * duty / (inductance * f_sw)
51
+ }
52
+
53
+ // Output voltage ripple.
54
+ @verify(lean, theorem = "buck_output_ripple_nonneg")
55
+ fn output_ripple(delta_il: Real, c_out: Real, f_sw: Real) -> Real
56
+ where chain_order <= 0,
57
+ domain: c_out > 0.0 && f_sw > 0.0 && delta_il >= 0.0
58
+ ensures (result >= 0.0)
59
+ {
60
+ delta_il / (8.0 * c_out * f_sw)
61
+ }
62
+
63
+ // Critical inductance -- below this, the buck enters DCM.
64
+ @verify(lean, theorem = "buck_critical_inductance_positive")
65
+ fn critical_inductance(v_out: Real, duty: Real,
66
+ i_load: Real, f_sw: Real) -> Real
67
+ where chain_order <= 0,
68
+ domain: v_out > 0.0 && f_sw > 0.0 && i_load > 0.0
69
+ requires (duty >= 0.0)
70
+ requires (duty <= 1.0)
71
+ ensures (result >= 0.0)
72
+ {
73
+ (1.0 - duty) * v_out / (2.0 * i_load * f_sw)
74
+ }
@@ -0,0 +1,75 @@
1
+ // cmos_inverter.eml -- TIER 2: ELECTRONICS, second demo.
2
+ //
3
+ // CMOS inverter transfer characteristic. Two MOSFETs (one
4
+ // n-type, one p-type) share a gate and a drain; the gate is the
5
+ // input node, the shared drain is the output. The output is
6
+ // V_DD when V_in is low and 0 when V_in is high -- a digital
7
+ // inverter.
8
+ //
9
+ // In the simple complementary regime (deep enough V_in that
10
+ // only one transistor conducts), the transfer is binary:
11
+ //
12
+ // V_out(0) = V_DD (PMOS on, NMOS off)
13
+ // V_out(V_DD) = 0 (NMOS on, PMOS off)
14
+ //
15
+ // Chain order 0 -- step function (or a smoothed sigmoid in the
16
+ // transition region we don't model here).
17
+
18
+ module cmos_inverter;
19
+
20
+ const V_DD: Real = 3.3 // supply rail (V), 3.3V CMOS
21
+
22
+ // Output at logic-low input. PMOS conducts, NMOS off, output
23
+ // pulled to the supply rail.
24
+ fn vout_at_low_input(v_dd: Real) -> Real
25
+ where chain_order <= 0
26
+ {
27
+ v_dd
28
+ }
29
+
30
+ // Output at logic-high input. NMOS conducts, PMOS off, output
31
+ // pulled to ground.
32
+ fn vout_at_high_input() -> Real
33
+ where chain_order <= 0
34
+ {
35
+ 0.0
36
+ }
37
+
38
+ // Switching point in a symmetric sized inverter (W_p / W_n
39
+ // chosen so the drive currents match): V_M = V_DD / 2.
40
+ fn switching_threshold(v_dd: Real) -> Real
41
+ where chain_order <= 0
42
+ {
43
+ v_dd * 0.5
44
+ }
45
+
46
+ // ── Mathematical certificates (Lean) ────────────────────────
47
+
48
+ // At a logic-low input the output rides exactly the rail.
49
+ @verify(lean, theorem = "cmos_low_in_high_out")
50
+ fn low_input_certificate(v_dd: Real) -> Real
51
+ where chain_order <= 0
52
+ ensures (result == v_dd)
53
+ {
54
+ v_dd
55
+ }
56
+
57
+ // At a logic-high input the output sits at ground.
58
+ @verify(lean, theorem = "cmos_high_in_low_out")
59
+ fn high_input_certificate() -> Real
60
+ where chain_order <= 0
61
+ ensures (result == 0.0)
62
+ {
63
+ 0.0
64
+ }
65
+
66
+ // Symmetric switching threshold sits at half the supply -- the
67
+ // design point that maximises noise margin on both rails.
68
+ @verify(lean, theorem = "cmos_threshold_positive_when_supply_positive")
69
+ fn vm_certificate(v_dd: Real) -> Real
70
+ where chain_order <= 0
71
+ requires (v_dd > 0.0)
72
+ ensures (result > 0.0)
73
+ {
74
+ v_dd * 0.5
75
+ }
@@ -0,0 +1,69 @@
1
+ // h_bridge.eml -- DC-motor H-bridge driver.
2
+ //
3
+ // Four MOSFETs (Q1..Q4) form an H around the load. Two control
4
+ // signals determine the four valid quadrants:
5
+ //
6
+ // forward : Q1, Q4 on -- current flows + -> motor + -> motor - -> -
7
+ // reverse : Q2, Q3 on -- reversed
8
+ // brake : Q3, Q4 on (low-side) or Q1, Q2 on (high-side)
9
+ // coast : all off
10
+ //
11
+ // PWM the gate signal at 20-50 kHz to control torque. Avoid the
12
+ // shoot-through condition where a high-side and matching low-side
13
+ // device are both ON -- the dead-time ensures a brief moment with
14
+ // both off between transitions.
15
+
16
+ module h_bridge;
17
+
18
+ @spice_voltage(name = "Vbus", a = "vbus", b = "0", value = 12.0)
19
+ @spice_resistor(name = "Rmot", a = "out_a", b = "out_b", value = 2.0)
20
+ @spice_capacitor(name = "Cdc", a = "vbus", b = "0", value = 100.0e-6)
21
+ fn circuit() -> Real
22
+ where chain_order <= 0
23
+ {
24
+ 0.0
25
+ }
26
+
27
+ // ── Mathematical certificates ─────────────────────────────────
28
+
29
+ // Output voltage as a function of duty cycle for forward direction.
30
+ // V_motor = duty * V_bus
31
+ @verify(lean, theorem = "h_bridge_forward_proportional_to_duty")
32
+ fn forward_voltage(duty: Real, v_bus: Real) -> Real
33
+ where chain_order <= 0,
34
+ domain: v_bus > 0.0
35
+ requires (duty >= 0.0)
36
+ requires (duty <= 1.0)
37
+ ensures (result >= 0.0)
38
+ ensures (result <= v_bus)
39
+ {
40
+ duty * v_bus
41
+ }
42
+
43
+ // Reverse direction.
44
+ @verify(lean, theorem = "h_bridge_reverse_proportional_to_duty")
45
+ fn reverse_voltage(duty: Real, v_bus: Real) -> Real
46
+ where chain_order <= 0,
47
+ domain: v_bus > 0.0
48
+ requires (duty >= 0.0)
49
+ requires (duty <= 1.0)
50
+ ensures (result <= 0.0)
51
+ ensures (result >= -v_bus)
52
+ {
53
+ -duty * v_bus
54
+ }
55
+
56
+ // Dead-time compensation -- the motor sees a slightly smaller
57
+ // voltage than the commanded duty due to the dead-band.
58
+ // V_eff = duty * V_bus * (1 - f_pwm * t_dead * 2)
59
+ @verify(lean, theorem = "h_bridge_dead_time_loss_nonneg")
60
+ fn dead_time_loss(duty: Real, v_bus: Real,
61
+ f_pwm: Real, t_dead: Real) -> Real
62
+ where chain_order <= 0,
63
+ domain: v_bus > 0.0 && f_pwm > 0.0 && t_dead >= 0.0
64
+ requires (duty >= 0.0)
65
+ requires (duty <= 1.0)
66
+ ensures (result >= 0.0)
67
+ {
68
+ duty * v_bus * (2.0 * f_pwm * t_dead)
69
+ }
@@ -0,0 +1,66 @@
1
+ // ldo.eml -- low-dropout linear regulator.
2
+ //
3
+ // Output voltage is set by the feedback divider:
4
+ //
5
+ // V_out = V_ref * (1 + R1 / R2)
6
+ //
7
+ // The pass element drops V_in - V_out at full load current; LDO
8
+ // efficiency is V_out / V_in (the rest is dissipated as heat).
9
+ // PSRR (power-supply rejection ratio) is set by the loop gain;
10
+ // stability requires a tame load capacitor with a particular ESR.
11
+
12
+ module ldo;
13
+
14
+ @spice_voltage(name = "Vin", a = "vin", b = "0", value = 5.0)
15
+ @spice_resistor(name = "R1", a = "out", b = "fb", value = 10000.0)
16
+ @spice_resistor(name = "R2", a = "fb", b = "0", value = 10000.0)
17
+ @spice_capacitor(name = "Cout", a = "out", b = "0", value = 10.0e-6)
18
+ fn circuit() -> Real
19
+ where chain_order <= 0
20
+ {
21
+ 0.0
22
+ }
23
+
24
+ // ── Mathematical certificates ─────────────────────────────────
25
+
26
+ @verify(lean, theorem = "ldo_output_voltage_above_reference")
27
+ fn output_voltage(v_ref: Real, r1: Real, r2: Real) -> Real
28
+ where chain_order <= 0,
29
+ domain: v_ref > 0.0 && r1 >= 0.0 && r2 > 0.0
30
+ ensures (result >= v_ref)
31
+ {
32
+ v_ref * (1.0 + r1 / r2)
33
+ }
34
+
35
+ @verify(lean, theorem = "ldo_efficiency_in_unit_interval")
36
+ fn efficiency(v_in: Real, v_out: Real) -> Real
37
+ where chain_order <= 0,
38
+ domain: v_in > 0.0 && v_out > 0.0 && v_in >= v_out
39
+ ensures (result >= 0.0)
40
+ ensures (result <= 1.0)
41
+ {
42
+ v_out / v_in
43
+ }
44
+
45
+ // Power dissipated in the pass element at load current i_load.
46
+ @verify(lean, theorem = "ldo_dissipation_nonneg")
47
+ fn dissipation(v_in: Real, v_out: Real, i_load: Real) -> Real
48
+ where chain_order <= 0
49
+ requires (v_in >= v_out)
50
+ requires (i_load >= 0.0)
51
+ ensures (result >= 0.0)
52
+ {
53
+ (v_in - v_out) * i_load
54
+ }
55
+
56
+ // Dropout voltage -- the minimum (V_in - V_out) the LDO needs to
57
+ // stay in regulation at i_load. Linear approximation.
58
+ @verify(lean, theorem = "ldo_dropout_nonneg")
59
+ fn dropout_voltage(r_ds_on: Real, i_load: Real) -> Real
60
+ where chain_order <= 0,
61
+ domain: r_ds_on > 0.0
62
+ requires (i_load >= 0.0)
63
+ ensures (result >= 0.0)
64
+ {
65
+ r_ds_on * i_load
66
+ }
@@ -0,0 +1,59 @@
1
+ // mosfet_iv.eml -- TIER 2: ELECTRONICS (electron carrier)
2
+ //
3
+ // MOSFET drain-current saturation model:
4
+ //
5
+ // I_D = (1/2) * mu * C_ox * (W/L) * (V_GS - V_th)^2
6
+ //
7
+ // Chain order 0 (polynomial). The carrier is the electron drift
8
+ // current; the wave equation reduces to a quasi-static
9
+ // constitutive relation. This is the equation that built every
10
+ // chip you've ever owned.
11
+ //
12
+ // EML demonstration: same compiler that emits ferron and magnon
13
+ // equations also emits this one. Carrier-substrate-independent.
14
+
15
+ module mosfet_iv;
16
+
17
+ // Process constants for a representative 65nm NMOS.
18
+ const MU_N: Real = 0.045 // m^2/V*s, electron mobility
19
+ const C_OX: Real = 1.7e-2 // F/m^2, gate oxide capacitance
20
+ const W_OVER_L: Real = 10.0 // device geometry ratio
21
+ const V_TH: Real = 0.4 // V, threshold voltage
22
+
23
+ // Saturation drain current vs. gate-source overdrive.
24
+ fn drain_current_sat(v_gs: Real, v_th: Real,
25
+ mu: Real, c_ox: Real, w_over_l: Real) -> Real
26
+ where chain_order <= 0
27
+ requires (v_gs >= v_th)
28
+ {
29
+ let vov = v_gs - v_th;
30
+ 0.5 * mu * c_ox * w_over_l * (vov * vov)
31
+ }
32
+
33
+ // ── Mathematical certificates (Lean) ────────────────────────
34
+
35
+ // At threshold (V_GS = V_th) the drain current vanishes. This
36
+ // is the textbook "device just turning on" boundary; any
37
+ // subthreshold model must agree with it at the matching point.
38
+ @verify(lean, theorem = "mosfet_zero_overdrive_zero_current")
39
+ fn id_at_threshold(mu: Real, c_ox: Real, w_over_l: Real) -> Real
40
+ where chain_order <= 0
41
+ ensures (result == 0.0)
42
+ {
43
+ 0.5 * mu * c_ox * w_over_l * ((0.0) * (0.0))
44
+ }
45
+
46
+ // Mobility, capacitance, geometry are all positive by
47
+ // construction (process parameters); positivity of the prefactor
48
+ // 0.5 * mu * C_ox * W/L is a precondition for a well-formed
49
+ // device model.
50
+ @verify(lean, theorem = "mosfet_prefactor_positive")
51
+ fn id_prefactor(mu: Real, c_ox: Real, w_over_l: Real) -> Real
52
+ where chain_order <= 0
53
+ requires (mu > 0.0)
54
+ requires (c_ox > 0.0)
55
+ requires (w_over_l > 0.0)
56
+ ensures (result > 0.0)
57
+ {
58
+ mu * c_ox * w_over_l
59
+ }
@@ -0,0 +1,63 @@
1
+ // pll_loop.eml -- TIER 2: ELECTRONICS, third demo.
2
+ //
3
+ // Phase-locked loop dynamics, type-1 (no integrator). In the
4
+ // linearised tracking regime the phase-error obeys:
5
+ //
6
+ // d_phi(t) / dt = -K * sin(d_phi(t)) ~ -K * d_phi(t) (small-angle)
7
+ //
8
+ // where K = K_VCO * K_PD is the loop gain. A locked PLL has
9
+ // d_phi -> 0; the locked steady-state phase error is zero, the
10
+ // VCO control voltage is constant, and the output frequency
11
+ // matches the reference.
12
+ //
13
+ // Chain order 0 (algebraic; small-angle approximation pulls the
14
+ // trig out of the chain).
15
+
16
+ module pll_loop;
17
+
18
+ const K_VCO: Real = 1.0e6 // Hz/V, VCO sensitivity
19
+ const K_PD: Real = 0.5 // V/rad, phase-detector gain
20
+
21
+ // Loop gain. Larger K -> faster lock, smaller residual phase
22
+ // error in the steady state, higher loop bandwidth.
23
+ fn loop_gain(k_vco: Real, k_pd: Real) -> Real
24
+ where chain_order <= 0
25
+ {
26
+ k_vco * k_pd
27
+ }
28
+
29
+ // Steady-state phase error in a locked, type-1 PLL with a
30
+ // constant frequency offset df: e_ss = df / K. Demonstrated
31
+ // here with df = 0 (matched reference) -> error = 0.
32
+ fn steady_state_error_at_zero_offset(k: Real) -> Real
33
+ where chain_order <= 0
34
+ requires (k > 0.0)
35
+ {
36
+ 0.0 / k
37
+ }
38
+
39
+ // ── Mathematical certificates (Lean) ────────────────────────
40
+
41
+ // Loop gain is positive whenever both stage gains are. The
42
+ // witness for "the loop will lock" -- a non-positive K either
43
+ // stalls (K=0) or runs away (K<0).
44
+ @verify(lean, theorem = "pll_loop_gain_positive")
45
+ fn loop_gain_certificate(k_vco: Real, k_pd: Real) -> Real
46
+ where chain_order <= 0
47
+ requires (k_vco > 0.0)
48
+ requires (k_pd > 0.0)
49
+ ensures (result > 0.0)
50
+ {
51
+ k_vco * k_pd
52
+ }
53
+
54
+ // At zero frequency offset the locked steady-state phase error
55
+ // is exactly zero -- the lock IS the proof of zero residual.
56
+ @verify(lean, theorem = "pll_zero_offset_zero_phase_error")
57
+ fn ss_error_certificate(k: Real) -> Real
58
+ where chain_order <= 0
59
+ requires (k > 0.0)
60
+ ensures (result == 0.0)
61
+ {
62
+ 0.0 / k
63
+ }
@@ -0,0 +1,98 @@
1
+ // rc_filter.eml -- single-pole RC low-pass filter, the canonical
2
+ // SPICE-backend smoke test, now also carrying the mathematical
3
+ // certificate kernels the Lean backend turns into proof obligations.
4
+ //
5
+ // Topology:
6
+ // Vin -> in
7
+ // R1 in -> out (1 kOhm)
8
+ // C1 out -> 0 (1 uF)
9
+ // .tran 1u 10m
10
+ //
11
+ // Cut-off frequency is 1 / (2*pi*R*C) ~= 159 Hz. Run with:
12
+ //
13
+ // eml-compile rc_filter.eml --target spice -o rc_filter.cir
14
+ // ngspice -b rc_filter.cir
15
+ //
16
+ // The @verify(lean, ...) kernel functions below capture the
17
+ // continuous-time properties of the filter that Phase E4 proves
18
+ // against MachLib (see ~/monogate/machlib/foundations/MachLib/
19
+ // Discovered/rc_filter.lean).
20
+ //
21
+ // (Phase E4 -- the SPICE backend emits the netlist; the KiCad
22
+ // backend emits a schematic; the JLCPCB mapper emits a BOM; and
23
+ // the Lean backend emits the proof obligations. Same source, four
24
+ // downstream artifacts.)
25
+
26
+ module rc_filter;
27
+
28
+ // ── Circuit netlist (E1+E2+E3 backends) ─────────────────────
29
+
30
+ @spice_resistor(name = "R1", a = "in", b = "out", value = 1000.0)
31
+ @spice_capacitor(name = "C1", a = "out", b = "0", value = 1.0e-6)
32
+ @spice_voltage(name = "Vin", a = "in", b = "0", value = 5.0)
33
+ @spice_analysis(tran = "1u 10m")
34
+ fn circuit() -> Real
35
+ where chain_order <= 0
36
+ {
37
+ 0.0
38
+ }
39
+
40
+ // ── Mathematical certificates (E4: Lean) ────────────────────
41
+
42
+ // Time constant τ = R * C. Definitional — used by every other
43
+ // claim in this module as the reference time scale.
44
+ @verify(lean, theorem = "rc_time_constant_def")
45
+ fn tau(r: Real, c: Real) -> Real
46
+ where chain_order <= 0
47
+ requires (r > 0.0)
48
+ requires (c > 0.0)
49
+ ensures (result == r * c)
50
+ {
51
+ r * c
52
+ }
53
+
54
+ // Steady-state output (t -> infinity): the capacitor is fully
55
+ // charged and the output equals the input. This is the hard
56
+ // asymptote any RC step response approaches.
57
+ @verify(lean, theorem = "rc_steady_state_equals_input")
58
+ fn vout_steady(vin: Real) -> Real
59
+ where chain_order <= 0
60
+ ensures (result == vin)
61
+ {
62
+ vin
63
+ }
64
+
65
+ // Initial output (t = 0): the capacitor starts empty so the
66
+ // output is zero regardless of the input voltage.
67
+ @verify(lean, theorem = "rc_initial_output_zero")
68
+ fn vout_initial() -> Real
69
+ where chain_order <= 0
70
+ ensures (result == 0.0)
71
+ {
72
+ 0.0
73
+ }
74
+
75
+ // Step-response decay (closed form): V_out(t) = V_in * (1 - exp(-t/tau))
76
+ // The @verify here proves only the definitional shape; the
77
+ // monotonicity-in-t and bounded-by-vin properties are extracted as
78
+ // separate kernels below so each carries an independent obligation.
79
+ @verify(lean, theorem = "rc_step_response_form")
80
+ fn vout_charging(vin: Real, t: Real, tau_val: Real) -> Real
81
+ where chain_order <= 1
82
+ requires (tau_val > 0.0)
83
+ ensures (result == vin * (1.0 - exp(-t / tau_val)))
84
+ {
85
+ vin * (1.0 - exp(-t / tau_val))
86
+ }
87
+
88
+ // Output at t = 0 of the closed-form solution: V_out(0) = 0.
89
+ // Combines the definition of vout_charging with exp(0) = 1.
90
+ // (Proof closes against MachLib's exp_zero axiom.)
91
+ @verify(lean, theorem = "rc_step_response_at_zero")
92
+ fn vout_charging_at_zero(vin: Real, tau_val: Real) -> Real
93
+ where chain_order <= 1
94
+ requires (tau_val > 0.0)
95
+ ensures (result == 0.0)
96
+ {
97
+ vin * (1.0 - exp(-0.0 / tau_val))
98
+ }
@@ -0,0 +1,68 @@
1
+ // voltage_divider.eml -- the textbook resistive divider, the
2
+ // simplest non-trivial SPICE deck, now also carrying the
3
+ // mathematical certificate kernels the Lean backend turns into
4
+ // proof obligations.
5
+ //
6
+ // Topology:
7
+ // Vin -> in
8
+ // R1 in -> mid (10 kOhm)
9
+ // R2 mid -> 0 (10 kOhm)
10
+ // .op
11
+ //
12
+ // Theory: V(mid) = Vin * R2 / (R1 + R2). With R1 = R2 the
13
+ // midpoint sits at exactly Vin / 2.
14
+
15
+ module voltage_divider;
16
+
17
+ // ── Circuit netlist (E1+E2+E3 backends) ─────────────────────
18
+
19
+ @spice_resistor(name = "R1", a = "in", b = "mid", value = 10000.0)
20
+ @spice_resistor(name = "R2", a = "mid", b = "0", value = 10000.0)
21
+ @spice_voltage(name = "Vin", a = "in", b = "0", value = 5.0)
22
+ @spice_analysis(op = "")
23
+ fn circuit() -> Real
24
+ where chain_order <= 0
25
+ {
26
+ 0.0
27
+ }
28
+
29
+ // ── Mathematical certificates (E4: Lean) ────────────────────
30
+
31
+ // Voltage-divider law: V_out = V_in * R2 / (R1 + R2).
32
+ // Definitional — the closed-form expression IS the body, so the
33
+ // theorem is provable by `rfl` after `unfold`.
34
+ @verify(lean, theorem = "voltage_divider_law")
35
+ fn vout_divider(vin: Real, r1: Real, r2: Real) -> Real
36
+ where chain_order <= 0
37
+ requires (r1 > 0.0)
38
+ requires (r2 > 0.0)
39
+ ensures (result == vin * r2 / (r1 + r2))
40
+ {
41
+ vin * r2 / (r1 + r2)
42
+ }
43
+
44
+ // Sum of the two resistances is strictly positive. Used as a
45
+ // hypothesis in every downstream proof that needs to divide by
46
+ // (R1 + R2).
47
+ @verify(lean, theorem = "voltage_divider_denom_pos")
48
+ fn rsum(r1: Real, r2: Real) -> Real
49
+ where chain_order <= 0
50
+ requires (r1 > 0.0)
51
+ requires (r2 > 0.0)
52
+ ensures (result > 0.0)
53
+ {
54
+ r1 + r2
55
+ }
56
+
57
+ // Midpoint at the symmetric divider (R1 = R2 = R): V_out = V_in / 2.
58
+ // Captures the most-common design point. Not provable by `rfl`
59
+ // alone (algebra: 2R*x / (R+R) = x reduces to x = x via cancel),
60
+ // but the proof closes against MachLib's mul_inv + div_def axioms.
61
+ @verify(lean, theorem = "voltage_divider_symmetric_half")
62
+ fn vout_symmetric(vin: Real, r: Real) -> Real
63
+ where chain_order <= 0
64
+ requires (r > 0.0)
65
+ ensures (result == vin * r / (r + r))
66
+ {
67
+ vin * r / (r + r)
68
+ }
@@ -0,0 +1,34 @@
1
+ // bangbang.eml -- bang-bang (relay) controller.
2
+ //
3
+ // The simplest possible feedback controller:
4
+ // u = u_max if error > 0 else u_min
5
+ //
6
+ // Used in thermostats, on/off relays, and as a sanity-check
7
+ // reference for more sophisticated controllers. Chain order 0;
8
+ // branchless under the optimiser via clamp(sign(...)*range, ...).
9
+
10
+ module bangbang;
11
+
12
+ @verify(lean, theorem = "bangbang_in_actuator_band")
13
+ fn bangbang(error: Real, u_max: Real, u_min: Real) -> Real
14
+ where chain_order <= 0
15
+ requires (u_max >= u_min)
16
+ ensures (result >= u_min)
17
+ ensures (result <= u_max)
18
+ {
19
+ let s = clamp(error * 1.0e30, -1.0, 1.0);
20
+ let mid = 0.5 * (u_max + u_min);
21
+ let amp = 0.5 * (u_max - u_min);
22
+ mid + s * amp
23
+ }
24
+
25
+ // Symmetric bang-bang -- output is +/- u_amp.
26
+ @verify(lean, theorem = "bangbang_sym_in_band")
27
+ fn bangbang_symmetric(error: Real, u_amp: Real) -> Real
28
+ where chain_order <= 0
29
+ requires (u_amp >= 0.0)
30
+ ensures (abs(result) <= u_amp)
31
+ {
32
+ let s = clamp(error * 1.0e30, -1.0, 1.0);
33
+ s * u_amp
34
+ }
@@ -0,0 +1,28 @@
1
+ // deadband.eml -- two-sided dead-zone (deadband) saturation.
2
+ //
3
+ // If |x| <= threshold the output is 0; otherwise the output is x
4
+ // shifted toward zero by `threshold`. Equivalent to
5
+ // y = x - clamp(x, -threshold, threshold)
6
+ //
7
+ // Chain order 0. Used to suppress sensor noise around a setpoint
8
+ // and to keep PIDs from chattering.
9
+
10
+ module deadband;
11
+
12
+ @verify(lean, theorem = "deadband_zero_inside")
13
+ fn deadband(x: Real, threshold: Real) -> Real
14
+ where chain_order <= 0
15
+ requires (threshold >= 0.0)
16
+ {
17
+ x - clamp(x, -threshold, threshold)
18
+ }
19
+
20
+ // Asymmetric deadband: distinct upper/lower thresholds.
21
+ @verify(lean, theorem = "deadband_asym_zero_inside")
22
+ fn deadband_asymmetric(x: Real, low: Real, high: Real) -> Real
23
+ where chain_order <= 0
24
+ requires (low <= 0.0)
25
+ requires (high >= 0.0)
26
+ {
27
+ x - clamp(x, low, high)
28
+ }
@@ -0,0 +1,28 @@
1
+ // hysteresis.eml -- Schmitt-trigger / hysteresis switching.
2
+ //
3
+ // if state == 0 (off): switch on iff x > threshold_on
4
+ // if state == 1 (on): switch off iff x < threshold_off
5
+ //
6
+ // Caller threads `state` through frames as a 0/1 Real. The kernel
7
+ // returns the new state. Chain order 0.
8
+ //
9
+ // The asymmetry threshold_on > threshold_off prevents chatter --
10
+ // ubiquitous in thermostat / relay / battery-charger logic.
11
+
12
+ module hysteresis;
13
+
14
+ @verify(lean, theorem = "hysteresis_state_in_zero_one")
15
+ fn hysteresis_step(x: Real, state: Real,
16
+ threshold_on: Real, threshold_off: Real) -> Real
17
+ where chain_order <= 0
18
+ requires (threshold_on > threshold_off)
19
+ requires (state == 0.0 || state == 1.0)
20
+ ensures (result >= 0.0)
21
+ ensures (result <= 1.0)
22
+ {
23
+ let on_via_x = clamp((x - threshold_on) * 1.0e30, 0.0, 1.0);
24
+ let off_via_x = clamp((threshold_off - x) * 1.0e30, 0.0, 1.0);
25
+ let next_when_off = on_via_x;
26
+ let next_when_on = 1.0 - off_via_x;
27
+ state * next_when_on + (1.0 - state) * next_when_off
28
+ }