| 12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576 |
- import json
- class HardwareConstraints:
- """
- Класс, хранящий аппаратные ограничения и настройки MRI-системы.
- Может инициализироваться из JSON-файла.
- """
- def __init__(self, json_path: str = None):
- # Значения по умолчанию (совместимые с pypulseq)
- self.rf_raster_time = 1e-6 # сек, шаг временной дискретизации RF
- self.grad_raster_time = 10e-6 # сек, шаг дискретизации градиента
- self.adc_raster_time = 100e-9 # сек, шаг дискретизации АЦП
- self.block_duration_raster = 10e-6 # сек, шаг дискретизации длительности блока
- # Системные ограничения (по умолчанию отсутствуют задержки мертвого времени)
- self.rf_dead_time = 0.0
- self.rf_ringdown_time = 0.0
- self.adc_dead_time = 0.0
- self.gamma = 42.576e6 # Гиромагнитное отношение (Гц/Т) для протона
- # Кастомные параметры системы
- self.TR_DELAY = 20e-9 # сек, задержка после съема (между TR)
- self.RF_DELAY = 500e-6 # сек, задержка перед RF-импульсом
- self.START_DELAY = 17e-6 # сек, начальная задержка перед последовательностью
- self.MIN_BLOCK_DURATION = 20e-9 # сек, минимальная длительность блока (квант времени последовательности)
- self.GRAD_DELAY = 1000e-9
- # Флаги вставки задержек в синхро-последовательность.
- # Если флаг False — соответствующий блок задержки не вставляется
- # (и не вычитается из соседнего), что убирает артефакты 1/0 тактов.
- self.TR_DELAY_ENABLED = True
- self.RF_DELAY_ENABLED = True
- self.START_DELAY_ENABLED = True
- # Максимальные амплитуды
- self.RF_MAX = 1.0 # относительная макс. амплитуда RF (нормирована на 1.0)
- self.GRAD_MAX = 9e-3 * self.gamma # макс. градиент (Гц/м) по умолчанию 9 mT/m * gamma
- # Загрузка параметров из JSON при указании пути
- if json_path:
- self.load_from_json(json_path)
- def load_from_json(self, json_path: str):
- """
- Загружает параметры аппаратных ограничений из JSON-файла.
- """
- with open(json_path, 'r') as f:
- data = json.load(f)
- # Обновление обязательных параметров (если указаны в файле)
- self.rf_raster_time = data.get("rf_raster_time", self.rf_raster_time)
- self.grad_raster_time = data.get("grad_raster_time", self.grad_raster_time)
- self.adc_raster_time = data.get("adc_raster_time", self.adc_raster_time)
- self.block_duration_raster = data.get("block_duration_raster", self.block_duration_raster)
- self.rf_dead_time = data.get("rf_dead_time", self.rf_dead_time)
- self.rf_ringdown_time = data.get("rf_ringdown_time", self.rf_ringdown_time)
- self.adc_dead_time = data.get("adc_dead_time", self.adc_dead_time)
- self.gamma = data.get("gamma", self.gamma)
- # Обновление пользовательских параметров
- self.TR_DELAY = data.get("TR_DELAY", self.TR_DELAY)
- self.RF_DELAY = data.get("RF_DELAY", self.RF_DELAY)
- if self.rf_raster_time == 0.5e-6:
- self.START_DELAY = 885 * self.MIN_BLOCK_DURATION
- elif self.rf_raster_time == 0.05e-6:
- self.START_DELAY = 89 * self.MIN_BLOCK_DURATION
- else:
- self.START_DELAY = self.MIN_BLOCK_DURATION * 10
- self.MIN_BLOCK_DURATION = data.get("MIN_BLOCK_DURATION", self.MIN_BLOCK_DURATION)
- # Флаги вставки задержек
- self.TR_DELAY_ENABLED = data.get("TR_DELAY_ENABLED", self.TR_DELAY_ENABLED)
- self.RF_DELAY_ENABLED = data.get("RF_DELAY_ENABLED", self.RF_DELAY_ENABLED)
- self.START_DELAY_ENABLED = data.get("START_DELAY_ENABLED", self.START_DELAY_ENABLED)
- # Обновление максимальных амплитуд (если указаны)
- self.RF_MAX = data.get("RF_MAX", self.RF_MAX)
- self.GRAD_MAX = data.get("GRAD_MAX", self.GRAD_MAX)
|