A few things: 1. Got it working again; 2. Renamed files to make more sense; 3. Replaced template tmp.tnt with an emptied out file that previously took data, now data is collected correctly (bug, I'm not sure where this need comes from but this is, as far as I know, a permanent workaround); 4. Added automatic COM interface restart on errors compiling; 5. Implemented variable acquisition times.
This commit is contained in:
105
frappy_psi/tnmr/sequence_generation.py
Normal file
105
frappy_psi/tnmr/sequence_generation.py
Normal file
@@ -0,0 +1,105 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
"""
|
||||
SequenceGeneration
|
||||
______________________
|
||||
|
||||
Version: 1.0
|
||||
Authors: Davis Garrad (Paul Scherrer Institute, CH)
|
||||
______________________
|
||||
|
||||
Wrapper for the API I wrote to generate pulse sequences programmatically in TNMR (Tecmag).
|
||||
"""
|
||||
import frappy_psi.tnmr.sequence_fileformat as se
|
||||
|
||||
from pydantic.utils import deep_update
|
||||
|
||||
import json
|
||||
|
||||
def get_single_pulse_block(name, pulse_width, pulse_height, relaxation_time, phase_cycle='0'):
|
||||
'''Generates a single block of data to create a sequence with.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
name: str, just the prefix for the column names. Ensure this is unique over the whole sequence!
|
||||
pulse_width: str, in the format '10u' (10 microseconds)
|
||||
pulse_height: str, in the format '40' (I'm not honestly sure what units this is in...)
|
||||
relaxation_time: str, in the format '10u'
|
||||
phase_cycle: a given phase cycle (steps of 4, 0-3 inc.) (eg., '0 0 1 1 2 3 0 1', etc.)
|
||||
|
||||
Returns
|
||||
-------
|
||||
a dictionary which can be updated with others to generate a larger, more complex sequence.
|
||||
'''
|
||||
|
||||
ph = name + '_phase'
|
||||
rl = name + '_relaxation'
|
||||
block = se.generate_default_sequence([ ph, rl ], [ pulse_width, relaxation_time ])
|
||||
|
||||
# COLUMNNS
|
||||
# PH column
|
||||
block['columns'][ph]['F1_Ampl']['value'] = str(pulse_height)
|
||||
block['columns'][ph]['Delay'] = str(pulse_width)
|
||||
block['columns'][ph]['F1_UnBlank']['value'] = '1'
|
||||
block['columns'][ph]['Rx_Blank']['value'] = '1'
|
||||
# relaxation column
|
||||
block['columns'][rl]['F1_UnBlank']['value'] = '1'
|
||||
block['columns'][rl]['Rx_Blank']['value'] = '1'
|
||||
|
||||
if(phase_cycle != ''):
|
||||
table_name = f'ph_{name}'
|
||||
block['columns'][ph]['F1_Ph']['table'] = table_name
|
||||
block['tables'][table_name] = { 'values': phase_cycle, 'typestr': 'HP', 'start': 1 }
|
||||
|
||||
return block
|
||||
|
||||
def get_initial_block():
|
||||
block = se.generate_default_sequence(['Phase reset', 'Unblank'], ['1u', '10u'])
|
||||
# Phase reset
|
||||
block['columns']['Phase reset']['F1_PhRst']['value'] = '1'
|
||||
# Unblank
|
||||
block['columns']['Unblank']['F1_UnBlank']['value'] = '1'
|
||||
block['columns']['Unblank']['Rx_Blank']['value'] = '1'
|
||||
|
||||
return block
|
||||
|
||||
def get_final_block(ringdown_time, preacquire_time, acquire_time, cooldown_time, acq_phase_cycle='0'):
|
||||
'''Generates the final block of data to create a sequence with.
|
||||
|
||||
Parameters
|
||||
----------
|
||||
ringdown_time: str, of format '10u', how long to ringdown
|
||||
preacquire_time: str, in the format '10u', how long to wait after ringdown before acquiring data. A good default is 1 usec
|
||||
acquire_time: str, in the format '10u', how long to acquire data for
|
||||
cooldown_time: str, in the format '40u', how long to wait after acquisition.
|
||||
acq_phase_cycle: str, the phase cycle that the acquisition should follow
|
||||
Returns
|
||||
-------
|
||||
a dictionary which can be updated with others to generate a larger, more complex sequence.
|
||||
'''
|
||||
block = se.generate_default_sequence(['Ringdown', 'RX On', 'Acquisition', 'Finish', ''], [ringdown_time, preacquire_time, acquire_time, cooldown_time, '1u'])
|
||||
block = se.generate_default_sequence(['Ringdown', 'RX On', 'Acquisition', 'Finish', ''], [ringdown_time, preacquire_time, acquire_time, cooldown_time, '1u'])
|
||||
|
||||
# ringdown
|
||||
block['columns']['Ringdown']['Rx_Blank']['value'] = '1'
|
||||
|
||||
# Acquire
|
||||
block['columns']['Acquisition']['Acq']['value'] = '1'
|
||||
#block['columns']['Acquisition']['Acq_phase']['value'] = '0'
|
||||
|
||||
if(acq_phase_cycle != ''):
|
||||
block['columns']['Acquisition']['Acq_phase']['table'] = 'phacq'
|
||||
block['tables']['phacq'] = { 'values': acq_phase_cycle, 'typestr': 'HP', 'start': 1 }
|
||||
|
||||
return block
|
||||
|
||||
def combine_blocks(l, r):
|
||||
return deep_update(l, r)
|
||||
|
||||
def save_sequence(filename, sequence):
|
||||
se.create_sequence_file(filename, sequence)
|
||||
|
||||
def save_sequence_cfg(filename, sequence):
|
||||
with open(filename + '.cfg', 'w') as file:
|
||||
json.dump(sequence, file, indent=4)
|
||||
file.close()
|
||||
|
||||
Reference in New Issue
Block a user