数学教育でよく扱われる「横軸を x とする関数」に基づく微分・積分・極限の問題は、抽象的で工学的な意味を見出しにくく、教養的・実用的な価値が薄いと感じられることもある。
そこで比較のために、デジタル信号処理に基づく数値的手法を以下に示す。これは、解析的に扱える現代の技術の進歩を確認する目的であり、実用性は限定的である点に注意する。
- 横軸の変更とサンプリング
教養数学では、関数は通常「横軸を x、縦軸を y」として表す。
しかし工学的な信号処理の文脈では、横軸を時間 t に置き換えることで解析がしやすくなる。
さらに、この連続時間信号をサンプリング周期 T ごとに区切って観測すると、離散時間信号 x[n] を得ることができる。
⸻
2. 微分(d/dt)のデジタル近似
連続時間:
y(t) = dx(t)/dt
離散時間(差分近似):
・前進差分: y[n] = (x[n+1] - x[n]) / T
・後退差分: y[n] = (x[n] - x[n-1]) / T
・中心差分: y[n] = (x[n+1] - x[n-1]) / (2T)
伝達関数(後退差分の場合):
H(z) = (1 - z^-1) / T
これはハイパスフィルタ的な特性を持つ。
⸻
3. 積分(∫)のデジタル近似
連続時間:
y(t) = ∫ x(t) dt
離散時間(台形則):
y[n] = y[n-1] + (T/2)(x[n] + x[n-1])
伝達関数:
H(z) = (T/2) * (1+z^-1) / (1-z^-1)
これはローパスフィルタのように動作する。
⸻
4. 定積分(∫区間付き)のデジタル近似
区間 [0, N] での積分:
∫0^NT x(t) dt ≈ T Σ (n=0→N) x[n]
伝達関数:
H(z) = T (1 + z^-1 + z^-2 + … + z^-N)
これは有限長のFIRフィルタ(窓積分)になる。
- 元の関数と時間信号化
• 数学教育で扱う形
y = sin(x)
• 工学信号処理に置き換え(横軸を時間 t に変更)
y(t) = sin(t)
• サンプリング周期 T ごとに離散化
y[n] = sin(nT)
ここで n は整数、T はサンプリング周期です。これにより連続信号が 離散時間信号 に変換されます。
⸻
- 微分の近似(差分フィルタ)
連続時間での微分:
dy/dt = cos(t)
離散化した場合、差分を使って近似できます:
• 前進差分
y'[n] ≈ (sin((n+1)T) - sin(nT)) / T
• 後退差分
y'[n] ≈ (sin(nT) - sin((n-1)T)) / T
• 中心差分(精度が高い)
y'[n] ≈ (sin((n+1)T) - sin((n-1)T)) / (2T)
→ 周波数領域で見ると、これらは ハイパスフィルタ特性 を持ちます。
⸻
- 積分の近似(累積和フィルタ)
連続時間での積分:
∫ sin(t) dt = -cos(t) + C
離散時間での近似(台形則を利用):
y[n] = y[n-1] + (T/2)(sin(nT) + sin((n-1)T))
これは「過去の値を足し合わせる構造」を持ち、ローパスフィルタの挙動に似ています。
⸻
- 定積分の近似(有限区間和)
区間 [0, NT] の定積分:
∫0^NT sin(t) dt
離散近似では:
∫0^NT sin(t) dt ≈ T Σ (k=0→N) sin(kT)
これは「有限区間の総和」であり、有限インパルス応答(FIR)フィルタ、特に 窓関数積分 に相当します。
最後に横軸を t から x に戻すことで、関数として数値的に解析することが可能になります。
また、サンプリングされた離散的な点は、直線で結んで補間しておくと全体の挙動が視覚的にわかりやすくなります。
import numpy as np
import matplotlib.pyplot as plt
# ================= Parameters =================
T = 0.1 # Sampling period / サンプリング周期
N = 100 # Number of samples / サンプル数
t = np.linspace(0, (N-1)*T, N) # Time vector / 時間ベクトル
# ================= Continuous & Discrete Signal =================
t_cont = np.linspace(0, (N-1)*T, 1000)
y_cont = np.sin(t_cont)
y_disc = np.sin(t)
# ================= Derivative Approximations =================
dy_cont = np.cos(t_cont)
dy_fwd = (np.roll(y_disc, -1) - y_disc) / T; dy_fwd[-1] = np.nan
dy_bwd = (y_disc - np.roll(y_disc, 1)) / T; dy_bwd[0] = np.nan
dy_ctr = (np.roll(y_disc, -1) - np.roll(y_disc, 1)) / (2*T); dy_ctr[0] = np.nan; dy_ctr[-1] = np.nan
# ================= Integral Approximations =================
int_cont = -np.cos(t_cont) + 1
int_disc = np.zeros(N)
for n in range(1, N):
int_disc[n] = int_disc[n-1] + (T/2)*(y_disc[n] + y_disc[n-1])
# ================= Definite Integral Approximation =================
true_definite = -np.cos(N*T) + np.cos(0)
def_sum = T * np.sum(y_disc)
# ================= Print Results =================
print("=== Numerical Results ===")
print(f"Sampling period T = {T}")
print(f"Number of samples N = {N}")
print(f"Interval length NT = {N*T}")
print(f"True definite integral ∫0^{N*T} sin(t) dt = {true_definite:.6f}")
print(f"Discrete sum approximation (Riemann sum) = {def_sum:.6f}")
print(f"Error (Discrete - True) = {def_sum - true_definite:.6e}")
# ================= Plots =================
plt.figure(figsize=(12, 10))
# 1. Original signals
plt.subplot(4,1,1)
plt.plot(t_cont, y_cont, 'b-', label='Continuous sin(t)')
plt.plot(t, y_disc, 'ro-', label='Discrete sin(nT)')
plt.title('Original Signal')
plt.xlabel('Time')
plt.ylabel('Amplitude')
plt.legend(); plt.grid(True)
# 2. Derivative
plt.subplot(4,1,2)
plt.plot(t_cont, dy_cont, 'k-', label='Continuous cos(t)')
plt.plot(t, dy_fwd, 'go-', label='Forward diff')
plt.plot(t, dy_bwd, 'co-', label='Backward diff')
plt.plot(t, dy_ctr, 'mo-', label='Central diff')
plt.title('Derivative Approximations')
plt.xlabel('Time')
plt.ylabel('Amplitude')
plt.legend(); plt.grid(True)
# 3. Integral
plt.subplot(4,1,3)
plt.plot(t_cont, int_cont, 'b-', label='Continuous ∫sin(t)dt')
plt.plot(t, int_disc, 'ro-', label='Discrete trapezoidal sum')
plt.title('Integral Approximations (Cumulative)')
plt.xlabel('Time')
plt.ylabel('Amplitude')
plt.legend(); plt.grid(True)
# 4. Definite Integral Approximation
plt.subplot(4,1,4)
bars = ['True ∫0^NT sin(t)dt', 'Discrete Sum']
values = [true_definite, def_sum]
plt.bar(bars, values, color=['blue','red'])
plt.title('Definite Integral Approximation over [0, NT]')
plt.ylabel('Value')
plt.grid(True, axis='y')
plt.tight_layout()
plt.show()