Gaminator 9 :: Soundchaser :: Прикладное моделирование волн

Во имя вселенской справедливости, в рамках ведения дневников разработки, в помощь тем, кто пойдёт по моей тропе, а также в целях привлечения внимания к своей персоне, пишу я этот пост.

Здесь пойдёт речь о том, что такое волна, зачем она нужна и на что похожа.

Что такое волна

Википедия глаголет нам, что волна — это периодическое изменение либо распространение некоего параметра в пространстве-времени. Многие физики-математики скажут вам, что волна — это нечто, удовлетворяющее волновому уравнению ∇^2 u с2 = d2 u/dt2, и будут почти правы (существуют более сложные волны, но все «хорошие» действительно описываются этим уравнением). Однако ни одно из определений не даёт ответа на вопрос о поведении волны и о способах её моделирования.

Дальнейшее изложение материала предполагает знакомство читателя с понятием производной, представление о частной производной и желание читать весь этот бред. Я постараюсь избежать подробного изложения математических деталей и в то же время дать наиболее полное представление о теме.

Как ведёт себя волна

Рассмотрим для простоты наше страшное уравнение в одномерном пространстве:

d2 u/dx2 c2 = d2 u/dt2 // ввиду слабых изобразительных средств редактора я буду писать частные производные именно так.

с — это некоторая константа, которую называют скоростью волны, сейчас будет ясно, почему.

Перенесём всё в левую часть и вынесем u за скобки:

(d2/dx2 c2 — d2/dt2) u = 0

(d/dx c — d/dt) (d/dx c + d/dt) u = 0

(d/d (x — ct)) (d/d (x + ct)) u = 0

(Здесь очень важно, что c — константа, иначе фокус не удастся).

Пусть a = x — ct, b = x + ct, тогда производная u (a, b) по b зависит только от b, поэтому u (a, b) = f (a) + g (b),

то есть u (x, t) = f (x — ct) + g (x + ct), где f, g — любые «хорошие» функции. То есть в любой момет времени наша волна — это сумма двух сигналов, которые движутся в разные стороны, но с одинаковой скоростью c.

В двумерном случае (и вообще в многомерном) возмущение также будет расходиться от каждой точки во все стороны с одинаковой скоростью. К двумерному случаю мы вернёмся позже.

Как моделировать волну

Первое, что приходит в голову человеку по здравом размышлении, имеет примерно следующий вид:

«Я знаю, я:

буду хранить волну в пространстве,

насчитывать её вторую производную по пространству, вычитая значения в близких точках,

потом считать вторую производную по времени,

прибавлять её к первой,

а первую прибавлять к значению."

Так вот, несмотря на всю очевидность этого пути, он чреват.

1. Он неточен. Фактически, мы учитываем вторую производную чуть позже, чем следовало бы.

2. Он нестабилен. Маленький разрыв — и привет, волна улетает на бесконечность.

Но, в принципе, он подходит посмотреть на дело рук своих и порадоваться. Я, помню, радовался дико :).

Немного рысканья по интернету говорит искателю о том, что есть такой метод конечных разностей (wiki:Finite difference method), который позволяет делать это всё несколько лучше. После несложных изысканий получаем, что

новое_значение_волны := ускорение * dt2 + 2 * текущее_значение_волны — старое_значение_волны.

Ещё пафоснее применить какой-то из неявных методов, но только если у вас под рукой есть способ решения огромных систем линейных уравнений. Особой разницы, кроме гарантий сходимости, нет.

Это работает гораздо лучше — при правильно заданных начальных условиях.

Для тех, кто хочет посмотреть, как это выглядит, вот картинка:

2012-02-24-024031_600x50_scrot.png

а вот ссылка на скрипт, для которого вам потребуется поставить Python 2.7, Pygame и SciPy:

http://dl.dropbox.com/u/45036808/simulation.py

Довольно красиво, надо сказать.

Удвоение количества измерений

Однако в случае моделирования двумерной волны возникает проблема скорости: для приличного качества необходимо иметь очень частую сетку, а это отрицательно отражается на производительности (особенно при использовании неявных методов — количество переменных равно количеству узлов сетки).

Тем не менее, симуляция вполне возможна. Вот скрипт, зависимости те же:

http://dl.dropbox.com/u/45036808/simulation3d.py

Несмотря на язык реализации, скорость не такая ужасающая.

Бесконечность — не предел!

Довольно скоро вы обнаружите, что волна имеет свойство отражаться от любого барьера. Иногда, впрочем, хочется эмулировать волну, уходящую на бесконечность (при этом её значение нас интересует только на конечном интервале). Для этого существует такое изменение свойств пространства, которое называется Perfectly matched layer и превращает периодическую волну в затухающую.

Скажу честно — на этом фронте у меня сплошные поражения. Вместо экспоненциального затухания у меня всё время выходило экспоненциальное нарастание. Сколько я ни перерыл литературы, причин фейла не нашёл.

Everything is … sinus?

To be written.

Завтра надеюсь дописать статью. Пока выказывайте замечания по оформлению и изложению материала.