Оптические системы
SVETlANNa предоставляет LinearOpticalSetup для сборки последовательных оптических систем.
LinearOpticalSetup
Основной класс для создания последовательных оптических систем.
from svetlanna import LinearOpticalSetup
from svetlanna.elements import ThinLens, FreeSpace, RoundAperture
from svetlanna.units import ureg
setup = LinearOpticalSetup([
RoundAperture(params, radius=2*ureg.mm),
ThinLens(params, focal_length=100*ureg.mm),
FreeSpace(params, distance=100*ureg.mm, method='AS'),
])
# Forward propagation
wf_out = setup(wf_in)
# Пошаговое распространение (возвращает промежуточные результаты)
intermediates = setup.stepwise_forward(wf_in)Все элементы в LinearOpticalSetup должны использовать один и тот же SimulationParameters. При несовпадении выводится предупреждение.
Методы
| Метод | Описание |
|---|---|
forward(wf) | Прямое распространение через все элементы |
stepwise_forward(wf) | Возвращает список промежуточных волновых фронтов |
Обратное распространение
Если все элементы поддерживают reverse(), система автоматически создаёт обратную сеть:
# Обратное распространение (если поддерживается)
if setup._reverse_net is not None:
wf_back = setup._reverse_net(wf_out)Альтернативы: nn.Sequential
Для простых случаев можно использовать стандартный nn.Sequential:
Базовый
import torch.nn as nn
system = nn.Sequential(
RoundAperture(params, radius=2*ureg.mm),
ThinLens(params, focal_length=100*ureg.mm),
FreeSpace(params, distance=100*ureg.mm, method='AS'),
)
wf_out = system(wf_in)Классические оптические системы
Фокусирующая система
from svetlanna import LinearOpticalSetup
def focusing_system(params, focal_length, aperture_radius=None):
"""Создаёт фокусирующую систему."""
elements = []
if aperture_radius is not None:
elements.append(RoundAperture(params, radius=aperture_radius))
elements.extend([
ThinLens(params, focal_length=focal_length),
FreeSpace(params, distance=focal_length, method='AS'),
])
return LinearOpticalSetup(elements)
# Использование
setup = focusing_system(params, focal_length=100*ureg.mm, aperture_radius=2*ureg.mm)
wf_focus = setup(wf_in)4f-система
def four_f_system(params, focal_length, filter_mask=None):
"""
4f-система для оптической фильтрации.
Структура: вход -> f -> L1 -> f -> [фильтр] -> f -> L2 -> f -> выход
"""
f = focal_length
prop = lambda: FreeSpace(params, distance=f, method='AS')
elements = [
prop(),
ThinLens(params, focal_length=f),
prop(),
]
if filter_mask is not None:
elements.append(Aperture(params, mask=filter_mask))
elements.extend([
prop(),
ThinLens(params, focal_length=f),
prop(),
])
return LinearOpticalSetup(elements)Телескоп Кеплера
def kepler_telescope(params, f1, f2):
"""
Телескоп Кеплера.
Увеличение M = -f2/f1
"""
return LinearOpticalSetup([
ThinLens(params, focal_length=f1),
FreeSpace(params, distance=f1 + f2, method='AS'),
ThinLens(params, focal_length=f2),
])
telescope = kepler_telescope(params, f1=50*ureg.mm, f2=200*ureg.mm)
# Увеличение: -4xДифракционные нейронные сети (DONN)
Многослойная D²NN
import torch
import torch.nn as nn
from svetlanna import LinearOpticalSetup
from svetlanna.elements import DiffractiveLayer, FreeSpace
class DONN(nn.Module):
"""Дифракционная оптическая нейронная сеть."""
def __init__(self, params, n_layers, layer_distance):
super().__init__()
elements = []
self.phase_masks = nn.ParameterList()
for i in range(n_layers):
# Обучаемая фазовая маска
phase = nn.Parameter(torch.rand(512, 512) * 2 * torch.pi)
self.phase_masks.append(phase)
elements.append(DiffractiveLayer(params, mask=phase))
elements.append(FreeSpace(params, distance=layer_distance, method='AS'))
self.optical = LinearOpticalSetup(elements)
def forward(self, wf):
return self.optical(wf)
# Использование
donn = DONN(params, n_layers=5, layer_distance=10*ureg.mm)
wf_out = donn(wf_in)С детектором для классификации
from svetlanna.detector import Detector, DetectorProcessorClf
class DONNClassifier(nn.Module):
def __init__(self, params, n_layers, n_classes):
super().__init__()
self.donn = DONN(params, n_layers=n_layers, layer_distance=10*ureg.mm)
self.detector = Detector(params, func='intensity')
self.processor = DetectorProcessorClf(
num_classes=n_classes,
simulation_parameters=params,
segmentation_type='strips'
)
def forward(self, wf):
wf = self.donn(wf)
intensity = self.detector(wf)
return self.processor.batch_forward(intensity)
classifier = DONNClassifier(params, n_layers=5, n_classes=10)Промежуточные результаты
Метод stepwise_forward возвращает волновой фронт после каждого элемента:
setup = LinearOpticalSetup([
RoundAperture(params, radius=2*ureg.mm),
ThinLens(params, focal_length=100*ureg.mm),
FreeSpace(params, distance=100*ureg.mm, method='AS'),
])
intermediates = setup.stepwise_forward(wf_in)
# intermediates[0] — после апертуры
# intermediates[1] — после линзы
# intermediates[2] — в фокусе
import matplotlib.pyplot as plt
fig, axes = plt.subplots(1, len(intermediates), figsize=(4*len(intermediates), 4))
for i, wf in enumerate(intermediates):
axes[i].imshow(wf.intensity.cpu(), cmap='hot')
axes[i].set_title(f'После элемента {i+1}')Работа с GPU
# Способ 1: перенос params, затем создание системы
params.to('cuda')
setup = LinearOpticalSetup([...]) # Автоматически на GPU
# Способ 2: перенос готовой системы
setup = LinearOpticalSetup([...])
setup = setup.to('cuda')
# Волновой фронт тоже должен быть на GPU
wf_gpu = wf.to('cuda')
wf_out = setup(wf_gpu)Сериализация
# Сохранение
torch.save(setup.state_dict(), 'optical_system.pth')
# Загрузка
setup = LinearOpticalSetup([...]) # Создать с той же структурой
setup.load_state_dict(torch.load('optical_system.pth'))См. также
- Оптические элементы — справочник по элементам
- Детекторы — измерение результата
- Оптимизация — обучение систем
- Туториал: D²NN — дифракционная нейросеть