Files
Learn_System/frontend/js/flagships/phys9_flag_F13_foucault.js
Maxim Dolgolyov e316d39264 feat(phys9 flagships): F6 дорога + F13 Фуко + F14 резонанс
F6. Симулятор скоростной дороги (§20 в ch2):
- 5 покрытий: сухой/мокрый асфальт, гравий, снег, лёд (μ=0.7..0.08)
- Slider скорости 20..180 км/ч
- Автомобиль едет по дороге, кнопка ТОРМОЗ → тормозит до 0
- Расчёт: s = v²/(2μg), t = v/(μg)
- На льду тормозной путь в ~8 раз длиннее асфальта

F13. Маятник Фуко (§36 в ch4):
- Маятник в виде розетки, плоскость вращается со скоростью
  ω = sin(φ) · 2π / 24h
- Slider широты 0..90° (от экватора до полюса)
- На полюсе — 24ч полного оборота, на экваторе — никогда
- Slider «ускорение времени» × (100..20000) — чтобы увидеть розетку
- Места: экватор/Каир/Рим/Минск/Москва/Заполярье/полюс

F14. Резонанс пружинного маятника (§36 в ch4):
- Слева: пружина с грузом + внешняя гармоническая сила
- Slider'ы: m, k, ν_внешн, γ затухание
- Кнопка «Настроить на резонанс» (ν_внешн = ν_собств)
- Реальная физика затухания: m·x'' = -kx - γv + F0·cos(ωt)
- Справа: график x(t) за последние 20 с
- Классификация: вынужденные / близко к резонансу / РЕЗОНАНС!

Подключение:
- ch2: F6 на p20
- ch4: F13 + F14 оба на p36 (маятники)

Co-Authored-By: Claude Opus 4.7 <noreply@anthropic.com>
2026-05-30 10:23:57 +03:00

164 lines
7.4 KiB
JavaScript
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
// F13. Маятник Фуко (§36 в ch4) — вращение Земли и розетка.
(function(){
'use strict';
const B = () => window.PHYS9_FLAG_BASE;
const C = () => window.PHYS9_COLORS || {};
function init(secId){
if (!B()) return false;
const body = ''
+ '<div class="flag-sliders">'
+ '<label>Широта φ, &#176;: <b id="F13-lv">52</b><input type="range" id="F13-l" min="0" max="90" step="1" value="52"></label>'
+ '<label>Ускорение времени, ×: <b id="F13-sv">3600</b><input type="range" id="F13-s" min="100" max="20000" step="100" value="3600"></label>'
+ '</div>'
+ '<canvas id="F13-cv" class="flag-canvas" width="640" height="380" style="height:380px"></canvas>'
+ '<div class="flag-controls">'
+ '<button class="flag-btn primary" id="F13-go">Запустить</button>'
+ '<button class="flag-btn" id="F13-reset">Сброс</button>'
+ '<button class="flag-btn" id="F13-clear">Очистить следы</button>'
+ '</div>'
+ '<div class="flag-stats">'
+ '<div class="flag-stat"><span class="lbl">Текущая широта</span><span class="val" id="F13-loc">Минск (52°)</span></div>'
+ '<div class="flag-stat"><span class="lbl">Период оборота плоскости</span><span class="val" id="F13-T">30.4 ч</span></div>'
+ '<div class="flag-stat"><span class="lbl">Реальное время</span><span class="val" id="F13-t">0 ч</span></div>'
+ '<div class="flag-stat"><span class="lbl">Поворот плоскости</span><span class="val" id="F13-rot">0&#176;</span></div>'
+ '</div>'
+ '<div class="flag-feedback" id="F13-fb"></div>';
const card = B().makeCard(secId,
'F13. Маятник Фуко',
'Маятник в Париже (1851) доказал вращение Земли. Период оборота плоскости: $T = 24/\\sin\\varphi$ часов. На полюсе — 24 ч, на экваторе — никогда.',
body);
if (!card) return false;
const cv = document.getElementById('F13-cv');
const ctx = cv.getContext('2d');
const W = cv.width, H = cv.height;
const cx = W/2, cy = H/2;
const R = 130;
let st = { phase: 0, planeAngle: 0, t: 0, running: false, trail: [] };
function update(){
const lat = +document.getElementById('F13-l').value;
const speed = +document.getElementById('F13-s').value;
document.getElementById('F13-lv').textContent = lat;
document.getElementById('F13-sv').textContent = speed;
let loc;
if (lat >= 89) loc = 'Северный полюс (90°)';
else if (lat >= 70) loc = 'Заполярье (70-89°)';
else if (lat >= 55) loc = 'Москва (55°)';
else if (lat >= 50) loc = 'Минск (52°)';
else if (lat >= 40) loc = 'Рим (42°)';
else if (lat >= 20) loc = 'Каир (30°)';
else if (lat >= 5) loc = 'тропики';
else loc = 'экватор (0°)';
document.getElementById('F13-loc').textContent = loc;
const sinL = Math.sin(lat * Math.PI/180);
const T = sinL > 0.001 ? 24 / sinL : Infinity;
document.getElementById('F13-T').textContent = isFinite(T) ? T.toFixed(1) + ' ч' : '∞ (нет поворота)';
}
function reset(){
st = { phase: 0, planeAngle: 0, t: 0, running: false, trail: [] };
document.getElementById('F13-go').textContent = 'Запустить';
draw();
}
function tick(dt){
if (!st.running) { draw(); return; }
const lat = +document.getElementById('F13-l').value;
const speed = +document.getElementById('F13-s').value;
const sinL = Math.sin(lat * Math.PI/180);
const realDt = dt * speed; /* условное реальное время в секундах */
st.t += realDt;
/* колебание маятника: период ~6 с реального времени */
st.phase += dt * 2 * Math.PI * 0.5; /* псевдо-период для красоты */
/* поворот плоскости: ω = 2π/(24·3600/sinL) рад/с */
const omega = sinL * 2 * Math.PI / (24*3600);
st.planeAngle += omega * realDt;
/* trail — текущее положение маятника */
const r = R * Math.cos(st.phase);
const px = cx + r * Math.cos(st.planeAngle);
const py = cy + r * Math.sin(st.planeAngle);
st.trail.push({ x: px, y: py });
if (st.trail.length > 5000) st.trail.shift();
document.getElementById('F13-t').textContent = (st.t/3600).toFixed(2) + ' ч';
document.getElementById('F13-rot').textContent = ((st.planeAngle * 180/Math.PI) % 360).toFixed(1) + '°';
draw();
}
function draw(){
const col = C();
ctx.fillStyle = col.bg || '#fafafa';
ctx.fillRect(0, 0, W, H);
/* пол */
ctx.fillStyle = col.bgSubtle || '#f8fafc';
ctx.beginPath(); ctx.arc(cx, cy, R + 30, 0, Math.PI*2); ctx.fill();
ctx.strokeStyle = col.axis || '#1e293b';
ctx.lineWidth = 2;
ctx.stroke();
/* радиальные направления (страны света) */
ctx.font = '12px Inter,sans-serif';
ctx.fillStyle = col.textMuted || '#64748b';
ctx.textAlign = 'center';
ctx.fillText('С', cx, cy - R - 15);
ctx.fillText('Ю', cx, cy + R + 25);
ctx.fillText('З', cx - R - 18, cy + 4);
ctx.fillText('В', cx + R + 18, cy + 4);
/* следы маятника */
if (st.trail.length > 1){
ctx.strokeStyle = col.velocity || '#0891b2';
ctx.lineWidth = 1.2;
ctx.globalAlpha = 0.5;
ctx.beginPath();
ctx.moveTo(st.trail[0].x, st.trail[0].y);
for (let i = 1; i < st.trail.length; i++) ctx.lineTo(st.trail[i].x, st.trail[i].y);
ctx.stroke();
ctx.globalAlpha = 1;
}
/* центральная точка крепления */
ctx.fillStyle = col.axis || '#1e293b';
ctx.beginPath(); ctx.arc(cx, cy, 5, 0, Math.PI*2); ctx.fill();
/* плоскость колебаний — линия */
ctx.strokeStyle = col.acceleration || '#ea580c';
ctx.lineWidth = 1.5;
ctx.setLineDash([6, 4]);
ctx.beginPath();
ctx.moveTo(cx - R * Math.cos(st.planeAngle), cy - R * Math.sin(st.planeAngle));
ctx.lineTo(cx + R * Math.cos(st.planeAngle), cy + R * Math.sin(st.planeAngle));
ctx.stroke();
ctx.setLineDash([]);
/* маятник — груз */
const r = R * Math.cos(st.phase);
const px = cx + r * Math.cos(st.planeAngle);
const py = cy + r * Math.sin(st.planeAngle);
ctx.fillStyle = col.forceGravity || '#2563eb';
ctx.beginPath(); ctx.arc(px, py, 10, 0, Math.PI*2); ctx.fill();
ctx.strokeStyle = col.bodyAccent || '#1e293b';
ctx.lineWidth = 1.5;
ctx.stroke();
ctx.textAlign = 'left';
}
document.getElementById('F13-go').addEventListener('click', () => {
st.running = !st.running;
document.getElementById('F13-go').textContent = st.running ? 'Пауза' : 'Запустить';
});
document.getElementById('F13-reset').addEventListener('click', reset);
document.getElementById('F13-clear').addEventListener('click', () => { st.trail = []; draw(); });
['F13-l','F13-s'].forEach(id => document.getElementById(id).addEventListener('input', update));
update();
draw();
B().startLoop('F13', cv, tick);
return true;
}
if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F13', { init: init, cleanup: function(){} });
else document.addEventListener('DOMContentLoaded', ()=>{
if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F13', { init: init, cleanup: function(){} });
});
})();