IoTで使うPython入門 Step4-Python3ソケット②DMM 34461A高速にデータを取得

 SCPIコマンドはとてもたくさんあるので、事例集を探しました。Keysightのサンプル・プログラムをダウンロードします。

  34460A/34461Aの入門SCPIシーケンス・サンプル

●FastDCV

 サンプルの中にある、まとめて高速にデータを取得するSCPIコマンドの事例です。

*IDN? 測定器のIDを取得

CONF:VOLT:DC 10, MAX;  DCV、10V レンジに固定、分解能最大
VOLT:DC:NPLC MIN;    積分時間を最小に
VOLT:DC:ZERO:AUTO OFF; オートゼロOFF
VOLT:DC:NULL:STAT OFF;  STATe

SAMP:COUN 1000; SAMPle:COUNt。サンプリング・カウント1000回
TRIG:SOUR BUS; 「トリガ待ち」状態になると、リモート・
          インターフェース経由で*TRGにより測定器の
          トリガが実行される

INIT;            測定開始
*TRG;            測定器をトリガ
DATA:REM? 1000, WAIT   REMove? データ問い合わせ。読み出して削除

SYST:ERR?          エラー有無の確認

 pythonで上記のコマンドの送信とデータを取得します。送る文字列はASCIIで、messageという文字列変数へ入れました。長いので、\ で分割しています。messageはmessage.encode()でバイト列にして送ります。

import socket

ipAddr = "K-34461A-16054.local"
ports  = 5025
message = '*IDN\n'\
'CONF:VOLT:DC 10, MAX;\n'\
'VOLT:DC:NPLC MIN;\n'\
'VOLT:DC:ZERO:AUTO OFF;\n'\
'VOLT:DC:NULL:STAT OFF;\n'\
'\n'\
'SAMP:COUN 1000;\n'\
'TRIG:SOUR BUS;\n'\
'INIT;\n'\
'*TRG;\n'\
'DATA:REM? 1000, WAIT\n'\
'\n'\
'SYST:ERR?\n'

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((ipAddr, ports))
    #print(message)
    s.send(message.encode())
    s = s.recv(16000)
    #print(type(s),s)
    ss = (str(s)[:-3])[2:]
    #print(type(ss),ss)
    sss = str(ss).split(',')
    #print(list(sss))
    f = [float(f) for f in sss]
    print(f,len(f))

 受け取った値は、

b'+2.49403830E+00, +2.49372795E+00, ではじまり、

,+2.49366361E+00\n'までの、1個のバイト列です。

 1000個のサンプリング・データは、s.recv(16000)の読み取り数で1000個ぴったりです。このバッファが大きすぎると、存在しない領域を読み取ろうとして、

\n-113,"Undefined header"\n'

というエラーが出ます。バッファが小さいと、すべてのデータを読み切れません。したがって、このバッファを数字を試行錯誤で求めないと、適切な読み出しにならないので、プログラムとしては不完全です。

 (str(s)[:-3])[2:]で、先頭のb'と末尾の\n'を削除しています。この結果、次の計測値だけのバイト列が得られます。

+2.49403830E+00, +2.49372795E+00, ... ,+2.49366361E+00

 str(ss).split(',')は、カンマでそれぞれの測定値を分離し、リスト形式にします。測定値は、この状態では文字列です。

 [float(f) for f in sss]は、内包形式のfor文で、文字列を数値に変更します。次の実行例のような数値データが得られます。

改良

 エラー・メッセージの’113’が受信したバイト列に入っていたら、そこまでのデータを出力するというように変更しました。

import socket

ipAddr = "K-34461A-16054.local"
ports  = 5025
message = '*IDN\n'\
'CONF:VOLT:DC 10, MAX;\n'\
'VOLT:DC:NPLC MIN;\n'\
'VOLT:DC:ZERO:AUTO OFF;\n'\
'VOLT:DC:NULL:STAT OFF;\n'\
'\n'\
'SAMP:COUN 1000;\n'\
'TRIG:SOUR BUS;\n'\
'INIT;\n'\
'*TRG;\n'\
'DATA:REM? 1000, WAIT\n'\
'\n'\
'SYST:ERR?\n'

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((ipAddr, ports))
    s.send(message.encode())
    s1 = b''
    i =0
    while 1:
        i= i+1
        s0 = s.recv(16) 
        if '113' in str(s0):
            break
        s1=s1+s0
    ss = (str(s1)[:-3])[2:]
    sss = str(ss).split(',')
    f = [float(f) for f in sss]
    print(f,len(f))

 DATA:REM? 1000, WAITは、FETC?でも同様に動作します。DATA:REM?はDMMの内部メモリを消去しています。FETC?は読み出すだけです。34461Aは、最大10,000個の測定値を保存できます。内部の読み値メモリがオーバフローすると 、保存された測定値のうち の最も古い値が新しい測定値によっ て上書きされ、常に、最新の測定値が維持されます。

(参考資料)

  Keysight Truevolt デジタル・マルチメータ 操作およびサービ ス・ガイ ド 

  34410A/11A プログラミング-こんなとき、どんなコマンドを使う?

コラム ロギングを止める

 プログラムの開発中には、DMM側のデータ・ロギングが動きっぱなしになっています。次のプログラムでクリアし、リモートを解除します。

import socket

ipAddr = "K-34461A-16054.local"
ports  = 5025

with socket.socket(socket.AF_INET, socket.SOCK_STREAM) as s:
    s.connect((ipAddr, ports))
    s.send(b'*RST;*CLS\n')
    s.send(b'SYSTem:LOCal\n')