• GeneralARTIQ
  • Dummy device for hardware-independent experiment

I'm working on some hardware-independent experimental template. The idea here is to define some general pulse functions like doppler_cooling() or qubit_pulse() running on FPGA. But since I don't know which TTL/DDS will be used for each of these pulses, I need a dummy device inside the build() stage.

My current workaround is to ask the user to create some TTL/DDS in device_db.py that connect to nothing. This looks a bit stupid. Does anyone have a better idea of creating such dummy devices (mostly, DDS and TTL)?

Thanks in advance.

It's hard to guess what you are trying to do exactly. Can you post simplified code examples? What should be the behavior of the dummy device when accessed by doppler_cooling()?

a simple example may looks like this:

class DummyEnv(HasEnvironment):
    def build(self): 
        self.core = self.get_device('core')
        self.doppler_cool_beam = self.get_device('dummyTTL')        
    
    def build_doppler(self, **kwargs):
        if 'ttl' in kwargs.keys():            
            self.doppler_cool_beam = kwargs('ttl')
            self.has_ttl = True
        else:
            self.has_ttl = False
    
    @kernel
    def run(self):
        # complicate sequence, for example:
        if self.has_ttl:
            self.doppler_cool_beam.pulse(2*ms)


class UserExperiment(DummyEnv, Experiment):
    def build(self):
        DummyEnv.build(self)
        self.ttl3 = self.get_device('ttl3')
        self.build_doppler(ttl=self.ttl3)

In this example, I only need to write the DummyEnv and define the pulses there.
But I don't know which TTL channel will be used for doppler_cool_beam.

When the user starts writing the real UserExperiment, he doesn't need to know how the sequence will work.
instead, he only needs to use self.build_doppler(ttl=self.ttl3) to specify that ttl3 should do this job.

Currently, I need to ask the user to make sure they have this dummyTTL in their device_db.py.
I just feel this should have a better way, is it?

What about defining a "fake TTL" class that has a pulse kernel method that does nothing? Then you can use that class instead of the real TTL when you don't want to use it, e.g. call get_argument in build, and then depending on the result either call get_device to obtain the real TTL, or create an instance of the fake TTL class.