Просмотр исходного кода

частотная и фазовая модуляции

ypv 1 день назад
Родитель
Сommit
bf3270d4ef
2 измененных файлов с 482 добавлено и 114 удалено
  1. 460 109
      ПМ.03.01/3.1.100/002/index.html
  2. 22 5
      ПМ.03.01/3.1.100/002/specification.md

+ 460 - 109
ПМ.03.01/3.1.100/002/index.html

@@ -13,6 +13,7 @@
   --red: #b22222;
   --green: #2a6a3a;
   --blue: #1a4a7a;
+  --purple: #6a3a8a;
   --mono: 'Roboto Mono', 'Courier New', monospace;
   --serif: 'PT Serif', Georgia, serif;
   --sans: 'Oswald', 'Arial Narrow', sans-serif;
@@ -48,7 +49,7 @@ header .sub {
   opacity: 0.7;
 }
 #progress-bar { height: 4px; background: var(--paper-dark); }
-#progress-fill { height: 100%; background: var(--red); width: 11.1%; transition: width 0.3s; }
+#progress-fill { height: 100%; background: var(--red); width: 9.1%; transition: width 0.3s; }
 main { max-width: 900px; margin: 0 auto; padding: 20px; }
 .scene { display: none; }
 .scene.active { display: block; animation: fadeIn 0.25s; }
@@ -215,6 +216,7 @@ footer { text-align: center; padding: 20px; font-family: var(--mono); font-size:
     <li>объяснить, почему ДВ огибает холм, а Wi-Fi за тем же холмом не работает;</li>
     <li>объяснить, почему КВ слышно за тысячи километров, а УКВ — только в прямой видимости;</li>
     <li>выбрать диапазон под задачу (подводная связь, вещание, мобильная, спутник);</li>
+    <li>объяснить, чем амплитудная, частотная и фазовая модуляции отличаются и где какая применяется;</li>
     <li>объяснить, как направленная антенна, ППРЧ и экранирование снижают риск перехвата и подавления.</li>
   </ul>
   <div class="nav"><span></span><button class="btn" onclick="goTo(2)">Начать →</button></div>
@@ -250,13 +252,15 @@ footer { text-align: center; padding: 20px; font-family: var(--mono); font-size:
       <dt>Длина волны</dt>
       <dd>λ = c / f, [м]. Частота f, [Гц].</dd>
       <dt>Модулирующий сигнал</dt>
-      <dd>Низкочастотный сигнал, содержащий информацию (звук, данные). Обозначение F<sub>м</sub>, [Гц].</dd>
+      <dd>Низкочастотный сигнал, содержащий информацию. Обозначение F<sub>м</sub>, [Гц].</dd>
       <dt>Несущая</dt>
       <dd>Высокочастотное колебание, переносящее сигнал. Обозначение f<sub>c</sub>, [Гц].</dd>
-      <dt>Модуляция</dt>
-      <dd>Изменение параметров несущей по закону модулирующего сигнала.</dd>
-      <dt>Полоса пропускания</dt>
-      <dd>Интервал частот, занимаемый сигналом. Для АМ: B = 2F<sub>м</sub>.</dd>
+      <dt>Амплитудная модуляция (АМ)</dt>
+      <dd>Амплитуда несущей меняется по закону сигнала. Полоса B = 2F<sub>м</sub>.</dd>
+      <dt>Частотная модуляция (ЧМ)</dt>
+      <dd>Частота несущей меняется по закону сигнала, амплитуда постоянна. Девиация Δf. Индекс β = Δf/F<sub>м</sub>. Полоса по Карсону B ≈ 2(Δf + F<sub>м</sub>).</dd>
+      <dt>Фазовая модуляция (ФМ)</dt>
+      <dd>Фаза несущей меняется по закону сигнала, амплитуда постоянна. Индекс β. Полоса B ≈ 2F<sub>м</sub>(β + 1).</dd>
       <dt>Дифракция</dt>
       <dd>Огибание волной препятствий, соизмеримых с λ.</dd>
       <dt>Ионосфера</dt>
@@ -271,7 +275,7 @@ footer { text-align: center; padding: 20px; font-family: var(--mono); font-size:
 
 <!-- 4 -->
 <section class="scene" data-scene="4">
-  <h2>4. Принцип радиосвязи: несущая и модуляция</h2>
+  <h2>4. Амплитудная модуляция (АМ)</h2>
   <p>Информацию переносит не сама несущая, а её изменение. Передатчик формирует высокочастотную несущую, модулятор накладывает на неё сигнал, антенна излучает. Приёмник отделяет сигнал обратно.</p>
 
   <div class="feedback" style="border-left-color:#2a6a3a;background:rgba(42,106,58,0.08)">
@@ -299,13 +303,71 @@ footer { text-align: center; padding: 20px; font-family: var(--mono); font-size:
   </div>
   <div class="readout" id="r-mod"></div>
   <div class="feedback" id="fb-mod"></div>
-  <p class="legend">Верхний график — модулирующий сигнал F_м (низкочастотный, зелёный). Средний — несущая f_c (синяя), <b>то же число осцилляций</b>, что на нижнем. Нижний — АМ-сигнал: <b style="color:#b22222">красная огибающая точно повторяет верхний график (F_м)</b>, <b style="color:#1a4a7a">заполнение под ней — несущая f_c, то же число осцилляций, что на среднем</b>. При движении F_м меняется только огибающая (верхний и нижний синхронно). При движении f_c — только число осцилляций несущей (средний и нижний синхронно). Масштаб осцилляций условный (реальное отношение f_c/F_м = 200:1 нечитаемо), реальные λ — в readout.</p>
+  <p class="legend">Верхний график — модулирующий сигнал F_м (зелёный). Средний — несущая f_c (синяя). Нижний — АМ-сигнал: <b style="color:#b22222">красная огибающая точно повторяет верхний график (F_м)</b>, <b style="color:#1a4a7a">заполнение под ней — несущая f_c, то же число осцилляций, что на среднем</b>. При движении F_м меняется только огибающая. При движении f_c — только число осцилляций несущей. Масштаб осцилляций условный (реальное 200:1 нечитаемо), реальные λ — в readout.</p>
   <div class="nav"><button class="btn" onclick="goTo(3)">← Назад</button><button class="btn" onclick="goTo(5)">Далее →</button></div>
 </section>
 
-<!-- 5 -->
+<!-- 5: ЧМ -->
 <section class="scene" data-scene="5">
-  <h2>5. Распространение: дифракция и прямая видимость</h2>
+  <h2>5. Частотная модуляция (ЧМ)</h2>
+  <p>В АМ меняется амплитуда несущей, а частота постоянна. В ЧМ наоборот: <b>амплитуда постоянна, а частота несущей меняется по закону модулирующего сигнала</b>. Информация заложена в отклонении частоты от среднего значения — в девиации.</p>
+  <p><b>Девиация Δf</b> — максимальное отклонение мгновенной частоты от несущей. <b>Индекс модуляции β = Δf / F<sub>м</sub></b> — насколько «глубоко» модулируем. Полоса по Карсону: <b>B ≈ 2(Δf + F<sub>м</sub>)</b>.</p>
+  <canvas id="c-fm"></canvas>
+  <div class="controls">
+    <div class="control-row">
+      <label>Модулирующий сигнал F<sub>м</sub></label>
+      <input type="range" id="s-fm-fm" min="1" max="20" step="0.5" value="5">
+      <span class="value-box" id="v-fm-fm">5 кГц</span>
+    </div>
+    <div class="control-row">
+      <label>Несущая f<sub>c</sub></label>
+      <input type="range" id="s-fc-fm" min="0.5" max="5" step="0.1" value="1">
+      <span class="value-box" id="v-fc-fm">1.0 МГц</span>
+    </div>
+    <div class="control-row">
+      <label>Девиация Δf</label>
+      <input type="range" id="s-dev-fm" min="1" max="50" step="1" value="10">
+      <span class="value-box" id="v-dev-fm">10 кГц</span>
+    </div>
+  </div>
+  <div class="readout" id="r-fm"></div>
+  <div class="feedback" id="fb-fm"></div>
+  <p class="legend">Верхний — модулирующий F_м. Средний — несущая f_c без модуляции (для сравнения). Нижний — ЧМ-сигнал: <b style="color:#6a3a8a">амплитуда постоянна</b>, но осцилляции <b>сгущаются</b> (частота выше) при положительной полуволне модулирующего и <b>разрежаются</b> (частота ниже) при отрицательной. Это и есть модуляция частоты. Масштаб осцилляций условный.</p>
+  <div class="nav"><button class="btn" onclick="goTo(4)">← Назад</button><button class="btn" onclick="goTo(6)">Далее →</button></div>
+</section>
+
+<!-- 6: ФМ -->
+<section class="scene" data-scene="6">
+  <h2>6. Фазовая модуляция (ФМ)</h2>
+  <p>В ФМ <b>амплитуда тоже постоянна</b>, но меняется не частота, а <b>фаза несущей</b> — она сдвигается вперёд-назад по закону модулирующего сигнала. Внешне сигнал похож на ЧМ, но есть принципиальное отличие: в ЧМ мгновенная частота пропорциональна модулирующему (sin), а в ФМ сама фаза пропорциональна модулирующему. Значит, мгновенная частота в ФМ меняется по производной — по cos, со сдвигом π/2 относительно огибающей.</p>
+  <p><b>Индекс модуляции β</b> — максимальный сдвиг фазы в радианах. Полоса: <b>B ≈ 2F<sub>м</sub>(β + 1)</b>.</p>
+  <canvas id="c-pm"></canvas>
+  <div class="controls">
+    <div class="control-row">
+      <label>Модулирующий сигнал F<sub>м</sub></label>
+      <input type="range" id="s-fm-pm" min="1" max="20" step="0.5" value="5">
+      <span class="value-box" id="v-fm-pm">5 кГц</span>
+    </div>
+    <div class="control-row">
+      <label>Несущая f<sub>c</sub></label>
+      <input type="range" id="s-fc-pm" min="0.5" max="5" step="0.1" value="1">
+      <span class="value-box" id="v-fc-pm">1.0 МГц</span>
+    </div>
+    <div class="control-row">
+      <label>Индекс модуляции β</label>
+      <input type="range" id="s-beta-pm" min="0" max="10" step="0.1" value="2">
+      <span class="value-box" id="v-beta-pm">2.0</span>
+    </div>
+  </div>
+  <div class="readout" id="r-pm"></div>
+  <div class="feedback" id="fb-pm"></div>
+  <p class="legend">Верхний — модулирующий F_м. Средний — несущая f_c без модуляции. Нижний — ФМ-сигнал: амплитуда постоянна, <b style="color:#6a3a8a">фаза смещается вперёд-назад</b> — видно, как осцилляции сдвигаются вправо-влево в такт с модулирующим, но частота меняется не в фазе с ним, а со сдвигом π/2. Это отличие от ЧМ. Масштаб условный.</p>
+  <div class="nav"><button class="btn" onclick="goTo(5)">← Назад</button><button class="btn" onclick="goTo(7)">Далее →</button></div>
+</section>
+
+<!-- 7 -->
+<section class="scene" data-scene="7">
+  <h2>7. Распространение: дифракция и прямая видимость</h2>
   <p>Волна огибает препятствие, если её длина соизмерима с препятствием. Если λ много меньше — за препятствием тень.</p>
   <p>Геометрия: передатчик и приёмник на земле, по 10 км от препятствия. Препятствие — ножевой край на 200 м выше линии прямой видимости. Меняйте λ и смотрите, что доходит до приёмника.</p>
   <canvas id="c-diff"></canvas>
@@ -319,12 +381,12 @@ footer { text-align: center; padding: 20px; font-family: var(--mono); font-size:
   <div class="readout" id="r-diff"></div>
   <div class="feedback" id="fb-diff"></div>
   <p class="legend">Вертикальный масштаб увеличен. Модель ножевого края (ITU-R P.526); реальный холм даёт меньше потерь, но качественно то же.</p>
-  <div class="nav"><button class="btn" onclick="goTo(4)">← Назад</button><button class="btn" onclick="goTo(6)">Далее →</button></div>
+  <div class="nav"><button class="btn" onclick="goTo(6)">← Назад</button><button class="btn" onclick="goTo(8)">Далее →</button></div>
 </section>
 
-<!-- 6 -->
-<section class="scene" data-scene="6">
-  <h2>6. Ионосфера: отражение и поглощение</h2>
+<!-- 8 -->
+<section class="scene" data-scene="8">
+  <h2>8. Ионосфера: отражение и поглощение</h2>
   <p>Почему ДВ/СВ/КВ идут за горизонт, а УКВ — нет. Меняйте частоту и время суток.</p>
   <canvas id="c-iono"></canvas>
   <div class="controls">
@@ -342,21 +404,21 @@ footer { text-align: center; padding: 20px; font-family: var(--mono); font-size:
   <div class="readout" id="r-iono"></div>
   <div class="feedback" id="fb-iono"></div>
   <p class="legend">Модель пороговая: 3 МГц и 30 МГц — качественные границы, не формула. Для инженерного расчёта — МПЧ, закон секанса, солнечная активность.</p>
-  <div class="nav"><button class="btn" onclick="goTo(5)">← Назад</button><button class="btn" onclick="goTo(7)">Далее →</button></div>
+  <div class="nav"><button class="btn" onclick="goTo(7)">← Назад</button><button class="btn" onclick="goTo(9)">Далее →</button></div>
 </section>
 
-<!-- 7 -->
-<section class="scene" data-scene="7">
-  <h2>7. Тренажёр диапазонов</h2>
+<!-- 9 -->
+<section class="scene" data-scene="9">
+  <h2>9. Тренажёр диапазонов</h2>
   <p>Выберите карточку, затем нажмите на корзину. Верно — карточка встанет на место с пояснением. Неверно — подсказка, попробуйте снова.</p>
   <div id="trainer"></div>
   <div class="feedback" id="fb-trainer" style="display:none"></div>
-  <div class="nav"><button class="btn" onclick="goTo(6)">← Назад</button><button class="btn" onclick="goTo(8)">Далее →</button></div>
+  <div class="nav"><button class="btn" onclick="goTo(8)">← Назад</button><button class="btn" onclick="goTo(10)">Далее →</button></div>
 </section>
 
-<!-- 8 -->
-<section class="scene" data-scene="8">
-  <h2>8. Применение и ИБ: атака и защита</h2>
+<!-- 10 -->
+<section class="scene" data-scene="10">
+  <h2>10. Применение и ИБ: атака и защита</h2>
   <p>Распространение волн — это ещё и зона перехвата. Чем шире зона, тем больше возможностей у «красных».</p>
   <canvas id="c-sec"></canvas>
   <div class="toggles" id="sec-toggles">
@@ -367,29 +429,30 @@ footer { text-align: center; padding: 20px; font-family: var(--mono); font-size:
   <div class="risk-bars" id="risk-bars"></div>
   <div class="feedback" id="fb-sec"></div>
   <p class="legend">Связь с триадой КЦД: перехват — конфиденциальность, подавление — доступность, имитация — целостность.</p>
-  <div class="nav"><button class="btn" onclick="goTo(7)">← Назад</button><button class="btn" onclick="goTo(9)">Далее →</button></div>
+  <div class="nav"><button class="btn" onclick="goTo(9)">← Назад</button><button class="btn" onclick="goTo(11)">Далее →</button></div>
 </section>
 
-<!-- 9 -->
-<section class="scene" data-scene="9">
-  <h2>9. Проверка</h2>
-  <p>Семь вопросов. После ответа — пояснение. Оценка — за первую попытку.</p>
+<!-- 11 -->
+<section class="scene" data-scene="11">
+  <h2>11. Проверка</h2>
+  <p>Девять вопросов. После ответа — пояснение. Оценка — за первую попытку.</p>
   <div id="test-container"></div>
-  <div class="score-box" id="score-box">Отвечено: 0 / 7</div>
+  <div class="score-box" id="score-box">Отвечено: 0 / 9</div>
   <div style="text-align:center"><button class="btn" onclick="initTest()">Пересдать</button></div>
   <div class="checklist" id="checklist" style="display:none">
     <div class="nb-title">ЧЕК-ЛИСТ КОНСПЕКТА</div>
     <ul>
       <li>λ = c / f, c = 3·10⁸ м/с</li>
-      <li>B = 2F<sub>м</sub> — полоса АМ-сигнала</li>
-      <li>Огибающая АМ повторяет модулирующий сигнал F_м; заполнение = несущая f_c</li>
+      <li>АМ: меняется амплитуда. Огибающая = модулирующий сигнал F_м, заполнение = несущая f_c. B = 2F_м.</li>
+      <li>ЧМ: меняется частота, амплитуда постоянна. Девиация Δf, индекс β = Δf/F_м. B ≈ 2(Δf + F_м).</li>
+      <li>ФМ: меняется фаза, амплитуда постоянна. Индекс β. B ≈ 2F_м(β + 1).</li>
       <li>Дифракция: λ соизмерима с препятствием → огибает</li>
       <li>Ионосфера отражает КВ, прозрачна для УКВ</li>
       <li>Радиогоризонт: d ≈ 3.57·(√h₁ + √h₂) км</li>
       <li>Направленная антенна сужает зону перехвата, ППРЧ защищает от узкополосной помехи, экранирование снижает утечку</li>
     </ul>
   </div>
-  <div class="nav"><button class="btn" onclick="goTo(8)">← Назад</button><span></span></div>
+  <div class="nav"><button class="btn" onclick="goTo(10)">← Назад</button><span></span></div>
 </section>
 
 </main>
@@ -401,6 +464,7 @@ footer { text-align: center; padding: 20px; font-family: var(--mono); font-size:
 
 let currentScene = 1;
 let currentDraw = null;
+const TOTAL_SCENES = 11;
 
 /* ---------- helpers ---------- */
 function prepCanvas(canvas, cssH) {
@@ -453,15 +517,17 @@ function goTo(n) {
   const scene = document.querySelector('.scene[data-scene="' + n + '"]');
   if (scene) scene.classList.add('active');
   currentScene = n;
-  document.getElementById('progress-fill').style.width = (n / 9 * 100) + '%';
+  document.getElementById('progress-fill').style.width = (n / TOTAL_SCENES * 100) + '%';
   window.scrollTo(0, 0);
   if (n === 2) initSpectrum();
   if (n === 4) initMod();
-  if (n === 5) initDiff();
-  if (n === 6) initIono();
-  if (n === 7) initTrainer();
-  if (n === 8) initSecurity();
-  if (n === 9) initTest();
+  if (n === 5) initFM();
+  if (n === 6) initPM();
+  if (n === 7) initDiff();
+  if (n === 8) initIono();
+  if (n === 9) initTrainer();
+  if (n === 10) initSecurity();
+  if (n === 11) initTest();
 }
 
 window.addEventListener('resize', () => { if (currentDraw) currentDraw(); });
@@ -563,13 +629,7 @@ function initSpectrum() {
 }
 
 /* ============================================================
-   SCENE 4 — modulation
-   
-   ЛОГИКА:
-   - Модулирующий F_м (низкочастотный) → огибающая АМ.
-   - Несущая f_c (высокочастотная) → заполнение под огибающей.
-   - Число осцилляций несущей ОДНО И ТО ЖЕ на среднем и нижнем графиках.
-   - Зависит ТОЛЬКО от f_c. Масштаб условный (реальное 200:1 нечитаемо).
+   SCENE 4 — AM
    ============================================================ */
 function initMod() {
   const canvas = document.getElementById('c-mod');
@@ -577,34 +637,27 @@ function initMod() {
   const sFc = document.getElementById('s-fc');
   const sM = document.getElementById('s-m');
 
-  const T_MOD_MS = 4;  // окно времени для модулирующего и АМ, мс
+  const T_MOD_MS = 4;
 
   function draw() {
     const { ctx, W, H } = prepCanvas(canvas, 540);
-    const Fm = parseFloat(sFm.value);  // кГц
-    const Fc = parseFloat(sFc.value);  // МГц
+    const Fm = parseFloat(sFm.value);
+    const Fc = parseFloat(sFc.value);
     const m = parseFloat(sM.value);
 
-    // Число циклов модулирующего в окне — только от Fm
     const nMod = Fm * T_MOD_MS;
-
-    // Число осцилляций несущей в окне — только от Fc, ОДНО И ТО ЖЕ на обоих графиках.
-    // 30..200 — условный масштаб, чтобы было читаемо при любом f_c.
-    // Реальная f_c за 4 мс дала бы 2000–20000 периодов — нечитаемо.
     const nOscDisplay = 30 + 170 * (Fc - 0.5) / 4.5;
 
     const x0 = 55, x1 = W - 20;
     const midX = (x0 + x1) / 2;
 
-    // ============================================================
-    // ГРАФИК 1 (верхний): МОДУЛИРУЮЩИЙ СИГНАЛ F_м — низкочастотный
-    // ============================================================
+    // верхний: модулирующий сигнал
     const mY = 22, mH = 80;
     const mMid = mY + mH / 2;
     ctx.fillStyle = '#1a2a4a';
     ctx.font = '10px "Roboto Mono", monospace';
     ctx.textAlign = 'left';
-    ctx.fillText('МОДУЛИРУЮЩИЙ СИГНАЛ F_м = ' + Fm.toFixed(1) + ' кГц — низкочастотный, содержит информацию', x0, mY - 6);
+    ctx.fillText('МОДУЛИРУЮЩИЙ СИГНАЛ F_м = ' + Fm.toFixed(1) + ' кГц', x0, mY - 6);
 
     ctx.strokeStyle = '#1a2a4a';
     ctx.beginPath();
@@ -634,16 +687,13 @@ function initMod() {
     ctx.textAlign = 'right';
     ctx.fillText('циклов: ' + nMod.toFixed(0), x1, mY - 6);
 
-    // ============================================================
-    // ГРАФИК 2 (средний): НЕСУЩАЯ f_c — высокочастотная
-    // ТО ЖЕ число осцилляций nOscDisplay, что на нижнем
-    // ============================================================
+    // средний: несущая
     const cY = 145, cH = 80;
     const cMid = cY + cH / 2;
     ctx.fillStyle = '#1a2a4a';
     ctx.font = '10px "Roboto Mono", monospace';
     ctx.textAlign = 'left';
-    ctx.fillText('НЕСУЩАЯ f_c = ' + Fc.toFixed(1) + ' МГц — высокочастотная, переносит сигнал', x0, cY - 6);
+    ctx.fillText('НЕСУЩАЯ f_c = ' + Fc.toFixed(1) + ' МГц', x0, cY - 6);
 
     ctx.strokeStyle = '#1a2a4a';
     ctx.beginPath();
@@ -673,11 +723,7 @@ function initMod() {
     ctx.textAlign = 'right';
     ctx.fillText('осцилляций: ' + nOscDisplay.toFixed(0), x1, cY - 6);
 
-    // ============================================================
-    // ГРАФИК 3 (нижний): АМ-СИГНАЛ
-    //   огибающая = 1 + m·sin(2π·nMod·t)      → совпадает с ВЕРХНИМ (F_м)
-    //   заполнение = sin(2π·nOscDisplay·t)    → совпадает со СРЕДНИМ (f_c)
-    // ============================================================
+    // нижний: АМ
     const tY = 265, tH = 140;
     const tMid = tY + tH / 2;
     ctx.fillStyle = '#1a2a4a';
@@ -697,7 +743,6 @@ function initMod() {
 
     const ampBase = (tH / 2 - 6) / 1.6;
 
-    // Красные огибающие ±(1 + m·sin(2π·nMod·t))
     ctx.strokeStyle = 'rgba(178,34,34,0.9)';
     ctx.lineWidth = 2;
     for (let sign = -1; sign <= 1; sign += 2) {
@@ -712,7 +757,6 @@ function initMod() {
       ctx.stroke();
     }
 
-    // Сам АМ-сигнал: то же nOscDisplay, что на среднем
     const tSamples = Math.max(1200, Math.ceil(nOscDisplay * 16));
     ctx.strokeStyle = '#1a4a7a';
     ctx.lineWidth = 1.5;
@@ -728,24 +772,15 @@ function initMod() {
     ctx.stroke();
     ctx.lineWidth = 1;
 
-    // Подпись под графиком
     ctx.font = '9px "Roboto Mono", monospace';
     ctx.textAlign = 'left';
     if (m > 1) {
       ctx.fillStyle = '#b22222';
       ctx.font = 'bold 11px "Roboto Mono", monospace';
       ctx.fillText('ПЕРЕМОДУЛЯЦИЯ: огибающая пересекает ноль', x0, tY + tH + 14);
-      ctx.fillStyle = '#3a4a6a';
-      ctx.font = '9px "Roboto Mono", monospace';
-      ctx.fillText('огибающая = верхний (' + nMod.toFixed(0) + ' циклов); заполнение = средний (' + nOscDisplay.toFixed(0) + ' осц.) — синхронно', x0, tY + tH + 28);
-    } else {
-      ctx.fillStyle = '#3a4a6a';
-      ctx.fillText('огибающая = верхний (' + nMod.toFixed(0) + ' циклов); заполнение = средний (' + nOscDisplay.toFixed(0) + ' осц.) — синхронно', x0, tY + tH + 14);
     }
 
-    // ============================================================
-    // ГРАФИК 4: Спектр
-    // ============================================================
+    // спектр
     const sY = 440, sH = 80;
     const sBase = sY + sH;
     ctx.fillStyle = '#1a2a4a';
@@ -794,48 +829,353 @@ function initMod() {
       ctx.fillText('B = 2F_м = ' + (2 * Fm).toFixed(1) + ' кГц', fcX, sBase - 66);
     }
 
-    // ============================================================
-    // Показания и обратная связь
-    // ============================================================
+    // readout
     const lamC = 300 / Fc;
     const lamMod = 3e8 / (Fm * 1e3);
     const lamModStr = lamMod >= 1000 ? (lamMod / 1000).toFixed(1) + ' км' : lamMod.toFixed(0) + ' м';
-    const lamModQuarter = lamMod / 4 >= 1000 ? (lamMod / 4000).toFixed(1) + ' км' : (lamMod / 4).toFixed(0) + ' м';
 
     document.getElementById('v-fm').textContent = Fm.toFixed(1) + ' кГц';
     document.getElementById('v-fc').textContent = Fc.toFixed(1) + ' МГц';
     document.getElementById('v-m').textContent = m.toFixed(2);
 
     document.getElementById('r-mod').innerHTML =
-      'F_м = <span class="hl">' + Fm.toFixed(1) + ' кГц</span> (модулирующий сигнал, λ = ' + lamModStr + ', λ/4 = ' + lamModQuarter + ')<br>' +
-      'f_c = <span class="hl">' + Fc.toFixed(1) + ' МГц</span> (несущая, λ = ' + lamC.toFixed(0) + ' м, λ/4 = ' + (lamC / 4).toFixed(0) + ' м)<br>' +
+      'F_м = <span class="hl">' + Fm.toFixed(1) + ' кГц</span> (λ = ' + lamModStr + ')<br>' +
+      'f_c = <span class="hl">' + Fc.toFixed(1) + ' МГц</span> (λ = ' + lamC.toFixed(0) + ' м)<br>' +
       'm = <span class="hl">' + m.toFixed(2) + '</span> · B = 2F_м = <span class="hl">' + (2 * Fm).toFixed(1) + ' кГц</span>';
 
     let fb;
-    if (m === 0) fb = 'Несущая есть, информации нет. Глубина модуляции нулевая.';
-    else if (m <= 0.5) fb = 'Малая глубина — сигнал слабый, но искажений нет.';
+    if (m === 0) fb = 'Несущая есть, информации нет.';
+    else if (m <= 0.5) fb = 'Малая глубина — сигнал слабый.';
     else if (m <= 1) fb = 'Глубина в норме. Боковые растут, полоса B = 2F_м.';
-    else fb = 'Перемодуляция: огибающая пересекает ноль. Приёмник искажает.';
+    else fb = 'Перемодуляция: огибающая пересекает ноль, приёмник искажает.';
+    document.getElementById('fb-mod').textContent = fb;
+  }
+
+  currentDraw = draw;
+  sFm.oninput = draw;
+  sFc.oninput = draw;
+  sM.oninput = draw;
+  draw();
+}
+
+/* ============================================================
+   SCENE 5 — ЧМ (FM)
+   Логика:
+   - Мгновенная частота: f(t) = Fc + Δf·sin(2π·Fm·t)
+   - Фаза: φ(t) = 2π·Fc·t - β·cos(2π·Fm·t), β = Δf/Fm
+   - Амплитуда постоянна.
+   Нормализованно: φ(t) = 2π·nOsc·t - β·cos(2π·nMod·t)
+   При положительной полуволне модулирующего — частота max, сгущение.
+   ============================================================ */
+function initFM() {
+  const canvas = document.getElementById('c-fm');
+  const sFm = document.getElementById('s-fm-fm');
+  const sFc = document.getElementById('s-fc-fm');
+  const sDev = document.getElementById('s-dev-fm');
+
+  const T_MOD_MS = 4;
+
+  function draw() {
+    const { ctx, W, H } = prepCanvas(canvas, 420);
+    const Fm = parseFloat(sFm.value);
+    const Fc = parseFloat(sFc.value);
+    const Dev = parseFloat(sDev.value);
+
+    const nMod = Fm * T_MOD_MS;
+    const nOscDisplay = 30 + 170 * (Fc - 0.5) / 4.5;
+    const beta = Dev / Fm;
+
+    const x0 = 55, x1 = W - 20;
+
+    // верхний: модулирующий
+    const mY = 22, mH = 80;
+    const mMid = mY + mH / 2;
+    ctx.fillStyle = '#1a2a4a';
+    ctx.font = '10px "Roboto Mono", monospace';
+    ctx.textAlign = 'left';
+    ctx.fillText('МОДУЛИРУЮЩИЙ СИГНАЛ F_м = ' + Fm.toFixed(1) + ' кГц', x0, mY - 6);
 
-    if (Fm <= 3) fb += ' Низкая F_м: огибающая редкая, полоса узкая, но информации мало.';
-    else if (Fm >= 15) fb += ' Высокая F_м: огибающая плотная, полоса широкая. Нужна более высокая несущая, чтобы боковые не налезли на ноль.';
+    ctx.strokeStyle = '#1a2a4a';
+    ctx.beginPath();
+    ctx.moveTo(x0, mMid);
+    ctx.lineTo(x1, mMid);
+    ctx.stroke();
+    ctx.beginPath();
+    ctx.moveTo(x0, mY);
+    ctx.lineTo(x0, mY + mH);
+    ctx.stroke();
 
-    if (Fc * 1e6 < 10 * Fm * 1e3) {
-      fb += ' Внимание: f_c меньше 10·F_м — боковые налезают друг на друга, огибающая на графике не читается. Это не ошибка модели, это физика.';
+    const mSamples = Math.max(200, Math.ceil(nMod * 20));
+    ctx.strokeStyle = '#2a6a3a';
+    ctx.lineWidth = 2;
+    ctx.beginPath();
+    for (let i = 0; i <= mSamples; i++) {
+      const x = x0 + (x1 - x0) * i / mSamples;
+      const phase = (i / mSamples) * nMod * 2 * Math.PI;
+      const y = mMid - (mH / 2 - 6) * Math.sin(phase);
+      if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
     }
+    ctx.stroke();
+    ctx.lineWidth = 1;
 
-    document.getElementById('fb-mod').textContent = fb;
+    // средний: эталонная несущая (без модуляции) для сравнения
+    const cY = 145, cH = 80;
+    const cMid = cY + cH / 2;
+    ctx.fillStyle = '#1a2a4a';
+    ctx.font = '10px "Roboto Mono", monospace';
+    ctx.textAlign = 'left';
+    ctx.fillText('НЕСУЩАЯ f_c = ' + Fc.toFixed(1) + ' МГц (без модуляции, для сравнения)', x0, cY - 6);
+
+    ctx.strokeStyle = '#1a2a4a';
+    ctx.beginPath();
+    ctx.moveTo(x0, cMid);
+    ctx.lineTo(x1, cMid);
+    ctx.stroke();
+    ctx.beginPath();
+    ctx.moveTo(x0, cY);
+    ctx.lineTo(x0, cY + cH);
+    ctx.stroke();
+
+    const cSamples = Math.max(600, Math.ceil(nOscDisplay * 16));
+    ctx.strokeStyle = '#1a4a7a';
+    ctx.lineWidth = 1.5;
+    ctx.beginPath();
+    for (let i = 0; i <= cSamples; i++) {
+      const x = x0 + (x1 - x0) * i / cSamples;
+      const phase = (i / cSamples) * nOscDisplay * 2 * Math.PI;
+      const y = cMid - (cH / 2 - 4) * Math.sin(phase);
+      if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
+    }
+    ctx.stroke();
+    ctx.lineWidth = 1;
+
+    // нижний: ЧМ-сигнал
+    const tY = 265, tH = 130;
+    const tMid = tY + tH / 2;
+    ctx.fillStyle = '#1a2a4a';
+    ctx.font = '10px "Roboto Mono", monospace';
+    ctx.textAlign = 'left';
+    ctx.fillText('ЧМ-СИГНАЛ: амплитуда постоянна, частота меняется по закону F_м', x0, tY - 6);
+
+    ctx.strokeStyle = '#1a2a4a';
+    ctx.beginPath();
+    ctx.moveTo(x0, tMid);
+    ctx.lineTo(x1, tMid);
+    ctx.stroke();
+    ctx.beginPath();
+    ctx.moveTo(x0, tY);
+    ctx.lineTo(x0, tY + tH);
+    ctx.stroke();
+
+    const ampBase = (tH / 2 - 4);
+    const tSamples = Math.max(1500, Math.ceil(nOscDisplay * 20));
+
+    ctx.strokeStyle = '#6a3a8a';
+    ctx.lineWidth = 1.5;
+    ctx.beginPath();
+    for (let i = 0; i <= tSamples; i++) {
+      const x = x0 + (x1 - x0) * i / tSamples;
+      const tNorm = i / tSamples;
+      // φ(t) = 2π·nOsc·t − β·cos(2π·nMod·t)
+      const phase = 2 * Math.PI * nOscDisplay * tNorm - beta * Math.cos(2 * Math.PI * nMod * tNorm);
+      const y = tMid - ampBase * Math.sin(phase);
+      if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
+    }
+    ctx.stroke();
+    ctx.lineWidth = 1;
+
+    ctx.fillStyle = '#3a4a6a';
+    ctx.font = '9px "Roboto Mono", monospace';
+    ctx.textAlign = 'left';
+    ctx.fillText('осцилляций: ' + nOscDisplay.toFixed(0) + ' · индекс β = Δf/F_м = ' + beta.toFixed(2), x0, tY + tH + 14);
+
+    // readout
+    const lamC = 300 / Fc;
+    const carson = 2 * (Dev + Fm);
+    document.getElementById('v-fm-fm').textContent = Fm.toFixed(1) + ' кГц';
+    document.getElementById('v-fc-fm').textContent = Fc.toFixed(1) + ' МГц';
+    document.getElementById('v-dev-fm').textContent = Dev.toFixed(0) + ' кГц';
+
+    document.getElementById('r-fm').innerHTML =
+      'F_м = <span class="hl">' + Fm.toFixed(1) + ' кГц</span> · ' +
+      'f_c = <span class="hl">' + Fc.toFixed(1) + ' МГц</span> (λ = ' + lamC.toFixed(0) + ' м)<br>' +
+      'Δf = <span class="hl">' + Dev.toFixed(0) + ' кГц</span> · ' +
+      'β = Δf/F_м = <span class="hl">' + beta.toFixed(2) + '</span><br>' +
+      'Полоса по Карсону B ≈ 2(Δf + F_м) = <span class="hl">' + carson.toFixed(0) + ' кГц</span>';
+
+    let fb;
+    if (beta < 0.5) fb = 'Узкополосная ЧМ (β < 0.5): по спектру похожа на АМ, но амплитуда постоянна — это плюс по помехоустойчивости.';
+    else if (beta < 5) fb = 'Обычная ЧМ (0.5 ≤ β < 5): заметно сгущение и разрежение осцилляций, амплитуда постоянна.';
+    else fb = 'Широкополосная ЧМ (β ≥ 5): большая девиация, широкая полоса, высокая помехоустойчивость. Цена — полоса.';
+    document.getElementById('fb-fm').textContent = fb;
   }
 
   currentDraw = draw;
   sFm.oninput = draw;
   sFc.oninput = draw;
-  sM.oninput = draw;
+  sDev.oninput = draw;
   draw();
 }
 
 /* ============================================================
-   SCENE 5 — diffraction
+   SCENE 6 — ФМ (PM)
+   Логика:
+   - Мгновенная фаза: φ(t) = 2π·Fc·t + β·sin(2π·Fm·t)
+   - Мгновенная частота: f(t) = Fc + β·Fm·cos(2π·Fm·t)
+   - Амплитуда постоянна.
+   Нормализованно: φ(t) = 2π·nOsc·t + β·sin(2π·nMod·t)
+   Отличие от ЧМ: в ФМ фаза меняется по sin, частота — по cos (сдвиг π/2).
+   ============================================================ */
+function initPM() {
+  const canvas = document.getElementById('c-pm');
+  const sFm = document.getElementById('s-fm-pm');
+  const sFc = document.getElementById('s-fc-pm');
+  const sBeta = document.getElementById('s-beta-pm');
+
+  const T_MOD_MS = 4;
+
+  function draw() {
+    const { ctx, W, H } = prepCanvas(canvas, 420);
+    const Fm = parseFloat(sFm.value);
+    const Fc = parseFloat(sFc.value);
+    const beta = parseFloat(sBeta.value);
+
+    const nMod = Fm * T_MOD_MS;
+    const nOscDisplay = 30 + 170 * (Fc - 0.5) / 4.5;
+
+    const x0 = 55, x1 = W - 20;
+
+    // верхний: модулирующий
+    const mY = 22, mH = 80;
+    const mMid = mY + mH / 2;
+    ctx.fillStyle = '#1a2a4a';
+    ctx.font = '10px "Roboto Mono", monospace';
+    ctx.textAlign = 'left';
+    ctx.fillText('МОДУЛИРУЮЩИЙ СИГНАЛ F_м = ' + Fm.toFixed(1) + ' кГц', x0, mY - 6);
+
+    ctx.strokeStyle = '#1a2a4a';
+    ctx.beginPath();
+    ctx.moveTo(x0, mMid);
+    ctx.lineTo(x1, mMid);
+    ctx.stroke();
+    ctx.beginPath();
+    ctx.moveTo(x0, mY);
+    ctx.lineTo(x0, mY + mH);
+    ctx.stroke();
+
+    const mSamples = Math.max(200, Math.ceil(nMod * 20));
+    ctx.strokeStyle = '#2a6a3a';
+    ctx.lineWidth = 2;
+    ctx.beginPath();
+    for (let i = 0; i <= mSamples; i++) {
+      const x = x0 + (x1 - x0) * i / mSamples;
+      const phase = (i / mSamples) * nMod * 2 * Math.PI;
+      const y = mMid - (mH / 2 - 6) * Math.sin(phase);
+      if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
+    }
+    ctx.stroke();
+    ctx.lineWidth = 1;
+
+    // средний: эталонная несущая
+    const cY = 145, cH = 80;
+    const cMid = cY + cH / 2;
+    ctx.fillStyle = '#1a2a4a';
+    ctx.font = '10px "Roboto Mono", monospace';
+    ctx.textAlign = 'left';
+    ctx.fillText('НЕСУЩАЯ f_c = ' + Fc.toFixed(1) + ' МГц (без модуляции, для сравнения)', x0, cY - 6);
+
+    ctx.strokeStyle = '#1a2a4a';
+    ctx.beginPath();
+    ctx.moveTo(x0, cMid);
+    ctx.lineTo(x1, cMid);
+    ctx.stroke();
+    ctx.beginPath();
+    ctx.moveTo(x0, cY);
+    ctx.lineTo(x0, cY + cH);
+    ctx.stroke();
+
+    const cSamples = Math.max(600, Math.ceil(nOscDisplay * 16));
+    ctx.strokeStyle = '#1a4a7a';
+    ctx.lineWidth = 1.5;
+    ctx.beginPath();
+    for (let i = 0; i <= cSamples; i++) {
+      const x = x0 + (x1 - x0) * i / cSamples;
+      const phase = (i / cSamples) * nOscDisplay * 2 * Math.PI;
+      const y = cMid - (cH / 2 - 4) * Math.sin(phase);
+      if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
+    }
+    ctx.stroke();
+    ctx.lineWidth = 1;
+
+    // нижний: ФМ-сигнал
+    const tY = 265, tH = 130;
+    const tMid = tY + tH / 2;
+    ctx.fillStyle = '#1a2a4a';
+    ctx.font = '10px "Roboto Mono", monospace';
+    ctx.textAlign = 'left';
+    ctx.fillText('ФМ-СИГНАЛ: амплитуда постоянна, фаза сдвигается по закону F_м', x0, tY - 6);
+
+    ctx.strokeStyle = '#1a2a4a';
+    ctx.beginPath();
+    ctx.moveTo(x0, tMid);
+    ctx.lineTo(x1, tMid);
+    ctx.stroke();
+    ctx.beginPath();
+    ctx.moveTo(x0, tY);
+    ctx.lineTo(x0, tY + tH);
+    ctx.stroke();
+
+    const ampBase = (tH / 2 - 4);
+    const tSamples = Math.max(1500, Math.ceil(nOscDisplay * 20));
+
+    ctx.strokeStyle = '#6a3a8a';
+    ctx.lineWidth = 1.5;
+    ctx.beginPath();
+    for (let i = 0; i <= tSamples; i++) {
+      const x = x0 + (x1 - x0) * i / tSamples;
+      const tNorm = i / tSamples;
+      // φ(t) = 2π·nOsc·t + β·sin(2π·nMod·t)
+      const phase = 2 * Math.PI * nOscDisplay * tNorm + beta * Math.sin(2 * Math.PI * nMod * tNorm);
+      const y = tMid - ampBase * Math.sin(phase);
+      if (i === 0) ctx.moveTo(x, y); else ctx.lineTo(x, y);
+    }
+    ctx.stroke();
+    ctx.lineWidth = 1;
+
+    ctx.fillStyle = '#3a4a6a';
+    ctx.font = '9px "Roboto Mono", monospace';
+    ctx.textAlign = 'left';
+    ctx.fillText('осцилляций: ' + nOscDisplay.toFixed(0) + ' · индекс β = ' + beta.toFixed(2) + ' рад', x0, tY + tH + 14);
+
+    // readout
+    const lamC = 300 / Fc;
+    const pmBand = 2 * Fm * (beta + 1);
+    document.getElementById('v-fm-pm').textContent = Fm.toFixed(1) + ' кГц';
+    document.getElementById('v-fc-pm').textContent = Fc.toFixed(1) + ' МГц';
+    document.getElementById('v-beta-pm').textContent = beta.toFixed(1);
+
+    document.getElementById('r-pm').innerHTML =
+      'F_м = <span class="hl">' + Fm.toFixed(1) + ' кГц</span> · ' +
+      'f_c = <span class="hl">' + Fc.toFixed(1) + ' МГц</span> (λ = ' + lamC.toFixed(0) + ' м)<br>' +
+      'β = <span class="hl">' + beta.toFixed(2) + ' рад</span><br>' +
+      'Полоса B ≈ 2F_м(β + 1) = <span class="hl">' + pmBand.toFixed(0) + ' кГц</span>';
+
+    let fb;
+    if (beta < 0.5) fb = 'Малый индекс: фаза колеблется слабо, спектр узкий. Похоже на узкополосную ЧМ.';
+    else if (beta < 5) fb = 'Обычная ФМ: заметны сдвиги фазы, частота меняется по cos — со сдвигом π/2 относительно модулирующего.';
+    else fb = 'Большой индекс: сильные фазовые сдвиги, широкая полоса. На практике применяется редко — при том же β помехоустойчивость как у ЧМ, но полоса та же.';
+    document.getElementById('fb-pm').textContent = fb;
+  }
+
+  currentDraw = draw;
+  sFm.oninput = draw;
+  sFc.oninput = draw;
+  sBeta.oninput = draw;
+  draw();
+}
+
+/* ============================================================
+   SCENE 7 — diffraction
    ============================================================ */
 function initDiff() {
   const canvas = document.getElementById('c-diff');
@@ -969,7 +1309,7 @@ function initDiff() {
 }
 
 /* ============================================================
-   SCENE 6 — ionosphere
+   SCENE 8 — ionosphere
    ============================================================ */
 function initIono() {
   const canvas = document.getElementById('c-iono');
@@ -1113,7 +1453,7 @@ function initIono() {
     if (f < 3e6) {
       band = 'ДВ/СВ';
       desc = isDay
-        ? 'День: D-слой поглощает, дальний приём пропадает. Земная волна вдоль поверхности.'
+        ? 'День: D-слой поглощает, дальний приём пропадает.'
         : 'Ночь: D-слой исчез, отражение от E. Дальняя связь.';
     } else if (f <= 3e7) {
       band = 'КВ';
@@ -1135,18 +1475,18 @@ function initIono() {
 }
 
 /* ============================================================
-   SCENE 7 — range trainer
+   SCENE 9 — trainer
    ============================================================ */
 const rangeData = [
   { id: 1,  text: 'Связь с подводной лодкой',     bin: 'dv',   expl: 'ДВ/СДВ проникают в воду на десятки метров (скин-слой). УКВ в воде затухает за сантиметры.' },
   { id: 2,  text: 'Международное КВ-вещание',      bin: 'kv',   expl: 'КВ отражается от ионосферы (слой F) и огибает Землю многократными скачками.' },
   { id: 3,  text: 'Местная AM-радиостанция',       bin: 'sv',   expl: 'СВ — сотни кГц. Земная волна вдоль поверхности. Днём D-слой поглощает дальний приём.' },
   { id: 4,  text: 'Wi-Fi 2.4 ГГц',                 bin: 'svch', expl: '2.4 ГГц — СВЧ. Прямая видимость в помещении, мебель огибает плохо.' },
-  { id: 5,  text: 'Мобильный телефон 900 МГц',     bin: 'ukv',  expl: '900 МГц — УКВ (дециметровый). Прямая видимость до базовой станции, дифракция за зданиями слабая.' },
-  { id: 6,  text: 'Радиорелейная линия',           bin: 'svch', expl: 'СВЧ, узкий луч, прямая видимость. Между вышками — потому что за горизонт не уходит.' },
+  { id: 5,  text: 'Мобильный телефон 900 МГц',     bin: 'ukv',  expl: '900 МГц — УКВ (дециметровый). Прямая видимость до базовой станции.' },
+  { id: 6,  text: 'Радиорелейная линия',           bin: 'svch', expl: 'СВЧ, узкий луч, прямая видимость. Между вышками.' },
   { id: 7,  text: 'Спутниковое ТВ',                bin: 'svch', expl: 'СВЧ проходит сквозь ионосферу — спутник видит Землю, Земля видит спутник.' },
-  { id: 8,  text: 'Радиолокатор аэропорта',        bin: 'svch', expl: 'СВЧ, узкий луч, малая λ — высокое разрешение по дальности и углу.' },
-  { id: 9,  text: 'Телевидение ДМВ',               bin: 'ukv',  expl: 'ДМВ (дециметровые) — УКВ. Прямая видимость, вышки на холмах.' },
+  { id: 8,  text: 'Радиолокатор аэропорта',        bin: 'svch', expl: 'СВЧ, узкий луч, малая λ — высокое разрешение.' },
+  { id: 9,  text: 'Телевидение ДМВ',               bin: 'ukv',  expl: 'ДМВ — УКВ. Прямая видимость, вышки на холмах.' },
   { id: 10, text: 'Навигационный радиомаяк',       bin: 'dv',   expl: 'ДВ/СВ — земная волна, устойчивый приём на большие расстояния.' }
 ];
 const binNames = { dv: 'ДВ/СДВ', sv: 'СВ', kv: 'КВ', ukv: 'УКВ', svch: 'СВЧ' };
@@ -1163,7 +1503,7 @@ function initTrainer() {
       fb.style.borderColor = '#2a6a3a';
       fb.style.background = 'rgba(42,106,58,0.1)';
     } else {
-      fb.textContent = 'Неверно. Вспомните: как волна распространяется в этом диапазоне? Где он на шкале?';
+      fb.textContent = 'Неверно. Вспомните: как волна распространяется в этом диапазоне?';
       fb.style.borderColor = '#b22222';
       fb.style.background = 'rgba(178,34,34,0.1)';
     }
@@ -1172,7 +1512,6 @@ function initTrainer() {
 
   function render() {
     container.innerHTML = '';
-
     const cardsDiv = document.createElement('div');
     cardsDiv.className = 'cards-area';
     rangeData.forEach(card => {
@@ -1219,7 +1558,7 @@ function initTrainer() {
     if (Object.keys(placed).length === rangeData.length) {
       const done = document.createElement('div');
       done.className = 'feedback';
-      done.innerHTML = '<b>Все карточки разложены.</b> Почему СВЧ так часто? Высокая частота даёт широкую полосу и узкий луч, малая λ — высокое разрешение. Цена — прямая видимость и затухание в дожде.';
+      done.innerHTML = '<b>Все карточки разложены.</b> Почему СВЧ так часто? Высокая частота даёт широкую полосу и узкий луч, малая λ — высокое разрешение. Цена — прямая видимость.';
       container.appendChild(done);
     }
   }
@@ -1228,7 +1567,7 @@ function initTrainer() {
 }
 
 /* ============================================================
-   SCENE 8 — security
+   SCENE 10 — security
    ============================================================ */
 function initSecurity() {
   const canvas = document.getElementById('c-sec');
@@ -1353,8 +1692,8 @@ function initSecurity() {
     if (!state.antenna && !state.fhss && !state.shield) {
       fb.push('Все меры выключены: широкая зона перехвата, помеха накрывает сигнал, утечка через корпус.');
     }
-    if (state.antenna) fb.push('Направленная антенна сузила зону перехвата, но требует точного наведения.');
-    if (state.fhss) fb.push('ППРЧ: сигнал скачет по частотам, узкополосная помеха промахивается. От широкополосной не спасает.');
+    if (state.antenna) fb.push('Направленная антенна сузила зону перехвата, но требует наведения.');
+    if (state.fhss) fb.push('ППРЧ: узкополосная помеха промахивается. От широкополосной не спасает.');
     if (state.shield) fb.push('Экранирование снизило утечку, но не дальность полезного сигнала.');
     document.getElementById('fb-sec').textContent = fb.join(' ');
   }
@@ -1373,7 +1712,7 @@ function initSecurity() {
 }
 
 /* ============================================================
-   SCENE 9 — test
+   SCENE 11 — test
    ============================================================ */
 const testQuestions = [
   {
@@ -1398,7 +1737,7 @@ const testQuestions = [
     q: 'Где полоса шире — на несущей 1 МГц или 100 МГц при той же F_м (модулирующем сигнале)?',
     opts: ['На 1 МГц', 'На 100 МГц', 'Одинакова: B = 2F_м', 'Зависит от глубины модуляции'],
     correct: 2,
-    expl: 'Полоса АМ-сигнала B = 2F_м зависит от модулирующего сигнала, не от несущей. Но на высокой несущей можно взять больший F_м.'
+    expl: 'Полоса АМ-сигнала B = 2F_м зависит от модулирующего сигнала, не от несущей.'
   },
   {
     q: 'Какой диапазон для связи со спутником?',
@@ -1417,6 +1756,18 @@ const testQuestions = [
     opts: ['D-слой поглощает', 'Ионосфера исчезает', 'Антенна хуже работает', 'Помехи от Солнца'],
     correct: 0,
     expl: 'Днём D-слой ионизирован и поглощает СВ. Ночью D исчезает — дальний приём возвращается.'
+  },
+  {
+    q: 'Где заложена информация в ЧМ-сигнале?',
+    opts: ['В амплитуде несущей', 'В отклонении частоты несущей от среднего (девиации)', 'В самой несущей частоте', 'В длине волны'],
+    correct: 1,
+    expl: 'В ЧМ амплитуда постоянна, а мгновенная частота меняется по закону модулирующего: f(t) = f_c + Δf·sin(2π·F_м·t). Информация — в девиации Δf, а не в амплитуде и не в самой несущей частоте.'
+  },
+  {
+    q: 'Чем ЧМ отличается от ФМ при одной и той же несущей и модулирующем сигнале?',
+    opts: ['В ЧМ меняется амплитуда, в ФМ — частота', 'В ЧМ мгновенная частота пропорциональна модулирующему, в ФМ — сама фаза', 'Это одно и то же, только названия разные', 'В ЧМ полоса уже, чем в АМ'],
+    correct: 1,
+    expl: 'В ЧМ f(t) = f_c + Δf·sin(2π·F_м·t) — частота меняется по синусу. В ФМ φ(t) = 2π·f_c·t + β·sin(2π·F_м·t) — фаза меняется по синусу, а частота (производная фазы) — по косинусу, со сдвигом π/2. Внешне похожи, но физика разная.'
   }
 ];
 

+ 22 - 5
ПМ.03.01/3.1.100/002/specification.md

@@ -103,16 +103,33 @@ ITU-R P.526 «Propagation by diffraction» — для модели ножево
 <td> 3 </td><td> 4. Принцип радиосвязи: несущая и модуляция </td><td> На итоговом графике модулируемая и модулирующая частота перепутаны, при перемещении ползунка на итоговом графике меняется другая частота</td><td>  </td><td>3.1.100/002_s4_2 </td>
 </tr><tr valign="top" textalign="left">
 <td colspan=5> Что выдал ИИ </td> 
-
+Исправлено
 </tr><tr valign="top" textalign="left">
 
-<td> 4 </td><td>  </td><td>Необходимо добавить сцены с Частотной моделяцией и Фазовой. </td><td>  </td><td>Коммит </td>
+<td> 4 </td><td>  </td><td>Необходимо добавить сцены с Частотной модуляцией и Фазовой. </td><td>  </td><td>частотная и фазовая модуляции </td>
 </tr><tr valign="top" textalign="left">
-<td colspan=5> Что выдал ИИ </td> 
-
+<td colspan=5> 
+### Сцена 5 — ЧМ (FM):
+- Три ползунка: F_м, f_c, девиация Δf (1–50 кГц).
+- Верхний график — модулирующий сигнал (зелёный).
+- Средний — эталонная несущая без модуляции (синяя).
+- Нижний — ЧМ-сигнал (фиолетовый): амплитуда постоянна, осцилляции сгущаются при положительной полуволне модулирующего и разрежаются при отрицательной. Формула φ(t) = 2π·nOsc·t − β·cos(2π·nMod·t), β = Δf/F_м.
+- Readout: девиация, индекс β, полоса по Карсону B ≈ 2(Δf + F_м).
+- Обратная связь: β < 0.5 — узкополосная (похожа на АМ), β ≥ 5 — широкополосная (помехоустойчивая, но широкая).
+### Сцена 6 — ФМ (PM):
+- Три ползунка: F_м, f_c, индекс β (0–10).
+- Те же три графика, но нижний — ФМ-сигнал: φ(t) = 2π·nOsc·t + β·sin(2π·nMod·t).
+- Визуально похоже на ЧМ, но частота в ФМ меняется по cos — со сдвигом π/2 относительно модулирующего. Это ключевое отличие, проговорено в тексте и обратной связи.
+- Readout: индекс β, полоса B ≈ 2F_м(β + 1).
+- Нумерация сдвинута: дифракция 5→7, ионосфера 6→8, тренажёр 7→9, ИБ 8→10, тест 9→11. Прогресс-бар и навигация обновлены.
+### Тест — 9 вопросов. Добавлены два:
+- вопрос 8: где заложена информация в ЧМ (ответ: в девиации частоты, а не в амплитуде);
+- вопрос 9: чем ЧМ отличается от ФМ (ответ: в ЧМ частота пропорциональна модулирующему, в ФМ — сама фаза; частота в ФМ идёт по cos со сдвигом π/2).
+- Чек-лист конспекта дополнен строками про ЧМ и ФМ с формулами полос.
+ </td> 
 </tr><tr valign="top" textalign="left">
 
-<td> 5 </td><td> Сцена 5 </td><td> Длина волны на риснке не изменяется. Надо чтобы огибание стало ясно видно, если длина волны мовопоставима с высотой препятнствия. Надо добавить ползунок, который позволяет изменять высоту препятствия</td><td>  </td><td>Коммит </td>
+<td> 5 </td><td> 7. Распространение: дифракция и прямая видимость </td><td> Длина волны на рисунке не изменяется. Надо чтобы огибание стало ясно видно, если длина волны сопоставима с высотой препятствия. Надо добавить ползунок, который позволяет изменять высоту препятствия</td><td>  </td><td>Коммит </td>
 </tr><tr valign="top" textalign="left">
 <td colspan=5> Что выдал ИИ </td>