自動化したい!
私は研究を行う上で、頻繁にIWATSU製のオシロスコープのお世話になっております。オシロスコープから電圧やらの波形を得て、それをcsvデータとしてUSBに出力することが度々あるのですが、オシロから直接出力されるcsvデータを再びグラフ化するには少し面倒な手段を踏む必要があります。
と言いますのも、IWATSUのオシロから得られるcsvデータは以下のような形式にまとめられています。
1~19行目までに計測条件、20行目にチャンネル、21行目以降から電圧値が表示されます。
もちろんこの計測条件の表示は重要な要素なのですが、やはりグラフ化や信号処理の足かせになります。また、電圧値の表示はありますが時間軸のデータはありません。
csvデータが2,3個しかないなら手動でグラフ化しても良いのですが、私の研究ではデータが100個ほど生じます。全部手動でやったら気が狂っちゃいます。
そこでPythonでコーディングを行い、以下のようなグラフを自動生成します。
動作環境
OS : Windows10 Python : 3.0系 開発環境 : Anaconda Spyder 4.1.5 オシロスコープ : IWATSU DIGITAL OSCILLOSCOPE DS-5412自動化プログラム
import tkinter
import tkinter.filedialog
import glob
import os
import csv
import numpy as np
import matplotlib.pyplot as plt
DeltaRow = 6 #時間幅が格納された行
DataRow = 21 #電圧値が格納された最初の行
global delta #サンプリング周期
#----------GUIからcsvを選び、選ばれたデータのみを戻す----------#
def file_open():
#---ファイルオープン---#
root = tkinter.Tk()
typ = [('csvファイル', '*.csv')]
DirIn = r'C:/Users'
fni = tkinter.filedialog.askopenfilenames(filetypes = typ, initialdir = DirIn)
root.destroy()
#選択したcsvデータのパスを格納
print(fni[0])
return fni
#----------GUIからcsvを選び、ディレクトリ内の全csvデータを戻す----------#
def files_open():
#---ファイルオープン---#
root = tkinter.Tk()
typ = [('csvファイル', '*.csv')]
DirIn = r'C:/Users'
fni = tkinter.filedialog.askopenfilenames(filetypes = typ, initialdir = DirIn)
root.destroy()
#ディレクトリ内の全てのcsvを選択
for i in range(len(fni)):
fno = fni[i][0:len(fni[i])-4] #fniのタプルからパスのみを抽出
filename= os.path.basename(fno)
csv_path = fno.replace(filename,'')
csv_files = glob.glob(csv_path + "*.csv") #ディレクトリ内の全てのcsvを格納
#戻り値:選択されたファイルのパス(type of tuple)
return csv_files
#----------csv_file内の数値をdata,timeリストに格納する----------#
def data_storing(csv_file_path):
count = 0
global delta #グローバル関数宣言
data = [] #Ch1の電圧
time = [] #時間を格納
with open(csv_file_path,'r') as file:
for row in csv.reader(file):
if(count == DeltaRow - 1): #サンプリング周期の格納
delta = float(row[1])
count += 1
elif(count >= DataRow - 1):
data.append(float(row[0])) #Ch1をdata1に格納
count += 1
else:
count += 1
#時間の格納
for time_count in range(len(data)):
time.append(time_count * delta)
#戻り値 : 電圧値、時間軸が格納されたリスト
return data,time
#----------グラフ出力----------#
def plot_graph(data,time,csv_file):
#data,timeをnp.array化
data = np.array(data)
time = np.array(time)
#パラメータの設定
fig = plt.figure(figsize=(15,10)) #Figure設定
fig.align_labels()
ax = fig.add_subplot(111) #Axes設定
ax.set_xlabel("Time[s]",fontsize=35) #xlabel
ax.set_ylabel("Voltage[V]",fontsize=35) #ylabel
#---全体のパラメータ設定---#
plt.rcParams["font.family"] = "Times New Roman"
plt.rcParams["xtick.direction"] = "in"
plt.rcParams["ytick.direction"] = "in"
plt.rcParams["axes.linewidth"] = 1.0
#---上、右にも目盛を置く---#
ax.tick_params(top = True)
ax.tick_params(right = True)
ax.tick_params(labelsize = 25)
#---目盛範囲制限---#
plt.xlim(0,5)
plt.ylim(-0.05,0.06)
plt.grid()
#---軸設定---#
plt.tick_params(width = 2,length = 15) #目盛りサイズ
plt.xticks(np.arange(0,5.1,0.5),position=(0.0,-0.015)) #時間軸設定
plt.yticks(position=(-0.015,0,0))
plt.plot(time,data,color="red",linewidth=3)
#画像の保存
graphs_path = csv_file.replace(os.path.basename(csv_file),"") + "/Graphs"
if(not(os.path.exists(graphs_path))):
os.mkdir(graphs_path)
plt.savefig(graphs_path + "/" + os.path.basename(csv_file)[:-4] + "_modified.jpg")
plt.show()
plt.close()
#----------取得したデータをcsv保存----------#
def save_csv(data,time,csv_path):
#保存先のパス
save_path = csv_path.replace(os.path.basename(csv_path),"") + "/modified_data"
if(not(os.path.exists(save_path))):
os.mkdir(save_path)
output = []
for j in range(len(data)):
if(j == 0):
output.append("Time[s]" + "," + "Voltage[V]" )
else:
output.append(str(time[j-1]) + ',' + str(data[j-1]))
#csv保存先
save_path = save_path + "/" + os.path.basename(csv_path)[:-4] + "_modified.csv"
print("save_path : " + save_path)
#保存
with open(save_path, 'w',encoding="UTF-8") as fo:
writer = csv.writer(fo, delimiter='\n')
writer.writerow(output)
if __name__ == "__main__":
csv_files = files_open() #複数のcsv_fileを処理
#csv_files = file_open() #単一のcsv_fileを処理
#csv_files内のデータを1つづつ関数に送り処理
for csv_file in csv_files:
csv_data = data_storing(csv_file) #csv_data[0] : 電圧 , csv_data[1] : 時間
data = csv_data[0]
time = csv_data[1]
plot_graph(data,time,csv_file)
save_csv(data,time,csv_file)
プログラム実行後
正常に処理が終了するとディレクトリ内部にGraphsディレクトリとmodified_dataディレクトリが自動生成されます。Graphsには生成されたグラフ画像がjpg形式で格納され、modified_dataには時間軸とそれに対応する電圧値が出力されたcsvファイルが格納されます。処理後のディレクトリ
出力されるmodified.csvデータ
コードの解説
プログラムを実行すると、tkinterからGUIが起動するので目的のcsvデータを選択します。 main関数内の csv_files = files_open() #複数のcsv_fileを処理
#csv_files = file_open() #単一のcsv_fileを処理
をコメントアウトで選択することで処理するcsvの数を制御できます。
file_open()を選択すると選んだcsvデータのみを処理し、files_open()を選択すると選んだcsvデータの存在するディレクトリ内部の全てのcsvを一気に処理します。
file_open(),files_open()内の変数DirInに代入するパスを書き換えると、プログラム実行時にそのパスのディレクトリが開きます。
DirIn = r'C:/Users'
data_storing()の引数として、対象となるcsvデータの絶対パスを送ることでリスト型変数にcsvの値を格納します。IWATSU製オシロから出力されるcsvデータには、セルB6にサンプリング周期が格納されているので、まずこれを変数deltaに格納します(DeltaRowに行数の6が代入されています)。
その後、リスト型変数dataに電圧値を追加していきます。
with open(csv_file_path,'r') as file:
for row in csv.reader(file):
if(count == DeltaRow - 1): #サンプリング周期の格納
delta = float(row[1])
count += 1
elif(count >= DataRow - 1):
data.append(float(row[0])) #Ch1をdata1に格納
count += 1
else:
count += 1
次に時間軸の値を設定する必要があります。n番目の電圧値に対応する時間は、
(サンプリング周期 delta) * n
で計算ができますので、データ番号とdeltaを掛けてリスト型変数timeに追加していきます。
#時間の格納
for time_count in range(len(data)):
time.append(time_count * delta)
これで電圧軸と時間軸の準備は完了です。これらをplot_graph()に送ることでグラフを自動生成し、ディレクトリに保存します。
グラフの表示範囲を変更したい場合は、以下の数値を書き換えます。
#---目盛範囲制限---#
plt.xlim(0,5)
plt.ylim(-0.05,0.06)
plt.grid()
#---軸設定---#
plt.tick_params(width = 2,length = 15) #目盛りサイズ
plt.xticks(np.arange(0,5.1,0.5),position=(0.0,-0.015)) #時間軸設定
plt.yticks(position=(-0.015,0,0))
plt.plot(time,data,color="red",linewidth=3)
最後にsave_csv()で電圧値と時間軸のみが格納されたcsvデータを保存します。これで信号処理などが簡単になると思います。
最後に
IWATSU製のオシロスコープでのみテストを行っています。他のオシロから得たcsvでも作動するのかは不明です。他社のオシロを持っている方がいらっしゃいましたら、csvの出力形式をご教授いただければ有難いです。本プログラムは自分の卒業研究に用いるために作ったものです。非常に限定された用途ではありますが、お役に立てれば幸いです。