この記事ではオシロスコープを使用した自動測定の実現方法と活用アイデア③について解説しています。
補正不足の場合
補正不足の場合は信号のエッジがなまった波形が表示されます。
プログラムを実行すると以下のように判定結果が表示され、適切な補正範囲から外れていることが確認できます。
-------------------------------------------------------------------------------------------------------
- チャンネル1の振幅: 3.002 V
- チャンネル1の周波数: 999.908 Hz
- 立ち上がり時間: 1.761 us
- 立ち下がり時間: 1.810 us
- 判定結果: 不合格
-------------------------------------------------------------------------------------------------------
過剰補正の場合
過剰な補正を行ったときには、信号のエッジがオーバーシュートした波形が表示されいます。
プログラムを実行すると以下のように判定結果が表示され、ここでも適切な補正範囲から外れていることが確認できます。
-------------------------------------------------------------------------------------------------------
- チャンネル1の振幅: 3.717 V
- チャンネル1の周波数: 999.907 Hz
- 立ち上がり時間: 0.710 us
- 立ち下がり時間: 0.713 us
- 判定結果: 不合格
-------------------------------------------------------------------------------------------------------
適切な補正の場合
適切な補正を行うと、テスト信号はきれいな矩形波として表示されます。
プログラムを実行すると判定結果が合格と表示されます。
-------------------------------------------------------------------------------------------------------
- チャンネル1の振幅: 3.058 V
- チャンネル1の周波数: 999.907 Hz
- 立ち上がり時間: 1.023 us
- 立ち下がり時間: 1.023 us
- 判定結果: 合格
-------------------------------------------------------------------------------------------------------
合否判定の記録
この合否判定プログラムの結果を測定業務のたびに記録するルールで運用していれば、あとから測定結果の妥当性を確認することができます。ここではPerplexityに以下のプロンプトを入力しました。
-------------------------------------------------------------------------------------------------------
結果として表示されるパラメータをまとめてCSVファイルで出力してください。
左端には日時を追加してください。
一度ファイルを作成したあとは、次の行に追記してください。
-------------------------------------------------------------------------------------------------------
すると以下のようなプログラムが生成されます。
**************************************************************************************
import pyvisa
import time
import csv
from datetime import datetime
# リソースマネージャーの初期化とオシロスコープへの接続
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')) # 立ち下がり時間を取得
# 判定
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:
judgment = "合格"
else:
judgment = "不合格"
# 結果の表示
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')
print(f'判定結果: {judgment}')
# CSVファイルに結果を追記
csv_file = 'oscilloscope_measurements.csv'
current_time = datetime.now().strftime('%Y-%m-%d %H:%M:%S')
try:
with open(csv_file, 'a', newline='') as file:
writer = csv.writer(file)
# ファイルが空の場合、ヘッダーを書き込む
if file.tell() == 0:
writer.writerow(['日時', '振幅(V)', '周波数(Hz)', '立ち上がり時間(us)', '立ち下がり時間(us)', '判定結果'])
writer.writerow([current_time, f'{vpp:.3f}', f'{freq:.3f}', f'{rise_time*1e6:.3f}', f'{fall_time*1e6:.3f}', judgment])
print(f"結果をCSVファイル '{csv_file}' に追記しました。")
except IOError:
print("CSVファイルへの書き込みに失敗しました。")
# 接続を閉じる
scope.close()
rm.close()
print("プログラムが終了しました。")
**************************************************************************************
補正の程度を変化させて複数回プログラムを実行したところ「oscilloscope_measurements.csv」には以下のようなデータが記録されました。
この表を見ると日時と合否の関係が一目瞭然で、あとから測定結果の妥当性を確認するのにも非常に役立ちます。
信号の時間経過
プログラムを上手く活用できればオシロスコープをデータロガーのように使用することもできます。例えば1秒間隔で電圧の時間変化を測定する例で考えてみます。
プログラムの生成
Perplexityのプロンプトは以下のように入力しました。
-------------------------------------------------------------------------------------------------------
以下の要件を満たすプログラムを生成して
・チャンネル1の実効値を1秒毎に取得
・クリックしてから測定開始、再度クリックすると測定終了
・実効値の変化をグラフ表示
-------------------------------------------------------------------------------------------------------
このプロンプトをもとに生成されたプログラムは以下のとおりです。
**************************************************************************************
import pyvisa
import time
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import tkinter as tk
rm = pyvisa.ResourceManager()
scope = rm.open_resource('USB0::0xF4EC::0x1017::SDS08A0X802449::INSTR')
# オシロスコープの初期設定
scope.write('*RST')
scope.write(':CHANnel1:SWITch ON')
scope.write(':CHANnel1:SCALe 0.5')
scope.write(':TIMebase:SCALe 1E-3')
scope.write(':TRIGger:MODE EDGE')
scope.write(':TRIGger:EDGE:SOURce CHANnel1')
scope.write(':TRIGger:EDGE:LEVel 0')
# グラフの初期化
fig, ax = plt.subplots()
x_data, y_data = [], []
line, = ax.plot([], [])
ax.set_xlim(0, 60)
ax.set_ylim(0, 5)
ax.set_xlabel('時間 (秒)')
ax.set_ylabel('実効値 (V)')
ax.set_title('チャンネル1の実効値の変化')
# 測定フラグ
measuring = False
def measure():
global measuring
measuring = not measuring
if measuring:
button.config(text="測定停止")
else:
button.config(text="測定開始")
def update(frame):
if measuring:
# 実効値の測定
scope.write(':MEASure:SIMPle:ITEM RMS')
rms = float(scope.query(':MEASure:SIMPle:VALue? RMS'))
x_data.append(frame)
y_data.append(rms)
line.set_data(x_data, y_data)
ax.relim()
ax.autoscale_view()
return line,
# GUIの設定
root = tk.Tk()
root.title("実効値測定")
button = tk.Button(root, text="測定開始", command=measure)
button.pack()
ani = FuncAnimation(fig, update, interval=1000, blit=True)
plt.show()
root.mainloop()
# 接続を閉じる
scope.close()
rm.close()
**************************************************************************************
プログラムの修正
このままのプログラムだと設定変更後に動作が安定せずにエラー表示されるため、待機時間を追加しました。またグラフ表示に関しても日本語は文字化けするため、英語表記に変更しました。変更後のプログラムは以下のとおりです。
**************************************************************************************
import pyvisa
import time
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
import tkinter as tk
rm = pyvisa.ResourceManager()
scope = rm.open_resource('USB0::0xF4EC::0x1017::SDS08A0X802449::INSTR')
# オシロスコープの初期設定
scope.write('*RST')
scope.write(':CHANnel1:SWITch ON')
scope.write(':CHANnel1:SCALe 0.2')
scope.write(':TIMebase:SCALe 1E-3')
scope.write(':TRIGger:MODE EDGE')
scope.write(':TRIGger:EDGE:SOURce CHANnel1')
scope.write(':TRIGger:EDGE:LEVel 0')
time.sleep(2) # 設定が安定するまで2秒待機
# 測定の設定
scope.write(':MEASure ON') # 測定機能をオン
# グラフの初期化
fig, ax = plt.subplots()
x_data, y_data = [], []
line, = ax.plot([], [])
ax.set_xlim(0, 100)
ax.set_ylim(0, 1)
ax.set_xlabel('Time (s)')
ax.set_ylabel('RMS (V)')
ax.set_title('Channel1')
# 測定フラグ
measuring = False
def measure():
global measuring
measuring = not measuring
if measuring:
button.config(text="Stop")
else:
button.config(text="Start")
def update(frame):
if measuring:
# 実効値の測定
scope.write(':MEASure:SIMPle:ITEM RMS')
rms = float(scope.query(':MEASure:SIMPle:VALue? RMS'))
x_data.append(frame)
y_data.append(rms)
line.set_data(x_data, y_data)
ax.relim()
ax.autoscale_view()
return line,
# GUIの設定
root = tk.Tk()
root.title("RMS Measurement")
button = tk.Button(root, text="Start", command=measure)
button.pack()
ani = FuncAnimation(fig, update, interval=1000, blit=True)
plt.show()
root.mainloop()
# 接続を閉じる
scope.close()
rm.close()
© 2024 T&Mコーポレーション株式会社