Skip to the content.

index


Hardware Interface

When we talk about an "interface" in the context of qudi, mean the hardware interface classes usually located in qudi.interface.

An interface is an abstract class and a subclass of the module Base class. It defines a set of abstract methods and properties.
These classes can not be instantiated directly (thus "abstract"). Instead they must be subclassed.

In order for the subclass to work and not be abstract itself, it needs to implement all the abstract members of the interface class it inherits.
So every class that inherits the same interface is guaranteed to provide at least the set of methods and properties defined in the interface.

Since the interface subclass that implements all the abstract members is also a subclass of Base, this class is then called a hardware module.

See also the detailed qudi modules documentation if you want to know more about what defines a qudi module and the respective inheritance trees.

It's always good to have a look at some example... so here is a simple interface class for you.

Example Interface:

from abc import abstractmethod
from qudi.core import Base

class MySimpleInterface(Base):
    """ Interface description and license/copyright header goes here
    """
    @abstractmethod
    def read_value(self) -> float:
        """ Reads a value from the instrument and returns it
        """
        pass
    
    @property
    @abstractmethod
    def some_setting(self) -> int:
        """ Property holding some integer type setting in the instrument 
        """
        pass
    
    @some_setting.setter
    def some_setting(self, value: int) -> None:
        """ Setter for property "some_setting" 
        """
        pass

⚠ WARNING:

Note the order of decorators when declaring an abstract property. You can not exchange @property and @abstractmethod!

This interface declares a method read_value and a read/write property some_setting. Note also that it inherits Base.

An actual hardware module implementation satisfying this interface could look like below, assuming you placed the above code in qudi/interface/my_simple_interface.py.

Hardware Implementation:

from qudi.interface.my_simple_interface import MySimpleInterface

class MySimpleInstrument(MySimpleInterface):
    """ Hardware module description and license/copyright header goes here
    """
        
    def on_activate(self):
        """ Initialize module upon activation """
        # Perform any module initialization here, e.g. establish a connection to the instrument etc.
        ...
        
    def on_deactivate(self):
        """ Perform module cleanup upon deactivation """
        # Clean up your module and free all resources, e.g. terminate the instrument connection
        ...

    def read_value(self) -> float:
        """ Reads a value from the instrument and returns it """
        value = ...  # Read a value from the instrument
        return value
    
    @property
    def some_setting(self) -> int:
        """ Property holding some integer type setting in the instrument """
        value = ...  # Retrieve the setting value from the instrument
        return value
    
    @some_setting.setter
    def some_setting(self, value: int) -> None:
        """ Setter for property <some_setting> """
        ...  # Perform some sanity checking apply the new setting value to the instrument

Please note that in addition to the interface members you also needed to implement on_activate and on_deactivate which are abstract methods inherited from the Base class.

Implementing the members shown above is the bare minimum the hardware class needs to provide.
Of course, you can always implement additional members (helper methods etc.) to structure your class in accordance with good programming practices.

⚠ WARNING:

Other qudi modules that connect to a hardware class through an interface must only ever use/call the members declared in the interface. All additional members must only ever be used by the hardware class internally. Consequentially, you should consider making them protected or even private, i.e. add single _ or double underscore __ name prefix, respectively.

Why Do All This?

An abstract interface class defines a common set of methods and properties to control and monitor a certain generalized type of hardware (CW microwave sources, lasers, AWGs, etc.).

Logic modules that orchestrate instruments via hardware modules usually just define what kind of interface they want to use and not the specific hardware module, i.e. they require a general type of hardware without explicitly specifying a specific device model.

This has the advantage that you can exchange your instruments with various devices of the same hardware type without changing the code for your experiment procedure (i.e. the logic modules). As long as all hardware modules use the same interface, you can freely exchange them in the config while GUI and logic modules will work just the same.
This is also called "hardware abstraction".


index