Microwave Sources - ACBJayichLab/NV_ABJ GitHub Wiki

A microwave source in this case is most closely linked to anything that we use to supply RF to the nitrogen vacancy. This may mean that other microwave sources don't fall into this abstract class it may also mean that more than one item makes the microwave source. For example, we consider the microwave source in most experiments to be the SG384 but in this use case we really should consider the microwave source to be the SG384 and the microwave switch. This is because the microwave switch adds the functionality of duration control which is essential for driving the nitrogen vacancy correctly. The microwave switch is also not necessary for experiments using triggered arbitrary wave generators but these devices fulfill the same roll so the class needs to specify the necessary components for the devices in use.

Required Abstract Functionality

For a class to be a microwave source you have to use the abstract MicrowaveSource class as a sub class for the module. By importing this abstract class as a subclass you will not be able to create a microwave source without the required functions defined. This doesn't assure the correctness of the code but it does encourage compatibility.

from NV_ABJ import MicrowaveSource
class SG380(MicrowaveSource):

frequency_range_hz

This is meant to return the frequency range of the device as a tuple in Hz. It may be something that is defined by the code and not interfaced from the device or it could be something that is pulled from the device when a new class is instantiated. It is a property function because this is not something that necessarily needs regular updating or computation it should be static through the duration of the class. (minimum frequency, maximum frequency)

@property
def frequency_range_hz(self)->tuple[float,float]:

power_range_dbm

This returns in the power range of the device that you are interfacing with as a tuple in dBm (minimum power, maximum power)

@property
def power_range_dbm(self)->tuple[float,float]:

get_frequency_hz

This should return the frequency in Hz that the microwave source is set to currently it is okay to have this as a pythonic based function for items like the AWG where the frequency is more set on creation and it might not be running the whole time.

def get_frequency_hz(self)->int:

get_power_dbm

Returns the power in dBm that the microwave source should be at. For items like the SRS SG384 it is appropriate to have this as a get function from the SRS.

def get_power_dbm(self)->float:

generate_sine_wave_hz_dbm

Generates a microwave source that is set to a specific frequency and amplitude this a general

def generate_sine_wave_hz_dbm(self,frequency:int,amplitude:float,*args,**kwargs):

set_power_dbm

Sets the power the microwave source should be at in dBm

def set_power_dbm(self,power:float):

set_frequency_hz

Sets the frequency in Hz for the microwave source

def set_frequency_hz(self,frequency_hz:int):

turn_on_signal

Turns on the RF signal by default we should not turn on the RF when using a context manger like the with keyword. This is because we want to send lists of data or change powers when the microwave source is not outputting to the sample

def turn_on_signal(self):

turn_off_signal

Turns off the microwave sources this should be expected to be called when exiting a context manager like the with keyword so that we can expect microwave sources stay off when not being interfaced with

def turn_off_signal(self):

load_frequency_list_hz

This is meant to be a command to load a frequency list to a device if the device can't do this it can be implemented using the set frequency and saving the list as a property to the class triggering you can just iterate through the list

def load_frequency_list_hz(self,frequency_list:list):

get_frequency_list_hz

returns the frequency list currently loaded

def get_frequency_list_hz(self)->list:

iterate

This will iterate through the loaded frequency list essentially setting the current frequency to the triggered values

def iterate(self):

all = ["MicrowaveSource","MicrowaveSourceConfiguration"]

from abc import ABCMeta, abstractmethod from NV_ABJ.abstract_interfaces.connected_device import ConnectedDevice import numpy.typing as npt import numpy as np from dataclasses import dataclass

@dataclass class MicrowaveSourceConfiguration: frequency_range_hz:tuple[float,float] amplitude_range_dbm:tuple[float,float]

class MicrowaveSource(ConnectedDevice,metaclass=ABCMeta): """This is a class for a signal generator not limited to but used for control of the RF supplied to the NV and allows for a general implementation for the singal frequency generators """

@property
@abstractmethod
def frequency_range_hz(self)->tuple[float,float]:
    """This is the frequency range that the prime sinusoidal rf is able to generate in 

    Returns:
        tuple[float,float]: (minimum frequency, maximum frequency)
    """

@property
@abstractmethod
def amplitude_range_dbm(self)->tuple[float,float]:
    """This is the amplitude range that the prime sinusoidal rf is able to generate in 

    Returns:
        tuple[float,float]: (minimum amplitude, maximum amplitude)
    """


@abstractmethod
def prime_sinusoidal_rf(self,frequency_list_hz:npt.NDArray[np.float64],
                    rf_amplitude_dbm:npt.NDArray[np.float64],
                    duration_s:npt.NDArray[np.float64],
                    *args,**kwargs):
    """This is a generalized function that is meant to allow for an experimental signal generation this 
    is meant to be implemented so the experimental logic for a cwesr, pulsed esr, or tau sweep will work properly.
    Not all actions need to be completed by the device but these are the expected inputs to constrain an arbitrary 
    waveform to the correct sinusoidal signal. This priming is not meant to start the signal but it is meant to queue
    up the frequency list for operation 

    A primed signal means that when a external trigger is applied to the device or device pair it will play the requested frequency 
    - For the SRS SG384 this means the signal is turned on and a microwave switch is expected to be present 
    - For a Keysight AWG the duration is added and we expect the sequence generator to trigger it on for a preset duration 
   
     Args:
        frequency_list_hz (npt.NDArray[np.float64]): A floating point numpy array that consists of the frequency in Hz 
        rf_amplitude_dbm (npt.NDArray[np.float64]): A floating point numpy array of the amplitude of the un-modulated sine wave dBm
        duration_s (npt.NDArray[np.float64]): A floating point numpy array of the duration in seconds for sine wave 
    """
    pass

@abstractmethod
def turn_on_signal(self)->None:
    """This turns on the signal source as a continuous operation 
    """
    pass 

@abstractmethod
def turn_off_signal(self)->None:
    """This turns off the signal source and will not turn off the device 
    """
    pass   
@abstractmethod
def iterate_next_waveform(self)->None:
    """This will iterate through the loaded frequency list essentially setting the current frequency to the triggered values
    """
    pass