LoginSignup
0
2

More than 3 years have passed since last update.

IWATSU製オシロスコープから得たcsvデータを自動でグラフ化したい!

Last updated at Posted at 2020-12-16

自動化したい!

私は研究を行う上で、頻繁にIWATSU製のオシロスコープのお世話になっております。

オシロスコープから電圧やらの波形を得て、それをcsvデータとしてUSBに出力することが度々あるのですが、オシロから直接出力されるcsvデータを再びグラフ化するには少し面倒な手段を踏む必要があります。

と言いますのも、IWATSUのオシロから得られるcsvデータは以下のような形式にまとめられています。

csv.png

1~19行目までに計測条件、20行目にチャンネル、21行目以降から電圧値が表示されます。
もちろんこの計測条件の表示は重要な要素なのですが、やはりグラフ化や信号処理の足かせになります。また、電圧値の表示はありますが時間軸のデータはありません。
csvデータが2,3個しかないなら手動でグラフ化しても良いのですが、私の研究ではデータが100個ほど生じます。全部手動でやったら気が狂っちゃいます。

そこでPythonでコーディングを行い、以下のようなグラフを自動生成します。
signal1_modified.jpg

動作環境

OS : Windows10
Python : 3.0系
開発環境 : Anaconda Spyder 4.1.5
オシロスコープ : IWATSU DIGITAL OSCILLOSCOPE DS-5412

自動化プログラム

oscilloGraph.py

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ファイルが格納されます。

処理後のディレクトリ
ディレクトリ.png
出力されるmodified.csvデータ
modified.png

コードの解説

プログラムを実行すると、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の出力形式をご教授いただければ有難いです。

本プログラムは自分の卒業研究に用いるために作ったものです。非常に限定された用途ではありますが、お役に立てれば幸いです。

0
2
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
0
2