Posted Fri, 31 Jan 2025 14:41:03 GMT by J., Nickolas

Hi everyone, i hope you can help me.
I'm currently trying to develop an application in Python to automate some measurements on Keithley 2636, I'm using PyVISA to communicate to my instrument via GPIB. I already have some GUI and data treatment features made, but I'm with some critical problems with the communication.
 Actually, it's not the comunicattion itself, because I succeeded controlling my instrument via PyVISA, but the timing of the communication.
At first, I built a IV sweep code in python (logic in python), on which I update the Keithley as my code updates (I know this is probably not the most optimized way), it means that I send and capture the signal from my instrument point by point, everytime my code updates. It works, but with several limitations, mainly timing limitations, and there's the problem, I need updating times of about μs, and it looks like the program has an intrinsic execution time, that limits my updating speed on about 100 ms, obviously, the Python code will have an execution time by itself, but I don't think it's is the only problem here.
So, summarizing, i need to build a Python apllication to run automated and customizable measurements scripts with very high speeds. And I'm currently facing this problem that I described.
Some observations:
•    At the same time that I need high speed capabilities on my program, I also need it to be extremely customizable, because I need to configure some extremely specific measurement routines.
•    I think that it can be, maybe in part, Python speed limitation, since it is not the fastest language by far.</li> <li>I though about speed limitations of GPIB, but I don't think so.
•    I know that the Keithley 2636 has several tools that I can use, like buffers, FIFO, and internal memory. I tried using some of this, but have not succeeded, if someone thinks it can be a possible solution, please help me implementing these features correctly.
•    I thought that maybe I can run TSP scripts that are saved in the Keithley internal memory, I think it should be faster, but I don't think I can make highly customizable scripts this way. Only if there might have been a way to load the script at the time of execution to the internal memory, run all the measurements, and after it is finished, delete the script so as not to occupy the internal memory.
•    I preferably need to plot my data in real time, if possible.
•    I will not upload any Python code here at the moment, because I don't think it's important at this point.
 If anyone can help me with any suggestion I would be extremely grateful.
Sincerely,
Nickolas J.

Posted Sun, 02 Feb 2025 14:53:39 GMT by C, Andrea
A couple comments and a file attachment that may help.
Example 3 in the attachment has some Python snippets and TSP code.

Comment 1:  if your model is 2636 without any letter suffix after, it does not support the smuX.trigger.xxx commands.
Comment 2:  check the readings/sec rate supported by the model for various settings (datasheet has them).  1 usec reading rates are way too fast of an expectation.
Posted Sun, 02 Feb 2025 15:36:41 GMT by J., Nickolas
Hy Andrea, thanks for the reply.

Replying to your comments by topics:

Comment 1: I have two 2636 equipments that I need to implement the objective, 2636A and 2636B, are the programming of these two models the same thing? Or maybe there are some difference between them?

Comment 2: I actually know that 1 usec reading rates are way too fast for this equipment. I don't think that the equipment limitation is the biggest challenge for me, It looks like that my script in Python has an intrinsic execution time (running in my computer) that acts like a "bottleneck", limmiting my measure speed. I would like to know the most optimized way that I could build my software so I can make customizable scripts that run fast. With your vast experience, could you help me with any suggestion? Maybe running the scripts in the internal memory of the Keithley, I don't know. I also found this time spec in the datasheet (image attachment), It looks like it's the maximum time that the instrument needs to process the command and update the output, <1ms is still OK to me if I could make my software send the signals to update faster than that.

Thanks for the file attachment, I'm going to study this document.

Sincerely,
Nickolas J.
 
Posted Sun, 09 Feb 2025 15:31:55 GMT by C, Andrea
How goes the project with the 4 SMU channels?

You can treat the A and B versions the same from command set standpoint.
Are you putting them on TSP-LINK and connect PC to just one of them?

For fast performance in the source + measure actions, using trigger model is way to go.
But this means place the data into buffers.
Most typically, the data is available when the trigger model task completes.
Your script/collection of commands could just print the data or you can have PC send a printbuffer() command.
So the task shifts to coordination of the 2600x trigger model with the PC/Python.

With the script writing feature of TSP, you can bundle the trigger model definition commands in a function that is loaded into runtime memory.  You can define parameters so that the function is flexible.  Also make a run_it() function.  Then your Python code does not have to send a lot of characters for each time you run it.
Posted Fri, 14 Feb 2025 13:02:54 GMT by J., Nickolas
Hi, thanks for the reply.

Actually I don't have the two Keithley (2636A and 2636B) running in TSP-LINK, they run on different equipments and separated.
At the moment I have already done transfer (IV curves) codes to characterize transistors purely in Python, and I think there's one of the biggest problems, since I have built all the logic of the signal generation in Python and I'm sending the commands individually, I think there occurs some kind of "bottleneck" due to Python's limited velocity. I have even tried running the GUI section of the Python code and the signal generation/acquisition section on two different threads of the CPU to parallelize the processes and speed up the code, it worked, but not enough.
If I understood correctly, running scripts with trigger features and saving the data on buffers to acess only pos measure is the fastest way to run measurements on Keithley 2636X. I have some questions about it: doesn't the buffer has a limited capacity that I will most probably exceed running bigger measures in which I get a lot of points? And if you could explain me a little on how to use trigger features on Keithley and give some examples I would be extremely grateful, because I have never worked with triggers with Keithley and the datasheet contains a lot of information about it, which I think I could understand better with some "start-point" basics.
Anyway, thanks for the tips, I'm going to study about the topics you mentioned.
Below is a function I had made in python to run a sweep (if : Initial-Final). I know there's probably so many improvements to be done here, I didn't use any tool like trigger, just built all the logic in Python and update the output in real time, step by step.

    def single_if(self):
        global time1, time2, time3, time4
        keithley.write("smub.reset()")
        keithley.write("smub.source.func = smub.OUTPUT_DCVOLTS")
        keithley.write("smub.source.autorangei = smub.AUTORANGE_ON")
        keithley.write("smub.source.autorangev = smub.AUTORANGE_ON")
        keithley.write("smub.source.limiti = 400e-3")  # Set current compliance to 100 mA
        keithley.write("smub.measure.autorangei = smub.AUTORANGE_ON")
        keithley.write("smub.measure.autorangev = smub.AUTORANGE_ON")
        keithley.write(f"smub.source.levelv = {self.source_drain_voltage_transfer}")
        voltage_values = np.arange(self.initial_voltage, self.final_voltage + self.step, self.step)
        keithley.write("smua.source.output = smua.OUTPUT_ON")
        keithley.write("smub.source.output = smub.OUTPUT_ON")
        ids_values = np.zeros_like(voltage_values)
        igs_values = np.zeros_like(voltage_values)
        vds_values = np.zeros_like(voltage_values)
        vgs_values = np.zeros_like(voltage_values)
        time_values = np.zeros_like(voltage_values)
        all_ids, all_igs, all_vds, all_vgs, all_time = [], [], [], [], []
        # Perform the sweep for each mode
        for j in range(self.sweeps):
            # Sweep forward (increase voltage)
            for i, voltage in enumerate(voltage_values):
                time1 = time.perf_counter()
                time3 = time.perf_counter()
                keithley.write(f"smua.source.levelv = {voltage}")
                self.Keithley_get()
                ids_values[i] = self.ids  # Update current value
                igs_values[i] = self.igs  # Update current value
                vds_values[i] = self.vds  # Update current value
                vgs_values[i] = self.vgs # Update current value
                time_values[i] = time.time()
                all_ids.append(self.ids)
                all_igs.append(self.igs)
                all_vds.append(self.vds)
                all_vgs.append(self.vgs)
                all_time.append(time.time())
                self.update_signal.emit(all_ids, all_igs, all_vds, all_vgs, all_time)
               
                QApplication.processEvents()
                time2 = time.perf_counter()
                time4 = time.perf_counter()
               
                self.delay1()
               
        # Turn off the output
        keithley.write("smua.source.output = smua.OUTPUT_OFF")
        keithley.write("smub.source.output = smub.OUTPUT_OFF")

Sincerely,
Nickolas J.
 

You must be signed in to post in this forum.