// 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 = '' + '
' + '' + '' + '' + '
' + '' + '
' + '' + '' + '
' + '
' + '
$a = (m_1-m_2)g/(m_1+m_2)$1.96 м/с²
' + '
Натяжение T23.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(){} }); }); })();