from types import SimpleNamespace from typing import List import numpy as np def asc_to_acoustic_resonances(asc : dict) -> List[dict]: """ Convert ASC dictionary from readasc to list of acoustic resonances Parameters ---------- asc : dict ASC dictionary, see readasc Returns ------- List[dict] List of acoustic resonances (specified by frequency and bandwidth fields). """ if 'aflGCAcousticResonanceFrequency' in asc: freqs = asc['aflGCAcousticResonanceFrequency'] bw = asc['aflGCAcousticResonanceBandwidth'] else: freqs = asc['asGPAParameters'][0]['sGCParameters']['aflAcousticResonanceFrequency'] bw = asc['asGPAParameters'][0]['sGCParameters']['aflAcousticResonanceBandwidth'] return [dict(frequency=f, bandwidth=b) for f,b in zip(freqs.values(), bw.values()) if f != 0] def asc_to_hw(asc : dict, cardiac_model : bool = False) -> SimpleNamespace: """ Convert ASC dictionary from readasc to SAFE hardware description. Parameters ---------- asc : dict ASC dictionary, see readasc cardiac_model : bool Whether or not to read the cardiac stimulation model instead of the default PNS model (returns None if not available) Returns ------- SimpleNamespace SAFE hardware description """ hw = SimpleNamespace() if 'asCOMP' in asc and 'tName' in asc['asCOMP']: hw.name = asc['asCOMP']['tName'] else: hw.name = 'unknown' if 'GradPatSup' in asc: asc_pns = asc['GradPatSup']['Phys']['PNS'] else: asc_pns = asc if cardiac_model: if 'GradPatSup' in asc and 'CarNS' in asc['GradPatSup']['Phys']: asc_pns = asc['GradPatSup']['Phys']['CarNS'] else: return None hw.x = SimpleNamespace() hw.x.tau1 = asc_pns['flGSWDTauX'][0] # ms hw.x.tau2 = asc_pns['flGSWDTauX'][1] # ms hw.x.tau3 = asc_pns['flGSWDTauX'][2] # ms hw.x.a1 = asc_pns['flGSWDAX'][0] hw.x.a2 = asc_pns['flGSWDAX'][1] hw.x.a3 = asc_pns['flGSWDAX'][2] hw.x.stim_limit = asc_pns['flGSWDStimulationLimitX'] # T/m/s hw.x.stim_thresh = asc_pns['flGSWDStimulationThresholdX'] # T/m/s hw.y = SimpleNamespace() hw.y.tau1 = asc_pns['flGSWDTauY'][0] # ms hw.y.tau2 = asc_pns['flGSWDTauY'][1] # ms hw.y.tau3 = asc_pns['flGSWDTauY'][2] # ms hw.y.a1 = asc_pns['flGSWDAY'][0] hw.y.a2 = asc_pns['flGSWDAY'][1] hw.y.a3 = asc_pns['flGSWDAY'][2] hw.y.stim_limit = asc_pns['flGSWDStimulationLimitY'] # T/m/s hw.y.stim_thresh = asc_pns['flGSWDStimulationThresholdY'] # T/m/s hw.z = SimpleNamespace() hw.z.tau1 = asc_pns['flGSWDTauZ'][0] # ms hw.z.tau2 = asc_pns['flGSWDTauZ'][1] # ms hw.z.tau3 = asc_pns['flGSWDTauZ'][2] # ms hw.z.a1 = asc_pns['flGSWDAZ'][0] hw.z.a2 = asc_pns['flGSWDAZ'][1] hw.z.a3 = asc_pns['flGSWDAZ'][2] hw.z.stim_limit = asc_pns['flGSWDStimulationLimitZ'] # T/m/s hw.z.stim_thresh = asc_pns['flGSWDStimulationThresholdZ'] # T/m/s if 'asGPAParameters' in asc: hw.x.g_scale = asc['asGPAParameters'][0]['sGCParameters']['flGScaleFactorX'] hw.y.g_scale = asc['asGPAParameters'][0]['sGCParameters']['flGScaleFactorY'] hw.z.g_scale = asc['asGPAParameters'][0]['sGCParameters']['flGScaleFactorZ'] else: print('Warning: Gradient scale factors not in ASC file: assuming 1/pi') hw.x.g_scale = 1/np.pi hw.y.g_scale = 1/np.pi hw.z.g_scale = 1/np.pi return hw