From 7acc606cc22a9aae979b248aae1bd9bbb4d9615b Mon Sep 17 00:00:00 2001 From: Maxim Dolgolyov Date: Fri, 29 May 2026 16:25:24 +0300 Subject: [PATCH] =?UTF-8?q?feat(phys10=20ch1=20wave2):=20=C2=A73=20=C2=AB?= =?UTF-8?q?=D0=98=D0=B4=D0=B5=D0=B0=D0=BB=D1=8C=D0=BD=D1=8B=D0=B9=20=D0=B3?= =?UTF-8?q?=D0=B0=D0=B7=C2=BB=20+=20=C2=A74=20=C2=AB=D0=A2=D0=B5=D0=BC?= =?UTF-8?q?=D0=BF=D0=B5=D1=80=D0=B0=D1=82=D1=83=D1=80=D0=B0=C2=BB=20+=20?= =?UTF-8?q?=D1=81=D0=B8=D0=BC=D1=83=D0=BB=D1=8F=D1=86=D0=B8=D0=B8?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- frontend/textbooks/physics_10_ch1.html | 704 ++++++++++++++++++++++++- 1 file changed, 692 insertions(+), 12 deletions(-) diff --git a/frontend/textbooks/physics_10_ch1.html b/frontend/textbooks/physics_10_ch1.html index 1c25f5f..a915518 100644 --- a/frontend/textbooks/physics_10_ch1.html +++ b/frontend/textbooks/physics_10_ch1.html @@ -1290,34 +1290,714 @@ function build_p2(){ function build_p3(){ const box = document.getElementById('p3-body'); let html = ''; - html += makeCard('theory', "Идеальный газ. Основное уравнение МКТ", "§3", ` -

Идеальный газ. Основное уравнение МКТ — этот параграф в разработке (Phase 1+).

-

Здесь появятся: теория, формулы, разобранные примеры и 3–4 интерактива в стиле «алгебры 11» — таблицы, симуляции, ползунки, drag-and-drop и автопроверяемые тренажёры.

-

- Phase 0: создан скелет учебника. Phase 1+: наполнение этого § содержанием по учебнику «Физика 10» (Беларусь, 2019). -

+ + /* THEORY 1 — модель идеального газа */ + html += makeCard('theory', "Модель идеального газа", "§3", ` +

Идеальный газ — упрощённая модель реального газа, в которой:

+
    +
  1. Размеры молекул пренебрежимо малы по сравнению с расстояниями между ними.
  2. +
  3. Молекулы взаимодействуют только при столкновениях (как упругие шары).
  4. +
  5. Между столкновениями молекулы движутся равномерно и прямолинейно.
  6. +
+

Реальные газы при низком давлении и не очень низкой температуре близки к идеальному.

+

Параметры газа:

+ `); + + /* THEORY 2 — основное уравнение МКТ */ + html += makeCard('rule', "Основное уравнение МКТ", "§3", ` +

Давление идеального газа создаётся ударами молекул о стенки сосуда. Связь между макро- и микропараметрами:

+

$$p = \\dfrac{1}{3} n m_0 \\overline{v^2}$$

+

где:

+ +

Это основное уравнение МКТ идеального газа.

+

Через среднюю кинетическую энергию поступательного движения $\\overline{E_k} = \\dfrac{1}{2} m_0 \\overline{v^2}$:

+

$$p = \\dfrac{2}{3} n \\overline{E_k}$$

+ `); + + /* THEORY 3 — средняя квадратичная скорость */ + html += makeCard('example', "Средняя квадратичная скорость", "§3", ` +

Средняя квадратичная скорость молекул:

+

$$v_{ср.кв.} = \\sqrt{\\overline{v^2}}$$

+

Из основного уравнения МКТ:

+

$$\\overline{v^2} = \\dfrac{3p}{n m_0}$$

+

Примеры скоростей (при $T = 300$ К):

+ +

Чем легче молекула — тем быстрее она движется при той же температуре.

+ `); + + /* INTERACTIVE 1 — Симуляция давления газа */ + html += `
+
ИНТЕРАКТИВ 1
Симуляция давления газа
+
Меняй число молекул и их скорость — наблюдай удары о правую стенку. Давление пропорционально частоте ударов и квадрату скорости: $p \\sim n \\cdot v^2$.
+
+ + +
+
+ +
+
+ + +
+
+
Ударов в правую стенку за последнюю секунду: 0
+
Давление (усл. ед., $\\propto n v^2$):
+
+
`; + + /* INTERACTIVE 2 — Калькулятор основного уравнения МКТ */ + html += `
+
ИНТЕРАКТИВ 2
Калькулятор уравнения МКТ
+
$p = \\dfrac{1}{3} n m_0 \\overline{v^2}$. Введи параметры и получи давление и среднюю кинетическую энергию молекулы.
+
+ + + +
+
+ +
+
+ +
`; + + /* INTERACTIVE 3 — квикфайр Идеальный/Реальный */ + html += `
+
ИНТЕРАКТИВ 3
Идеальный или реальный газ?
+
6 ситуаций. Газ близок к идеальному при низком $p$ и не очень низком $T$. Жми соответствующую кнопку.
+
Задача 1 / 6Очки: 0 / 6
+
+
+ +
+
`; + + /* INTERACTIVE 4 — тренажёр МКТ */ + html += `
+
ИНТЕРАКТИВ 4
Тренажёр МКТ
+
5 задач на $p = \\frac{1}{3} n m_0 \\overline{v^2}$. Допуск $\\pm 5\\%$.
+
Задача 1 / 5Очки: 0 / 5
+
+
+ ответ = + + + +
+ +
`; + html += secNav('p2', 'p4'); html += readButton('p3'); + box.innerHTML = html; renderMath(box); + + /* IV1 — Симуляция давления газа */ + (function(){ + const svg = document.getElementById('p3-iv1-svg'); + const nInp = document.getElementById('p3-iv1-n'); + const vInp = document.getElementById('p3-iv1-v'); + const nLab = document.getElementById('p3-iv1-nL'); + const vLab = document.getElementById('p3-iv1-vL'); + const hitsEl = document.getElementById('p3-iv1-hits'); + const presEl = document.getElementById('p3-iv1-pres'); + const btnPause = document.getElementById('p3-iv1-pause'); + const btnReset = document.getElementById('p3-iv1-reset'); + const W = 400, H = 220, OX = 10, OY = 30; + let raf = null, lastT = 0, paused = false; + let sim = null; + let hitTimes = []; // timestamps ударов о правую стенку (сек) + let lastUpdate = 0; + const tempChanges = new Set(); + let _xpDone = false; + + function makeSim(){ + const N = +nInp.value; + const v = +vInp.value; + sim = PHYS.createGasSim({W, H, N, speed: v, r: 3}); + hitTimes = []; + } + function frame(t){ + raf = requestAnimationFrame(frame); + if(!lastT){ lastT = t; return; } + let dt = (t - lastT) / 1000; + lastT = t; + if(paused){ render(); return; } + if(dt > 0.06) dt = 0.06; + // подсчёт ударов о правую стенку (до step) — отслеживаем переход через правую границу + const R = sim.r; + const beforeX = sim.particles.map(p => p.x); + sim.step(dt); + for(let i = 0; i < sim.particles.length; i++){ + // если после step координата x = W - r и vx стало отрицательным — был удар + if(beforeX[i] < W - R - 0.1 && sim.particles[i].x >= W - R - 0.5 && sim.particles[i].vx < 0){ + hitTimes.push(t / 1000); + } + // более надёжный признак: за последний кадр частица отскочила от правой стенки (vx < 0 после step), а до этого vx > 0 + // мы упрощаем: считаем удар, если частица сейчас касается правой стенки + } + // удаляем старые удары (>1 сек назад) + const tSec = t / 1000; + while(hitTimes.length && hitTimes[0] < tSec - 1) hitTimes.shift(); + + if(tSec - lastUpdate > 0.3){ + lastUpdate = tSec; + const hits = hitTimes.length; + hitsEl.textContent = hits; + const n = +nInp.value; + const v = +vInp.value; + // условное «давление» — пропорционально n*v^2 / 1000 + const p = (n * v * v) / 1000; + presEl.textContent = p.toFixed(1); + } + render(); + } + function render(){ + let g = ''; + // рамка сосуда + g += ``; + // правая стенка — подсвечена + g += ``; + g += `стенка`; + // молекулы — сдвигаем в (OX, OY) + for(const p of sim.particles){ + g += ``; + } + svg.innerHTML = g; + } + + makeSim(); + raf = requestAnimationFrame(frame); + + nInp.addEventListener('input', () => { + nLab.textContent = nInp.value; + makeSim(); + tempChanges.add('n'+nInp.value+'v'+vInp.value); + if(!_xpDone && tempChanges.size >= 4){ + _xpDone = true; addXp(10, 'p3-iv1'); bumpProgress('p3', 15); + } + }); + vInp.addEventListener('input', () => { + vLab.textContent = vInp.value; + // не пересоздаём — масштабируем скорость + const cur = +vInp.value; + let avg = 0; + for(const p of sim.particles) avg += Math.hypot(p.vx, p.vy); + avg /= sim.particles.length; + if(avg > 0.01) sim.setSpeed(cur / avg); + tempChanges.add('n'+nInp.value+'v'+vInp.value); + if(!_xpDone && tempChanges.size >= 4){ + _xpDone = true; addXp(10, 'p3-iv1'); bumpProgress('p3', 15); + } + }); + btnPause.addEventListener('click', () => { + paused = !paused; + btnPause.textContent = paused ? 'Продолжить' : 'Пауза'; + }); + btnReset.addEventListener('click', () => { makeSim(); }); + document.addEventListener('visibilitychange', () => { + if(document.hidden && raf){ cancelAnimationFrame(raf); raf = null; lastT = 0; } + else if(!document.hidden && !raf){ raf = requestAnimationFrame(frame); } + }); + })(); + + /* IV2 — Калькулятор основного уравнения МКТ */ + (function(){ + const nI = document.getElementById('p3-iv2-n'); + const mI = document.getElementById('p3-iv2-m'); + const vI = document.getElementById('p3-iv2-v'); + const out = document.getElementById('p3-iv2-out'); + const fb = document.getElementById('p3-iv2-fb'); + const go = document.getElementById('p3-iv2-go'); + const used = new Set(); + let _done = false; + + function calc(){ + const n = parseFloat(nI.value); + const m0 = parseFloat(mI.value); + const v2 = parseFloat(vI.value); + if(!isFinite(n) || !isFinite(m0) || !isFinite(v2) || n <= 0 || m0 <= 0 || v2 <= 0){ + feedback(fb, false, '✗ Введи положительные значения во все поля.'); + return; + } + // n × 10^25, m0 × 10^-26, v2 × 10^6 → p = 1/3 · n·m0·v2 × 10^(25-26+6) = × 10^5 + const pCoef = (1/3) * n * m0 * v2; + const pPa = pCoef * 1e5; // Па + // средняя кинетическая энергия: Ek = (1/2) m0 v2 = (1/2) m0(10^-26) · v2(10^6) = (1/2) m0 v2 × 10^-20 Дж + const EkCoef = 0.5 * m0 * v2; // в 10^-20 Дж + const EkJ = EkCoef * 1e-20; + const EkEv = EkJ / 1.6e-19; + + out.innerHTML = + '
Подставляем:
' + + '
$p = \\dfrac{1}{3} \\cdot ' + (+n.toFixed(3)) + ' \\cdot 10^{25} \\cdot ' + (+m0.toFixed(3)) + ' \\cdot 10^{-26} \\cdot ' + (+v2.toFixed(3)) + ' \\cdot 10^{6}$
' + + '
Давление: $p \\approx ' + (+pCoef.toFixed(3)) + ' \\cdot 10^{5}$ Па $\\approx ' + (+(pPa/1e5).toFixed(3)) + '$ атм
' + + '
Средняя кинетическая энергия молекулы: $\\overline{E_k} = \\dfrac{1}{2} m_0 \\overline{v^2} \\approx ' + (+EkCoef.toFixed(3)) + ' \\cdot 10^{-20}$ Дж $\\approx ' + (+EkEv.toFixed(4)) + '$ эВ
'; + renderMath(out); + feedback(fb, true, '✓ Вычислено.'); + used.add((+n.toFixed(2))+':'+(+m0.toFixed(2))+':'+(+v2.toFixed(2))); + if(!_done && used.size >= 3){ _done = true; addXp(10, 'p3-iv2'); bumpProgress('p3', 15); } + } + go.addEventListener('click', calc); + [nI, mI, vI].forEach(el => el.addEventListener('keydown', e => { if(e.key === 'Enter') calc(); })); + })(); + + /* IV3 — квикфайр Идеальный/Реальный */ + (function(){ + const Q = [ + { q:'Воздух в комнате (комнатная температура, атмосферное давление)', ans:0, why:'При обычных условиях воздух близок к идеальному.' }, + { q:'Водяной пар у поверхности кипящей воды (готов конденсироваться)', ans:1, why:'Близок к конденсации — взаимодействия молекул нельзя пренебречь.' }, + { q:'Гелий при $T = 4$ К (на грани ожижения)', ans:1, why:'При очень низкой $T$ молекулы сильно взаимодействуют.' }, + { q:'Кислород в баллоне под давлением 200 атм', ans:1, why:'При высоком давлении расстояния между молекулами малы.' }, + { q:'Воздух в верхних слоях атмосферы (низкое давление)', ans:0, why:'Чем ниже $p$ — тем ближе к идеальному газу.' }, + { q:'Разреженный газ в плазме разряда (низкое $p$, очень высокая $T$)', ans:0, why:'Низкое давление и высокая $T$ — идеальные условия для модели.' }, + ]; + let i = 0, score = 0; + const qEl = document.getElementById('p3-iv3-q'); + const oEl = document.getElementById('p3-iv3-opts'); + const fb = document.getElementById('p3-iv3-fb'); + const iEl = document.getElementById('p3-iv3-i'); + const sEl = document.getElementById('p3-iv3-s'); + + function show(){ + if(i >= Q.length){ + qEl.innerHTML = 'Готово! Результат: ' + score + ' / ' + Q.length; + oEl.innerHTML = ''; + if(score === Q.length){ addXp(15, 'p3-iv3'); bumpProgress('p3', 25); } + else if(score >= 4){ addXp(8, 'p3-iv3'); bumpProgress('p3', 15); } + return; + } + iEl.textContent = (i+1); sEl.textContent = score; + const item = Q[i]; + qEl.innerHTML = item.q; + oEl.innerHTML = ''; + fb.style.display = 'none'; + renderMath(qEl); + oEl.querySelectorAll('button').forEach(b => { + b.addEventListener('click', () => { + const v = +b.dataset.v; + if(v === item.ans){ score++; feedback(fb, true, '✓ Верно! ' + item.why + ' Дальше ▶'); } + else feedback(fb, false, '✗ Неверно. ' + item.why + ' Дальше ▶'); + sEl.textContent = score; + oEl.querySelectorAll('button').forEach(x => x.disabled = true); + i++; + setTimeout(show, 1500); + }); + }); + } + document.getElementById('p3-iv3-restart').addEventListener('click', () => { i = 0; score = 0; show(); }); + show(); + })(); + + /* IV4 — тренажёр МКТ */ + (function(){ + const Q = [ + { q:'$n = 3 \\cdot 10^{25}$ м$^{-3}$, $m_0 = 5 \\cdot 10^{-26}$ кг, $\\overline{v^2} = 4 \\cdot 10^{5}$ м²/с². Введи коэффициент при $10^5$ Па.', ans:2, hint:'$p = \\frac{1}{3} \\cdot 3 \\cdot 5 \\cdot 4 \\cdot 10^{25-26+5} = 20 \\cdot 10^{4} = 2 \\cdot 10^{5}$' }, + { q:'$\\overline{E_k} = 6 \\cdot 10^{-21}$ Дж, $n = 5 \\cdot 10^{25}$ м$^{-3}$. Введи коэффициент при $10^5$ Па.', ans:2, hint:'$p = \\frac{2}{3} n \\overline{E_k} = \\frac{2}{3} \\cdot 5 \\cdot 10^{25} \\cdot 6 \\cdot 10^{-21} = 2 \\cdot 10^{5}$' }, + { q:'Если давление и концентрацию увеличить вдвое, во сколько раз изменится $\\overline{v^2}$?', ans:1, hint:'$p = \\frac{1}{3} n m_0 \\overline{v^2}$: если $p$ и $n$ ×2, то $\\overline{v^2}$ не меняется.' }, + { q:'Если массу молекулы $m_0$ увеличить в 4 раза при том же $p$ и $n$, во сколько раз изменится $\\overline{v^2}$?', ans:0.25, hint:'$\\overline{v^2} \\sim 1/m_0$ при фиксированных $p, n$ — уменьшится в 4 раза.' }, + { q:'Концентрация газа $n = 2{,}5 \\cdot 10^{25}$ м$^{-3}$. Сколько молекул в $1$ м³? Введи коэффициент при $10^{25}$.', ans:2.5, hint:'$N = n \\cdot V = 2{,}5 \\cdot 10^{25}$.' }, + ]; + let i = 0, score = 0; + function show(){ + if(i >= Q.length){ + document.getElementById('p3-iv4-q').innerHTML = 'Готово! Результат: ' + score + ' / ' + Q.length; + if(score === Q.length){ addXp(15, 'p3-iv4'); bumpProgress('p3', 25); } + else if(score >= 3){ addXp(8, 'p3-iv4'); bumpProgress('p3', 15); } + return; + } + document.getElementById('p3-iv4-i').textContent = (i+1); + document.getElementById('p3-iv4-s').textContent = score; + document.getElementById('p3-iv4-q').innerHTML = Q[i].q; + document.getElementById('p3-iv4-ans').value = ''; + renderMath(document.getElementById('p3-iv4-q')); + document.getElementById('p3-iv4-fb').style.display = 'none'; + } + function go(){ + if(i >= Q.length) return; + const fb = document.getElementById('p3-iv4-fb'); + const raw = document.getElementById('p3-iv4-ans').value.replace(',', '.'); + const ans = parseFloat(raw); + if(isNaN(ans)){ feedback(fb, false, '✗ Введи число.'); return; } + const tol = Math.max(0.05 * Math.abs(Q[i].ans), 0.05); + if(Math.abs(ans - Q[i].ans) < tol){ score++; feedback(fb, true, '✓ Верно! '+Q[i].hint+'. Дальше ▶'); } + else feedback(fb, false, '✗ Неверно. Ответ: $'+Q[i].ans+'$. '+Q[i].hint+'. Дальше ▶'); + document.getElementById('p3-iv4-s').textContent = score; + i++; + setTimeout(show, 1700); + } + document.getElementById('p3-iv4-go').addEventListener('click', go); + document.getElementById('p3-iv4-ans').addEventListener('keydown', e => { if(e.key === 'Enter') go(); }); + document.getElementById('p3-iv4-start').addEventListener('click', () => { i = 0; score = 0; show(); }); + show(); + })(); + wireReadBtn('p3'); } function build_p4(){ const box = document.getElementById('p4-body'); let html = ''; - html += makeCard('theory', "Температура. Тепловое равновесие", "§4", ` -

Температура. Тепловое равновесие — этот параграф в разработке (Phase 1+).

-

Здесь появятся: теория, формулы, разобранные примеры и 3–4 интерактива в стиле «алгебры 11» — таблицы, симуляции, ползунки, drag-and-drop и автопроверяемые тренажёры.

-

- Phase 0: создан скелет учебника. Phase 1+: наполнение этого § содержанием по учебнику «Физика 10» (Беларусь, 2019). -

+ + /* THEORY 1 — тепловое равновесие и температура */ + html += makeCard('theory', "Тепловое равновесие и температура", "§4", ` +

Тепловое равновесие — состояние термодинамической системы, в котором её макроскопические параметры (температура, давление, плотность) не меняются со временем.

+

Температура — физическая величина, характеризующая состояние теплового равновесия. Если два тела находятся в тепловом равновесии — их температуры равны.

+

Шкалы температуры:

+
    +
  • Цельсия ($t$, °C): $0°$C — таяние льда, $100°$C — кипение воды (при $p = 101{,}3$ кПа).
  • +
  • Кельвина ($T$, К): абсолютная шкала. $T = 0$ K — абсолютный нуль.
  • +
+

Связь шкал:

+

$$T = t + 273{,}15 \\approx t + 273$$

+

Абсолютный нуль ($0$ К $= -273{,}15°$C) — теоретический предел: невозможно охладить вещество ниже.

`); + + /* THEORY 2 — температура и средняя кинетическая энергия */ + html += makeCard('rule', "Температура и средняя кинетическая энергия", "§4", ` +

Постоянная Больцмана: $k_B = 1{,}38 \\cdot 10^{-23}$ Дж/К.

+

Главная формула — связь температуры и средней кинетической энергии молекул:

+

$$\\overline{E_k} = \\dfrac{3}{2} k_B T$$

+

Из этой формулы и основного уравнения МКТ ($p = \\frac{2}{3} n \\overline{E_k}$) получаем уравнение состояния:

+

$$p = n k_B T$$

+

Температура — мера средней кинетической энергии хаотического теплового движения молекул.

+ `); + + /* THEORY 3 — средняя квадратичная скорость */ + html += makeCard('example', "Средняя квадратичная скорость молекул", "§4", ` +

Из $\\overline{E_k} = \\dfrac{1}{2} m_0 \\overline{v^2} = \\dfrac{3}{2} k_B T$ выводим:

+

$$\\overline{v^2} = \\dfrac{3 k_B T}{m_0}$$

+

Средняя квадратичная скорость:

+

$$v_{ср.кв.} = \\sqrt{\\dfrac{3 k_B T}{m_0}} = \\sqrt{\\dfrac{3 R T}{M}}$$

+

где $R = N_A \\cdot k_B = 8{,}314$ Дж/(моль·К) — универсальная газовая постоянная.

+

Примеры (при $T = 300$ К):

+
    +
  • Водород ($M = 2$ г/моль): $v \\approx 1934$ м/с.
  • +
  • Азот ($M = 28$ г/моль): $v \\approx 517$ м/с.
  • +
  • Кислород ($M = 32$ г/моль): $v \\approx 484$ м/с.
  • +
  • Углекислый газ ($M = 44$ г/моль): $v \\approx 412$ м/с.
  • +
+

Чем выше $T$ и легче молекула — тем больше скорость.

+ `); + + /* INTERACTIVE 1 — Температурный визуализатор */ + html += `
+
ИНТЕРАКТИВ 1
Температурный визуализатор
+
Меняй $T$ — наблюдай, как меняется скорость молекул ($\\sim \\sqrt{T}$) и цвет (от холодного к горячему).
+
+ +
+
+ +
+
+ + +
+
+
$T = $ 300 К ($t = $ 27 °C)
+
$\\overline{E_k} = \\dfrac{3}{2} k_B T \\approx$ 6.21 $\\cdot 10^{-21}$ Дж
+
$v_{ср.кв.}$ (для азота, $m_0 = 4{,}65 \\cdot 10^{-26}$ кг) $\\approx$ 517 м/с
+
+
`; + + /* INTERACTIVE 2 — Калькулятор температуры и скорости */ + html += `
+
ИНТЕРАКТИВ 2
Калькулятор $T$, $\\overline{E_k}$ и $v_{ср.кв.}$
+
Введи $T$ и выбери газ — получи среднюю кинетическую энергию и среднюю квадратичную скорость.
+
+ + +
+
+ +
+
+ +
`; + + /* INTERACTIVE 3 — Конвертер шкал */ + html += `
+
ИНТЕРАКТИВ 3
Конвертер шкал и быстрая проверка
+
6 вопросов: переведи температуру по шкалам или узнай типичное значение. Выбери правильный ответ.
+
Задача 1 / 6Очки: 0 / 6
+
+
+ +
+
`; + + /* INTERACTIVE 4 — Тренажёр температуры */ + html += `
+
ИНТЕРАКТИВ 4
Тренажёр температуры
+
5 задач. Используй $k_B = 1{,}38 \\cdot 10^{-23}$ Дж/К, $R = 8{,}3$ Дж/(моль·К).
+
Задача 1 / 5Очки: 0 / 5
+
+
+ ответ = + + + +
+ +
`; + html += secNav('p3', 'p5'); html += readButton('p4'); + box.innerHTML = html; renderMath(box); + + /* IV1 — Температурный визуализатор */ + (function(){ + const svg = document.getElementById('p4-iv1-svg'); + const tInp = document.getElementById('p4-iv1-T'); + const tLab = document.getElementById('p4-iv1-tL'); + const T2 = document.getElementById('p4-iv1-T2'); + const tc = document.getElementById('p4-iv1-tc'); + const EkEl = document.getElementById('p4-iv1-Ek'); + const vEl = document.getElementById('p4-iv1-v'); + const btnPause = document.getElementById('p4-iv1-pause'); + const btnReset = document.getElementById('p4-iv1-reset'); + const W = 400, H = 220, OX = 10, OY = 30; + const baseSpeed = 80; // соответствует T0 = 300 К + let raf = null, lastT = 0, paused = false; + let sim = null; + const tempChanges = new Set(); + let _xpDone = false; + + function tempColor(T){ + // 100 К → синий (#60a5fa), 300 К → бирюзовый, 600 К → жёлтый, 1000 К → красный + const t = Math.max(0, Math.min(1, (T - 100) / 900)); + // интерполяция: синий (0.16, 0.5, 0.96) → красный (0.94, 0.27, 0.21) + const r = Math.round(255 * (0.16 + t * (0.94 - 0.16))); + const g = Math.round(255 * (0.5 + t * (0.27 - 0.5))); + const b = Math.round(255 * (0.96 + t * (0.21 - 0.96))); + return `rgb(${r},${g},${b})`; + } + function makeSim(){ + sim = PHYS.createGasSim({W, H, N: 40, speed: baseSpeed, r: 4}); + applyTemp(+tInp.value); + } + function applyTemp(T){ + const targetScale = Math.sqrt(T/300); + let curAvg = 0; + for(const p of sim.particles) curAvg += Math.hypot(p.vx, p.vy); + curAvg /= sim.particles.length; + const targetAvg = baseSpeed * targetScale; + if(curAvg > 0.01) sim.setSpeed(targetAvg / curAvg); + updateLabels(T); + } + function updateLabels(T){ + const kB = PHYS.CONST.kB; + const Ek = 1.5 * kB * T; // Дж + // m0 для азота: M = 0.028 кг/моль / NA = 4.65e-26 кг + const m0 = 0.028 / PHYS.CONST.NA; + const v = Math.sqrt(3 * kB * T / m0); + T2.textContent = T; + tc.textContent = (T - 273.15).toFixed(1); + EkEl.textContent = (Ek / 1e-21).toFixed(2); + vEl.textContent = Math.round(v); + } + function frame(t){ + raf = requestAnimationFrame(frame); + if(!lastT){ lastT = t; return; } + let dt = (t - lastT) / 1000; + lastT = t; + if(paused){ render(); return; } + if(dt > 0.06) dt = 0.06; + sim.step(dt); + render(); + } + function render(){ + const T = +tInp.value; + const col = tempColor(T); + let g = ''; + g += ``; + // лейбл температуры + g += `T = ${T} K`; + for(const p of sim.particles){ + g += ``; + } + svg.innerHTML = g; + } + + makeSim(); + raf = requestAnimationFrame(frame); + + tInp.addEventListener('input', () => { + const T = +tInp.value; + tLab.textContent = T; + applyTemp(T); + // snap к ключевым точкам + tempChanges.add(T); + if(!_xpDone && tempChanges.size >= 4){ + _xpDone = true; addXp(10, 'p4-iv1'); bumpProgress('p4', 15); + } + }); + btnPause.addEventListener('click', () => { + paused = !paused; + btnPause.textContent = paused ? 'Продолжить' : 'Пауза'; + }); + btnReset.addEventListener('click', () => { makeSim(); }); + document.addEventListener('visibilitychange', () => { + if(document.hidden && raf){ cancelAnimationFrame(raf); raf = null; lastT = 0; } + else if(!document.hidden && !raf){ raf = requestAnimationFrame(frame); } + }); + })(); + + /* IV2 — Калькулятор T, Ek, v */ + (function(){ + const TI = document.getElementById('p4-iv2-T'); + const MI = document.getElementById('p4-iv2-M'); + const out = document.getElementById('p4-iv2-out'); + const fb = document.getElementById('p4-iv2-fb'); + const go = document.getElementById('p4-iv2-go'); + const used = new Set(); + let _done = false; + + function calc(){ + const T = parseFloat(TI.value); + const Mg = parseFloat(MI.value); // г/моль + if(!isFinite(T) || T <= 0){ feedback(fb, false, '✗ Введи положительную температуру (К).'); return; } + const kB = PHYS.CONST.kB; + const R = PHYS.CONST.R; + const M = Mg * 1e-3; // кг/моль + const Ek = 1.5 * kB * T; // Дж + const v = Math.sqrt(3 * R * T / M); + const m0 = M / PHYS.CONST.NA; + + out.innerHTML = + '
Подставляем:
' + + '
$\\overline{E_k} = \\dfrac{3}{2} k_B T = \\dfrac{3}{2} \\cdot 1{,}38 \\cdot 10^{-23} \\cdot ' + (+T.toFixed(2)) + ' \\approx ' + (+(Ek/1e-21).toFixed(2)) + ' \\cdot 10^{-21}$ Дж
' + + '
$v_{ср.кв.} = \\sqrt{\\dfrac{3 R T}{M}} = \\sqrt{\\dfrac{3 \\cdot 8{,}314 \\cdot ' + (+T.toFixed(2)) + '}{' + Mg + ' \\cdot 10^{-3}}} \\approx ' + Math.round(v) + '$ м/с
' + + '
Масса одной молекулы: $m_0 = M/N_A \\approx ' + (+(m0/1e-26).toFixed(3)) + ' \\cdot 10^{-26}$ кг
'; + renderMath(out); + feedback(fb, true, '✓ Вычислено.'); + used.add(T+':'+Mg); + if(!_done && used.size >= 3){ _done = true; addXp(10, 'p4-iv2'); bumpProgress('p4', 15); } + } + go.addEventListener('click', calc); + TI.addEventListener('keydown', e => { if(e.key === 'Enter') calc(); }); + })(); + + /* IV3 — Конвертер шкал */ + (function(){ + const opts = ['0 К', '273 К', '300 К', '373 К']; + const Q = [ + { q:'$t = 0°$C — это сколько К?', ans:1, why:'$T = 0 + 273 = 273$ К.' }, + { q:'$t = -273°$C — это сколько К? (округлим)', ans:0, why:'$T = -273 + 273 = 0$ К — абсолютный нуль.' }, + { q:'$t = 100°$C — это сколько К?', ans:3, why:'$T = 100 + 273 = 373$ К.' }, + { q:'$t = 27°$C (комнатная) — это сколько К?', ans:2, why:'$T = 27 + 273 = 300$ К.' }, + { q:'Абсолютный нуль — это какая температура?', ans:0, why:'Абсолютный нуль = $0$ К $= -273{,}15°$C.' }, + { q:'Тёплая комната ($t \\approx 27°$C) — это какая температура $T$?', ans:2, why:'Комнатная $T \\approx 300$ К.' }, + ]; + let i = 0, score = 0; + const qEl = document.getElementById('p4-iv3-q'); + const oEl = document.getElementById('p4-iv3-opts'); + const fb = document.getElementById('p4-iv3-fb'); + const iEl = document.getElementById('p4-iv3-i'); + const sEl = document.getElementById('p4-iv3-s'); + + function show(){ + if(i >= Q.length){ + qEl.innerHTML = 'Готово! Результат: ' + score + ' / ' + Q.length; + oEl.innerHTML = ''; + if(score === Q.length){ addXp(15, 'p4-iv3'); bumpProgress('p4', 25); } + else if(score >= 4){ addXp(8, 'p4-iv3'); bumpProgress('p4', 15); } + return; + } + iEl.textContent = (i+1); sEl.textContent = score; + const item = Q[i]; + qEl.innerHTML = item.q; + oEl.innerHTML = opts.map((o, j) => '').join(''); + fb.style.display = 'none'; + renderMath(qEl); + oEl.querySelectorAll('button').forEach(b => { + b.addEventListener('click', () => { + const v = +b.dataset.v; + if(v === item.ans){ score++; feedback(fb, true, '✓ Верно! ' + item.why + ' Дальше ▶'); } + else feedback(fb, false, '✗ Неверно. ' + item.why + ' Дальше ▶'); + sEl.textContent = score; + oEl.querySelectorAll('button').forEach(x => x.disabled = true); + i++; + setTimeout(show, 1500); + }); + }); + } + document.getElementById('p4-iv3-restart').addEventListener('click', () => { i = 0; score = 0; show(); }); + show(); + })(); + + /* IV4 — Тренажёр температуры */ + (function(){ + const Q = [ + { q:'При $T = 300$ К средняя кинетическая энергия молекулы. Введи мантиссу для $a \\cdot 10^{-21}$ Дж.', ans:6.2, hint:'$E_k = \\frac{3}{2} k_B T = 1{,}5 \\cdot 1{,}38 \\cdot 10^{-23} \\cdot 300 \\approx 6{,}21 \\cdot 10^{-21}$ Дж' }, + { q:'$t = 27°$C — это сколько К?', ans:300, hint:'$T = t + 273 = 300$' }, + { q:'При какой температуре $\\overline{E_k}$ удвоится по сравнению с $T = 300$ К?', ans:600, hint:'$E_k \\sim T$, значит $T = 2 \\cdot 300 = 600$ К' }, + { q:'$v_{ср.кв.}$ молекул азота ($M = 28$ г/моль) при $T = 300$ К, в м/с (допуск $\\pm 20$).', ans:516, hint:'$v = \\sqrt{3 R T / M} = \\sqrt{3 \\cdot 8{,}3 \\cdot 300 / 0{,}028} \\approx 516$ м/с' }, + { q:'При $T = 0$ К средняя кинетическая энергия молекулы (Дж)?', ans:0, hint:'$E_k = \\frac{3}{2} k_B \\cdot 0 = 0$' }, + ]; + let i = 0, score = 0; + function show(){ + if(i >= Q.length){ + document.getElementById('p4-iv4-q').innerHTML = 'Готово! Результат: ' + score + ' / ' + Q.length; + if(score === Q.length){ addXp(15, 'p4-iv4'); bumpProgress('p4', 25); } + else if(score >= 3){ addXp(8, 'p4-iv4'); bumpProgress('p4', 15); } + return; + } + document.getElementById('p4-iv4-i').textContent = (i+1); + document.getElementById('p4-iv4-s').textContent = score; + document.getElementById('p4-iv4-q').innerHTML = Q[i].q; + document.getElementById('p4-iv4-ans').value = ''; + renderMath(document.getElementById('p4-iv4-q')); + document.getElementById('p4-iv4-fb').style.display = 'none'; + } + function go(){ + if(i >= Q.length) return; + const fb = document.getElementById('p4-iv4-fb'); + const raw = document.getElementById('p4-iv4-ans').value.replace(',', '.'); + const ans = parseFloat(raw); + if(isNaN(ans)){ feedback(fb, false, '✗ Введи число.'); return; } + let tol; + if(Q[i].ans === 0) tol = 0.05; + else if(Q[i].ans === 516) tol = 20; + else tol = Math.max(0.05 * Math.abs(Q[i].ans), 0.05); + if(Math.abs(ans - Q[i].ans) < tol + 0.001){ score++; feedback(fb, true, '✓ Верно! '+Q[i].hint+'. Дальше ▶'); } + else feedback(fb, false, '✗ Неверно. Ответ: $'+Q[i].ans+'$. '+Q[i].hint+'. Дальше ▶'); + document.getElementById('p4-iv4-s').textContent = score; + i++; + setTimeout(show, 1700); + } + document.getElementById('p4-iv4-go').addEventListener('click', go); + document.getElementById('p4-iv4-ans').addEventListener('keydown', e => { if(e.key === 'Enter') go(); }); + document.getElementById('p4-iv4-start').addEventListener('click', () => { i = 0; score = 0; show(); }); + show(); + })(); + wireReadBtn('p4'); }