シミュレーションでパルス(0→1→0)の信号を入れるとき、立ち上がりと立ち下がりをどう表現するかを調べていたのでそれについて備忘録としてまとめました。
記号
- ton : 立ち上がり開始時刻
- toff : 立ち下がり開始時刻
- trise : 立ち上がり時間(0→1へ変化するまでの時間)
- tfall : 立ち上がり時間(1→0へ変化するまでの時間)
1. ステップ関数型
f(t)={10ton≦t<toffotherwise.
とても簡単ですが、立ち上がり・立ち下がり時間が0なので予期しない高周波成分の原因になりシミュレーションが不安定になります。
実装が簡単で便利ですがもう少し丁寧にしたいです。
def step_func_pulse(t, t_on, t_off):
if t_on <= t < t_off:
return 1
return 0
最もシンプルな実装ですがこれには立ち上がり時間、立ち上がり時間を考慮していないという課題があります。
実際のパルスは立ち上がり、立ち上がり時間が存在します。

2. 線形ランプ
立ち上がりと立ち下がりを時間に対して直線でつなぐ方法です。
f(t)risef(t)fall=triset−ton=1−tfallt−toff
def pulse_with_tr_tf(t, t0, t_rise, t_fall, width):
if t0 <= t < t0 + t_rise:
return (t - t0) / t_rise
if t0 + t_rise <= t < t0 + t_rise + width:
return 1
if t0 + t_rise + width <= t < t0 + t_rise + width + t_fall:
return 1 - (t - (t0 + t_rise + width)) / t_fall
return 0
良い点としてはステップ関数型とは違い立ち上がり立下り時間を考慮できています。しかし、立ち上がり開始・終了、立ち下がり開始・終了で傾き(1階微分)が不連続になります。場合によっては悪影響を及ぼす可能性があります。

3. 1階微分までなめらかにしたい時
3.1 smoothstep型
[0,1]で3x2−2x3を使う形。端点で傾きが0になるので接続が自然になります。
多項式で計算できるので後で紹介するものよりも計算が簡単です。
f(t)risef(t)fall=3(triset−ton)2−2(triset−ton)3=1−(3(tfallt−toff)2−2(tfallt−toff)3)
def smoothstep_pulse(t, t0, t_rise, t_fall, width):
if t0 <= t < t0 + t_rise:
x = (t - t0) / t_rise
return 3*x**2 - 2*x**3
if t0 + t_rise <= t < t0 + t_rise + width:
return 1
if t0 + t_rise + width <= t < t0 + t_rise + width + t_fall:
x = (t - (t0 + t_rise + width)) / t_fall
return 1 - (3*x**2 - 2*x**3)
return 0
より高次の多項式バージョンもあるようです。参考: Wikipedia Smoothstep

3.2 cos型
コサインを半周期だけ使うやり方です。こちらも端点の傾きが0になるので繋がりが滑らかです。
f(t)risef(t)fall=21(1−cos(πtriset−ton))=21(1+cos(πtfallt−toff))
def cos_pulse(t, t0, t_rise, t_fall, t_width):
if t0 <= t < t0 + t_rise:
return (1 - cos(pi * (t - t0) / t_rise)) / 2
if t0 + t_rise <= t < t0 + t_rise + t_width:
return 1
if t0 + t_rise + t_width <= t < t0 + t_rise + t_width + t_fall:
return (1 + cos(pi * (t - (t0 + t_rise + t_width)) / t_fall)) / 2
return 0

4. 任意階微分が連続な波形
4.1 tanh型
f(t)=21(tanhτriset−ton−tanhτfallt−toff)
tanhは無限回微分可能でなめらかです。
この波形では滑らかに0と1を漸近的に行き来します。そのため、f(t)=0やf(t)=1に到達する有限の時刻は存在しません。
そこで、立ち上がり時間を「ピーク値の10%から90%に達するまでの時間」、立ち下り時間を「ピーク値の90%から10%に到達するまでの時間」と定義します。
以下では十分に長いパルスを前提にします。
パルスの立ち上がり前の時間、すなわち立ち上がりが始まる十分前t≪toffには
tanhτfallt−toff≈−1
と近似できるので、f(x)は
f(t)≈21(tanh(τriset−ton)+1)
となります。
ここで、0<f(t)<1であるので、任意の割合p∈(0,1)を用いて式を変形すると、
p2p−1=21(tanh(τriset−ton)+1)=tanh(τriset−ton)
tanhの逆関数は21ln1−x1+xであるので、
21ln1−pp=τriset−ton
ピーク時の10%、すなわちp=0.1の時刻tsは、
21ln91ts=τrisets−ton=2τriseln91+ton
ピーク時の90%、すなわちp=0.9の時刻teは、
21ln9te=τrisete−ton=2τriseln9+ton
よって、立ち上がり時間は
te−ts=(2τriseln9+ton)−(2τriseln91+ton)=τriseln9
同様に立下りでは立ち上がり時間の十分後t≪tonである時、
tanhτriset−ton≈1
であるので
f(t)≈21(1−tanhτfallt−toff)
となるので同じ手順で
tfall=τfallln9
と求めることができます。
まとめると、
- 立ち上がり時間 : τriseln9
- 立ち下がり時間 : τfallln9

sigmoid型
f(t)=1+exp(−τrise(t−ton))1−1+exp(−τfall(t−toff))1
tanh型と同様にf(t)=0やf(t)=1に到達する有限の時刻は存在しません。そのため先ほどと同様の定義でパルスの立ち上がり、立ち下がり時間を求めます。
t≪toffの時、
1+exp(−τfall(t−toff))1≈0
よって、
f(t)≈1+exp(−τrise(t−ton))1
0<f(t)<1なのでp∈(0,1)を用いて変形すると、
pp1−plnp1−p=1+exp(−τrise(t−ton))1=exp(−τrise(t−ton))=−τrise(t−ton)
ピーク時の10%、すなわちp=0.1の時刻tsは
ln9ts=−τrise(ts−ton)=−τriseln9+ton
ピーク時の90%、すなわちp=0.9の時刻teは
−ln9te=−τrise(te−ton)=τriseln9+ton
立ち上がり時間は
trise=τriseln9+ton−(−τriseln9+ton)=2τriseln9
立ち下がり時間はt≫tonにおいて、
1+exp(−τrise(t−ton))1≈1
となるので
f(t)=1−1+exp(−τfall(t−toff))1
同じ手順で求めることができる
tfall=2τfallln9
まとめると、
- 立ち上がり時間 : 2τriseln9
- 立ち下がり時間 : 2τfallln9
Sigmoid型とtanh型のパルスの形状は同じになります。

まとめ
- 手早く試すなら:線形型
- 傾きの段差をなくすなら: cosかsmoothsteps
- 滑らかさが重要なら:tanhかsigmoid
各パルスの立ち上がり
紹介したパルスの立ち上がり方をまとめました。
