2025, Nov 17 03:02
Генерация гладкого 2D-поля в Python: аттракторы и контролируемый белый шум
Создайте гладкое 2D-поле без резких границ: аттракторы задают структуру, белый шум добавляет текстуру. Простой пример на Python с контролируемой гладкостью.
Когда вы заполняете двумерную сетку независимыми случайными значениями, получается пятнистая текстура с высокой локальной вариативностью и почти без структуры. Для белого шума это нормально, но не для фонового поля, которое должно плавно меняться в пределах соседних областей и при этом демонстрировать глобальные различия по всей карте. Ниже показан компактный подход, позволяющий контролировать гладкость и крупномасштабные узоры без появления резких границ.
Постановка задачи
Прямолинейный способ заполнить meshgrid — независимо сэмплировать каждый пиксель. Это даёт шумную поверхность с резкими локальными отклонениями и без пространственной корреляции.
import numpy as np
u = np.linspace(-2, 2, 100)
v = np.linspace(-2, 2, 100)
U, V = np.meshgrid(u, v)
W = np.random.rand(100, 100)
Результат — классическая текстура белого шума: доминируют высокочастотные изменения, а соседние пиксели не «согласуются» друг с другом. Для поверхности в стиле карты фоновой радиации обычно нужна локальная плавность и широкие, постепенные изменения по всей области.
Почему базовый подход выглядит шумным
При независимом сэмплировании в каждом пикселе соседние значения никак не связаны между собой, поэтому у поверхности нет пространственной согласованности. Вы видите сильную локальную вариативность, но минимум структуры на больших масштабах. Если вы хотите, чтобы поле медленно менялось в малых окрестностях и при этом сохраняло глобальные отличия при отдалении, нужно ввести пространственную корреляцию, а затем при желании добавить контролируемое количество аддитивного шума.
Подход с контролируемым полем: базовый слой + аддитивный белый шум
Простой способ добавить структуру — задать гладкое базовое поле через набор аттракторов (точек, влияющих на сетку), суммировать их вклад по всей карте и затем добавить немного белого шума для мелкой текстуры. Так вы получаете прямой контроль и над крупномасштабной формой, и над локальной шероховатостью.
Идея проста. Случайно размещаем аттракторы с положительными или отрицательными весами. Для каждого пикселя суммируем влияние всех аттракторов с помощью функции, похожей на обратную зависимость от расстояния. Получившееся поле гладкое и глобально разнообразное. В завершение при необходимости добавляем настраиваемый аддитивный белый шум, чтобы внести лёгкие локальные неровности.
Реализация
import numpy as np
import matplotlib.pyplot as plt
def synth_region(side: int, jitter_amp: float):
# Повторяемый генератор случайных чисел
prng = np.random.default_rng(seed=14)
# Выходное поле
field = np.empty((side, side), dtype=float)
# Число аттракторов
k_anchors = int(side)
# Координаты аттракторов
anchor_xy = prng.integers(0, side, (k_anchors, 2), endpoint=False)
# Веса аттракторов в диапазоне [-1, 1]
anchor_gain = prng.random(size=k_anchors) * 2 - 1
# Накопление влияния аттракторов для каждого пикселя
for ix in range(side):
for iy in range(side):
accum = 0.0
for pt, weight in zip(anchor_xy, anchor_gain):
accum += (np.linalg.norm(pt - (ix, iy)) + side ** 0.5) ** -1 * weight
field[ix, iy] = accum
# Аддитивный белый шум, масштабированный через jitter_amp
field += prng.random(size=(side, side)) * jitter_amp
plt.imshow(field)
plt.show()
# Примеры с нарастающей мелкомасштабной текстурой
synth_region(100, 0.0)
synth_region(100, 0.01)
synth_region(100, 0.05)
Это даёт гладкое поле, формируемое пространственно распределёнными источниками влияния. Параметр jitter_amp управляет количеством высокочастотной текстуры поверх базовой структуры. Нулевое значение подчёркивает крупномасштабную вариацию и плавные переходы; повышение параметра добавляет локальную шероховатость.
Можно менять число аттракторов, их позиции и веса, чтобы сформировать нужный ландшафт. Также можно изменить функцию влияния, регулируя скорость затухания с расстоянием. Эти настройки делают метод очень гибким и помогают избежать блочных переходов и жёстких границ.
Почему это важно
Когда нужна 2D-поверхность, которая выглядит более «физичной», а не случайной — то есть медленно меняется на коротких дистанциях, но заметно варьируется на больших масштабах, — ключ в управлении пространственной корреляцией. Определив базовое поле и добавив небольшое количество аддитивного белого шума, вы получите предсказуемое, воспроизводимое поведение с минимумом артефактов и сможете точно задать степень гладкости или разнообразия карты.
Если предпочитаете начинать с грубой разметки и уточнять её, можно интерполировать разреженную сетку до плотной, например с помощью scipy.interpolate.griddata. А если цель — повысить энергию на низких пространственных частотах, направленная коррекция спектра тоже даст сильную глобальную вариацию при ограничённых локальных изменениях.
Итоги
Независимое пер-пиксельное сэмплирование даёт белый шум и разрушает локальную согласованность. Если вам нужен гладкий фон с глобальной структурой, сформируйте коррелированное базовое поле и, только при необходимости, добавьте контролируемое количество аддитивного белого шума. Показанный выше паттерн накопления влияния аттракторов — компактный путь к результату; его легко настраивать, варьируя расположение аттракторов, их веса, форму функции влияния и итоговую амплитуду шума.