[Python] [SCPI DMM] High Frequency Data Acquisition on the Keysight 34420A - Page 1
Forum section: electronics / projects

author: potato24
author_rank: Newbie
timestamp: March 13, 2024, 07:55:52 pm
content: I have a Keysight/Agilent 34420A 7.5 Digit Nano Volt/Micro Ohm Meter. I am using this for continuous resistance measurements on a system. I need a high sample rate to detect changes in the system in real-timeThis is quite similar to what is done here:https://www.eevblog.com/forum/projects/(python)-flexible-data-acquisition-on-the-keysight-34465a/msg4898915/#msg4898915The Digital Multi Meter (DMM) is able to get very fast data points, down to 0.3 ms per sample (3000 Hz). I only need 100 Hz as a sample rate. I am able to achieve an average of about 60 Hz sample rate, with some points being much slower (~30 Hz) and some points being faster with the following code:Code:import pyvisa as visaimport timeimport csvfrom datetime import datetime# Connect instrumentrm = visa.ResourceManager()inst= rm.open_resource('GPIB0::22::INSTR') # Open instrument over USB - connected to GPIB of instrumentprint(inst.query("*IDN?")) # Should return the meter's identification string: "HEWLETT-PACKARD, 34420A, 0,X.X-X.X-X.X"# Setup instrumentinst.write("SENSe:FUNCtion \"FRESistance\"") # Set the instrument to the 4-wire resistance mode - FRES = Four resistance modeinst.write("INPut:FILTer:STATe OFF") # Turn off the instrument filter - This filter is a moving averageinst.write("SENSe:FRESistance:NPLC 0.2") # Set the integration time to 0.2 power cycles -- If 60 Hz current, 0.2*(1/60)s = 3.3 ms or 300 readings/sinst.write("SENSe:FRESistance:RANGE:AUTO OFF") # Turn off the AUTO range mode for 4-wire resistance - Will run faster -inst.write("SENSe:FRESistance:RANGE 100") # Set the 4-wire resistance range to 100 ohminst.write("SENSe:FRESistance:OCOMpensated OFF") # Turn off the offset compensation for the 4-wire resistance modeinst.write("SENSe:FRESistance:POWer:LIMit OFF ") # Turn off the lower power limit modeinst.write("SENSe:FRESistance:NULL OFF") # Turn off the null function (reading = measurement - null)inst.write("DISPlay OFF") # Turn off the instrument display - Will run faster# Setting the Trigger settingsinst.write("TRIGger:DELay:AUTO OFF") # Turn off the auto trigger delay - Will run fasterinst.write("TRIGger:DELay 0") # Set the trigger delay to 0 ms - Will get another reading instantly after completing the readinginst.write("TRIGger:COUNt 1") # Get infinite 1 data point when triggeredinst.write("TRIGger:SOURce IMMediate") # Set the instrument in the wait for trigger state, and trigger immediately with any command# Start recording# Writing to a filewith open("Resistance_Data_"+start_time.strftime("%Y-%m-%d_%H-%M-%S")+".csv", "w", newline="") as file:csv_writer = csv.writer(file, dialect="excel") # Create a csv writer for the filecsv_writer.writerow(["Resistance ","Time "])print("recording starting")while not flag: # Flag used to stop the recording in another threadcsv_writer.writerow([float(inst.query("READ?")),datetime.now()]) #Perform reads as fast as possible# The READ? query tells the isntrument to get 1 reading and return it. Loops when done.# This happens at a variable speed.print("recording stopped")# Recording is now done, set the instrument into a more normal mode and close the connectioninst.write("DISPlay ON") # Turn off the instrument display - Will run fasterinst.write("SENSe:FRESistance:NPLC 10") # Reset the number of power cycles per integrationinst.write("SENSe:FRESistance:RANGE:AUTO ON")inst.close()Things to note about the code:Each point only needs 1/300 seconds to be measuredThe code gets 1 data point per "READ?" querySince the setup time of the instrument is slower than the sampling rate (Configuration Rates = 26/s to 50/s vs Measurement rate of 300/s), the actual measurement rate is slowerThe setup time being non-constant or variable, which is effectively the time per measurement, basically breaks the possibility of doing fast fourrier transform (FFT) (which requires a constant time interval for each point).I am trying to modify the code to "TRIGger:COUNt INFinity" instead of "TRIGger:COUNT 1" so that it will continuously get data at the desired sample rate, and store it to memory. The issue is that the memory fills up really fast (Internal memory limited to 1024 readings). I am looking to modify the code in the following way, but I can't get it to work. My thoughts: roughly every second, when 300 points are stored in memory, query those and then the limited internal memory doesn't roll over and write over itself.Main changes:"TRIGger:COUNt INFinity" instead of "TRIGger:COUNT 1"Triggering with "INITiate" firstUsing "READ?" every so often to get the data dumped backCode:import pyvisa as visaimport timeimport csvfrom datetime import datetime# Connect instrumentrm = visa.ResourceManager()inst= rm.open_resource('GPIB0::22::INSTR') # Open instrument over USB - connected to GPIB of instrumentprint(inst.query("*IDN?")) # Should return the meter's identification string: "HEWLETT-PACKARD, 34420A, 0,X.X-X.X-X.X"# Setup instrumentinst.write("SENSe:FUNCtion \"FRESistance\"") # Set the instrument to the 4-wire resistance mode - FRES = Four resistance modeinst.write("INPut:FILTer:STATe OFF") # Turn off the instrument filter - This filter is a moving averageinst.write("SENSe:FRESistance:NPLC 0.2") # Set the integration time to 0.2 power cycles -- If 60 Hz current, 0.2*(1/60)s = 3.3 ms or 300 readings/sinst.write("SENSe:FRESistance:RANGE:AUTO OFF") # Turn off the AUTO range mode for 4-wire resistance - Will run faster -inst.write("SENSe:FRESistance:RANGE 100") # Set the 4-wire resistance range to 100 ohminst.write("SENSe:FRESistance:OCOMpensated OFF") # Turn off the offset compensation for the 4-wire resistance modeinst.write("SENSe:FRESistance:POWer:LIMit OFF ") # Turn off the lower power limit modeinst.write("SENSe:FRESistance:NULL OFF") # Turn off the null function (reading = measurement - null)inst.write("DISPlay OFF") # Turn off the instrument display - Will run faster# Setting the Trigger settingsinst.write("TRIGger:DELay:AUTO OFF") # Turn off the auto trigger delay - Will run fasterinst.write("TRIGger:DELay 0") # Set the trigger delay to 0 ms - Will get another reading instantly after completing the readinginst.write("TRIGger:COUNt INFinity") # Get infinite data until stoppedinst.write("TRIGger:SOURce IMMediate") # Set the instrument in the wait for trigger state, and trigger immediately with any command# Start recording# Writing to a filewith open("Resistance_Data_"+start_time.strftime("%Y-%m-%d_%H-%M-%S")+".csv", "w", newline="") as file:csv_writer = csv.writer(file, dialect="excel") # Create a csv writer for the filecsv_writer.writerow(["Resistance "])print("recording starting")inst.write("INITiate") # Trigger the instrument to start recording.while not flag: # Flag used to stop the recording in another threadtime.sleep(1) # wait 1 second to get the readings, and then readcsv_writer.writerow([float(inst.query("READ?"))])# I think this should dump all the values stored in the memory into the csv (I can format later)inst.write("DCL") # Device clear to stop the infinite loopingprint("recording stopped")# Recording is now done, set the instrument into a more normal mode and close the connectioninst.write("DISPlay ON") # Turn off the instrument display - Will run fasterinst.write("SENSe:FRESistance:NPLC 10") # Reset the number of power cycles per integrationinst.write("SENSe:FRESistance:RANGE:AUTO ON")inst.close()I can't get this to work. I get some error with the DMM when I "INITiate" and I also tried using "READ?" to start, but then I get a timeout error. I think I might also have an issue because I am not emptying the memory? I'm not really sure, and I was hoping to get some help.Some additional information from the user manual attached:Number of TriggersNormally, the meter will accept only one trigger before returning to the “idle”trigger state. You can, however, instruct the meter to accept multiple triggers.This feature is available only from the remote interface. If you set the trigger countand then go to local (front panel), the meter ignores the trigger count setting;when you return to remote, the trigger count returns to the value you selected.– The selected number of triggers is stored in volatile memory; the meter setsthe trigger count to 1 when power has been off or after a remote interfacereset or preset. The CONFigure and MEASure? commands automatically setthe trigger count to 1.– The number of triggers can be set to any number between 1 (MIN) and 50000(MAX) or can be set to be INFinity. When the trigger count is set to be infinite,use the READ? command to collect the readings. Send a device clear to stopthe measurements. See page 211 for information about device clear.TRIGger:COUNt {<value>|MIN|MAX|INFinity}Internal TriggeringIn the internal trigger mode (remote interface only), thetrigger signal is always present. When you place the meter in the wait-for-triggerstate, the trigger is issued immediately. This is the power-on trigger source forremote interface operation.To select the internal trigger source, send the following command. TheCONFigure and MEASure? commands automatically set the trigger source toIMMediate.TRIGger:SOURce IMMediateAfter setting the source to IMMediate, an INITitate or a READ? command willtrigger the measurement.Thanks in advance.

author: BennoG
author_rank: Frequent Contributor
timestamp: March 13, 2024, 08:49:57 pm
content: Why not let the meter running in free running mode and only request the latest measurement as fast as you can ?Benno

author: potato24
author_rank: Newbie
timestamp: March 14, 2024, 03:23:09 pm
content: From my understanding, I thought that is what my code is doing in the first bit of code. But there seems to be an autotriggering mode, which triggers (measures) as fast as possible for the current configuration.I'm just not sure if I can get autotriggering to work with a remote connection: "You must specify the source from which the meter will accept a trigger. – The trigger source is stored in volatile memory; the source is set to autotrigger (front panel) or immediate (remote interface) when power has been off or after a remote interface reset. Autotriggering In the autotrigger mode (front panel only), the meter continuously takes readings at the fastest rate possible for the present configuration. This is the power-on trigger source for front-panel operation."The notes on immediate triggering (which is what I currently have written into the code): "Internal Triggering In the internal trigger mode (remote interface only), the trigger signal is always present. When you place the meter in the wait-for-trigger state, the trigger is issued immediately. This is the power-on trigger source for remote interface operation. To select the internal trigger source, send the following command. The CONFigure and MEASure? commands automatically set the trigger source to IMMediate.TRIGger:SOURce IMMediateAfter setting the source to IMMediate, an INITitate or a READ? command will trigger the measurement."I also read that: "When using the READ? function Readings are not stored in the meter’s internal memory." Which may be one of the reasons I am having issues.I'll try using the FETCH? command maybe: "Use the FETCh? command to transfer the readings from the meter’s internal memory to the meter’s output buffer where you can read them into your bus controller. The INIT and FETCh? commands use the meter’s memory."

author: Kleinstein
author_rank: Super Contributor
timestamp: March 14, 2024, 06:06:12 pm
content: A 100 Hz sampling rate is a bit odd, as this is just a little faster than 1 PLC ( 60Hz in Canada) and would be quite sensitive to mains hum. If 60 SPS is still fast enough this would make things a lot lower noise / interference. If not, one could get better result from considerably faster (e.g. 500 SPS) readings and than externally subtracting the 60 Hz mains hum. This would however need a really stable reading rate.The HP34420 linke the 34401 is not really that suitable for fast readings. The ADC is far from 7 digits, maybe not even 5 digits at higher speed. So unless you really need the low noise (but without AZ mode not necessary low dift) for really low votlages the HP34420 may not be the best choice.

author: potato24
author_rank: Newbie
timestamp: March 19, 2024, 06:30:45 pm
content: The 100 Hz minimum is specifically because the physical phenomena trying to be observed will affect the measurement at a frequency between 2-50 Hz. So as per the Nyquist theorum, I'm trying to get 2x50 as a minimum sampling rate. There isn't an issue to go faster though.You bring up a good point with the power. I am eventually looking to also change my recording methods to set up the resistance measurement to be real-time with a pressure sensor. Currently I have pressure transducers like these (4-20 mA with fast response time <1 ms:https://canada.newark.com/omega/px309-005a5v/pressure-sensor-analogue-5psi/dp/30AC8106). I don't know how I will set up the recording of resistance and pressure to be done at the same time. I was considering a DAQ like ahttps://labjack.com/but these only seem to do voltage measurements, and the pressure transducer does current signal. I'm also not sure how to integrate a 4-point resistivity measurement in recording system in this way.