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-time
This 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:
import pyvisa as visa
import time
import csv
from datetime import datetime
# Connect instrument
rm = visa.ResourceManager()
inst= rm.open_resource('GPIB0::22::INSTR') # Open instrument over USB - connected to GPIB of instrument
print(inst.query("*IDN?")) # Should return the meter's identification string: "HEWLETT-PACKARD, 34420A, 0,X.X-X.X-X.X"
# Setup instrument
inst.write("SENSe:FUNCtion \"FRESistance\"") # Set the instrument to the 4-wire resistance mode - FRES = Four resistance mode
inst.write("INPut:FILTer:STATe OFF") # Turn off the instrument filter - This filter is a moving average
inst.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/s
inst.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 ohm
inst.write("SENSe:FRESistance:OCOMpensated OFF") # Turn off the offset compensation for the 4-wire resistance mode
inst.write("SENSe:FRESistance:POWer:LIMit OFF ") # Turn off the lower power limit mode
inst.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 settings
inst.write("TRIGger:DELay:AUTO OFF") # Turn off the auto trigger delay - Will run faster
inst.write("TRIGger:DELay 0") # Set the trigger delay to 0 ms - Will get another reading instantly after completing the reading
inst.write("TRIGger:COUNt 1") # Get infinite 1 data point when triggered
inst.write("TRIGger:SOURce IMMediate") # Set the instrument in the wait for trigger state, and trigger immediately with any command
# Start recording
# Writing to a file
with 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 file
csv_writer.writerow(["Resistance [ohm]","Time [datetime]"])
print("recording starting")
while not flag: # Flag used to stop the recording in another thread
csv_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 connection
inst.write("DISPlay ON") # Turn off the instrument display - Will run faster
inst.write("SENSe:FRESistance:NPLC 10") # Reset the number of power cycles per integration
inst.write("SENSe:FRESistance:RANGE:AUTO ON")
inst.close()
Things to note about the code:
- Each point only needs 1/300 seconds to be measured
- The code gets 1 data point per "READ?" query
- Since 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 slower
- The 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" first
- Using "READ?" every so often to get the data dumped back
import pyvisa as visa
import time
import csv
from datetime import datetime
# Connect instrument
rm = visa.ResourceManager()
inst= rm.open_resource('GPIB0::22::INSTR') # Open instrument over USB - connected to GPIB of instrument
print(inst.query("*IDN?")) # Should return the meter's identification string: "HEWLETT-PACKARD, 34420A, 0,X.X-X.X-X.X"
# Setup instrument
inst.write("SENSe:FUNCtion \"FRESistance\"") # Set the instrument to the 4-wire resistance mode - FRES = Four resistance mode
inst.write("INPut:FILTer:STATe OFF") # Turn off the instrument filter - This filter is a moving average
inst.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/s
inst.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 ohm
inst.write("SENSe:FRESistance:OCOMpensated OFF") # Turn off the offset compensation for the 4-wire resistance mode
inst.write("SENSe:FRESistance:POWer:LIMit OFF ") # Turn off the lower power limit mode
inst.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 settings
inst.write("TRIGger:DELay:AUTO OFF") # Turn off the auto trigger delay - Will run faster
inst.write("TRIGger:DELay 0") # Set the trigger delay to 0 ms - Will get another reading instantly after completing the reading
inst.write("TRIGger:COUNt INFinity") # Get infinite data until stopped
inst.write("TRIGger:SOURce IMMediate") # Set the instrument in the wait for trigger state, and trigger immediately with any command
# Start recording
# Writing to a file
with 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 file
csv_writer.writerow(["Resistance [ohm]"])
print("recording starting")
inst.write("INITiate") # Trigger the instrument to start recording.
while not flag: # Flag used to stop the recording in another thread
time.sleep(1) # wait 1 second to get the readings, and then read
csv_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 looping
print("recording stopped")
# Recording is now done, set the instrument into a more normal mode and close the connection
inst.write("DISPlay ON") # Turn off the instrument display - Will run faster
inst.write("SENSe:FRESistance:NPLC 10") # Reset the number of power cycles per integration
inst.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 count
and 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 sets
the trigger count to 1 when power has been off or after a remote interface
reset or preset. The CONFigure and MEASure? commands automatically set
the 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 stop
the measurements. See page 211 for information about device clear.
TRIGger:COUNt {<value>|MIN|MAX|INFinity}
Internal TriggeringIn 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 IMMediate
After setting the source to IMMediate, an INITitate or a READ? command will
trigger the measurement.
Thanks in advance.