constraints.py 4.7 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576
  1. import json
  2. class HardwareConstraints:
  3. """
  4. Класс, хранящий аппаратные ограничения и настройки MRI-системы.
  5. Может инициализироваться из JSON-файла.
  6. """
  7. def __init__(self, json_path: str = None):
  8. # Значения по умолчанию (совместимые с pypulseq)
  9. self.rf_raster_time = 1e-6 # сек, шаг временной дискретизации RF
  10. self.grad_raster_time = 10e-6 # сек, шаг дискретизации градиента
  11. self.adc_raster_time = 100e-9 # сек, шаг дискретизации АЦП
  12. self.block_duration_raster = 10e-6 # сек, шаг дискретизации длительности блока
  13. # Системные ограничения (по умолчанию отсутствуют задержки мертвого времени)
  14. self.rf_dead_time = 0.0
  15. self.rf_ringdown_time = 0.0
  16. self.adc_dead_time = 0.0
  17. self.gamma = 42.576e6 # Гиромагнитное отношение (Гц/Т) для протона
  18. # Кастомные параметры системы
  19. self.TR_DELAY = 20e-9 # сек, задержка после съема (между TR)
  20. self.RF_DELAY = 500e-6 # сек, задержка перед RF-импульсом
  21. self.START_DELAY = 17e-6 # сек, начальная задержка перед последовательностью
  22. self.MIN_BLOCK_DURATION = 20e-9 # сек, минимальная длительность блока (квант времени последовательности)
  23. self.GRAD_DELAY = 1000e-9
  24. # Флаги вставки задержек в синхро-последовательность.
  25. # Если флаг False — соответствующий блок задержки не вставляется
  26. # (и не вычитается из соседнего), что убирает артефакты 1/0 тактов.
  27. self.TR_DELAY_ENABLED = True
  28. self.RF_DELAY_ENABLED = True
  29. self.START_DELAY_ENABLED = True
  30. # Максимальные амплитуды
  31. self.RF_MAX = 1.0 # относительная макс. амплитуда RF (нормирована на 1.0)
  32. self.GRAD_MAX = 9e-3 * self.gamma # макс. градиент (Гц/м) по умолчанию 9 mT/m * gamma
  33. # Загрузка параметров из JSON при указании пути
  34. if json_path:
  35. self.load_from_json(json_path)
  36. def load_from_json(self, json_path: str):
  37. """
  38. Загружает параметры аппаратных ограничений из JSON-файла.
  39. """
  40. with open(json_path, 'r') as f:
  41. data = json.load(f)
  42. # Обновление обязательных параметров (если указаны в файле)
  43. self.rf_raster_time = data.get("rf_raster_time", self.rf_raster_time)
  44. self.grad_raster_time = data.get("grad_raster_time", self.grad_raster_time)
  45. self.adc_raster_time = data.get("adc_raster_time", self.adc_raster_time)
  46. self.block_duration_raster = data.get("block_duration_raster", self.block_duration_raster)
  47. self.rf_dead_time = data.get("rf_dead_time", self.rf_dead_time)
  48. self.rf_ringdown_time = data.get("rf_ringdown_time", self.rf_ringdown_time)
  49. self.adc_dead_time = data.get("adc_dead_time", self.adc_dead_time)
  50. self.gamma = data.get("gamma", self.gamma)
  51. # Обновление пользовательских параметров
  52. self.TR_DELAY = data.get("TR_DELAY", self.TR_DELAY)
  53. self.RF_DELAY = data.get("RF_DELAY", self.RF_DELAY)
  54. if self.rf_raster_time == 0.5e-6:
  55. self.START_DELAY = 885 * self.MIN_BLOCK_DURATION
  56. elif self.rf_raster_time == 0.05e-6:
  57. self.START_DELAY = 89 * self.MIN_BLOCK_DURATION
  58. else:
  59. self.START_DELAY = self.MIN_BLOCK_DURATION * 10
  60. self.MIN_BLOCK_DURATION = data.get("MIN_BLOCK_DURATION", self.MIN_BLOCK_DURATION)
  61. # Флаги вставки задержек
  62. self.TR_DELAY_ENABLED = data.get("TR_DELAY_ENABLED", self.TR_DELAY_ENABLED)
  63. self.RF_DELAY_ENABLED = data.get("RF_DELAY_ENABLED", self.RF_DELAY_ENABLED)
  64. self.START_DELAY_ENABLED = data.get("START_DELAY_ENABLED", self.START_DELAY_ENABLED)
  65. # Обновление максимальных амплитуд (если указаны)
  66. self.RF_MAX = data.get("RF_MAX", self.RF_MAX)
  67. self.GRAD_MAX = data.get("GRAD_MAX", self.GRAD_MAX)