asc_to_hw.py 3.7 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105
  1. from types import SimpleNamespace
  2. from typing import List
  3. import numpy as np
  4. def asc_to_acoustic_resonances(asc : dict) -> List[dict]:
  5. """
  6. Convert ASC dictionary from readasc to list of acoustic resonances
  7. Parameters
  8. ----------
  9. asc : dict
  10. ASC dictionary, see readasc
  11. Returns
  12. -------
  13. List[dict]
  14. List of acoustic resonances (specified by frequency and bandwidth fields).
  15. """
  16. if 'aflGCAcousticResonanceFrequency' in asc:
  17. freqs = asc['aflGCAcousticResonanceFrequency']
  18. bw = asc['aflGCAcousticResonanceBandwidth']
  19. else:
  20. freqs = asc['asGPAParameters'][0]['sGCParameters']['aflAcousticResonanceFrequency']
  21. bw = asc['asGPAParameters'][0]['sGCParameters']['aflAcousticResonanceBandwidth']
  22. return [dict(frequency=f, bandwidth=b) for f,b in zip(freqs.values(), bw.values()) if f != 0]
  23. def asc_to_hw(asc : dict, cardiac_model : bool = False) -> SimpleNamespace:
  24. """
  25. Convert ASC dictionary from readasc to SAFE hardware description.
  26. Parameters
  27. ----------
  28. asc : dict
  29. ASC dictionary, see readasc
  30. cardiac_model : bool
  31. Whether or not to read the cardiac stimulation model instead of the
  32. default PNS model (returns None if not available)
  33. Returns
  34. -------
  35. SimpleNamespace
  36. SAFE hardware description
  37. """
  38. hw = SimpleNamespace()
  39. if 'asCOMP' in asc and 'tName' in asc['asCOMP']:
  40. hw.name = asc['asCOMP']['tName']
  41. else:
  42. hw.name = 'unknown'
  43. if 'GradPatSup' in asc:
  44. asc_pns = asc['GradPatSup']['Phys']['PNS']
  45. else:
  46. asc_pns = asc
  47. if cardiac_model:
  48. if 'GradPatSup' in asc and 'CarNS' in asc['GradPatSup']['Phys']:
  49. asc_pns = asc['GradPatSup']['Phys']['CarNS']
  50. else:
  51. return None
  52. hw.x = SimpleNamespace()
  53. hw.x.tau1 = asc_pns['flGSWDTauX'][0] # ms
  54. hw.x.tau2 = asc_pns['flGSWDTauX'][1] # ms
  55. hw.x.tau3 = asc_pns['flGSWDTauX'][2] # ms
  56. hw.x.a1 = asc_pns['flGSWDAX'][0]
  57. hw.x.a2 = asc_pns['flGSWDAX'][1]
  58. hw.x.a3 = asc_pns['flGSWDAX'][2]
  59. hw.x.stim_limit = asc_pns['flGSWDStimulationLimitX'] # T/m/s
  60. hw.x.stim_thresh = asc_pns['flGSWDStimulationThresholdX'] # T/m/s
  61. hw.y = SimpleNamespace()
  62. hw.y.tau1 = asc_pns['flGSWDTauY'][0] # ms
  63. hw.y.tau2 = asc_pns['flGSWDTauY'][1] # ms
  64. hw.y.tau3 = asc_pns['flGSWDTauY'][2] # ms
  65. hw.y.a1 = asc_pns['flGSWDAY'][0]
  66. hw.y.a2 = asc_pns['flGSWDAY'][1]
  67. hw.y.a3 = asc_pns['flGSWDAY'][2]
  68. hw.y.stim_limit = asc_pns['flGSWDStimulationLimitY'] # T/m/s
  69. hw.y.stim_thresh = asc_pns['flGSWDStimulationThresholdY'] # T/m/s
  70. hw.z = SimpleNamespace()
  71. hw.z.tau1 = asc_pns['flGSWDTauZ'][0] # ms
  72. hw.z.tau2 = asc_pns['flGSWDTauZ'][1] # ms
  73. hw.z.tau3 = asc_pns['flGSWDTauZ'][2] # ms
  74. hw.z.a1 = asc_pns['flGSWDAZ'][0]
  75. hw.z.a2 = asc_pns['flGSWDAZ'][1]
  76. hw.z.a3 = asc_pns['flGSWDAZ'][2]
  77. hw.z.stim_limit = asc_pns['flGSWDStimulationLimitZ'] # T/m/s
  78. hw.z.stim_thresh = asc_pns['flGSWDStimulationThresholdZ'] # T/m/s
  79. if 'asGPAParameters' in asc:
  80. hw.x.g_scale = asc['asGPAParameters'][0]['sGCParameters']['flGScaleFactorX']
  81. hw.y.g_scale = asc['asGPAParameters'][0]['sGCParameters']['flGScaleFactorY']
  82. hw.z.g_scale = asc['asGPAParameters'][0]['sGCParameters']['flGScaleFactorZ']
  83. else:
  84. print('Warning: Gradient scale factors not in ASC file: assuming 1/pi')
  85. hw.x.g_scale = 1/np.pi
  86. hw.y.g_scale = 1/np.pi
  87. hw.z.g_scale = 1/np.pi
  88. return hw