Відправна точка: що таке електромагнітна хвиля?
Джеймс Клерк Максвелл об'єднав електрику й магнетизм у 1865 році чотирма рівняннями. Ключове розуміння для цієї симуляції — хвильове рівняння, що з них випливає: змінне електричне поле індукує магнітне поле, і навпаки. Два поля переслідують одне одного крізь простір зі швидкістю світла.
У 2D ми працюємо з поперечно-магнітним (TM) режимом: електричне
поле має лише z-компоненту Ez, а магнітне поле має
x- і y-компоненти Hx та Hy. Це зводить
рівняння ротора Максвелла до трьох рівнянь оновлення — достатньо
простих для обчислення на кожній комірці сітки щокадру.
FDTD: ґратка Йі
Метод скінченних різниць у часовій області (FDTD), запроваджений Кейном Йі в 1966 році, дискретизує рівняння Максвелла на зміщеній просторово-часовій сітці. Компоненти електричного й магнітного полів зміщені на половину просторового й часового кроку, що автоматично задовольняє закон Гаусса (∇·B = 0) без жодного кроку корекції.
// Рівняння оновлення FDTD режиму TM (2D, рівномірна сітка)
// E і H чергуються: спочатку оновлюється H, потім E
// Оновити Hx і Hy на кроці часу n+½
Hx[i][j] -= (Cz / dy) * (Ez[i][j+1] - Ez[i][j])
Hy[i][j] += (Cz / dx) * (Ez[i+1][j] - Ez[i][j])
// Оновити Ez на кроці часу n+1
Ez[i][j] += Cz * (
(Hy[i][j] - Hy[i-1][j]) / dx -
(Hx[i][j] - Hx[i][j-1]) / dy
)
// Cz = dt / (ε₀ · μ₀) — число Куранта
Умова стабільності Куранта вимагає
dt ≤ dx / (c · √2) для рівномірної 2D сітки. Ми
встановлюємо dt = 0.9 · dx / (c · √2) — 90 % від
межі стабільності для невеликого запасу безпеки. Із сіткою
200×200 і dx = 0.01 м крок часу становить близько 21 пс на
оновлення.
Хронологія побудови
Почав із масиву JavaScript 100×100, чистий CPU, одне точкове джерело. Хвиля поширювалася правильно — концентричні кільця, що розходяться назовні. Але вона ідеально відбивалася від країв, тож весь простір заповнився стоячими хвилями за секунди. Явно потрібні поглинальні межі.
PML — стандартна поглинальна межа FDTD: втратна «губчаста» область навколо домену, де поля затухають без відбиття. Її реалізація подвоїла складність коду, але майже ідеально усунула відбиття. Домен тепер здавався «відкритим» — хвилі виходять чисто.
Реалізація на CPU працювала на ~30 FPS на сітці 100×100. Розширення до 200×200 (мінімальна сітка для корисної візуалізації) знизило це до 8 FPS. Рівняння оновлення FDTD бентежно паралельні — кожну комірку можна оновлювати незалежно. Перемістив цикл оновлення у фрагментний шейдер WebGL, що записує в пару текстур із плаваючою комою (схема «пінг-понг»). Стрибнув до 60 FPS на 400×400.
Відобразив поле Ez на синьо-червону колірну шкалу (від від'ємного до додатного), додав синусоїдальне точкове джерело, модульоване гаусовою обвідною, щоб уникнути початкового «клацання», і реалізував апертуру подвійної щілини для класично відомого візерунка дифракції. Додав дипольне джерело, джерело плоскої хвилі та рухому діелектричну область, яку користувач може розмістити на полотні.
Накладання Hx/Hy як стрілок за допомогою інстансованих лінійних сегментів у WebGL. Стрілки підвибираються до сітки 20×20, масштабуються за величиною поля та повертаються за напрямком поля. Поєднання колірної карти Ez та стрілок поля H дає відчутне розуміння того, як два поля перебувають у квадратурі.
Найважча частина: текстури з плаваючою комою
WebGL1 не підтримує читання з текстури з плаваючою комою, у яку
ви щойно записали — розширення «render to float texture»
(OES_texture_float) існує, але не є універсально
доступним для запису. Рішення — буфер «пінг-понг»:
два фреймбуфери, що обмінюються ролями щокадру. Шейдер читає з
буфера A і пише в буфер B; наступного кадру він читає з B і пише
в A.
На iOS Safari розширення взагалі не було доступне, що вимагало запасного варіанту з 16-бітними напівплаваючими текстурами зі зменшеним динамічним діапазоном. Значення поля нормалізуються перед зберіганням і масштабуються назад при читанні — невелика втрата точності, але непомітна за колірної роздільної здатності дисплея.
Текстура діелектричної проникності
Щоб дозволити користувачам розміщувати матеріали (скло, метал тощо) у домені, коефіцієнти оновлення FDTD повинні змінюватися просторово. Ми запікаємо проникність εr у окрему текстуру R8 і вибираємо її під час виконання шейдера оновлення. Натискання кнопки на панелі інструментів встановлює «режим пензля» — подальші події миші малюють значення проникності в текстуру матеріалу через невеликий вторинний фреймбуфер.
// У GLSL-шейдері оновлення — читання текстури матеріалу float eps_r = texture2D(u_material, vTexCoord).r * 10.0 + 1.0; // Діапазон: [1.0, 11.0] — від повітря до склоподібного діелектрика float Cz_local = dt / (eps_r * eps0 * mu0 * dx * dx); // Та сама формула оновлення, але Cz змінюється залежно від матеріалу
Використання в класі: що працює, а що ні
Ми отримали відгуки від кількох вчителів фізики після запуску симуляції. Функції, що виявилися найціннішими в класі:
- Пресет дифракції на подвійній щілині — учні можуть безпосередньо спостерігати принцип Гюйгенса: кожна щілина стає вторинним джерелом, а візерунок інтерференції виникає з фізики FDTD без будь-якого ручного налаштування.
- Повзунок швидкості світла — масштабування c вниз у 10× уповільнює поширення хвилі достатньо, щоб простежити оком. Робить це відчутним.
- Перемикач режиму поляризації — перемикання між режимами TE й TM показує, що дві поляризації світла — це просто повернуті версії тієї самої структури поля.
Що не спрацювало: початковий інструмент вільного малювання діелектрика заплутував учнів, оскільки «малювання скла» виглядало точнісінько як «малювання повітря», доки хвиля не вдаряла. Ми додали постійне колірне накладання для розміщених матеріалів (бурштиновий відтінок = діелектрик, сірий = провідник), що дуже допомогло.
Спробуйте самі: відкрийте симуляцію EM Waves, натисніть пресет «Double Slit» і перетягніть повзунок відстані між щілинами. Ви побачите, як візерунок дифракції змінюється в реальному часі — та сама фізика, що й в експерименті Томаса Юнга 1801 року, що працює у вашому браузері.
Наступні кроки для симуляції
2D FDTD режиму TM — потужний навчальний інструмент, але є природні розширення, які я хочу побудувати:
- 3D-режим — усі шість компонент поля на 3D ґратці Йі. Потребує WebGPU compute для проходу оновлення; дані не вміщуються в 2D-текстуру при корисних розмірах сітки.
- Дисперсійні матеріали — модель Друде для металів (частотно-залежна проникність), що вмикає візуалізацію плазмонного резонансу.
- Перетворення ближнього поля в дальнє — обчислення візерунка випромінювання в дальньому полі (антенного візерунка) з ближнього поля, збереженого на «коробці Гюйгенса» навколо джерела.