// F5. Машина Атвуда (§22 в ch2) — связанные массы через блок.
(function(){
'use strict';
const B = () => window.PHYS9_FLAG_BASE;
const C = () => window.PHYS9_COLORS || {};
function init(secId){
if (!B()) return false;
const body = ''
+ '
'
+ '$m_1$ (левая), кг: 3 '
+ '$m_2$ (правая), кг: 2 '
+ 'Трение в блоке: 0 '
+ '
'
+ ' '
+ ''
+ 'Запустить '
+ 'Сброс '
+ '
'
+ ''
+ '
$a = (m_1-m_2)g/(m_1+m_2)$ 1.96 м/с²
'
+ '
Натяжение T 23.5 Н
'
+ '
$v$ текущая 0 м/с
'
+ '
$t$ прошло 0 с
'
+ '
';
const card = B().makeCard(secId,
'F5. Машина Атвуда',
'Две массы через блок на нити. Бо́льшая опускается, меньшая поднимается. Физика: $a = (m_1-m_2)g/(m_1+m_2)$.',
body);
if (!card) return false;
const cv = document.getElementById('F5-cv');
const ctx = cv.getContext('2d');
const W = cv.width, H = cv.height;
const blockX = W/2, blockY = 60, blockR = 28;
let st = { y1: 220, y2: 220, v: 0, t: 0, running: false };
/* y — расстояние от блока вниз, +v = m1 опускается */
function readSliders(){
const m1 = +document.getElementById('F5-m1').value;
const m2 = +document.getElementById('F5-m2').value;
const fr = +document.getElementById('F5-fr').value;
document.getElementById('F5-m1v').textContent = m1.toFixed(2);
document.getElementById('F5-m2v').textContent = m2.toFixed(2);
document.getElementById('F5-frv').textContent = fr.toFixed(2);
const g = 9.8;
const a = ((m1 - m2)*g - fr) / (m1 + m2);
const T = m2 * (g + a);
document.getElementById('F5-a').textContent = a.toFixed(2) + ' м/с²';
document.getElementById('F5-T').textContent = T.toFixed(1) + ' Н';
}
function reset(){
st = { y1: 220, y2: 220, v: 0, t: 0, running: false };
document.getElementById('F5-go').textContent = 'Запустить';
document.getElementById('F5-v').textContent = '0 м/с';
document.getElementById('F5-t').textContent = '0 с';
draw();
}
function tick(dt){
if (!st.running) { draw(); return; }
const m1 = +document.getElementById('F5-m1').value;
const m2 = +document.getElementById('F5-m2').value;
const fr = +document.getElementById('F5-fr').value;
const g = 9.8;
const a = ((m1 - m2)*g - fr*Math.sign(st.v || (m1-m2))) / (m1 + m2);
st.v += a * dt;
/* движение: m1 опускается со скоростью v, m2 поднимается */
const dy = st.v * dt * 30; /* масштаб 30 px/м */
st.y1 += dy;
st.y2 -= dy;
/* ограничения */
if (st.y1 > H - 80){ st.y1 = H - 80; st.v = 0; st.running = false; document.getElementById('F5-go').textContent='Запустить'; }
if (st.y2 < 100){ st.y2 = 100; st.v = 0; st.running = false; document.getElementById('F5-go').textContent='Запустить'; }
if (st.y1 < 100){ st.y1 = 100; st.v = 0; st.running = false; document.getElementById('F5-go').textContent='Запустить'; }
if (st.y2 > H - 80){ st.y2 = H - 80; st.v = 0; st.running = false; document.getElementById('F5-go').textContent='Запустить'; }
st.t += dt;
document.getElementById('F5-v').textContent = st.v.toFixed(2) + ' м/с';
document.getElementById('F5-t').textContent = st.t.toFixed(1) + ' с';
draw();
}
function draw(){
const col = C();
ctx.fillStyle = col.bg || '#fafafa';
ctx.fillRect(0, 0, W, H);
/* потолок */
ctx.fillStyle = col.surface || '#a16207';
ctx.fillRect(0, 0, W, 30);
for (let x = 0; x < W; x += 12){
ctx.strokeStyle = '#7c4a08';
ctx.beginPath(); ctx.moveTo(x, 0); ctx.lineTo(x+6, 6); ctx.stroke();
}
/* кронштейн к блоку */
ctx.strokeStyle = col.axis || '#1e293b';
ctx.lineWidth = 4;
ctx.beginPath(); ctx.moveTo(blockX, 30); ctx.lineTo(blockX, blockY - blockR); ctx.stroke();
/* блок */
ctx.fillStyle = col.bodyLight || '#cbd5e1';
ctx.beginPath(); ctx.arc(blockX, blockY, blockR, 0, Math.PI*2); ctx.fill();
ctx.strokeStyle = col.axis || '#1e293b';
ctx.lineWidth = 2.5;
ctx.stroke();
/* радиальные линии (вращение) */
const rot = st.v * 0.1;
for (let i = 0; i < 4; i++){
const a = rot + i*Math.PI/2;
ctx.beginPath();
ctx.moveTo(blockX + (blockR-5)*Math.cos(a), blockY + (blockR-5)*Math.sin(a));
ctx.lineTo(blockX + 5*Math.cos(a), blockY + 5*Math.sin(a));
ctx.stroke();
}
/* нити */
const cordL = blockX - blockR;
const cordR = blockX + blockR;
ctx.lineWidth = 2;
ctx.beginPath();
ctx.moveTo(cordL, blockY); ctx.lineTo(cordL, st.y1);
ctx.moveTo(cordR, blockY); ctx.lineTo(cordR, st.y2);
ctx.stroke();
/* грузы */
const m1 = +document.getElementById('F5-m1').value;
const m2 = +document.getElementById('F5-m2').value;
const r1 = Math.min(40, 12 + m1*3);
const r2 = Math.min(40, 12 + m2*3);
ctx.fillStyle = col.forceGravity || '#2563eb';
ctx.fillRect(cordL - r1, st.y1, r1*2, r1);
ctx.strokeStyle = col.axis || '#1e293b';
ctx.lineWidth = 1.5;
ctx.strokeRect(cordL - r1, st.y1, r1*2, r1);
ctx.fillStyle = col.fail || '#dc2626';
ctx.fillRect(cordR - r2, st.y2, r2*2, r2);
ctx.strokeRect(cordR - r2, st.y2, r2*2, r2);
ctx.fillStyle = '#fff';
ctx.font = 'bold 12px Inter,sans-serif';
ctx.textAlign = 'center';
ctx.fillText('m₁ = '+m1.toFixed(1)+' кг', cordL, st.y1 + r1/2 + 4);
ctx.fillText('m₂ = '+m2.toFixed(1)+' кг', cordR, st.y2 + r2/2 + 4);
ctx.textAlign = 'left';
/* векторы силы тяжести */
if (st.t < 0.5 || !st.running){
B().arrow(ctx, cordL, st.y1 + r1, cordL, st.y1 + r1 + 40, col.forceGravity || '#2563eb', 2);
ctx.fillStyle = col.forceGravity || '#2563eb';
ctx.font = 'bold 12px Inter,sans-serif';
ctx.fillText('m₁g', cordL + 8, st.y1 + r1 + 30);
B().arrow(ctx, cordR, st.y2 + r2, cordR, st.y2 + r2 + 40, col.forceGravity || '#2563eb', 2);
ctx.fillText('m₂g', cordR + 8, st.y2 + r2 + 30);
/* T снизу */
B().arrow(ctx, cordL, st.y1, cordL, st.y1 - 30, col.forceTension || '#16a34a', 2);
ctx.fillStyle = col.forceTension || '#16a34a';
ctx.fillText('T', cordL + 8, st.y1 - 20);
B().arrow(ctx, cordR, st.y2, cordR, st.y2 - 30, col.forceTension || '#16a34a', 2);
ctx.fillText('T', cordR + 8, st.y2 - 20);
}
}
document.getElementById('F5-go').addEventListener('click', ()=>{
if (st.y1 >= H - 80 || st.y2 >= H - 80 || st.y1 < 110 || st.y2 < 110) reset();
st.running = !st.running;
document.getElementById('F5-go').textContent = st.running ? 'Пауза' : 'Запустить';
});
document.getElementById('F5-reset').addEventListener('click', reset);
['F5-m1','F5-m2','F5-fr'].forEach(id => document.getElementById(id).addEventListener('input', ()=>{
readSliders();
if (!st.running) reset();
}));
readSliders();
draw();
B().startLoop('F5', cv, tick);
return true;
}
if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F5', { init: init, cleanup: function(){} });
else document.addEventListener('DOMContentLoaded', ()=>{
if (window.PHYS9_FLAG_BASE) window.PHYS9_FLAG_BASE.register('F5', { init: init, cleanup: function(){} });
});
})();