IoTで使うPython入門 Step5-Python3 VISA②DMM Keithley 2000 電圧測定(その1)

 VISAという規約を使って計測器と通信をします。前回、GPIB-USB変換器を利用してPCとつなぎました。ここでは、具体的に接続したDMMを使って電圧を測定します。

電圧の測定

 2台のDMMで同じ電圧源を測定します。電圧源はTL431を使った2.5V出力です。

import visa
from time import sleep

Keithley2000_1_Addr = "GPIB0::6"
Keithley2000_2_Addr = "GPIB0::18"

r = visa.ResourceManager()
keithley2000_1 = r.open_resource(Keithley2000_1_Addr)
keithley2000_2 = r.open_resource(Keithley2000_2_Addr)

keithley2000_1.write(":conf:VOLT:DC:range 10")
keithley2000_2.write(":conf:VOLT:DC:range 10")

while 1:
    data6 = keithley2000_1.query(":read?") 
    data18 = keithley2000_2.query(":read?") 
    sleep(1)
    print("6DC: ", float(data6))
    print("18DC: ", float(data18))

 実行している様子です。

6DC: 2.49226917
18DC: 2.4924012
6DC: 2.49227095
18DC: 2.49240339
6DC: 2.49227077
18DC: 2.49240394
6DC: 2.49226933
18DC: 2.49240256
6DC: 2.4922712
18DC: 2.49240278
6DC: 2.49227047
18DC: 2.49240329
6DC: 2.49226995
18DC: 2.49240302
6DC: 2.49226884
18DC: 2.49240154

まとめて計測

 100個のデータをロギングしてPCに読み込みます。動作しているDMMは1台だけです。このプログラムは、検索するといろいろなところで見かけます。

10行;*rstはリセット・コマンド、*clsはステータス・レジスタの消去

14行;インターバル時間を1msに設定。サンプルでは500msでした。
15行;測定データの読み取る数を100個に設定。サンプルでは10個でした。
16行;*sre 1はService request enableコマンドを1に設定。レジスタは1バイトで、ビットごとに定義され、6個あり、最上位ビットから、OSB = Operation Summary Bit、0、ESB = Event Summary Bit、MAV = Message Available、QSB = Questionable Summary Bit、EAV = Error Available、0、MSB = Measurement Summary Bitが定義されている。指定するときは、おもみ付けの数値を加算した合計を書く。全部のビットが'1'ならば512になる。
17行;トリガを10回
18行;「トリガ待ち」状態になると、リモート・インタフェース経由で*TRGにより測定器のトリガが実行される
19行;トリガ遅延時間
20行;合計10の読み取りをキャプチャするようにバッファのサイズを設定
21行;バッファがいっぱいになったときに充填を停止する。ここまでが設定の記述。
22行;設定内容に従って測定開始

23行;ソフトウェア・トリガをデバイスに送信
24行;待ち状態のサービス・リクエスト(SRQ)イベントが完了するのを待つ

import visa

Keithley2000_1_Addr = "GPIB0::6"
Keithley2000_2_Addr = "GPIB0::18"

r = visa.ResourceManager()
keithley2000_1 = r.open_resource(Keithley2000_1_Addr, timeout = 20)  # , values_format = single)
keithley2000_2 = r.open_resource(Keithley2000_2_Addr)

keithley2000_1.write("*rst; status:preset; *cls")
data6 = []
print('\n---start ---')
try:
    interval_in_ms = 1
    number_of_readings = 100
    keithley2000_1.write("status:measurement:enable 512; *sre 1")
    keithley2000_1.write("sample:count %d" % number_of_readings)
    keithley2000_1.write("trigger:source bus")
    keithley2000_1.write("trigger:delay %f" % (interval_in_ms / 1000.0))
    keithley2000_1.write("trace:points %d" % number_of_readings)
    keithley2000_1.write("trace:feed sense1; feed:control next")
    keithley2000_1.write("initiate")
    keithley2000_1.assert_trigger()
    keithley2000_1.wait_for_srq(timeout=None)

    data6 = keithley2000_1.query_ascii_values("trace:data?") 
    print("6DC : ", len(data6), data6)
except KeyboardInterrupt:
    print('CTRL-C')
    
print('\n -- end --')

 write、assert_trigger、query_ascii_valuesなどは、/pyvisa/resources/messagebased.pyに定義されています。しかし、writeで書かれている16行から22行の内容を解説した文書が見つかりません。したがって、SCPIコマンドの何が発行されているかが不明です。
 wait_for_srqは、/pyvisa/resources/gpib.py に定義されています。

得られたデータでグラフを描画

 得られた測定データを使って、最頻度グラフを描きます。上記のプログラムの先頭に、

import matplotlib.pyplot as plt

を記述し、次の2行を最後に追加しています。

plt.hist(data6, rwidth=0.8)
plt.show()

 実行結果です。

SCPIコマンドで書き直す

「Model 2000 Multimeter User’s Manual2000-900-01 Rev. J / August 2010」
 C Example Programsの事例

「DMM6500 in a Model 2000 Application Emulation and Migration Guide」
 Example 2 - Multi-point 2-wire resistance measurement with external
triggeringの事例

「Model DAQ6510 Data Acquisition nad Multimeter System User's Manual」
 Using SCPI commandsの事例

などを参考にして、まったく同じではないですが、SCPIコマンドを使うように書き直しました。データの取得は40までならエラーなく動きます。100個を取得するとき、sleep(5)を入れて待ちます。INITを送った後に、データが用意できたかを確認するプログラムを入れるのが確実です(次回予定)。

import visa
from time import sleep

Keithley2000_1_Addr = "GPIB0::6"
Keithley2000_2_Addr = "GPIB0::18"

r = visa.ResourceManager()
keithley2000_1 = r.open_resource(Keithley2000_1_Addr)
keithley2000_2 = r.open_resource(Keithley2000_2_Addr)

keithley2000_1.write("*rst;*cls")
data6 = []
print('\n---start ---')
try:
    interval_in_ms = 1
    number_of_readings = 40
    keithley2000_1.write("STAT:MEAS:ENAB 512:*SRE 1")
    keithley2000_1.write(":CONF:VOLT:DC:range 10")
    keithley2000_1.write(":TRIG:COUN %d" % number_of_readings)
    keithley2000_1.write(":TRIGer:DELay %f" % (interval_in_ms / 1000.0)) 
    keithley2000_1.write(":TRAC:POIN %d" % number_of_readings)
    keithley2000_1.write(":TRAC:FEED SENS1;FEED:CONT NEXT")
    keithley2000_1.write(":INIT")

    data6 = keithley2000_1.query_ascii_values(":TRACE:DATA?") 
    print("6DC : ", len(data6), data6)
except KeyboardInterrupt:
    print('CTRL-C')
    
print('\n -- end --')

二つの計測を表示

 エラーが取り切れていませんが、測定部分を関数にしました。plt.hist(data1, rwidth=0.8) とplt.hist(data2, rwidth=0.8)のように同じ描画コマンドを実行すると、同じグラフ枠の上に、色を変えて表示します。

import visa
from time import sleep
import matplotlib.pyplot as plt

Keithley2000_1_Addr = "GPIB0::6"
Keithley2000_2_Addr = "GPIB0::18"

r = visa.ResourceManager()
keithley2000_1 = r.open_resource(Keithley2000_1_Addr)
keithley2000_2 = r.open_resource(Keithley2000_2_Addr)

#print('\n---start ---')
def read_Keithley2000(GPIB, number):
    GPIB.write("*rst;*cls")
    interval_in_ms = 1
    number_of_readings = number
    GPIB.write("STAT:MEAS:ENAB 512:*SRE 1")
    GPIB.write(":CONF:VOLT:DC:range 10")
    GPIB.write(":SENS:RES:NPLC 1")
    GPIB.write(":TRIG:COUN %d" % number_of_readings)
    GPIB.write(":TRIG:DEL %f" % (interval_in_ms / 1000.0)) 
    GPIB.write(":TRAC:POIN %d" % number_of_readings)
    GPIB.write(":TRAC:FEED SENS1;FEED:CONT NEXT")
    GPIB.write(":INIT")
    sleep(10)
    
    data = GPIB.query_ascii_values(":TRACE:DATA?") 
    return data
    
#print('\n -- end --')
data1 = read_Keithley2000(keithley2000_1,100)
data2 = read_Keithley2000(keithley2000_2,100)
print(data1)
print(data2)
plt.hist(data1, rwidth=0.8)
plt.hist(data2, rwidth=0.8)
plt.show()

 重なって表示されると思ったのですが、ずれました。ヤフオクで購入した古い機材なので、少し確度が異なるようです。