commit 43ca2adc5653391e637bac89412ddc6166faaba1 Author: Eggert Jung Date: Wed Jun 15 07:21:52 2022 +0200 initial commit diff --git a/kisli.py b/kisli.py new file mode 100644 index 0000000..4d8d020 --- /dev/null +++ b/kisli.py @@ -0,0 +1,226 @@ +""" ============================================================= +*** modified 2022 - four wire resistance mode +*** Institut f. Konstruktionsrechnik, Eggert Jung +============================================================= """ + + +""" ================================================================================ +*** Copyright 2019 Tektronix, Inc. *** +*** See www.tek.com/sample-license for licensing terms. *** +================================================================================ """ + +""" +==================================================================================================== + This example configures a series of channels within the 3706A mainframe for + DCV measurement scanning. Additionally, a log file is created on a USB drive + connected to the front port of the meter and writes the measurement information + after each scan. +==================================================================================================== +""" + +import socket +import struct +import math +import time + +echoCmd = 0 + +def instrConnect(mySocket, myAddress, myPort, timeOut, doReset, doIdQuery): + mySocket.connect((myAddress, myPort)) # input to connect must be a tuple + mySocket.settimeout(timeOut) + if doReset == 1: + instrSend(mySocket, "reset()") + if doIdQuery == 1: + tmpId = instrQuery(mySocket, "*IDN?", 100) + print(tmpId) + return mySocket + +def instrDisconnect(mySocket): + mySocket.close() + return + +def instrSend(mySocket, cmd): + if echoCmd == 1: + print(cmd) + cmd = "{0}\n".format(cmd) + mySocket.send(cmd.encode()) + return + +def instrQuery(mySocket, cmd, rcvSize): + instrSend(mySocket, cmd) + time.sleep(0.1) + return mySocket.recv(rcvSize).decode() + +def Write_Data(output_data_path, dataStr): + # This function writes the floating point data to the + # target file. + #for f in floats: + ofile = open(output_data_path, "a") # append the target data + dataStr = "{0}".format(dataStr) + ofile.write(dataStr) + + ofile.close() # Close the data file. + + return + +def Configure_4WO_Scan(s, scan_channels, scan_count): + instrSend(s, "reset()") + instrSend(s, "dmm.func = \"fourwireohms\"") + + instrSend(s, "dmm.autorange = dmm.OFF") + instrSend(s, "dmm.range = 100") + + instrSend(s, 'dmm.setconfig("slot1", "fourwireohms")') + + instrSend(s, "scan.create(\"{0}\")".format(scan_channels)) # Create the scan + instrSend(s, "scan.scancount = {0}".format(scan_count)) # Set the Scan Count + instrSend(s, "reading_buffer = dmm.makebuffer(scan.scancount * scan.stepcount)") # Configure Buffer + instrSend(s, "scan.background(reading_buffer)") # Execute Scan and save to buffer + return + + +def Configure_TWO_Scan(s, scan_channels, scan_count): + instrSend(s, "reset()") # Reset + instrSend(s, "dmm.func = dmm.TWO_WIRE_OHMS") # Set measurement function + instrSend(s, "dmm.nplc=1") # Set NPLC + + instrSend(s, "dmm.autorange = dmm.OFF") + instrSend(s, "dmm.range = 100") + + instrSend(s, "dmm.autodelay = dmm.ON") # Ensure Auto Delay is enabled + instrSend(s, "dmm.autozero = dmm.ON") # Enable Auto Zero + + instrSend(s, "dmm.configure.set(\"test\")") # Save Configuration + instrSend(s, "dmm.setconfig(\"{0}\",\"test\")".format(scan_channels)) # Assign configuration to channels + + instrSend(s, "channel.connectrule = channel.BREAK_BEFORE_MAKE") + + #if scan_interval > 0.1: + # # Establish the settings that will apply the interval between the start of scans + # instrSend(s, "trigger.timer[1].reset()") # Ensure the timer gets to a known relative time start point + # instrSend(s, "trigger.timer[1].count = 0") # No reapeating timer events + # instrSend(s, "trigger.timer[1].delay = {0}".format(scan_interval)) # Apply the anticipated scan interval + # instrSend(s, "trigger.timer[1].stimulus = scan.trigger.EVENT_MEASURE_COMP") # + # instrSend(s, "trigger.timer[1].passthrough = false") # Trigger only initiates the delay + # instrSend(s, "trigger.blender[1].reset()") # Configure the blender stimulus... + # instrSend(s, "trigger.blender[1].orenable = true") # ... for OR'ing operation + # instrSend(s, "trigger.blender[1].stimulus[1] = trigger.timer[1].EVENT_ID") # ... to respond/notify upon a timer event + # instrSend(s, "trigger.blender[1].stimulus[2] = scan.trigger.EVENT_SCAN_READY") # ... or when then scan is ready (configured) + # instrSend(s, "scan.trigger.arm.stimulus = trigger.blender[1].EVENT_ID") # Key triggering off of the blender event + + + instrSend(s, "scan.create(\"{0}\")".format(scan_channels)) # Create the scan + instrSend(s, "scan.scancount = {0}".format(scan_count)) # Set the Scan Count + instrSend(s, "reading_buffer = dmm.makebuffer(scan.scancount * scan.stepcount)") # Configure Buffer + instrSend(s, "scan.background(reading_buffer)") # Execute Scan and save to buffer + return + + +def Configure_DCV_Scan(s, scan_channels, dcv_range, use_input_divider, scan_count, scan_interval): + instrSend(s, "reset()") # Reset + instrSend(s, "dmm.func = dmm.DC_VOLTS") # Set measurement function + instrSend(s, "dmm.nplc=1") # Set NPLC + if dcv_range < 0.001: # Set Range + instrSend(s, "dmm.autorange = dmm.ON") + else: + instrSend(s, "dmm.autorange = dmm.OFF") + instrSend(s, "dmm.range = {0}".format(dcv_range)) + + instrSend(s, "dmm.autodelay = dmm.ON") # Ensure Auto Delay is enabled + instrSend(s, "dmm.autozero = dmm.ON") # Enable Auto Zero + if use_input_divider == 1: # Apply the 10M input divider as needed + instrSend(s, "dmm.inputdivider = dmm.ON") + else: + instrSend(s, "dmm.inputdivider = dmm.OFF") + + instrSend(s, "dmm.configure.set(\"mydcvolts\")") # Save Configuration + instrSend(s, "dmm.setconfig(\"{0}\",\"mydcvolts\")".format(scan_channels)) # Assign configuration to channels + + instrSend(s, "channel.connectrule = channel.BREAK_BEFORE_MAKE") + + if scan_interval > 0.1: + # Establish the settings that will apply the interval between the start of scans + instrSend(s, "trigger.timer[1].reset()") # Ensure the timer gets to a known relative time start point + instrSend(s, "trigger.timer[1].count = 0") # No reapeating timer events + instrSend(s, "trigger.timer[1].delay = {0}".format(scan_interval)) # Apply the anticipated scan interval + instrSend(s, "trigger.timer[1].stimulus = scan.trigger.EVENT_MEASURE_COMP") # + instrSend(s, "trigger.timer[1].passthrough = false") # Trigger only initiates the delay + instrSend(s, "trigger.blender[1].reset()") # Configure the blender stimulus... + instrSend(s, "trigger.blender[1].orenable = true") # ... for OR'ing operation + instrSend(s, "trigger.blender[1].stimulus[1] = trigger.timer[1].EVENT_ID") # ... to respond/notify upon a timer event + instrSend(s, "trigger.blender[1].stimulus[2] = scan.trigger.EVENT_SCAN_READY") # ... or when then scan is ready (configured) + instrSend(s, "scan.trigger.arm.stimulus = trigger.blender[1].EVENT_ID") # Key triggering off of the blender event + + + instrSend(s, "scan.create(\"{0}\")".format(scan_channels)) # Create the scan + instrSend(s, "scan.scancount = {0}".format(scan_count)) # Set the Scan Count + instrSend(s, "reading_buffer = dmm.makebuffer(scan.scancount * scan.stepcount)") # Configure Buffer + instrSend(s, "scan.background(reading_buffer)") # Execute Scan and save to buffer + return + +""" ============================================================================================================== + MAIN CODE STARTS HERE +============================================================================================================== """ +ip_address = "192.168.0.53" # Place your instrument's IP address here. +my_port = 5025 + +output_data_path = time.strftime("data_%Y-%m-%d_%H-%M-%S.csv") # This is the output file that is created which + # will hold your readings provided in ASCII + # format in a text file. + + +s = socket.socket() # Establish a TCP/IP socket object +# Open the socket connection +instrConnect(s, ip_address, my_port, 20000, 1, 1) + +t1 = time.time() # Start the timer... + +scanchannels = "1015" # Define the channels to scan here. Note the following format possibilities... + # 1001:10060 - All channels starting with 1001 and ending with 1060 + # 1001,1002,1004 - Just channels 1001, 1002, and 1004 + # 1007:1010,1021,1031:1040 - Channels 1007 through 1010, channel 1021, and channels 1031 through 1040 +rangedcv = 10 # Define the DCV range. If auto-ranging is desired, pass 0 +useinputdivider = 1 # 1 = True; 0 = False +scancount = 3 # Number of times to run the scan +scaninterval = 1 # Delay between the start of each scan (if needed) + +#Configure_DCV_Scan(s, scanchannels, rangedcv, useinputdivider, scancount, scaninterval) +#Configure_TWO_Scan(s, scanchannels, scancount) +Configure_4WO_Scan(s, scanchannels, scancount) + + +expectedCnt = 30 +channelcount = int(float(instrQuery(s, "print(scan.stepcount)", 64))) +startindex = 1 +endindex = channelcount +total_readings_count = 0 +target = channelcount * scancount +cntr = 1 + +# Extract readings while the scan is running.... +while(total_readings_count < target): + vals = int(float(instrQuery(s, "print(reading_buffer.n)", 16))) + + while(vals < endindex): + time.sleep(0.1) + vals = int(float(instrQuery(s, "print(reading_buffer.n)", 16))) + + data_string = instrQuery(s, "printbuffer({},{}, reading_buffer.readings)".format(startindex, endindex), 2048) + print("Scan {0:4} : {1}".format(cntr, data_string)) + Write_Data(output_data_path, data_string) + startindex += channelcount + endindex += channelcount + total_readings_count += channelcount + cntr += 1 + + +# Close the socket connection +instrDisconnect(s) +t2 = time.time() + +# Notify the user of completion and the data streaming rate achieved. +print("done") +print("Total Time Elapsed: {0:.3f} s".format(t2-t1)) + +input("Press Enter to continue...") +exit()