Proper implementation of measure(), request_result(), read_result()

Hello forum,
I am currently working on integrating my first driver into the official repo. I got some initial feedback suggesting that it would be best to separate the measure() function for parallelisation. After reading again the SCPI manual, I found that it is indeed possible to read Voltage, Current and Power at once (actually it only gives current and voltage when testing), which would enable implementing it like this. However, I am now a bit unsure about how to implement it. I could not find another driver with this, so I hope to get some insights here. At the moment, it works like this (pseudo-code):

def measure(self):
     self.port.write("Current?")
     self.curr = self.port.read()
     self.port.write("Voltage?")
     self.vol = self.port.read()

which I could now write as

def measure(self):
   self.port.write("ALL?")
   self.vol, self.curr = self.port.read().split(",")

While it seems clear to me that read_result() should contain the second line, I don’t know if I should omit measure() completely and just put the first ā€œself.port.write(ā€œALL?ā€)ā€ line into request_result() or into measure() and omit request_result(). If I only put the ā€œself.port.writeā€ line into measure, it behaves differently from before. Does sweep take care of this automatically? Thanks in advance for the feedback on this.
Best
Tjorben

1 Like

Hi Tjorben,

thanks for creating this topic.

The idea of unblocking parallization is that the semantic phase functions of each driver are called for all drivers in the active branch one after another.

It means that SweepMe! calls ā€œapplyā€ for all drivers, then ā€œmeasureā€ for all drivers, then ā€œread_resultā€ for all drivers and so on.

I add here for all other readers the Wiki article about semantic functions calls:
https://wiki.sweep-me.net/wiki/Sequencer_procedure

If you would have multiple power supplies and they let’s say all need 1 s to return the result, the time to take a measurement point would scale with the number of instruments and could become very long. Instead, it would be better to first ask all instruments in ā€˜measure’ to acquire the data and then readout the result in ā€˜read_result’. In this case, one only needs to wait for the first instrument to return its data and the data of the other instruments is then probably already waiting in the buffer.

To do so I recommend the following code

def measure(self):
    self.port.write("ALL?")

def read_result(self):
    self.vol, self.curr = self.port.read().split(",")

This approach does not only help with having multiple times the same instrument, but can also help when instruments from different vendors should be triggered in ā€˜measure’ to start the measurement/the data acquisition.

Hope this helps, and let us know if any question remains.

Thanks and best,
Axel

Hi Axel,
Thanks for explaining this in detail, I get now how to properly implement it in my case.
For completeness reasons, only one question remains for me: In what case do I use request_result()? After thinking a bit more about it, my guess is that it is meant in cases where multiple results are stored into an internal memory of the device and then have to be internally evaluated before being ready for proper read-out. Is this correct?
It is not needed in my case here, but maybe I will have more complex measurement devices in the future (and maybe people search for it in the future, as it is in the title of the topic).
Best
Tjorben

1 Like

Yes, you are right. In some instruments, there are commands to trigger the acquisition and commands to start sending the result. In this case, this more fine-grained structure with ā€˜measure’, ā€˜request_result’ and ā€˜read_result’ can be used to further keep parallization of the tasks.

In some drivers, you will see that just ā€˜measure’ and ā€˜call’ are used. But whenever a user needs more control, we can split the command calls into more semantic phases.

By the way, the parallelization should also work if you do not use the command ā€œALL?ā€, but the individual commands to query voltage and current. The reason is that by communication with a COM port, the buffer keeps all results. The Port manager of SweepMe! reads the buffer until the occurence of the terminator character e.g. \n and leaves the rest in the buffer. This way it is possible to first read the voltage value from the buffer followed by reading the current from the buffer and still splitting self.port.write and self.port.read into different semantic phase functions.

Thanks and best,
Axel