Физика v3: коэффициент заполнения железа + фикс зависаний решателя
ЭКСПЛОЙТ (нашёлся по подозрительным 75-82% КПД на дашборде): модель умножала ВСЮ индуктивность катушки на (mu_eff-1)*overlap, как будто железо заполняет всё сечение. Тонкий снаряд (4мм) в толстой катушке (29мм) получал ~50x нефизичной силы бесплатно, и эволюция сгрузилась именно туда. Фикс: iron_fill_factor = A_снаряда/A_среднего витка (классическое λ = n*(B_fe*A_fe + B_возд*(A-A_fe))). ЗАВИСАНИЯ (сервер стоял 35+ мин на одной конфигурации): - сглаживание сухого трения tanh(v/0.01) вместо разрывного sign(v) - событие тока удержания ключа (SCR закрывается при I<0.1А после пика) -- передемпфированный хвост больше не молотит весь 20мс бюджет - полная формула отражения вихревого контура (ωM)²R2/(R2²+(ωL2)²) вместо резистивного приближения (114кОм -> 2.5кОм на вырожденных катушках) - гард: L/R < 100нс = вне области применимости модели, мгновенный отказ Бенч 200 геномов: 608с -> 22с, худшая оценка 540с -> 2.5с. MODEL_VERSION -> gausse-physics-v3. 104 теста. Co-Authored-By: Claude Fable 5 <noreply@anthropic.com>
This commit is contained in:
@@ -164,3 +164,59 @@ def test_friction_force_smooth_at_zero_velocity():
|
||||
assert abs(retarding_force_n(p, 1e-6) + retarding_force_n(p, -1e-6)) < 1e-12
|
||||
# вдали от нуля выходит на полное трение
|
||||
assert retarding_force_n(p, 1.0) > 0.9 * p.retard_const_n
|
||||
|
||||
|
||||
def test_iron_fill_factor_punishes_thin_slug_in_fat_coil():
|
||||
"""Регрессия на эксплойт «КПД 82%»: тонкий снаряд в толстой катушке
|
||||
не может усиливать весь поток — только долю сечения, которую занимает."""
|
||||
from gausse.physics.inductance import CoilInductanceModel
|
||||
|
||||
base = dict(l_air_h=1e-3, coil_length_m=0.05, slug_length_m=0.02,
|
||||
mu_eff=40.0, smoothing_width_m=0.001, total_turns=300)
|
||||
full = CoilInductanceModel(**base, iron_fill_factor=1.0)
|
||||
thin = CoilInductanceModel(**base, iron_fill_factor=0.02) # ⌀4мм в ⌀29мм
|
||||
# сила при том же токе в 50 раз меньше — халявы больше нет
|
||||
f_full = float(full.force_newtons(-0.03, 100.0))
|
||||
f_thin = float(thin.force_newtons(-0.03, 100.0))
|
||||
assert f_thin < 0.03 * f_full
|
||||
|
||||
|
||||
def test_degenerate_coil_fails_fast():
|
||||
"""Регрессия на завис 540с: вырожденная катушка бракуется мгновенно."""
|
||||
import time
|
||||
from dataclasses import replace
|
||||
|
||||
stage = make_stage()
|
||||
degenerate = replace(stage, turns_per_layer=2, layers=2) # 4 витка, ~2мм
|
||||
t0 = time.time()
|
||||
res = run_stage(-0.06, 3.0, degenerate, make_projectile())
|
||||
assert time.time() - t0 < 5.0, "вырожденный конфиг должен отваливаться быстро"
|
||||
# либо честно отбракован гардом, либо честно посчитан быстро — оба исхода ок
|
||||
if not res.feasible:
|
||||
assert res.reason
|
||||
|
||||
|
||||
def test_eddy_reflection_bounded_at_high_frequency():
|
||||
"""Полная формула отражения (R₂²+(ωL₂)² в знаменателе): на высоких ω
|
||||
заметно ниже старого резистивно-доминированного приближения, на низких —
|
||||
сходится к нему. Совсем вырожденные катушки добивает гард L/R в run_stage."""
|
||||
import math as _m
|
||||
|
||||
from gausse.physics.constants import MU_0
|
||||
from gausse.physics.losses import EDDY_COUPLING_FACTOR, eddy_reflected_resistance_ohm
|
||||
|
||||
kwargs = dict(slug_radius_m=0.002, slug_length_m=0.03,
|
||||
slug_resistivity_ohm_m=1.6e-7, mu_eff=259.0,
|
||||
total_turns=5, coil_length_m=0.002)
|
||||
|
||||
def resistive_approx(om):
|
||||
a = _m.pi * kwargs["slug_radius_m"] ** 2
|
||||
m = EDDY_COUPLING_FACTOR * MU_0 * kwargs["mu_eff"] * (5 / 0.002) * a
|
||||
r2 = 2 * _m.pi * kwargs["slug_resistivity_ohm_m"] / kwargs["slug_length_m"]
|
||||
return (om * m) ** 2 / r2
|
||||
|
||||
om_hi, om_lo = 1.25e5, 1e2
|
||||
r_hi = eddy_reflected_resistance_ohm(**kwargs, char_omega_rad_s=om_hi)
|
||||
r_lo = eddy_reflected_resistance_ohm(**kwargs, char_omega_rad_s=om_lo)
|
||||
assert r_hi < 0.5 * resistive_approx(om_hi) # высокие ω: ограничена
|
||||
assert abs(r_lo - resistive_approx(om_lo)) < 0.05 * resistive_approx(om_lo) # низкие: сходится
|
||||
|
||||
Reference in New Issue
Block a user