【Python/Pandas】パルス信号の時定数、立ち上がり、立ち下がりを計算

PythonモジュールPandasでパルス信号の立ち上がり、立ち下がりを計算する方法についてソースコード付きでまとめました。

スポンサーリンク

【Pandas】時間信号データの実効値を計算

パルス信号データ(CSV)を読み込んで、波形の時定数、立上り時間、立下り時間、ON(HIGH)の時間を計算します。

種別 概要
立ち上がり時間 時間信号が10%から90%に上がるまでの時間。
立ち下がり時間 時間信号が90%から10%に下がるまでの時間。
時定数 時間信号が10%から63.2%に上がるまでの時間。
RMS 二乗平均平方根(Root Mean Square)。二乗した値の平均を求めその平方根を計算する。
【信号処理】実効値の計算式・計算例(Excel、Pythonなど)
読み込んだデータ
CSV current.csv

current.csv

time,current
-6,0
-5.8,1
-5.6,0
-5.4,0
︙
0,0
0.2,1
0.4,2
︙
2.4,13
2.6,12
2.8,16
︙

サンプルコード

# -*- coding: utf-8 -*-
import os
import pandas as pd
import matplotlib
import matplotlib.pyplot as plt
import numpy as np
import math


class Pulse():
    # 波形の各種時間(立上り、下がり、ON)を計算
    def calc_time(self, ts, ys, Ymax=None, Ymin=None, upper_threshold=0.9, lower_threshold=0.1, Tr_start_min=None, Ton_min=None):
        dst = {}

        # 最小時間が指定されていなければ、最も小さい時間をセット
        if Tr_start_min == None:
            Tr_start_min = ts.min()

        # 最小時間が指定されていなければ、最も小さい時間をセット
        if Ton_min == None:
            Ton_min = 0

        if Ymax == None:
            Ymax = ys.max()

        if Ymin == None:
            Ymin = ys.min()

        dst["Ymax"] = Ymax
        dst["Ymin"] = Ymin
        dst["Yamp"] = Yamp = Ymax - Ymin

        dst["upper"] = upper_threshold
        dst["lower"] = lower_threshold

        # 立上り開始時間(信号がしきい値と最小値を超えた直後の時間)を取得
        Trs_start = ts[ys > Yamp * lower_threshold]
        dst["tr_start"] = Tr_start = Trs_start[Trs_start > Tr_start_min].min()

        # 立上り終了時間を取得
        Trs_end = ts[ys > Yamp * upper_threshold]
        dst["tr_end"] = Tr_end = Trs_end[Trs_end > Tr_start].min()

        # 立上り時間を計算
        dst["tr"] = Tr = Tr_end - Tr_start

        # 立下り開始時間を取得( > 立上り終了時間 + ON最小時間)
        try:
            Tfs_start = ts[ys < Yamp * upper_threshold]
            dst["tf_start"] = Tf_start = Tfs_start[Tfs_start >
                                                   Tr_end + Ton_min].min()
        except:
            dst["tf_start"] = Tf_start = ts[-1]

        # ONの時間を計算(立上り終了時間~立下り開始時間)
        dst["ton"] = Ton = Tf_start - Tr_end

        # 立下り終了時間を取得
        try:
            Tfs_end = ts[ys < Yamp * 0.1]
            dst["tf_end"] = Tf_end = Tfs_end[Tfs_end > Tf_start].min()
        except:
            dst["tf_end"] = Tf_end = ts[-1]

        # 立下り時間を計算
        dst["tf"] = Tf = Tf_end - Tf_start

        # 時定数を計算
        taus = ts[ys >= Yamp * 0.632]
        dst["tau"] = tau = taus[taus > Tr_start_min].min() - Tr_start
        self.pulse_times = dst

        return dst

    # 波形の各種時間(立上り、下がり、ON)を計算
    def show_time(self):
        dst = {}
        tr_start = self.pulse_times["tr_start"]
        tr_end = self.pulse_times["tr_end"]
        tr = self.pulse_times["tr"]
        ton = self.pulse_times["ton"]
        tf_start = self.pulse_times["tf_start"]
        tf_end = self.pulse_times["tf_end"]
        tf = self.pulse_times["tf"]
        tau = self.pulse_times["tau"]
        Ymax = self.pulse_times["Ymax"]
        Ymin = self.pulse_times["Ymin"]
        Yamp = self.pulse_times["Yamp"]

        print("Tr start:", tr_start)
        print("Tr end:", tr_end)
        print("Tr:", tr)
        print("Ton:", ton)
        print("Tf start:", tf_start)
        print("Tr end:", tf_end)
        print("Tf:", tf)
        print("Tau:", tau)

    def save_graph(self, x, y, xlabel, ylabel, save_path, label_name="Y"):
        tr_start = self.pulse_times["tr_start"]
        tr_end = self.pulse_times["tr_end"]
        tr = self.pulse_times["tr"]
        ton = self.pulse_times["ton"]
        tf_start = self.pulse_times["tf_start"]
        tf_end = self.pulse_times["tf_end"]
        tf = self.pulse_times["tf"]
        tau = self.pulse_times["tau"]
        Ymax = self.pulse_times["Ymax"]
        Ymin = self.pulse_times["Ymin"]
        Yamp = self.pulse_times["Yamp"]
        upper_threshold = self.pulse_times["upper"]
        lower_threshold = self.pulse_times["lower"]

        # 保存先のディレクトリパスが存在しなければ作成
        dir_path = os.path.dirname(save_path)
        if not os.path.exists(dir_path):
            os.mkdir(dir_path)

        # グラフ化
        ax = plt.axes()
        plt.rcParams['font.family'] = 'Times New Roman'  # 全体のフォント
        plt.rcParams['axes.linewidth'] = 1.0  # 軸の太さ

        # 電流値をプロット
        plt.plot(x, y, lw=1, c="r", alpha=0.7, ms=2, label=label_name)

        # 立上り・下りの開始、終了時間、時定数に垂線をプロット
        plt.vlines(tr_start, min(y), max(y), ls='--',
                   color="b", lw=1, label="Tr start")
        plt.vlines(tr_end, min(y), max(y), ls='--',
                   color="g", lw=1, label="Tr end")
        plt.vlines(tf_start, min(y), max(y),
                   ls='--', lw=1, label="Tf start")
        plt.vlines(tf_end, min(y), max(y), ls='--',
                   color="m", lw=1, label="Tf end")
        plt.vlines(tau, min(y), max(y), ls='-', lw=1, label="Tau")

        # 電流最大値の10%、90%に水平線をプロット
        plt.hlines(Yamp * 0.9, min(x), max(x), ls='--',
                   color="r", lw=1, label="Amp " + str(upper_threshold*100)+"%")
        plt.hlines(Yamp * 0.1, min(x), max(x), ls='--',
                   color="y", lw=1, label="Amp " + str(lower_threshold*100)+"%")

        # グラフの保存
        plt.legend(loc="best")     # 凡例の表示(2:位置は第二象限)
        plt.xlabel('Time[msec]', fontsize=12)  # x軸ラベル
        plt.ylabel('Current[A]', fontsize=12)  # y軸ラベル
        plt.grid()  # グリッドの表示
        plt.legend(loc="best")  # 凡例の表示
        plt.savefig(save_path)
        plt.clf()

    # 実効値の計算
    def calc_rms(self, y):
        return math.sqrt(np.sum(y ** 2) / y.size)

def main():
    pulse = Pulse()

    # 読み込むCSVファイルのパス
    csv_path = "C:/prog/python/auto/current.csv"
    save_path = "C:/prog/python/auto/"

    # 空のデータフレームを作成
    df = pd.DataFrame({})

    # CSVファイルのロードし、データフレームへ格納
    df = pd.read_csv(csv_path, encoding="UTF-8", skiprows=0)

    # 電流値の列データを取り出し
    Its = df.loc[:, "current"]

    # 経過時間の列データを取り出し
    ts = df.loc[:, "time"]

    # 各種時間を計算(上限90%、下限10%)
    pulse.calc_time(ts, Its, Ymin=0, Ton_min=50)
    times = pulse.show_time()
    pulse.save_graph(
        ts, Its, xlabel="Time[msec]", ylabel="Current[A]", save_path=save_path+"a.png", label_name="I(t)")

    """
        Tr start: 8.4
        Tr end: 328.2
        Tr: 319.8
        Ton: 278.8
        Tf start: 607.0
        Tr end: 620.8
        Tf: 13.799999999999955
        Tau: 114.39999999999999
        RMS: 249.061976770524
    """
    print("RMS:", pulse.calc_rms(Its))

if __name__ == "__main__":
    main()

【Python】Pandasで信号処理入門
PythonモジュールPandasで信号処理する方法についてまとめました。
【Pandas入門】使い方とサンプル集
Pythonモジュール「Pandas」でデータ分析する方法についてサンプルコード付きで入門者向けに使い方を解説します。
【Python超入門】使い方とサンプル集
Pythonとは、統計処理や機械学習、ディープラーニングといった数値計算分野を中心に幅広い用途で利用されている人気なプログラミング言語です。 主な特徴として「効率のよい、短くて読みやすいコードを書きやすい」、「ライブラリが豊富なのでサクッと...
Python
スポンサーリンク

コメント

  1. 匿名 より:

    お世話になります。
    「【Python/Pandas】パルス信号の時定数、立ち上がり、立ち下がりを計算」のコードを実行したのですが、WIN10ではうまくいったのですが、ラズパイ(ターミナルから実施)で実施するとうまくいきませんでした。データのCSVは同じです。
    Win10とラズパイ(Linux)の違いだと、思いますが、もし心当たりがあれば教えてください。

    Traceback (most recent call last):
    File “Delay_1.py”, line 196, in
    main()
    File “Delay_1.py”, line 180, in main
    ts, Its, xlabel=”Time[msec]”, ylabel=”Current[A]”, save_path=save_path+”a.png”, label_name=”I(t)”)
    File “Delay_1.py”, line 129, in save_graph
    color=”b”, lw=1, label=”Tr start”)
    File “/usr/lib/python3/dist-packages/matplotlib/pyplot.py”, line 3036, in vlines
    **kwargs)
    File “/usr/lib/python3/dist-packages/matplotlib/__init__.py”, line 1812, in inner
    return func(ax, *args, **kwargs)
    File “/usr/lib/python3/dist-packages/matplotlib/axes/_axes.py”, line 1143, in vlines
    lines.update(kwargs)
    File “/usr/lib/python3/dist-packages/matplotlib/artist.py”, line 916, in update
    ret = [_update_property(self, k, v) for k, v in props.items()]
    File “/usr/lib/python3/dist-packages/matplotlib/artist.py”, line 916, in
    ret = [_update_property(self, k, v) for k, v in props.items()]
    File “/usr/lib/python3/dist-packages/matplotlib/artist.py”, line 912, in _update_property
    raise AttributeError(‘Unknown property %s’ % k)
    AttributeError: Unknown property ls

    • 管理人 より:

      コメントありがとうございます. ls引数がないと怒られているようですのでlsをlinestyleに修正してみてください.