文章目录
- 前言
- 一、软硬件准备
- 二、使用步骤
- 1.引入库
- 2.连接仪器、配置使用代码
- 总结
前言
本文主要介绍逆变器测试常用仪器恒河功率计的基于pyvisa控制使用。
一、软硬件准备
开始前,计算机安装python开发环境,如Anaconda、VS code。
使用pip 指令安装pyvisa 库。
到横河功率计官网下载安装USB驱动,
二、使用步骤
1.引入库
代码如下(示例):
import pyvisa as visa
import time
2.连接仪器、配置使用代码
代码如下(示例):
# -*- coding: utf-8 -*-
"""
Created on Wed Jun 16 14:02:18 2021
@author: USER
"""
import pyvisa as visa
import time
def Error_Record(e):
with open(r'D:\ATE\Error_Record.txt','r+') as f:
old = f.read() # 先读取内容保存一份
f.seek(0) # 将光标定位到起始位置
f.writelines(time.strftime('%Y.%m.%d %H:%M:%S', time.localtime(time.time()))+'\n')
f.writelines('Error occured in: ' + str(e)+'\n')
f.writelines("\n*******************\n")
f.write(old)
f.close()
class WT():
name="YOKOGAWA,WT"
chan="element1,element2,element3,element4,element5,element6"
answer="" #存储最近发指令,仪器回复的结果
Reconnect_Resource=0
Save_Stop=False
Function1={
"Urms":"Urms",
"Irms":"Irms",
"Udc":"Udc",
"Idc":"Idc",
"Uac":"Uac",
"Iac":"Iac",
"P":"P",
"S":"S",
"Q":"Q",
"PF":"Lambda",
"FreqU":"FU",
"FreqI":"FI",
"Ithd":"Ithd",
"Uthd":"Uthd",
"U(k)":"Uk",
"I(k)":"Ik",
"Uhdf(k)":"Uhdfk",
"Ihdf(k)":"Ihdfk",
"Q(k)":"Qk",
"P(k)":"Pk",
"S(k)":"Sk",
"PF(k)":"Lambdak",
}
Function2={
"η1":"ETA1",
"η2":"ETA2",
"η3":"ETA3",
"η4":"ETA4",
"η5":"ETA5",
"η6":"ETA6",
"F1":"F1",
"F2":"F2",
"F3":"F3",
"F4":"F4",
"F5":"F5",
"F6":"F6",
"F7":"F7",
"F8":"F8",
"F9":"F9",
"F10":"F10",
"F11":"F11",
"F12":"F12",
"F13":"F13",
"F14":"F14",
"F15":"F15",
"F16":"F16",
"F17":"F17",
"F18":"F18",
"F19":"F19",
"F20":"F20"
}
SaveItem=[]
SavePath=r"D:\ATE\Testdata"
SaveUpdate=200 #200ms更新速率,注意单位
SaveLine=100000
Thread_Stop=True
PA=0
Save_Name=""
def __init__(self):
rm = visa.ResourceManager('C:/Windows/System32/visa64.dll')
if len(rm.list_resources())>0:
for item in rm.list_resources():
A = rm.open_resource(item)
try:
self.answer=A.query('*IDN?')
except Exception as e:
error="函数WT_init:"
if self.answer.find(self.name)!=-1:
print("横河功率计连接成功: ",self.answer)
A.write(":communicate:remote on") #设定远程控制,防止手动操作影响
A.write(":communicate:header 0") #设定回复不包括字头
A.write(":numeric:format ASCII") #设定查询回复数据类型为ASCII
self.PA=A
self.Reconnect_Resource=item
if self.answer.find("WT5000")!=-1:
A.write(":scaling:STAte:all 1")
A.write(":scaling:ct:all 1000") #设定查询回复数据类型为ASCII
break
else:
A.close()
def Reconnection(self):
self.PA.close()
rm = visa.ResourceManager('C:/Windows/System32/visa64.dll')
if len(rm.list_resources())>0:
for item in rm.list_resources():
if item == self.Reconnect_Resource:
A = rm.open_resource(item)
try:
self.answer=A.query('*IDN?')
except Exception as e:
error="函数WT_init:"
if self.answer.find(self.name)!=-1:
print("横河功率计重接成功: ",self.answer)
self.PA=A
break
else:
A.close()
def WT_Close(self):
self.PA.write(":communicate:remote oFF\n")
time.sleep(2)
self.answer=self.PA.query(":communicate:remote?")
if self.answer.lower().find("0") != -1:
return True
else:
return False
def WT_Range(self,Channel="all",Auto="",Type="Voltage",Range="",crest_factor=3):
'''
Parameters
----------
Channel : string. 通道选择,全部选"all",其它输入"element1/element2/element3.../element6"
DESCRIPTION. The default is "all".
Type : string, Voltage/Current,电压电流选择
Range : string, 量程设置,crest_factor=3时,
对于电流,可选档为1A,2A,5A,10A,20A,50A
对于电压,可选档为1.5V,3V,6V,10V,15V,30V,60V,100V,150V,300V,600V,1000V
crest_factor=6时,
对于电压,可选档为?
对于电流,可选档为?
Auto : string, 自动量程开关,"1" 意为 auto range on, "0" 意为 auto range off.
crest_factor : int, 3/6。预留参数,暂不支持修改
Returns
-------
bool
True,设置成功;False,设置失败
回复值,请读取参数self.answer
'''
for Rei in range(0,5):
try:
if Auto=="0" or Auto=="1":
command=":input:"+ Type +":auto:"+Channel+' '+Auto
self.PA.write(command)
command=":input:"+ Type +":auto?"
self.answer=self.PA.query(command).replace("\n","")
if Channel=="all":
if self.answer.count(" 1")!=6:
return False
return True
elif self.chan.find(Channel.lower()) !=-1:
if self.answer.split(";")[int(Channel.replace("element",""))-1].find(" 1")!=-1 :
return True
else:
print(self.answer)
return False
else:
return False
elif Range!="":
a=float(Range.replace("A","" ).replace("V", ""))
command=":input:"+ Type +":range:"+Channel+' '+Range
self.PA.write(command)
command=":input:"+ Type +":range?"
self.answer=self.PA.query(command).replace("\n","")
if Channel=="all":
for item in self.answer.split(";"):
if float(item) != a:
return False
return True
elif Channel=="element1" or Channel=="element2" or Channel=="element3" or Channel=="element4" or Channel=="element5" or Channel=="element6" :
if float(self.answer.split(";")[int(Channel.replace("element",""))-1])==a:
return True
else:
return False
else:
return False
else :
return None
except Exception as e:
self.Reconnection()
error="函数WT_Range:"
Error_Record(error+str(e))
return False
def WT_Filter(self,Channel="all",Type="freq",Range="",ON_OFF=""):
for Rei in range(0,5):
result=True
try:
if ON_OFF.upper()=="OFF" or ON_OFF.upper()=="ON" :
command=":input:filter:"+Type+":"+Channel+" "+ON_OFF
self.PA.write(command)
if self.chan.find(Channel.lower())!=-1:
command=":input:filter:"+Type+":"+Channel+"?"
self.answer=self.PA.query(command)
if ON_OFF.upper()=="OFF" and self.answer.find(ON_OFF.upper())==-1 :
result= False
elif ON_OFF.upper()=="ON" and self.answer.find("OFF")!=-1:
result= False
elif Channel.lower()=="all" :
command=":input:filter:"+Type+"?"
self.answer=self.PA.query(command)
if ON_OFF.upper()=="OFF" and self.answer.count("OFF")==6 :
pass
elif ON_OFF.upper()=="ON" and self.answer.count("OFF")==0:
pass
else:
result=False
if Range!="":
command=":input:filter:"+Type+":"+Channel+" "+Range
self.PA.write(command)
command=":input:filter:"+Type+":"+Channel+"?"
self.answer=self.PA.query(command)
return result
except Exception as e:
self.Reconnection()
error="函数WT_Filter:"
Error_Record(error+str(e))
return False
def WT_Update(self,t="200ms"):
'''
更新率设置
Parameters
----------
t : TYPE, optional
DESCRIPTION. The default is "200ms".
可选值,T=['50ms','100ms','200ms','500ms','1s','2s','5s','10s','20s',
'0.05s','0.1s','0.2s','0.5s','1000ms','2000ms','5000ms','10000ms','20000ms',
]
Returns
-------
bool
DESCRIPTION.
'''
for Rei in range(0,5):
try:
T=['50ms','100ms','200ms','500ms','1s','2s','5s','10s','20s',
'0.05s','0.1s','0.2s','0.5s','1000ms','2000ms','5000ms','10000ms','20000ms',
]
t=t.lower()
if t in T :
command=":Rate " + t
self.PA.write(command)
command=":Rate?"
self.answer=self.PA.query(command).replace("\n","")
re= float(self.answer.replace(":RATE ",""))
if t.find('ms') != -1 or t.find('MS') != -1:
t=float(t.replace("ms", "").replace("MS", ""))/1000
else:
t=float(t.replace("S", "").replace("s", ""))
if t==re:
return True
else:
return False
else:
return False
except Exception as e:
self.Reconnection()
error="函数WT_Update:"
Error_Record(error+str(e))
return False
def WT_Wiring(self,wiring="P1W2,P1W2,P1W2,P3W4"):
'''
接线设置
Parameters
----------
wiring : string, 常用值:"P1W2,P1W2,P1W2,P1W2,P1W2,P1W2","P1W2,P1W2,P1W2,P3W4"
DESCRIPTION. The default is "P1W2,P1W2,P1W2,P3W4".
Returns
-------
bool
DESCRIPTION.
'''
for Rei in range(0,5):
try:
command = ":input:wiring?"
re=self.PA.query(command).replace(":WIR ","").replace("\n","")
if re==wiring.upper():
return True
command = ":input:wiring "+wiring
self.PA.write(command)
command = ":input:wiring?"
re=self.PA.query(command).replace(":WIR ","").replace("\n","")
if re==wiring.upper():
return True
else:
return False
except Exception as e:
self.Reconnection()
error="函数WT_Wiring:"
Error_Record(error+str(e))
return False
def WT_Averaging(self,Counter=2,Type="EXP",State="OFF"):
'''
平均个数,平均类型,平均开关
Parameters
----------
counter : int,可选值2/4/8/16/32/64
DESCRIPTION. The default is "2".
Type : string,可选值EXP/Linear
DESCRIPTION. The default is "EXP".
State : string,可选值On/OFF
DESCRIPTION. The default is "OFF".
Returns
-------
bool
DESCRIPTION.
'''
for Rei in range(0,5):
try:
command=":measure:averaging:state "+State
l1=len(command)+2
l2=self.PA.write(command)
if l2!=l1 :
print(l1,l2)
return False
command=":measure:averaging:type "+Type
l1=len(command)+2
l2=self.PA.write(command)
if l2!=l1 :
print(l1,l2)
return False
command=":measure:averaging:count "+str(Counter)
l1=len(command)+2
l2=self.PA.write(command)
if l2!=l1 :
print(l1,l2)
return False
return True
except Exception as e:
self.Reconnection()
error="函数WT_Averaging:"
Error_Record(error+str(e))
return False
def WT_SYNC(self,Channel="all",Source="U6"):
'''
Parameters
----------
Channel : 设置对象,可选值 "all/element1/.../element6/SigmA/SigMB/sigmC"
DESCRIPTION. The default is "all".
Source : 同步源,可选值 I1~I6,U1~U6
DESCRIPTION. The default is "U6".
Returns
-------
bool
DESCRIPTION.
'''
for Rei in range(0,5):
try:
command=":input:sync:"+Channel+" "+Source
l1=len(command)+2
l2=self.PA.write(command)
if l2!=l1 :
print(l1,l2)
return False
return True
except Exception as e:
self.Reconnection()
error="函数WT_SYNC:"
Error_Record(error+str(e))
return False
def WT_UDF(self,Number,Expression,Name,Unit,ON_OFF=1):
'''
自定义参数功能,N
umber int,对应F1~F20的数字号,
Expression string,为表达式,
Unit string,为单位,
ON_OFF int,开关,1开0关
Returns
-------
bool
DESCRIPTION.
'''
for Rei in range(0,5):
try:
Expression='"'+Expression+'"'
Name='"'+Name+'"'
Unit='"'+Unit+'"'
command=":measure:Function"+str(Number)+":Expression "+Expression
self.PA.write(command)
command=":measure:Function"+str(Number)+":Expression?"
self.answer=self.PA.query(command)
if self.answer.find(Expression)==-1 :
return False
command=":measure:Function"+str(Number)+":Name "+Name
self.PA.write(command)
command=":measure:Function"+str(Number)+":Name?"
self.answer=self.PA.query(command)
if self.answer.find(Name)==-1 :
return False
command=":measure:Function"+str(Number)+":Unit "+Unit
self.PA.write(command)
command=":measure:Function"+str(Number)+":Unit?"
self.answer=self.PA.query(command)
if self.answer.find(Unit)==-1 :
return False
command=":measure:Function"+str(Number)+":Unit "+Unit
self.PA.write(command)
command=":measure:Function"+str(Number)+":Unit?"
self.answer=self.PA.query(command)
if self.answer.find(Unit)==-1 :
return False
command=":measure:Function"+str(Number)+' '+str(ON_OFF)
self.PA.write(command)
return True
except Exception as e:
self.Reconnection()
error="函数WT_UDF:"
Error_Record(error+str(e))
return False
def WT_Integrate(self,Status="",Mode="",T1=0,T2=0,T3=0):
'''
该函数有三个功能,但同时只能设置一个功能,优先级为status>mode>time
Parameters
----------
Status : string, 可选值为“start/reset/stop”,控制积分开始/停止/结束
Mode : 积分模式,只可设normal.
T1 : int,积分时间H值设置,
T2 : int,积分时间M值设置,
T3 : int,积分时间S值设置,
Returns
-------
bool
DESCRIPTION.
'''
for Rei in range(0,5):
try:
if Status.lower()=="start":
command=":integrate:start"
l1=len(command)+2
l2=self.PA.write(command)
if l1==l2:
return True
else:
return False
elif Status.lower()=="stop":
command=":integrate:stop"
l2=self.PA.write(command)
l1=len(command)+2
if l1==l2:
return True
else:
return False
elif Status.lower()=="reset":
command=":integrate:reset"
l2=self.PA.write(command)
l1=len(command)+2
if l1==l2:
return True
else:
return False
return True
elif Mode.lower()=="normal":
command=":integrate:mode normal"
l2=self.PA.write(command)
l1=len(command)+2
if l1==l2:
return True
else:
return False
return True
elif T1!=0 or T2!=0 or T3!=0:
command=":integrate:TMALL " + str(T1) + ',' + str(T2) + ',' + str(T3)
l2=self.PA.write(command)
l1=len(command)+2
if l1==l2:
return True
else:
return False
return True
else:
return False
except Exception as e:
self.Reconnection()
error="函数WT_Integrate:"
Error_Record(error+str(e))
return False
def WT_HarSet(self,PLL,Order):
'''
Parameters
----------
PLL : string, 可选值U1/U2/U3/U4/U5/U6
谐波同步源. The default is "".
Order : string, 输入形式"1,50"、"0,50"、"1,200".
测量谐波次数
Returns
-------
bool
DESCRIPTION.
'''
for Rei in range(0,5):
try:
if PLL!="":
command=":harmonics1:PLLSOURCE " + PLL
l1=len(command)+2
l2=self.PA.write(command)
if l1!=l2:
return False
if Order !="" :
command=":harmonics1:order " + Order
l1=len(command)+2
l2=self.PA.write(command)
if l1==l2:
return True
else:
return False
except Exception as e:
self.Reconnection()
error="函数WT_Harset:"
Error_Record(error+str(e))
return False
def WT_ItemValue(self,Item="",Channel="",Order=""):
for Rei in range(0,5):
try:
if Item.lower().find("(k)")==-1:
command=':numeric:normal:item1 '+self.Function1[Item]+','+Channel
elif Item.lower().find("(k)")!=-1:
command=':numeric:normal:item1 '+self.Function1[Item]+','+Channel+','+Order
l1=len(command)+2
l2=self.PA.write(command)
if l1!=l2:
return False
command=":numeric:normal:number 1"
l1=len(command)+2
l2=self.PA.write(command)
if l1!=l2:
return False
command=":numeric:normal:value?"
self.answer=self.PA.query(command).replace('\n','')
inittime=time.time()
while self.answer=="nan" or self.answer=="NAN" :
command=":numeric:normal:value?"
self.answer=self.PA.query(command).replace('\n','')
if time.time()-inittime>60:
break
return float(self.answer)
except Exception as e:
self.Reconnection()
error="函数WT_ItemValue:"+self.answer
Error_Record(error+str(e))
return False
def WT_SaveSetting(self,Element,Item,Item2,Order):
'''
Parameters
----------
Element : list,输入格式如[1,2,3]、[4,5,6]、[1,2,3,4,5,6].
保存通道选择。
Item : list, 输入格式如['Urms','Irms',...],
注意,该项输入的是与通道选择有关的
Item2 : list, 输入格式如['F1','η1','F2','η2',...],
注意,该项输入的是与通道选择无关的
Order : int,取值1~100,
记录谐波最大次数
Returns
-------
bool
DESCRIPTION.
'''
for Rei in range(0,5):
try:
command=[]
n_normal=0
item_normal=['Date','Time']
for item2 in Item:
if item2 in self.Function1 and item2.find('(k)')==-1:
for item1 in Element:
if item1>0 and item1 < 7 :
n_normal+=1
header=':numeric:normal:item'
command.append(header+str(n_normal)+' '+self.Function1[item2]+','+str(item1))
item_normal.append(item2+'-'+str(item1))
for item1 in Item2:
if item1 in self.Function2:
n_normal+=1
command.append(':numeric:normal:item'+str(n_normal)+' '+item1)
if item1.upper().find("F") !=-1:
mid1=item1[1:]
self.answer=self.PA.query(":measure:function"+mid1+":expression?").replace("\n","").replace('"','')
item_normal.append(self.answer)
else:
item_normal.append(item1)
else:
error="函数WT_SaveSetting:"
Error_Record("参数错误,既有信息无法找到此参数"+item2)
return False
for item2 in Item:
if item2 in self.Function1 and item2.find('(k)')!=-1:
for item1 in Element:
if item1>0 and item1 < 7 :
header=':numeric:normal:item'
for i in range(1,Order+1):
n_normal+=1
command.append(header+str(n_normal)+' '+self.Function1[item2]+','+str(item1)+','+str(i))
item_normal.append(item2+'-'+str(item1)+'-'+str(i))
self.SaveItem=item_normal
# self.PA.write(":numeric:normal:number "+str( n_normal))
# self.PA.write(":numeric:list:order "+str(Order))
command.append(":numeric:format ASCII")
command.append(":numeric:normal:number "+str( n_normal))
command.append(":numeric:list:order "+str(Order))
for item in command:
l1=len(item)+2
l2=self.PA.write(item)
if l1==l2:
continue
else:
return False
return True
except Exception as e:
self.Reconnection()
error="函数WT_SaveSetting:"
Error_Record(error+str(e))
return False
def WT_SaveFile(self,Time=60,Name=""):
try:
result=[]
result.append(','.join(self.SaveItem))
counter=int(Time * 60 / self.SaveUpdate *1000)+10
if counter > 1:
inittime=time.time()
for i in range(0,counter):
RX0=self.PA.query(":SYSTem:date?;:System:time?").replace("\n",'')
RX1=self.PA.query(":numeric:normal:value?")
RX=RX0+RX1
if i>0 :
result.append(RX.replace('\n','').replace('";"',',').replace('"',',').replace(',','',1))
if self.Save_Stop:
break
while time.time()-inittime < self.SaveUpdate/1000*(i+1):
pass
if Name=="" and self.Save_Name=="":
Name=time.strftime('%Y.%m.%d %H:%M:%S', time.localtime(time.time())).replace(':','.')
elif Name=="" and self.Save_Name!="":
Name=self.Save_Name
with open(self.SavePath+'\\'+Name+'.csv','w') as f:
for item in result:
f.writelines(item+'\n')
f.close()
except Exception as e:
error="函数WT_SaveFile:"
Error_Record(error+str(e))
return False
if __name__=="__main__" :
WT=WT()
if WT.answer.find("YOKOGAWA,WT")==-1 :
exit(0)
WT.WT_ItemValue(Item="Urms",Channel="2")
# Output_Channel=[4]
# WT.WT_Integrate(Status="reset")
# WT.WT_HarSet("U"+str(Output_Channel[0]), "1,1")
# WT.WT_Range(Channel='all',Auto='1',Type="Voltage")
# WT.WT_Range(Channel='all',Auto='1',Type="Current")
# WT.WT_Update()
# WT.SaveUpdate=200
# WT_SaveItem1=["Urms","Irms","P","S","Q","PF","Idc","FreqU"]
# WT_SaveItem2=["F1","F2","F3"]
# WT.SavePath=r"D:\ATE\Testdata\\"
# WT.WT_SaveSetting(Output_Channel, WT_SaveItem1, WT_SaveItem2, 1)
# time.sleep(0.1)
# WT.WT_SaveFile(Time=1,Name="4.4.2_Test_1")
总结
类WT的初始化函数,会自动检索查询横河功率计仪器,成功后会print 连接成功字样及ID。类的其它函数则是用来配置仪器、使用仪器。