This Python example performs a differential IMD measurement (input 1 and 2 and output 2 and 4), using two internal combiners (requires Option 471, 479, 481, or 489) and Option CB2 for the combiner on the second test port.
|
""" This example is done for PNAX-Pro for differential IMD (input 1 and 2 and output 2 and 4) using internal combiners (requires options 471 or 479 or 481 or 489) and CB2 for the combiner on the second test port.
"""
def Mbox(title, text, style): return ctypes.windll.user32.MessageBoxW(0, text, title, style) ## Styles: ## 0 : OK ## 1 : OK | Cancel ## 2 : Abort | Retry | Ignore ## 3 : Yes | No | Cancel ## 4 : Yes (6)| No (7) ## 5 : Retry | Cancel ## 6 : Cancel | Try Again | Continue
import numpy as np import pyvisa as visa from win32com.client import * import ctypes # An included library with Python install. import time import matplotlib.pyplot as plt import pyvisa
rm = pyvisa.ResourceManager() rm.list_resources() ressource_list = rm.list_resources() address = "SOCKET"
if address =="INSTR": PNA_X = rm.open_resource('TCPIP0::localhost::inst0::INSTR',write_termination='\n',read_termination='\n',timeout=20000) IDN_PNAX=PNA_X.query("*IDN?") print(IDN_PNAX)
if address =="SOCKET": PNA_X = rm.open_resource('TCPIP0::localhost::5025::SOCKET',write_termination='\n',read_termination='\n',timeout=20000) IDNPNA=PNA_X.query("*IDN?") print(IDNPNA)
PNA_X.write('OUTP OFF') ActiveChannel=1 channelOne=1
answePreset=Mbox('','Do a Preset?',1) if answePreset==1: PNA_X.write("SYST:FPR") PNA_X.write("*OPC")
Mbox('','Configuration of Diff IMD measurements ',0) InputPort_diffP1=1 InputPort_diffN1=2 InputPort_diffP2=3 InputPort_diffN2=4
# Define option groups based on your constraints mutually_exclusive_group = {"471", "479", "481", "489"} mandatory_option = "CB2"
# This part is just to check the options for the PNAX try: # Query instrument options opt_string = PNA_X.query("*OPT?").strip()
# Clean and convert the string into a Python set for efficient comparison installed_options = {opt.strip().replace('"', '') for opt in opt_string.split(',')}
# 1. Verify the mandatory CB2 option has_cb2 = mandatory_option in installed_options
# 2. Use set intersection to find which exclusive options are installed found_exclusive_options = mutually_exclusive_group.intersection(installed_options) has_exactly_one_exclusive = len(found_exclusive_options) == 1
# Display diagnostic results print("--- PNA-X Configuration Analysis ---") print(f"Detected options: {', '.join(installed_options)}") print(f"Mandatory option CB2: {'✅ Present' if has_cb2 else '❌ Missing'}") print(f"Exclusive options found: {list(found_exclusive_options)}")
# Final constraints validation if has_cb2 and has_exactly_one_exclusive: print(f"\n✅ VALID Configuration: CB2 is present and only option {list(found_exclusive_options)} is installed.") Mbox('',f'\n✅ VALID Configuration: CB2 is present and only option {list(found_exclusive_options)} is installed.',0)
else: print("\n❌ INVALID Configuration:") if not has_cb2: print(" - The mandatory option CB2 is missing.") Mbox('',f"\n❌ INVALID Configuration:"" - The mandatory option CB2 is missing.",0)
if len(found_exclusive_options) == 0: print(f" - No option from the group {list(mutually_exclusive_group)} was found (exactly one required).") Mbox('',f"\n❌ INVALID Configuration:"f" - No option from the group {list(mutually_exclusive_group)} was found (exactly one required).",0)
elif len(found_exclusive_options) > 1: print(f" - Conflict! Multiple exclusive options detected simultaneously: {list(found_exclusive_options)}")
except pyvisa.VisaIOError as e: print(f"VISA Communication Error: {e}")
#Create DIQ channel #Channel1 PNA_X.write("DISP:WIND ON") PNA_X.write("DISPlay:WINDow"+str(channelOne)+":TITLe:DATA 'RF frequency sweep DIFF IMD'") PNA_X.write("DISPlay:WINDow"+str(channelOne)+":TITLe:STATe 1")
PNA_X.write("CALC1:MEAS1:DEF 'IPwrF1:Differential I/Q'") #Create DIQ Trace PNA_X.write("DISP:WIND1 ON") #Create Window 1 on turn state on PNA_X.write("DISP:MEAS1:FEED 1") #Dislay the Trace 1 in window 1 PNA_X.write("CALC"+str(channelOne)+":PAR:MNUM 1,FAST") #Select trace 1 PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'PwrMainLoIn-','a{InputPort_diffP1}_F2'")#Create a new DIQ parameters with custom equation PNA_X.write("CALC"+str(channelOne)+":CUST:MOD 'PwrMainLoIn-'")# Modify the measurement 1 (Trace 1 ) with the new parameters PNA_X.write("SENSe"+str(channelOne)+":SWEep:MODE HOLD")# Put sweep to Hold
# Put all port to combiner mode PNA_X.write(f"SENS{channelOne}:PATH:CONF:ELEM 'Port1Bypass','combiner'") PNA_X.write(f"SENS{channelOne}:PATH:CONF:ELEM 'Port2Bypass','combiner'") PNA_X.write(f"SENS{channelOne}:PATH:CONF:ELEM 'Port3Bypass','combiner'") PNA_X.write(f"SENS{channelOne}:PATH:CONF:ELEM 'Port4Bypass','combiner'")
PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffP1}:POW:ATT:AUTO 0,'Port {InputPort_diffP1}';*OPC") # to avoid warning message phase control has disabled auto attenuation on controlled port
user_RFstartfreq=500e6 #First tone start freq user_RFstopfreq=2e9 #First tone stop freq user_RFdeltafreq=10e6 #Second tone will be First tone + delta frequency user_IFBW=1000
PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG1:STAR "+str(user_RFdeltafreq)) PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG1:STOP "+str(user_RFdeltafreq)) PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG1:IFBW "+str(user_IFBW))
PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG:ADD")# Add new segment PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG2:STAR "+str(user_RFstartfreq)) PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG2:STOP "+str(user_RFstopfreq)) PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG2:IFBW "+str(user_IFBW))
PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG:ADD") PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG3:COUP:STATe ON") PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG3:COUP:ID 2") PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG3:COUP:OFFS 1") PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG3:COUP:UCONvert 1")
PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG:ADD") #2f1-f2 PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG4:COUP:STATe ON") PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG4:COUP:ID 2") PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG4:COUP:OFFS 3") PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG4:COUP:UCONvert 0") PNA_X.write("SENSe"+str(channelOne)+":DIQ:FREQuency:RANGe4:COUPle:MULTiplier 2")
PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG:ADD") #2f2-f1 PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG5:COUP:STATe ON") PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG5:COUP:ID 3") PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG5:COUP:OFFS 2") PNA_X.write("SENS"+str(channelOne)+":DIQ:FREQ:RANG5:COUP:UCONvert 0") PNA_X.write("SENSe"+str(channelOne)+":DIQ:FREQuency:RANGe5:COUPle:MULTiplier 2")
#InputPort_diffP1=1 PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffP1}:POW:ATT:AUTO 0,'Port {InputPort_diffP1}';*OPC") # to avoid warning message phase control has disabled auto attenuation on controlled port PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffP1}:RANG 2,'Port {InputPort_diffP1}';*OPC") PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffP1}:STAT AUTO,'Port {InputPort_diffP1}';*OPC") PNA_X.write("SENS"+str(channelOne)+":DIQ:PORT"+str(InputPort_diffP1)+":PHASe:STARt 0;*OPC") PNA_X.write("SENS"+str(channelOne)+":DIQ:PORT"+str(InputPort_diffP1)+":PHASe:STOP 0;*OPC")
#InputPort_diffN1=2 PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffN1}:PHAS:REF 'Port {InputPort_diffP1}';*OPC") PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffN1}:POW:ATT:AUTO 0,'Port {InputPort_diffN1}';*OPC") # to avoid warning message phase control has disabled auto attenuation on controlled port PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffN1}:RANG 2,'Port {InputPort_diffN1}';*OPC") PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffN1}:STAT AUTO,'Port {InputPort_diffN1}';*OPC") PNA_X.write(f"SENS"+str(channelOne)+":DIQ:PORT"+str(InputPort_diffN1)+":PHASe:STARt 180;*OPC") PNA_X.write(f"SENS"+str(channelOne)+":DIQ:PORT"+str(InputPort_diffN1)+":PHASe:STOP 180;*OPC") PNA_X.write(f"SENS"+str(channelOne)+":DIQ:PORT"+str(InputPort_diffN1)+":PHAS:STAT CONT;*OPC") PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffN1}:PHAS:PAR 'a2/a1'")
#InputPort_diffP2=3 Port 1 Src3 PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffP2+2}:POW:ATT:AUTO 0,'Port 1 Src3';*OPC") # to avoid warning message phase control has disabled auto attenuation on controlled port PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffP2+2}:RANG 3, 'Port 1 Src3';*OPC") PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffP2+2}:STAT AUTO,'Port 1 Src3';*OPC") PNA_X.write("SENS"+str(channelOne)+":DIQ:PORT"+str(InputPort_diffP2+2)+":PHASe:STARt 0, 'Port 1 Src3';*OPC") PNA_X.write("SENS"+str(channelOne)+":DIQ:PORT"+str(InputPort_diffP2+2)+":PHASe:STOP 0, 'Port 1 Src3';*OPC")
#InputPort_diffN2=4 Port 2 Src4 PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffN2+2}:PHAS:REF 'Port 1 Src3','Port 2 Src4';*OPC") PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffN2+2}:POW:ATT:AUTO 0,'Port 2 Src4';*OPC") # to avoid warning message phase control has disabled auto attenuation on controlled port PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffN2+2}:RANG 3,'Port 2 Src4';*OPC") PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffN2+2}:STAT AUTO,'Port 2 Src4';*OPC") PNA_X.write(f"SENS"+str(channelOne)+":DIQ:PORT"+str(InputPort_diffN2+2)+":PHASe:STARt 180,'Port 2 Src4';*OPC") PNA_X.write(f"SENS"+str(channelOne)+":DIQ:PORT"+str(InputPort_diffN2+2)+":PHASe:STOP 180,'Port 2 Src4';*OPC") PNA_X.write(f"SENS"+str(channelOne)+":DIQ:PORT"+str(InputPort_diffN2+2)+":PHAS:STAT CONT,'Port 2 Src4';*OPC") PNA_X.write(f"SENS{channelOne}:DIQ:PORT{InputPort_diffN2+2}:PHAS:PAR 'a2/a1','Port 2 Src4';*OPC")
NextTr=2 PNA_X.write(f"CALC1:MEAS{NextTr}:DEF 'IPwrF1:Differential I/Q'") PNA_X.write(f"DISP:MEAS{NextTr}:FEED 1") PNA_X.write(f"CALC{channelOne}:PAR:MNUM {NextTr},FAST") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'PwrMainLoIn+','a{InputPort_diffN1}_F2'") PNA_X.write(f"CALC{channelOne}:CUST:MOD 'PwrMainLoIn+'") PNA_X.write(f"SENS{channelOne}:SWE:MODE HOLD")
NextTr=NextTr+1 PNA_X.write(f"CALC1:MEAS{NextTr}:DEF 'IPwrF1:Differential I/Q'") PNA_X.write(f"DISP:MEAS{NextTr}:FEED 1") PNA_X.write(f"CALC{channelOne}:PAR:MNUM {NextTr},FAST") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'PwrMainHiIn-','a{InputPort_diffP1}_F3'") PNA_X.write(f"CALC{channelOne}:CUST:MOD 'PwrMainHiIn-'") PNA_X.write(f"SENS{channelOne}:SWE:MODE HOLD")
NextTr=NextTr+1 PNA_X.write(f"CALC1:MEAS{NextTr}:DEF 'IPwrF1:Differential I/Q'") PNA_X.write(f"DISP:MEAS{NextTr}:FEED 1") PNA_X.write(f"CALC{channelOne}:PAR:MNUM {NextTr},FAST") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'PwrMainHiIn+','a{InputPort_diffN1}_F3'") PNA_X.write(f"CALC{channelOne}:CUST:MOD 'PwrMainHiIn+'") PNA_X.write(f"SENS{channelOne}:SWE:MODE HOLD")
PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'PwrMainLo','(b{InputPort_diffP2}_F2-b{InputPort_diffN2}_F2)/SQRT(2)'") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'PwrMainHi','(b{InputPort_diffP2}_F3-b{InputPort_diffN2}_F3)/SQRT(2)'")
PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'Pwr3Lo','(b{InputPort_diffP2}_F4-b{InputPort_diffN2}_F4)/SQRT(2)'") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'Pwr3Hi','(b{InputPort_diffP2}_F5-b{InputPort_diffN2}_F5)/SQRT(2)'")
NextTr=NextTr+1 PNA_X.write(f"CALC1:MEAS{NextTr}:DEF 'IPwrF1:Differential I/Q'") PNA_X.write(f"DISP:MEAS{NextTr}:FEED 1") PNA_X.write(f"CALC{channelOne}:PAR:MNUM {NextTr},FAST") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'IM3Lo','(b{InputPort_diffP2}_F4-b{InputPort_diffN2}_F4)/(b{InputPort_diffP2}_F2-b{InputPort_diffN2}_F2)'") PNA_X.write(f"CALC{channelOne}:CUST:MOD 'IM3Lo'") PNA_X.write(f"SENS{channelOne}:SWE:MODE HOLD")
NextTr=NextTr+1 PNA_X.write(f"CALC1:MEAS{NextTr}:DEF 'IPwrF1:Differential I/Q'") PNA_X.write(f"DISP:MEAS{NextTr}:FEED 1") PNA_X.write(f"CALC{channelOne}:PAR:MNUM {NextTr},FAST") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'IM3Hi','(b{InputPort_diffP2}_F5-b{InputPort_diffN2}_F5)/(b{InputPort_diffP2}_F3-b{InputPort_diffN2}_F3)'") PNA_X.write(f"CALC{channelOne}:CUST:MOD 'IM3Hi'") PNA_X.write(f"SENS{channelOne}:SWE:MODE HOLD")
NextTr=NextTr+1 PNA_X.write(f"CALC1:MEAS{NextTr}:DEF 'IPwrF1:Differential I/Q'") PNA_X.write(f"DISP:MEAS{NextTr}:FEED 1") PNA_X.write(f"CALC{channelOne}:PAR:MNUM {NextTr},FAST") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'IM3InLo','(a{InputPort_diffP1}_F4-a{InputPort_diffN1}_F4)/(a{InputPort_diffP1}_F2-a{InputPort_diffN1}_F2)'") PNA_X.write(f"CALC{channelOne}:CUST:MOD 'IM3InLo'") PNA_X.write(f"SENS{channelOne}:SWE:MODE HOLD")
NextTr=NextTr+1 PNA_X.write(f"CALC1:MEAS{NextTr}:DEF 'IPwrF1:Differential I/Q'") PNA_X.write(f"DISP:MEAS{NextTr}:FEED 1") PNA_X.write(f"CALC{channelOne}:PAR:MNUM {NextTr},FAST") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'IM3InHi','(a{InputPort_diffP1}_F5-a{InputPort_diffN1}_F5)/(a{InputPort_diffP1}_F4-a{InputPort_diffN1}_F4)'") PNA_X.write(f"CALC{channelOne}:CUST:MOD 'IM3InHi'") PNA_X.write(f"SENS{channelOne}:SWE:MODE HOLD")
PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'OIP3Lo','(b{InputPort_diffP2}_F2-b{InputPort_diffN2}_F2)/SQRT(2)*sqrt((b{InputPort_diffP2}_F2-b{InputPort_diffN2}_F2)/(b{InputPort_diffP2}_F4-b{InputPort_diffN2}_F4))'") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'OIP3Hi','(b{InputPort_diffP2}_F3-b{InputPort_diffN2}_F3)/SQRT(2)*sqrt((b{InputPort_diffP2}_F3-b{InputPort_diffN2}_F3)/(b{InputPort_diffP2}_F5-b{InputPort_diffN2}_F5))'")
PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'IIP3Lo','(a{InputPort_diffP1}_F2-a{InputPort_diffN1}_F2)/SQRT(2)*sqrt((b{InputPort_diffP2}_F2-b{InputPort_diffN2}_F2)/(b{InputPort_diffP2}_F4-b{InputPort_diffN2}_F4))'") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'IIP3Hi','(a{InputPort_diffP1}_F3-a{InputPort_diffN1}_F3)/SQRT(2)*sqrt((b{InputPort_diffP2}_F3-b{InputPort_diffN2}_F3)/(b{InputPort_diffP2}_F5-b{InputPort_diffN2}_F5))'")
PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'PwrMainLoIn','(a{InputPort_diffP1}_F2-a{InputPort_diffN1}_F2)/SQRT(2)'") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'PwrMainHiIn','(a{InputPort_diffP1}_F3-a{InputPort_diffN1}_F3)/SQRT(2)'")
PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'ToneGainLo','(b{InputPort_diffP2}_F2-b{InputPort_diffN2}_F2)/(a{InputPort_diffP1}_F2-a{InputPort_diffN1}_F2)'") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'ToneGainHi','(b{InputPort_diffP2}_F3-b{InputPort_diffN2}_F3)/(a{InputPort_diffP1}_F3-a{InputPort_diffN1}_F3)'")
PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'PwrMainLoBal','(b{InputPort_diffP2}_F2/b{InputPort_diffN2}_F2)'") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'PwrMainHiBal','(b{InputPort_diffP2}_F3/b{InputPort_diffN2}_F3)'")
PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'PwrMainLoBalIn','(a{InputPort_diffP1}_F2/a{InputPort_diffN1}_F2)'") PNA_X.write(f"SENS{channelOne}:DIQ:PAR:DEF 'PwrMainHiBalIn','(a{InputPort_diffP1}_F3/a{InputPort_diffN1}_F3)'")
PNA_X.write("sense"+str(channelOne)+":diq:parameter:delete 'IPwrF1'") PNA_X.write("sense"+str(channelOne)+":diq:parameter:delete 'OPwrF1'") PNA_X.write("sense"+str(channelOne)+":diq:parameter:delete 'GainF1'") Mbox('','Done with diff IMD config',0)
|