diff --git a/src/gausse/optim/objective.py b/src/gausse/optim/objective.py index 7a03f39..d11e28b 100644 --- a/src/gausse/optim/objective.py +++ b/src/gausse/optim/objective.py @@ -21,10 +21,11 @@ from gausse.physics.inductance import air_core_inductance_wheeler, winding_geome from gausse.sim.coilgun import CoilgunResult, run_coilgun from gausse.storage.schema import RunRecord -# v3: коэффициент заполнения железа (fill factor) — закрыт эксплойт «тонкий -# снаряд в толстой катушке»; полная формула отражения вихревого контура; -# гард вырожденных катушек. v2: Доуэлл, трение+воздух, импульсные токи ключей. -MODEL_VERSION = "gausse-physics-v3" +# v4: диффузия поля в снаряд — намагничивается только скин-кольцо глубиной δ, +# закрыт эксплойт «медленной» катушки (30%). v3: fill factor (эксплойт тонкого +# снаряда), полное отражение вихрей, гард вырожденных катушек. v2: Доуэлл, +# трение+воздух, паспортные импульсные токи ключей. +MODEL_VERSION = "gausse-physics-v4" @dataclass diff --git a/src/gausse/physics/ac_resistance.py b/src/gausse/physics/ac_resistance.py index 37297db..5af638b 100644 --- a/src/gausse/physics/ac_resistance.py +++ b/src/gausse/physics/ac_resistance.py @@ -33,6 +33,32 @@ def skin_depth_m(resistivity_ohm_m: float, omega_rad_s: float) -> float: return math.sqrt(2.0 * resistivity_ohm_m / (omega_rad_s * MU_0)) +def iron_penetration_fraction( + slug_radius_m: float, + slug_resistivity_ohm_m: float, + mu_r: float, + omega_rad_s: float, +) -> float: + """Доля сечения снаряда, реально намагниченная за импульс (диффузия поля). + + Переменное поле проникает в проводящее железо на глубину скин-слоя + δ = √(2ρ/(ω·μ₀·μᵣ)) — за миллисекундный импульс у стали это доли + миллиметра. Внутренность снаряда не успевает намагнититься и силы не + даёт. Работает кольцо глубиной δ: A_eff/A = 1−(1−δ/a)². + + ЧЕСТНО: это одночастотная оценка (ω=1/√(LC)) решения уравнения диффузии, + а не само решение; ошибка — десятки процентов. Но без неё модель считала, + что намагничивается ВСЁ сечение, и оптимизатор строил «медленные» + катушки с нефизично высоким КПД (30%+). + """ + if omega_rad_s <= 0 or slug_resistivity_ohm_m <= 0 or mu_r < 1 or slug_radius_m <= 0: + return 1.0 + delta = math.sqrt(2.0 * slug_resistivity_ohm_m / (omega_rad_s * MU_0 * mu_r)) + if delta >= slug_radius_m: + return 1.0 + return 1.0 - (1.0 - delta / slug_radius_m) ** 2 + + def dowell_ac_factor( wire_bare_d_m: float, wire_insulated_d_m: float, diff --git a/src/gausse/sim/stage.py b/src/gausse/sim/stage.py index 8c7bcd5..f8015da 100644 --- a/src/gausse/sim/stage.py +++ b/src/gausse/sim/stage.py @@ -28,7 +28,7 @@ from gausse.physics.inductance import ( effective_permeability, winding_geometry, ) -from gausse.physics.ac_resistance import dowell_ac_factor +from gausse.physics.ac_resistance import dowell_ac_factor, iron_penetration_fraction from gausse.physics.constants import ( AIR_DENSITY_KG_M3, DRAG_COEFF_CYLINDER, @@ -190,8 +190,16 @@ def build_stage_physics(stage: StageConfig, projectile: ProjectileConfig) -> Sta char_omega_rad_s=char_omega, ) # доля сечения катушки, реально занятая железом (см. inductance.py): - # тонкий снаряд в толстой катушке не может усиливать ВЕСЬ поток + # тонкий снаряд в толстой катушке не может усиливать ВЕСЬ поток; + # и из этого железа за импульс намагничивается только скин-кольцо + # глубиной δ (диффузия поля, см. ac_resistance.iron_penetration_fraction) fill = min((projectile.diameter_m / 2) ** 2 / geometry.mean_radius_m**2, 1.0) + fill *= iron_penetration_fraction( + projectile.diameter_m / 2, + projectile.material.resistivity_ohm_m, + projectile.material.mu_r, + char_omega, + ) inductance_model = CoilInductanceModel( l_air_h=l_air_h, coil_length_m=geometry.coil_length_m, diff --git a/tests/test_realism_v2.py b/tests/test_realism_v2.py index 26e3f88..86a7842 100644 --- a/tests/test_realism_v2.py +++ b/tests/test_realism_v2.py @@ -220,3 +220,19 @@ def test_eddy_reflection_bounded_at_high_frequency(): 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) # низкие: сходится + + +def test_iron_penetration_fraction_limits(): + """Диффузия поля: тонкий снаряд/медленный импульс — всё сечение; толстый + снаряд на быстром импульсе — только скин-кольцо (эксплойт «30%» закрыт).""" + from gausse.physics.ac_resistance import iron_penetration_fraction + + # очень низкая частота: поле успевает пропитать всё сечение + assert iron_penetration_fraction(0.005, 1.4e-7, 500.0, 1.0) == 1.0 + # сталь ⌀9.3мм на ω~1350 рад/с (медленная катушка из эксплойта): + # намагничивается лишь внешнее кольцо — заметно меньше половины сечения + frac = iron_penetration_fraction(0.00465, 1.4e-7, 500.0, 1350.0) + assert 0.02 < frac < 0.5 + # быстрее импульс -> тоньше кольцо (монотонность по ω) + frac_fast = iron_penetration_fraction(0.00465, 1.4e-7, 500.0, 13500.0) + assert frac_fast < frac