1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

VISA計測器制御で周波数vs振幅特性の自動計測をするのに、オブジェクト指向的には継承の使い時だという例①

Last updated at Posted at 2025-05-27

概要

ファンクションジェネレータの周波数設定を変化させ、それに伴うオシロスコープの観測波形の画面キャプチャとPeak to Peakの計測値をロギングする作業をPythonで自動化したときの例を紹介します

話の要点

実用的な自動計測を組むにはVISAのオブジェクト(計測器)は複数登場してきます。
計測器は各々で個別の機能をもっていますが、共通する部分も多々あるので、規定クラスを作って継承するには良いテーマと思い紹介します

お断り事項

  • とりあえず出来る計測器制御の最小構成を示している訳ではないので、コードがやや長いです
  • VISAのコマンドについてのお作法の詳細までは説明しません
  • オブジェクト指向と継承は分かっている前提とします
  • 計測器によって微妙にコマンドが異なる場合もありますので,他の計測器では適宜変更が必要
  • 話の要点を関連が薄い部分のコードは省略していますので、脳死でコピペしても動きません

環境構築

VISAドライバインストール

VISAのドライバを入手してインストールしてください。テクトロニクス様、NI様、HIOKI様などから提供されています。

Python と pyvisa のインストール

Python をインストールして pipで pyvisaを入れてください。

使用した計測器

今回使用した計測器です。 

  • Tektronix (オシロスコープ)TBS1202C
  • NF回路 (ファンクションジェネレータ)WF1968

コード

基底クラス

基底クラスのlist_up()という静的メソッドではVISAのドライバで認識しているアイテムをリストアップします。インスタンスするよりも前にlist_up()を使いたいと思いますので静的メソッドにしています。

コンストラクタでリソース名を利用して計測器オープンし、オープンしっぱなしという思想としています。

VisaBase.py
#//////////////////////////////////////////////////////////////////////
# VISA計測器の基底クラス。 pyvisaのインストールが必要でなおかつ
# Visaのドライバーがインストールされている必要があります。
#//////////////////////////////////////////////////////////////////////
import pyvisa
import sys
import time
class VisaBase:
    #------------------------------------------------------
    #キーワードと接続方式が一致するVISAリソースをリストで返す
    @staticmethod
    def serch(key_word,connection_type):
        __resource_name= []
        _rm = pyvisa.ResourceManager()
        _visa_list = _rm.list_resources() #VISAリソースのリストを取得
        for _item in _visa_list:
            #接続方式が一致するものだけOPENしてIDを尋ねる
            if connection_type in _item:
                _inst =_rm.open_resource(_item)
                _response = _inst.query('*IDN?')
                #IDNで尋ねた結果キーワードと部分一致したらリソース名として覚える
                if key_word in _response:
                    __resource_name.append(_item)
                _inst.close()
        return __resource_name
    #------------------------------------------------------
    #VISAリソースをリストで返す
    @staticmethod
    def list_up():
        #_resource_list= []
        _rm = pyvisa.ResourceManager()
        _visa_list = _rm.list_resources()
        for _item in _visa_list:
            print(f"Available resource: {_item}")
    #------------------------------------------------------
    #コンストラクタ:
    def __init__(self,resource_name):
        self.rm = pyvisa.ResourceManager()
        self.inst = self.rm.open_resource(resource_name)
    #------------------------------------------------------
    #破棄する時にクローズ
    def __del__(self):
        '''--コード省略--'''
    #------------------------------------------------------
    @property
    def name(self):
        '''--コード省略--'''
    #------------------------------------------------------
    #コマンド書き込み:リストやタプルなら複数コマンドとして扱う
    def write(self, command):
        if isinstance(command, (list, tuple)):
            for cmd in command:
                self.inst.write(cmd)
        else:
            self.inst.write(command)
    #-----------------------------------------------
    #待ち時間を表示するプログレスバー
    def wait(self,title,seconds, bar_length=20):
        '''--コード省略--'''
################################################################
if __name__ == "__main__":
    VisaBase.list_up()

ファンクションジェネレータの派生クラス

ファンクションジェネレータを呼び出す上位のアプリケーションコードで、
wf.Frequency(100)ではなく、wf.Frequency=100 みたいに書きたかったので、@propertyを使っています。

WF1968
#//////////////////////////////////////////////////////////////////////
# NF回路ファンクションジェネレータ(WF1968シリーズ)用
#//////////////////////////////////////////////////////////////////////
from VisaBase import VisaBase  # Visa計測器の基底クラス
   
class WF1968(VisaBase):
    def __init__(self,connection_type="USB"):
        #機器名をキーワードにしてリソース名を検索
        resource_list = VisaBase.serch("WF1968", connection_type)
        if not resource_list:
            '''--コード省略--'''
        super().__init__(resource_list[0])
    #------------------------------------------------------
    # 出力ON/OF状態を設定するプロパティ
    @property
    def Output(self):
        return self.inst.query("OUTPut?").strip()
    @Output.setter
    def Output(self, value):
        if value in ["ON", "OFF"]:
            self.inst.write(f"OUTPut {value}")
        else:
            '''--コード省略--'''
    #------------------------------------------------------
    #周波数を設定するプロパティ(例なのでch1固定です)
    @property
    def Frequency(self):
        return self.inst.query("FREQ?").strip()
    @Frequency.setter
    def Frequency(self, value):
        self.inst.write(f"SOURce1:FREQ {value}")
        self.wait(f"Frequency {value}", 1)
################################################################
# 出力周波数を100kから200kまで10k刻みで変化させるテストコード
if __name__ == "__main__":
    import time
    wf = WF1968("USB")
    wf.Output = "ON"  # 出力をONに設定
    for i in range(11):
        wf.Frequency = 100000 + (i * 10000)  # 周波数を1kHzから10kHzまで設定
    wf.Output = "OFF"  # 出力をONに設定

長くなってきましたので、2つめの派生クラスであるオシロスコープは次の記事にします。
オシロスコープではスクリーンキャプチャの処理がポイントになります。

1
1
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
1
1

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?