|
|
import torch as _torch
|
|
|
import numpy as _np
|
|
|
from abc import ABC as _ABC
|
|
|
from typing import Tuple as _Tuple
|
|
|
import collections as _collections
|
|
|
import pickle as _pickle
|
|
|
|
|
|
class ConfigOpticBase(_ABC):
|
|
|
"""
|
|
|
Абстрактный класс базовой информации о работе опттической установки.
|
|
|
|
|
|
Поля:
|
|
|
wavelength: длина волны, используемая в оптической установке.
|
|
|
K: волновое число.
|
|
|
distance: дистанция распространения светового поля между плоскостями.
|
|
|
"""
|
|
|
def __init__(self, wavelength: float, distance: float):
|
|
|
"""
|
|
|
Конструктор класса базовой информации о работе опттической установки.
|
|
|
|
|
|
Args:
|
|
|
wavelength: длина волны, используемая в оптической установке.
|
|
|
distance: дистанция распространения светового поля между плоскостями.
|
|
|
"""
|
|
|
self._wavelength: float = wavelength
|
|
|
self._K: float = 2 * _np.pi / wavelength
|
|
|
self._distance = distance
|
|
|
|
|
|
@property
|
|
|
def wavelength(self) -> float:
|
|
|
"""
|
|
|
Returns: длинна волны.
|
|
|
"""
|
|
|
return self._wavelength
|
|
|
|
|
|
@property
|
|
|
def K(self) -> float:
|
|
|
"""
|
|
|
Returns: волновое число.
|
|
|
"""
|
|
|
return self._K
|
|
|
|
|
|
@property
|
|
|
def distance(self) -> float:
|
|
|
"""
|
|
|
Returns: дистанция распространения.
|
|
|
"""
|
|
|
return self._distance
|
|
|
|
|
|
class ConfigDesignPlane:
|
|
|
"""
|
|
|
Класс данных о расчётной плоскости.
|
|
|
"""
|
|
|
def __init__(self,
|
|
|
pixel_count: None | int | _Tuple[int, int] = None,
|
|
|
pixel_size: None | float | _Tuple[float, float] = None,
|
|
|
aperture: None | float | _Tuple[float, float] = None
|
|
|
):
|
|
|
"""
|
|
|
Конструктор класса данных о расчётной плоскости.
|
|
|
|
|
|
Args:
|
|
|
pixel_count: данные о кол-ве пикселей в измерении.
|
|
|
pixel_size: данные о размере пикселей в измерении.
|
|
|
aperture: данные о апертуре измерения.
|
|
|
|
|
|
Note:
|
|
|
1. Достаточно указать два из трёх входных аргумента.
|
|
|
2. Если было переданно одно число, будет считаться, что значение у каждого измерения совпадают,
|
|
|
если было переданно два числа, то первое число будет ассоциированно с Y измерением, второе с X.
|
|
|
"""
|
|
|
if aperture is None:
|
|
|
aperture = ConfigDesignPlane.__get_excluded_third(pixel_count, pixel_size, False)
|
|
|
elif pixel_count is None:
|
|
|
pixel_count = ConfigDesignPlane.__get_excluded_third(aperture, pixel_size)
|
|
|
elif pixel_size is None:
|
|
|
pixel_size = ConfigDesignPlane.__get_excluded_third(aperture, pixel_count)
|
|
|
|
|
|
self._pixel_count: int | _Tuple[int, int] = pixel_count
|
|
|
self._pixel_size: float | _Tuple[float, float] = pixel_size
|
|
|
self._aperture: float | _Tuple[float, float] = aperture
|
|
|
|
|
|
@staticmethod
|
|
|
def __get_excluded_third(first_element, second_element, div: bool = True):
|
|
|
ConfigDesignPlane.__check_for_none(first_element, second_element)
|
|
|
first_element_y, first_element_x = ConfigDesignPlane.__return_tuple(first_element)
|
|
|
second_element_y, second_element_x = ConfigDesignPlane.__return_tuple(second_element)
|
|
|
if div:
|
|
|
return first_element_y / second_element_y, first_element_x / second_element_x
|
|
|
else:
|
|
|
return first_element_y * second_element_y, first_element_x * second_element_x
|
|
|
|
|
|
@staticmethod
|
|
|
def __check_for_none(first_element, second_element):
|
|
|
if (first_element is None) or (second_element is None):
|
|
|
raise TypeError("One of the provided elements is None, it is not possible to obtain the full dimensions of the calculated plane.")
|
|
|
|
|
|
@staticmethod
|
|
|
def __return_element(element: int | _Tuple[int, int], dim: int = 0):
|
|
|
if isinstance(element, _collections.abc.Sequence):
|
|
|
return element[dim]
|
|
|
else:
|
|
|
return element
|
|
|
|
|
|
@staticmethod
|
|
|
def __return_tuple(element: int | _Tuple[int, int]):
|
|
|
if isinstance(element, _collections.abc.Sequence):
|
|
|
return element
|
|
|
else:
|
|
|
return element, element
|
|
|
|
|
|
@staticmethod
|
|
|
def __get_linspace_by_dim(aperture, pixel_count):
|
|
|
linspace = _torch.linspace(-aperture / 2, aperture / 2, pixel_count + 1)[:pixel_count]
|
|
|
linspace += aperture / (2 * pixel_count)
|
|
|
return linspace
|
|
|
|
|
|
@property
|
|
|
def pixel_count_by_x(self) -> float:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о кол-ве пикселей по оси X.
|
|
|
"""
|
|
|
return ConfigDesignPlane.__return_element(self._pixel_count, 1)
|
|
|
@property
|
|
|
def pixel_count_by_y(self) -> float:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о кол-ве пикселей по оси Y.
|
|
|
"""
|
|
|
return ConfigDesignPlane.__return_element(self._pixel_count)
|
|
|
@property
|
|
|
def pixel_count(self) -> _Tuple[float, float]:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о кол-ве пикселей по каждой оси [Y, x].
|
|
|
"""
|
|
|
return ConfigDesignPlane.__return_tuple(self._pixel_count)
|
|
|
@property
|
|
|
def pixel_size_by_x(self) -> int:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о размере пикселей по оси X.
|
|
|
"""
|
|
|
return ConfigDesignPlane.__return_element(self._pixel_size, 1)
|
|
|
@property
|
|
|
def pixel_size_by_y(self) -> int:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о размере пикселей по оси Y.
|
|
|
"""
|
|
|
return ConfigDesignPlane.__return_element(self._pixel_size)
|
|
|
@property
|
|
|
def pixel_size(self) -> _Tuple[int, int]:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о размере пикселей по каждой оси [Y, x].
|
|
|
"""
|
|
|
return ConfigDesignPlane.__return_tuple(self._pixel_size)
|
|
|
@property
|
|
|
def aperture_width(self) -> float:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о ширине расчётной плоскасти.
|
|
|
"""
|
|
|
return ConfigDesignPlane.__return_element(self._aperture, 1)
|
|
|
@property
|
|
|
def aperture_height(self) -> float:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о высоте расчётной плоскасти.
|
|
|
"""
|
|
|
return ConfigDesignPlane.__return_element(self._aperture)
|
|
|
@property
|
|
|
def aperture(self) -> _Tuple[float, float]:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о высоте и ширине расчётной плоскасти [H, W].
|
|
|
"""
|
|
|
return ConfigDesignPlane.__return_tuple(self._aperture)
|
|
|
@property
|
|
|
def linspace_by_x(self) -> _torch.Tensor:
|
|
|
"""
|
|
|
Returns:
|
|
|
Расчётная сетка по оси X.
|
|
|
"""
|
|
|
return ConfigDesignPlane.__get_linspace_by_dim(self.aperture_width, self.pixel_count_by_x)
|
|
|
@property
|
|
|
def linspace_by_y(self) -> _torch.Tensor:
|
|
|
"""
|
|
|
Returns:
|
|
|
Расчётная сетка по оси Y.
|
|
|
"""
|
|
|
return ConfigDesignPlane.__get_linspace_by_dim(self.aperture_height, self.pixel_count_by_y)
|
|
|
@property
|
|
|
def meshgrid(self) -> _Tuple[_torch.Tensor, _torch.Tensor]:
|
|
|
"""
|
|
|
Returns:
|
|
|
Расчётная сетка по осям [Y, X].
|
|
|
"""
|
|
|
linspace_by_x = self.linspace_by_x
|
|
|
linspace_by_y = self.linspace_by_y
|
|
|
return _torch.meshgrid((linspace_by_y, linspace_by_x))
|
|
|
|
|
|
class ConfigModelBase(_ABC):
|
|
|
"""
|
|
|
Абстрактный класс базовой информации об оптической установке.
|
|
|
"""
|
|
|
def __init__(self,
|
|
|
input_vector_plane: ConfigDesignPlane,
|
|
|
first_lens_plane: ConfigDesignPlane,
|
|
|
matrix_plane: ConfigDesignPlane,
|
|
|
second_lens_plane: ConfigDesignPlane,
|
|
|
output_vector_plane: ConfigDesignPlane
|
|
|
):
|
|
|
self._input_vector_plane: ConfigDesignPlane = input_vector_plane
|
|
|
self._first_lens_plane: ConfigDesignPlane = first_lens_plane
|
|
|
self._matrix_plane: ConfigDesignPlane = matrix_plane
|
|
|
self._second_lens_plane: ConfigDesignPlane = second_lens_plane
|
|
|
self._output_vector_plane: ConfigDesignPlane = output_vector_plane
|
|
|
|
|
|
@property
|
|
|
def input_vector_plane(self) -> ConfigDesignPlane:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о расчётной плоскости входного вектора.
|
|
|
"""
|
|
|
return self._input_vector_plane
|
|
|
@property
|
|
|
def first_lens_plane(self) -> ConfigDesignPlane:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о расчётной плоскости первой скрещенной линзы.
|
|
|
"""
|
|
|
return self._first_lens_plane
|
|
|
@property
|
|
|
def matrix_plane(self) -> ConfigDesignPlane:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о расчётной плоскости элемента матрицы.
|
|
|
"""
|
|
|
return self._matrix_plane
|
|
|
@property
|
|
|
def second_lens_plane(self) -> ConfigDesignPlane:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о расчётной плоскости второй скрещенной линзы.
|
|
|
"""
|
|
|
return self._second_lens_plane
|
|
|
@property
|
|
|
def output_vector_plane(self) -> ConfigDesignPlane:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о расчётной плоскости выходного вектора оптической установки.
|
|
|
"""
|
|
|
return self._output_vector_plane
|
|
|
|
|
|
class Config(ConfigOpticBase, ConfigModelBase):
|
|
|
"""
|
|
|
Класс конфигурации, хранит полную информацию о расчётной системе.
|
|
|
"""
|
|
|
def __init__(self,
|
|
|
right_matrix_count_columns: int,
|
|
|
right_matrix_count_rows: int,
|
|
|
right_matrix_width: float,
|
|
|
right_matrix_height: float,
|
|
|
min_height_gap: float,
|
|
|
right_matrix_split_x: int = 1,
|
|
|
right_matrix_split_y: int = 1,
|
|
|
left_matrix_split_x: int = 1,
|
|
|
left_matrix_split_y: int = 1,
|
|
|
result_matrix_split: int = 1,
|
|
|
camera_pixel_size: float = 3.6e-6,
|
|
|
wavelength: float = 532e-9,
|
|
|
distance: float = 0.03,
|
|
|
lens_pixel_size: float = 1.8e-6,
|
|
|
lens_size: int = 8192):
|
|
|
"""
|
|
|
Конструктор класса.
|
|
|
|
|
|
Args:
|
|
|
right_matrix_count_columns: число столбцов в правой матрице, участвующей в операции матричного умножения.
|
|
|
right_matrix_count_rows: число строк в правой матрице, участвующей в операции матричного умножения.
|
|
|
right_matrix_width: ширина в метрах оптического элемента правой матрицы, участвующей в операции матричного умножения.
|
|
|
right_matrix_height: высота в метрах оптического элемента правой матрицы, участвующей в операции матричного умножения.
|
|
|
min_height_gap: минимально возможный зазор для отображения вектора левой матрицы, участвующей в операции матричного умножения.
|
|
|
right_matrix_split_x: число дробления элементов правой матрицы по X (используется для более точного моделирования).
|
|
|
right_matrix_split_y: число дробления элементов правой матрицы по Y (используется для более точного моделирования).
|
|
|
left_matrix_split_x: число дробления элементов левой матрицы по X (используется для более точного моделирования).
|
|
|
left_matrix_split_y: число дробления элементов левой матрицы по Y (используется для более точного моделирования).
|
|
|
result_matrix_split: число дробления элементов результирующей матрицы (используется для более точного моделирования).
|
|
|
camera_pixel_size: физический размер пикселя камеры, считывающей результирующее световое поле.
|
|
|
wavelength: длины волн в метрах используемых в системе.
|
|
|
distance: дистанция в метрах распространения светового поля между плоскостями.
|
|
|
lens_pixel_size: размер пикселя в метрах скрещенных линз в оптической системе (нужен исключительно для моделирования).
|
|
|
lens_size: размер скрещенных линз в метрах в оптической системе (нужен исключительно для моделирования).
|
|
|
"""
|
|
|
ConfigOpticBase.__init__(self, wavelength, distance)
|
|
|
|
|
|
config_plane_one = ConfigDesignPlane((left_matrix_split_y, left_matrix_split_x * right_matrix_count_rows),
|
|
|
aperture=(min_height_gap, right_matrix_height)
|
|
|
)
|
|
|
config_plane_lens = ConfigDesignPlane(lens_size, lens_pixel_size)
|
|
|
config_plane_three = ConfigDesignPlane((right_matrix_count_columns * left_matrix_split_x, right_matrix_count_rows * right_matrix_split_y),
|
|
|
aperture=(right_matrix_width, right_matrix_height)
|
|
|
)
|
|
|
config_plane_five = ConfigDesignPlane((right_matrix_count_columns * result_matrix_split, 1),
|
|
|
aperture=(right_matrix_width, camera_pixel_size)
|
|
|
)
|
|
|
ConfigModelBase.__init__(self,
|
|
|
config_plane_one,
|
|
|
config_plane_lens,
|
|
|
config_plane_three,
|
|
|
config_plane_lens,
|
|
|
config_plane_five
|
|
|
)
|
|
|
|
|
|
self._matrix_split_x: int = right_matrix_split_x
|
|
|
self._matrix_split_y: int = right_matrix_split_y
|
|
|
self._input_vector_split_x: int = left_matrix_split_x
|
|
|
self._input_vector_split_y: int = left_matrix_split_y
|
|
|
self._result_vector_split: int = result_matrix_split
|
|
|
|
|
|
@property
|
|
|
def matrix_split_x(self) -> int:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о разбиении пикселей элементов матрицы по оси X.
|
|
|
"""
|
|
|
return self._matrix_split_x
|
|
|
@property
|
|
|
def matrix_split_y(self) -> int:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о разбиении пикселей элементов матрицы по оси Y.
|
|
|
"""
|
|
|
return self._matrix_split_y
|
|
|
@property
|
|
|
def input_vector_split_x(self) -> int:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о разбиении пикселей элементов входного вектора по оси X.
|
|
|
"""
|
|
|
return self._input_vector_split_x
|
|
|
@property
|
|
|
def input_vector_split_y(self) -> int:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о разбиении пикселей элементов входного вектора по оси Y.
|
|
|
"""
|
|
|
return self._input_vector_split_y
|
|
|
@property
|
|
|
def result_vector_split(self) -> int:
|
|
|
"""
|
|
|
Returns:
|
|
|
Информация о разбиении пикселей элементов выходного вектора по оси Y.
|
|
|
"""
|
|
|
return self._result_vector_split
|
|
|
|
|
|
def save(self, filename: str = "config.pth"):
|
|
|
"""
|
|
|
Метод сохранения параметров конфигурации в файл.
|
|
|
|
|
|
Args:
|
|
|
filename: название файла с параметрами конфигурации.
|
|
|
"""
|
|
|
with open(filename, 'wb') as f:
|
|
|
_pickle.dump(self, f, protocol=_pickle.HIGHEST_PROTOCOL)
|
|
|
|
|
|
@staticmethod
|
|
|
def load(filename: str = "config.pth") -> 'Config':
|
|
|
"""
|
|
|
Метод загрузки параметров конфигурации из файла.
|
|
|
|
|
|
Args:
|
|
|
filename: название файла с параметрами конфигурации.
|
|
|
"""
|
|
|
with open(filename, 'rb') as f:
|
|
|
return _pickle.load(f)
|