この記事ではオシロスコープを使用した自動測定の実現方法と活用アイデア②について解説しています。
プログラミング方法
計測器のプログラムは制御コマンドを組み合わせてプログラミングします。SDS804Xの制御コマンドはプログラミングガイドにまとめられています。
https://siglent.co.jp/upload_file/document/SDS800XHD_Series_ProgrammingGuide_EN11G.pdf
オシロスコープのプログラミングで使用頻度の高い代表的なコマンドは以下のようなものがあります。
- *RST : オシロスコープをデフォルト設定にリセット
- :AUToset : 入力信号に合わせて自動的に設定を調整
- :ACQuire:MODE : 波形取得モードを設定 (YT、XY、ROLLなど)
- :ACQuire:TYPE : データ取得タイプを設定 (NORMal、PEAK、AVERageなど)
- :CHANnel<n>:SCALe : 指定チャンネルの垂直感度を設定
- :CHANnel<n>:OFFSet : 指定チャンネルの垂直オフセットを設定
- :CHANnel<n>:COUPling : 指定チャンネルの結合モードを設定 (DC、AC、GND)
- :CHANnel<n>:PROBe VALue : 指定チャンネルの減衰率を設定
- :TIMebase:SCALe : 水平時間軸のスケールを設定
- :TRIGer:MODE :トリガーモードを設定(Auto、Normal、Single、強制)
- :TRIGger:TYPE : トリガータイプを設定 (EDGE、PULSE、SLOPeなど)
- :TRIGger:SOURce : トリガーソースを指定
- :TRIGger:EDGE:LEVel : トリガーレベルを指定
- :MEASure:SOURce : 測定ソースを指定
- :MEASure:ITEM : 測定項目を設定
- :WAVeform:DATA? : 波形データを取得
- :SAVE:IMAGe : 画面イメージを保存
- :MATH:OPERator : 演算機能の演算子を設定
- :ACQuire:MDEPth : メモリ深度を設定
- :MEASure:STATistics : 測定統計機能を設定
- :DECode:MODE : デコード機能を設定
プログラムはPyVisaライブラリを使用して各種コマンドを実行します。なお計測器のコマンドは書き込み(Write)、読み込み(Read)、書き込みと読み込みの組わせ(Query)の3つの実行パターンがあります。
実際のプログラミング作業はAIを活用すると便利です。AIはPDFドキュメントを読み込んで、その情報をもとにプログラムを生成することができます。ここでは簡単な例として、Perplexityに「Siglent製SDS804Xでチャンネル1の振幅と周波数を読み取るプログラム」とプロンプトを入力して、そこから生成されたプログラムを一部修正して実行します。なお自動測定とは言え基本的な手順はマニュアル操作と同じで、垂直軸、水平軸、トリガーの順にパラメータを設定していきます。
【修正前】
**************************************************************************************
import pyvisa
import time
try:
# オシロスコープに接続
rm = pyvisa.ResourceManager()
scope = rm.open_resource('USB0::0xF4EC::0x1017::SDS08A0X802449::INSTR')
# オシロスコープをリセット
scope.write('*RST')
time.sleep(1)
# チャンネル1の設定
scope.write(':CHANnel1:SWITch ON')
scope.write(':CHANnel1:PROBe VALue,1.00E+01') # プローブ減衰率を10xに設定
scope.write(':CHANnel1:SCALe 0.5')
scope.write(':CHANnel1:OFFSet -1.5')
# 水平軸の設定
scope.write(':TIMebase:SCALe 5E-4')
# トリガーの設定
scope.write(':TRIGger:MODE EDGE')
scope.write(':TRIGger:EDGE:SOURce CHANnel1')
scope.write(':TRIGger:EDGE:LEVel 1.5')
time.sleep(2) # 設定が安定するまで待機
# 測定の設定
scope.write(':MEASure ON')
scope.write(':MEASure:SIMPle:ITEM PKPK,FREQ')
scope.write(':MEASure:SIMPle:SOURce CHANnel1')
# 測定値の取得
vpp = float(scope.query(':MEASure:SIMPle:VALue? PKPK'))
freq = float(scope.query(':MEASure:SIMPle:VALue? FREQ'))
print(f'チャンネル1の振幅: {vpp:.3f} V')
print(f'チャンネル1の周波数: {freq:.3f} Hz')
except pyvisa.errors.VisaIOError as e:
print(f"VISA IOエラー: {e}")
except ValueError as e:
print(f"値エラー: {e}")
except Exception as e:
print(f"予期せぬエラー: {e}")
finally:
if 'scope' in locals():
scope.close()
rm.close()
print("プログラムが終了しました。")
**************************************************************************************
修正内容としてはエラー処理やリソース管理を省略して、処理内容をより簡潔にしています。
【修正後】
**************************************************************************************
import pyvisa
import time
# リソースマネージャーの初期化とオシロスコープへの接続
rm = pyvisa.ResourceManager()
scope = rm.open_resource('USB0::0xF4EC::0x1017::SDS08A0X802449::INSTR')
# オシロスコープをリセット
scope.write('*RST')
# チャンネル1の設定
scope.write(':CHANnel1:SWITch ON') # チャンネル1をオン
scope.write(':CHANnel1:PROBe VALue,1.00E+01') # プローブ減衰率を10xに設定
scope.write(':CHANnel1:SCALe 0.5') # 垂直スケールを0.5V/divに設定
scope.write(':CHANnel1:OFFSet -1.5') # オフセットを-1.5Vに設定
# 水平軸の設定
scope.write(':TIMebase:SCALe 5E-4') # 時間軸を1ms/divに設定
# トリガーの設定
scope.write(':TRIGger:TYPE EDGE') # エッジトリガーモードに設定
scope.write(':TRIGger:EDGE:SOURce CHANnel1') # トリガーソースをチャンネル1に設定
scope.write(':TRIGger:EDGE:LEVel 1.5') # トリガーレベルを1.5Vに設定
scope.write(':TRIGger:MODE SINGle') # シングルトリガーに設定
time.sleep(2) # 設定が安定するまで2秒待機
# 測定の設定
scope.write(':MEASure ON') # 測定機能をオン
# 測定値の取得
vpp = float(scope.query(':MEASure:SIMPle:VALue? PKPK')) # ピーク間電圧を取得
freq = float(scope.query(':MEASure:SIMPle:VALue? FREQ')) # 周波数を取得
# 結果の表示
print(f'チャンネル1の振幅: {vpp:.3f} V')
print(f'チャンネル1の周波数: {freq:.3f} Hz')
**************************************************************************************
プローブ用の校正信号を測定した状態でこのプログラムを実行すると以下のような結果が得られます。
- チャンネル1の振幅: 3.077 V
- チャンネル1の周波数: 999.906 Hz
この取得した値はMeasurementに表示されているPk-PkとFreqと一致しています。
自動測定の活用アイデア
ここからはプログラムによる自動測定を活用するためのアイデアをいくつか挙げてみます。
テスト信号の合否判定
ルーチン化された測定業務で最も効果的なのが信号の合否判定への活用です。測定対象となる信号はDUTによって違いはありますが、要求仕様を満足しているかどうかを自動で判定してくれると非常に便利です。ここではテスト端子でプローブの周波数特性の補正を行うにあたって、補正の妥当性を判断するプログラムを考えてみます。過剰補正にはピーク電圧Vpp、補正不足に対しては立ち上がり時間Trと立ち下がり時間Tfで判定します。
プログラムの生成
Perplexityのプロンプトは以下のように入力しました。
-------------------------------------------------------------------------------------------------------
プログラムに以下の項目を追加してください。
・ピーク間電圧が2.9V~3.1Vの範囲に入っているか確認
・立ち上がり時間が0.95us~1.05usの範囲に入っているか確認
・立ち下がり時間が0.95us~1.05usの範囲に入っているか確認
・3つの確認項目すべてを満足している場合は合格、1つでも満足していない場合は不合格と表示
-------------------------------------------------------------------------------------------------------
このプロンプトをもとに生成されたプログラムは以下のとおりです。
**************************************************************************************
import pyvisa
import time
# リソースマネージャーの初期化とオシロスコープへの接続
rm = pyvisa.ResourceManager()
scope = rm.open_resource('USB0::0xF4EC::0x1017::SDS08A0X802449::INSTR')
# オシロスコープをリセット
scope.write('*RST')
# チャンネル1の設定
scope.write(':CHANnel1:SWITch ON') # チャンネル1をオン
scope.write(':CHANnel1:PROBe VALue,1.00E+01') # プローブ減衰率を10xに設定
scope.write(':CHANnel1:SCALe 0.5') # 垂直スケールを0.5V/divに設定
scope.write(':CHANnel1:OFFSet -1.5') # オフセットを-1.5Vに設定
# 水平軸の設定
scope.write(':TIMebase:SCALe 5E-4') # 時間軸を0.5ms/divに設定
# トリガーの設定
scope.write(':TRIGger:TYPE EDGE') # エッジトリガーモードに設定
scope.write(':TRIGger:EDGE:SOURce CHANnel1') # トリガーソースをチャンネル1に設定
scope.write(':TRIGger:EDGE:LEVel 1.5') # トリガーレベルを1.5Vに設定
scope.write(':TRIGger:MODE SINGle') # シングルトリガーに設定
time.sleep(2) # 設定が安定するまで2秒待機
# 測定の設定
scope.write(':MEASure ON') # 測定機能をオン
# 測定値の取得
vpp = float(scope.query(':MEASure:SIMPle:VALue? PKPK')) # ピーク間電圧を取得
freq = float(scope.query(':MEASure:SIMPle:VALue? FREQ')) # 周波数を取得
rise_time = float(scope.query(':MEASure:SIMPle:VALue? RISE')) # 立ち上がり時間を取得
fall_time = float(scope.query(':MEASure:SIMPle:VALue? FALL')) # 立ち下がり時間を取得
# 結果の表示
print(f'チャンネル1の振幅: {vpp:.3f} V')
print(f'チャンネル1の周波数: {freq:.3f} Hz')
print(f'立ち上がり時間: {rise_time*1e6:.3f} us')
print(f'立ち下がり時間: {fall_time*1e6:.3f} us')
# 判定
vpp_ok = 2.9 <= vpp <= 3.1
rise_ok = 0.95e-6 <= rise_time <= 1.05e-6
fall_ok = 0.95e-6 <= fall_time <= 1.05e-6
if vpp_ok and rise_ok and fall_ok:
print("判定結果: 合格")
else:
print("判定結果: 不合格")
# 接続を閉じる
scope.close()
rm.close()
© 2024 T&Mコーポレーション株式会社