FFTコード


```
import numpy as np
import matplotlib.pyplot as plt

# パラメータ設定
alpha = 1.0  # ガウス関数のパラメータ
T = 5        # 時間の範囲
N = 1024     # サンプル数
fs = 1000    # サンプリング周波数

# 時間と周波数の範囲
t = np.linspace(-T, T, N)
dt = t[1] - t[0]  # サンプリング間隔
f = np.fft.fftfreq(N, dt)  # FFTの周波数軸

# ガウス関数
x_t = np.exp(-alpha * t**2)

# FFTの計算
X_f_fft = np.fft.fftshift(np.fft.fft(x_t))
f_shifted = np.fft.fftshift(f)  # 周波数軸を0を中心にシフト

# フーリエ変換の計算
X_f = np.sqrt(np.pi / alpha) * np.exp(- (2 * np.pi * f)**2 / (4 * alpha))

# プロット
plt.figure(figsize=(15, 6))

# ガウス関数のプロット
plt.subplot(1, 3, 1)
plt.plot(t, x_t, label='$x(t) = e^{-\\alpha t^2}$')
plt.title('Gaussian Function $x(t)$')
plt.xlabel('Time $t$')
plt.ylabel('$x(t)$')
plt.legend()
plt.grid(True)

# フーリエ変換のプロット
plt.subplot(1, 3, 2)
plt.plot(f, X_f, label='$X(f) = \\sqrt{\\frac{\\pi}{\\alpha}} e^{-\\frac{(2\\pi f)^2}{4\\alpha}}$', color='orange')
plt.title('Theoretical Fourier Transform $X(f)$')
plt.xlabel('Frequency $f$')
plt.ylabel('$X(f)$')
plt.legend()
plt.grid(True)

# FFT のプロット
plt.subplot(1, 3, 3)
plt.plot(f_shifted, np.abs(X_f_fft), label='FFT of $x(t)$', color='green')
plt.title('FFT of $x(t)$')
plt.xlabel('Frequency $f$')
plt.ylabel('Magnitude')
plt.legend()
plt.grid(True)

plt.tight_layout()
plt.show()
```

```
import numpy as np
import matplotlib.pyplot as plt

# 矩形波の生成
def rectangular_wave(t, T):
    return np.where((t % T) < T / 2, 1, 0)

# 時間領域
T = 1.0
t = np.linspace(-2 * T, 2 * T, 1000)
x_t = rectangular_wave(t, T)

# フーリエ変換の理論的結果
def fourier_transform_rectangular_wave(frequency, T):
    return T * np.sinc(frequency * T)

frequencies = np.linspace(-10, 10, 500)
X_f = fourier_transform_rectangular_wave(frequencies, T)

# FFTの計算
N = 512  # サンプル数
t_discrete = np.linspace(-2 * T, 2 * T, N, endpoint=False)
x_t_discrete = rectangular_wave(t_discrete, T)

X_f_discrete = np.fft.fft(x_t_discrete)
frequencies_discrete = np.fft.fftfreq(N, d=(t_discrete[1] - t_discrete[0]))

# プロット
plt.figure(figsize=(14, 6))

# 時間領域
plt.subplot(1, 3, 1)
plt.plot(t, x_t)
plt.title('Time Domain - Rectangular Wave')
plt.xlabel('Time')
plt.ylabel('Amplitude')

# 周波数領域 (理論的なフーリエ変換)
plt.subplot(1, 3, 2)
plt.plot(frequencies, X_f)
plt.title('Frequency Domain - Theoretical')
plt.xlabel('Frequency')
plt.ylabel('Magnitude')

# FFT結果
plt.subplot(1, 3, 3)
plt.plot(frequencies_discrete, np.abs(X_f_discrete))
plt.title('Frequency Domain - FFT')
plt.xlabel('Frequency')
plt.ylabel('Magnitude')
plt.xlim(-10, 10)  # 表示する周波数範囲を指定

plt.tight_layout()
plt.show()
```

```
import numpy as np
import matplotlib.pyplot as plt

# パラメータ
f0 = 5  # コサイン関数の周波数
t = np.linspace(0, 1, 500)  # 時間軸
cosine_wave = np.cos(2 * np.pi * f0 * t)  # コサイン関数

# 周波数軸
f = np.linspace(-10, 10, 1000)
delta = 0.1  # ガウス関数の標準偏差
def gaussian(x, mu, sigma):
    return np.exp(-0.5 * ((x - mu) / sigma)**2) / (sigma * np.sqrt(2 * np.pi))

# フーリエ変換
X = 0.5 * (gaussian(f, f0, delta) + gaussian(f, -f0, delta))

# FFT
N = len(t)
T = t[1] - t[0]
yf = np.fft.fft(cosine_wave)
xf = np.fft.fftfreq(N, T)
xf = np.fft.fftshift(xf)
yf = np.fft.fftshift(yf)

# パワースペクトルの計算
power_spectrum = np.abs(yf) ** 2

# プロット
fig, (ax1, ax2, ax3, ax4) = plt.subplots(4, 1, figsize=(10, 16))

# コサイン関数のプロット
ax1.plot(t, cosine_wave, label=r'$\cos(2\pi f_0 t)$')
ax1.set_xlabel('Time (s)')
ax1.set_ylabel('Amplitude')
ax1.set_title('Cosine Function')
ax1.grid(True)
ax1.legend()

# フーリエ変換のプロット
ax2.plot(f, X, label=r'$0.5 [\delta(f - f_0) + \delta(f + f_0)]$')
ax2.set_xlabel('Frequency (Hz)')
ax2.set_ylabel('Amplitude')
ax2.set_title('Fourier Transform of $\cos(2\pi f_0 t)$')
ax2.grid(True)
ax2.legend()

# FFTのプロット
ax3.plot(xf, np.abs(yf), label='FFT of $\cos(2\pi f_0 t)$')
ax3.set_xlabel('Frequency (Hz)')
ax3.set_ylabel('Magnitude')
ax3.set_title('FFT of Cosine Function')
ax3.grid(True)
ax3.legend()

# パワースペクトルのプロット
ax4.plot(xf, power_spectrum, label='Power Spectrum of $\cos(2\pi f_0 t)$')
ax4.set_xlabel('Frequency (Hz)')
ax4.set_ylabel('Power')
ax4.set_title('Power Spectrum')
ax4.grid(True)
ax4.legend()

plt.tight_layout()
plt.show()


```
```

import numpy as np
import matplotlib.pyplot as plt

# Define parameters
T = 1  # Period of the rectangular and triangular waves
Fs = 1000  # Sampling frequency for FFT
N = 2048  # Number of samples for better frequency resolution
t = np.linspace(-2*T, 2*T, N)  # Time range

# Define the rectangular and triangular waves
def rect(t, T):
    return np.where(np.abs(t) <= T / 2, 1, 0)

def tri(t, T):
    return np.maximum(0, 1 - np.abs(t) / (T / 2))

# Define the sinc function
def sinc(x):
    return np.sin(x) / x

# Rectangular and triangular wave signals with zero padding
rect_wave = rect(t, T)
tri_wave = tri(t, T)

# Apply windowing
window = np.hanning(N)
rect_wave_windowed = rect_wave * window
tri_wave_windowed = tri_wave * window

# Zero padding (if not using full length of N)
rect_wave_padded = np.pad(rect_wave_windowed, (0, max(0, N - len(rect_wave_windowed))), mode='constant')
tri_wave_padded = np.pad(tri_wave_windowed, (0, max(0, N - len(tri_wave_windowed))), mode='constant')

# Compute the FFT
def compute_fft(signal, Fs):
    fft_vals = np.fft.fftshift(np.fft.fft(signal))
    freqs = np.fft.fftshift(np.fft.fftfreq(len(signal), 1/Fs))
    return freqs, np.abs(fft_vals)

# FFT for rectangular and triangular waves
rect_freqs, rect_fft = compute_fft(rect_wave_padded, Fs)
tri_freqs, tri_fft = compute_fft(tri_wave_padded, Fs)

# Frequency range for theoretical spectra (in Hz)
omega = np.linspace(-10 * np.pi, 10 * np.pi, N)  # Frequency range in rad/s
freqs_hz = omega / (2 * np.pi)  # Convert to Hz

# Fourier Transforms
rect_spectrum = T * sinc(omega * T / (2 * np.pi))
tri_spectrum = (T**2 / 2) * sinc(omega * T / (2 * np.pi))**2

# Plotting
plt.figure(figsize=(14, 10))

# Rectangular wave and its spectrum
plt.subplot(2, 2, 1)
plt.plot(t, rect_wave)
plt.title('Rectangular Wave')
plt.xlabel('Time (t)')
plt.ylabel('Amplitude')
plt.grid(True)

plt.subplot(2, 2, 2)
plt.plot(freqs_hz, rect_spectrum)
plt.title('Rectangular Wave Spectrum (Theoretical)')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

# Triangular wave and its spectrum
plt.subplot(2, 2, 3)
plt.plot(t, tri_wave)
plt.title('Triangular Wave')
plt.xlabel('Time (t)')
plt.ylabel('Amplitude')
plt.grid(True)

plt.subplot(2, 2, 4)
plt.plot(freqs_hz, tri_spectrum)
plt.title('Triangular Wave Spectrum (Theoretical)')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.tight_layout()
plt.show()

# Plot FFT results
plt.figure(figsize=(14, 8))

# FFT of rectangular wave
plt.subplot(2, 2, 1)
plt.plot(rect_freqs, rect_fft)
plt.title('FFT of Rectangular Wave')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

# FFT of triangular wave
plt.subplot(2, 2, 2)
plt.plot(tri_freqs, tri_fft)
plt.title('FFT of Triangular Wave')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.tight_layout()
plt.show()
```
```py

import numpy as np
import matplotlib.pyplot as plt

# 基本パラメータ設定
N = 4096         # サンプル数
dt = 1e-6        # サンプリング間隔 (秒)
f0 = 1e3         # 信号周波数 (Hz)

# 時間軸の作成
t = np.arange(0, N*dt, dt)

# 信号の生成 (例えば、サイン波にノイズを加えた信号)
signal = 0.5 * np.sin(2 * np.pi * f0 * t) + 0.05 * np.random.randn(N)

# FFTの計算
F = np.fft.fft(signal)
freq = np.fft.fftfreq(N, dt)
freq_norm = freq / (1 / dt)  # 正規化

# パワースペクトルを計算
Power = np.abs(F)**2

# シグナルを探す
max_index = np.argmax(Power[1:int(N/2)]) + 1
Signal = Power[max_index]

# パワースペクトルをdB値に変換 (シグナル基準)
Pow_dB = 10 * np.log10(Power / Signal)

# 直流成分とシグナルを除いたノイズパワーの和
Noise = np.sum(Power[1:int(N/2)]) - Signal

# SNDRとENOBの計算
SNDR = 10 * np.log10(Signal / Noise)
ENOB = (SNDR - 1.76) / 6.02

# 結果の表示
print("SNDR =", SNDR, "dB")
print("ENOB =", ENOB, "bit")

# グラフの表示
plt.figure(figsize=(16, 8))

# 時間領域でのプロット
plt.subplot(121)
plt.plot(t, signal, label='Signal')
plt.xlabel("Time [sec]")
plt.ylabel("Amplitude")
plt.grid()
plt.title("Time Domain Signal")
plt.legend()

# 周波数領域でのプロット
plt.subplot(122)
plt.plot(freq_norm[1:int(N/2)], Pow_dB[1:int(N/2)], label='Magnitude Spectrum')
plt.xlabel('Frequency [Hz]')
plt.ylabel('Power [dB]')
plt.title("Frequency Domain")
plt.grid()
plt.text(0.4, -5.3, "SNDR = "+str(round(SNDR, 2))+" dB")
plt.text(0.4, -10.3, "ENOB = "+str(round(ENOB, 2))+" bit")
plt.legend()

plt.tight_layout()
plt.show()

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3759109/b8a96e19-12ae-d8de-2c2f-f8adf3117f2a.png)




```py
import numpy as np

# 基本パラメータの設定
N = 7                      # サンプル数の指数部
fs = 392.1568627 * (10**3) # サンプリング周波数 (Hz)
finRate = 8                # 入力周波数の位置

# FFTポイント数とナイキストポイントの計算
FFT_points = 2**N
nyquist_points = FFT_points // 2

# 周波数の計算とリストの初期化
freq = []

# 2からN-1までの範囲で周波数分解能を計算
for n in range(2, N):
    prime = 2**n - 1  # 2^n - 1
    fin_per_fs = prime / FFT_points
    freq.append(fin_per_fs)

# 入力周波数の位置に基づいて最も近い周波数を探す関数
def find_nearest(array, value):
    array = np.array(array)
    index = (np.abs(array - value)).argmin()
    return index

# ターゲット周波数に最も近い周波数のインデックスを取得
target_freq = 1 / finRate
index = find_nearest(freq, target_freq)

# 最適な入力周波数の計算
fin = freq[index] * fs

# 単位を設定
if fin >= 1e9:
    unit = ' [G] Hz'
    fin /= 1e9
elif fin >= 1e6:
    unit = ' [M] Hz'
    fin /= 1e6
elif fin >= 1e3:
    unit = ' [K] Hz'
    fin /= 1e3
else:
    unit = ' Hz'

# 結果をフォーマットして表示
print(f"最適な入力周波数は {fin:.6f}{unit} です。")


```




```py

import numpy as np
import matplotlib.pyplot as plt

# 基本パラメータの設定
N = 1024  # FFTポイント数
f_signal = 109.375e3  # 信号周波数 (Hz)
t_sampling = 1e-6  # サンプリング時間間隔 (秒)
duration = N * t_sampling  # 信号の持続時間 (秒)
t = np.arange(0, duration, t_sampling)  # 時間軸
v_amplitude = 5  # 信号の振幅
v_offset = 0  # 信号のDCオフセット

# 信号の生成 (サイン波)
v_signal = v_amplitude * np.sin(2 * np.pi * f_signal * t) + v_offset

# ADCパラメータ
n_bits = 12  # デジタル出力のビット数
v_min = -5.0  # 最小入力電圧
v_max = 5.0  # 最大入力電圧

# ADC変換関数
def adc_convert(input_voltage, n_bits, v_min, v_max):
    voltage_range = (v_max - v_min) / (2 ** n_bits)
    digital_level = int((input_voltage - v_min) / voltage_range)
    digital_level = np.clip(digital_level, 0, 2 ** n_bits - 1)
    return digital_level

# ADC変換
d_signal = np.zeros_like(v_signal, dtype=np.int16)
for i in range(len(v_signal)):
    d_signal[i] = adc_convert(v_signal[i], n_bits, v_min, v_max)

# FFT
F = np.fft.fft(d_signal)
freq = np.fft.fftfreq(N, t_sampling)
freq_norm = freq / (1 / t_sampling)  # 正規化

# パワースペクトルを計算
Power = np.abs(F) ** 2
max_index = np.argmax(Power[1:int(N / 2)]) + 1
Signal = Power[max_index]
Pow_dB = 10 * np.log10(Power / Signal)

# 直流成分とシグナルを除いたノイズパワーの和
Noise = np.sum(Power[1:int(N / 2)]) - Signal
SNDR = 10 * np.log10(Signal / Noise)
ENOB = (SNDR - 1.76) / 6.02

print("SNDR=", SNDR, "dB")
print("ENOB=", ENOB, "bit")

# デジタル信号のソート
def wave_sort(data, fs, f_signal):
    data_num = len(data)
    t_signal = 1 / f_signal
    Ts = 1 / fs
    dx_list = []
    for n in range(data_num):
        i = int((Ts * n) / t_signal)
        dx_list.append((Ts * n) - (t_signal * i))
    sorted_indices = sorted(range(len(dx_list)), key=lambda k: dx_list[k])
    sort = [data[i] for i in sorted_indices]
    return sort

sort = wave_sort(d_signal, 1 / t_sampling, f_signal)

# グラフ表示
plt.figure(figsize=(16, 8))

# 時間領域のプロット
plt.subplot(121)
plt.plot(t, sort, label='Sorted Digital Signal')
plt.xlabel("Time [sec]")
plt.ylabel("Signal")
plt.grid()

# 周波数領域のプロット
plt.subplot(122)
plt.plot(freq_norm[1:int(N / 2)], Pow_dB[1:int(N / 2)], label='Power Spectrum')
plt.xlabel('f/fs')
plt.ylabel('Power [dB]')
plt.text(0.4, -5.3, f"SNDR = {SNDR:.2f} dB")
plt.text(0.4, -10.3, f"ENOB = {ENOB:.2f} bit")
plt.grid()

plt.show()

```



```py

import numpy as np
import matplotlib.pyplot as plt

# コヒーレントサンプリングされた波形を1周期に並び替える
def wave_sort(data, fs, f_signal):
    data_num = len(data)
    t_signal = 1/f_signal
    Ts = 1/fs
    dx_list = []
    for n in range(data_num):
        i = int((Ts*n)/t_signal)
        dx_list.append((Ts*n)-(t_signal*i))
    sorted_indices = sorted(range(len(dx_list)), key=lambda k: dx_list[k])
    sort = [data[i] for i in sorted_indices]
    return sort

# 入力信号にノイズを追加
def add_noise(signal, noise_level):
    noise = np.random.normal(0, noise_level, size=signal.shape)
    return signal + noise

# FFTとSNDR計算
def analyze_signal(signal, dt):
    F = np.fft.fft(signal)
    F[np.abs(F) < 1E-9] = 1E-9
    freq = np.fft.fftfreq(len(signal), dt)
    freq_norm = freq / (1 / dt)
    Power = np.abs(F) ** 2
    max_index = np.argmax(Power[1:int(len(signal) / 2)]) + 1
    Signal = Power[max_index]
    Noise = np.sum(Power[1:int(len(signal) / 2)]) - Signal

    if Noise == 0:
        SNDR = np.inf
    else:
        SNDR = 10 * np.log10(Signal / Noise)

    ENOB = (SNDR - 1.76) / 6.02
    Pow_dB = 10 * np.log10(Power / Signal)
    return freq_norm, Power, Pow_dB, SNDR, ENOB

# パラメータ設定
N = 64
dt = 1e-6
f_signal = 109.375e3
t = np.arange(0, N*dt, dt)

# サンプルデータ（CSVがない場合の仮のデータ）
f = np.random.randint(0, 2**12, size=N)

# ノイズ追加
noise_level = 0.1  # ノイズレベルの設定
f_noisy = add_noise(f, noise_level)

# 波形並び替え
f_sorted = wave_sort(f_noisy, 1/dt, f_signal)

# 信号解析
freq_norm, Power, Pow_dB, SNDR, ENOB = analyze_signal(f_sorted, dt)

# グラフ表示
plt.figure(figsize=(16, 8))

# 時間領域のプロット
plt.subplot(121)
plt.plot(t, f_sorted, marker='.', markersize=5, label='f(n)')
plt.xlabel("Time [sec]")
plt.ylabel("Signal")
plt.title("Time Domain Signal")
plt.grid()

# 周波数領域のプロット
plt.subplot(122)
plt.plot(freq_norm[1:int(N / 2)], Pow_dB[1:int(N / 2)], label='|F(k)|')
plt.xlabel('f/fs')
plt.ylabel('Power [dB]')
plt.title("Frequency Domain Signal")
plt.text(0.4, -5.3, f"SNDR = {SNDR:.2f} dB")
plt.text(0.4, -10.3, f"ENOB = {ENOB:.2f} bit")
plt.grid()

plt.show()

```
![image.png](https://qiita-image-store.s3.ap-northeast-1.amazonaws.com/0/3759109/42352fa9-8a46-2f65-3d69-8a3661024fa1.png)


```

import numpy as np
import matplotlib.pyplot as plt

# 波形生成
def generate_signal(amplitude, frequency, sampling_rate, num_samples):
    t = np.arange(num_samples) / sampling_rate
    signal = amplitude * np.sin(2 * np.pi * frequency * t)
    return t, signal

# ADC変換
def adc_convert(input_voltage, n_bits, v_min, v_max):
    voltage_range = (v_max - v_min) / (2 ** n_bits)
    digital_level = int((input_voltage - v_min) / voltage_range)
    digital_level = np.clip(digital_level, 0, 2 ** n_bits - 1)
    return digital_level

# SNDR, ENOB, SFDRの計算
def analyze_signal(signal, dt, n_bits):
    N = len(signal)
    F = np.fft.fft(signal)
    F[np.abs(F) < 1E-9] = 1E-9
    freq = np.fft.fftfreq(N, dt)
    freq_norm = freq / (1 / dt)
    Power = np.abs(F) ** 2
    
    # Peak Signal
    max_index = np.argmax(Power[1:int(N / 2)]) + 1
    Signal = Power[max_index]
    
    # Noise
    Noise = np.sum(Power[1:int(N / 2)]) - Signal

    if Noise == 0:
        SNDR = np.inf
    else:
        SNDR = 10 * np.log10(Signal / Noise)
    
    ENOB = (SNDR - 1.76) / 6.02
    
    # SFDR Calculation
    harmonic_freqs = np.fft.fftfreq(N, dt)
    harmonics = [f for f in harmonic_freqs if f > 0 and f % frequency == 0]
    peak_power = max(Power)
    spurs = [Power[int(i)] for i in range(N) if np.abs(freq[i] - frequency) > 0.1]
    SFDR = 10 * np.log10(peak_power / max(spurs)) if spurs else np.inf

    Pow_dB = 10 * np.log10(Power / Signal)
    return freq_norm, Power, Pow_dB, SNDR, ENOB, SFDR

# パラメータ設定
amplitude = 1.5
frequency = 27.34375e3
sampling_rate = 250e3
num_samples = 256
n_bits = 6
v_min = -1.5
v_max = 1.5
noise_stddev = 0.1  # ノイズの標準偏差

# 信号生成
t, signal = generate_signal(amplitude, frequency, sampling_rate, num_samples)

# ノイズ追加
noise = noise_stddev * np.random.randn(num_samples)
noisy_signal = signal + noise

# ADC変換
adc_signal = np.array([adc_convert(v, n_bits, v_min, v_max) for v in noisy_signal])

# 分析
dt = 1 / sampling_rate
freq_norm, Power, Pow_dB, SNDR, ENOB, SFDR = analyze_signal(adc_signal, dt, n_bits)

# グラフ表示
plt.figure(figsize=(16, 8))

# 時間領域のプロット
plt.subplot(121)
plt.plot(t, adc_signal, marker='.', markersize=5, label='ADC Signal with Noise')
plt.xlabel("Time [sec]")
plt.ylabel("Amplitude")
plt.title("Time Domain Signal")
plt.grid()

# 周波数領域のプロット
plt.subplot(122)
plt.plot(freq_norm[1:int(num_samples / 2)], Pow_dB[1:int(num_samples / 2)], label='Power Spectrum with Noise')
plt.xlabel('Frequency [Hz]')
plt.ylabel('Power [dB]')
plt.title("Frequency Domain Signal")
plt.text(0.4, -5.3, f"SNDR = {SNDR:.2f} dB")
plt.text(0.4, -10.3, f"ENOB = {ENOB:.2f} bit")
plt.text(0.4, -15.3, f"SFDR = {SFDR:.2f} dB")
plt.grid()

plt.show()
```

```
import numpy as np
import matplotlib.pyplot as plt

def fft_recursive(x):
    N = len(x)
    if N <= 1:
        return x

    even = fft_recursive(x[::2])
    odd = fft_recursive(x[1::2])
    
    combined = np.zeros(N, dtype=complex)
    for k in range(N // 2):
        t = np.exp(-2j * np.pi * k / N) * odd[k]
        combined[k] = even[k] + t
        combined[k + N // 2] = even[k] - t
    
    return combined

# サンプル数とサンプリング周波数
N = 512
Fs = 1000.0
# 時間配列
t = np.arange(N) / Fs
# 周波数成分を持つ信号を生成
f1, f2 = 50, 120
signal = 0.5 * np.sin(2 * np.pi * f1 * t) + 0.3 * np.sin(2 * np.pi * f2 * t)

# FFTの計算（Cooley-Tukeyアルゴリズム）
fft_result = fft_recursive(signal)
frequencies = np.fft.fftfreq(N, 1 / Fs)

# 結果をプロット
plt.figure(figsize=(12, 6))

# 時間領域の信号
plt.subplot(2, 1, 1)
plt.plot(t, signal)
plt.title('Time Domain Signal')
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')

# 周波数領域の信号
plt.subplot(2, 1, 2)
plt.plot(frequencies[:N // 2], np.abs(fft_result[:N // 2]))
plt.title('Frequency Domain Signal (Custom FFT)')
plt.xlabel('Frequency [Hz]')
plt.ylabel('Magnitude')

plt.tight_layout()
plt.show()


```




```
import numpy as np
import matplotlib.pyplot as plt

def plot_butterfly(x1, x2, w, stage):
    # Calculate the butterfly operation
    y1 = x1 + w * x2
    y2 = x1 - w * x2
    
    # Extract real parts for plotting
    x1_real, x2_real = np.real(x1), np.real(x2)
    y1_real, y2_real = np.real(y1), np.real(y2)
    
    plt.figure(figsize=(12, 4))
    
    # Original values
    plt.subplot(1, 3, 1)
    plt.title(f'Stage {stage} - Original')
    plt.plot([0, 1], [x1_real, x2_real], 'ro-', markersize=10)
    plt.xlabel('Index')
    plt.ylabel('Value')
    plt.ylim(min(x1_real, x2_real) - 1, max(x1_real, x2_real) + 1)
    
    # After butterfly operation
    plt.subplot(1, 3, 2)
    plt.title(f'Stage {stage} - After Operation')
    plt.plot([0, 1], [y1_real, y2_real], 'bo-', markersize=10)
    plt.xlabel('Index')
    plt.ylabel('Value')
    plt.ylim(min(y1_real, y2_real) - 1, max(y1_real, y2_real) + 1)
    
    # Visual representation of butterfly structure
    plt.subplot(1, 3, 3)
    plt.title(f'Stage {stage} - Butterfly Structure')
    plt.arrow(0.1, x1_real, 0.4, 0, head_width=0.05, head_length=0.1, fc='k', ec='k')
    plt.arrow(0.1, x2_real, 0.4, 0, head_width=0.05, head_length=0.1, fc='k', ec='k')
    plt.arrow(0.6, y1_real, 0.4, 0, head_width=0.05, head_length=0.1, fc='b', ec='b')
    plt.arrow(0.6, y2_real, 0.4, 0, head_width=0.05, head_length=0.1, fc='b', ec='b')
    plt.text(0, x1_real, 'x1', verticalalignment='bottom', horizontalalignment='right')
    plt.text(0, x2_real, 'x2', verticalalignment='bottom', horizontalalignment='right')
    plt.text(1, y1_real, 'y1', verticalalignment='bottom', horizontalalignment='left')
    plt.text(1, y2_real, 'y2', verticalalignment='bottom', horizontalalignment='left')
    plt.xlabel('Index')
    plt.ylabel('Value')
    plt.ylim(min(x1_real, x2_real, y1_real, y2_real) - 1, max(x1_real, x2_real, y1_real, y2_real) + 1)
    plt.gca().invert_yaxis()

    plt.tight_layout()
    plt.show()

# Example of butterfly operation
N = 8
x = np.random.rand(N) * 10 + 1j * np.random.rand(N) * 10
w = np.exp(-2j * np.pi * np.arange(N) / N)  # Twiddle factors for FFT
plot_butterfly(x[0], x[1], w[0], 1)  # Show stage 1 butterfly operation



```



```
import numpy as np
import pywt
import matplotlib.pyplot as plt

# サンプルデータの生成
sampling_rate = 1000  # サンプリングレート
t = np.arange(0, 1, 1/sampling_rate)  # 時間軸
frequency = 10  # サイン波の周波数
data = np.sin(2 * np.pi * frequency * t)  # サイン波

# ウェーブレット変換のパラメータ
wavelet = 'db4'  # Daubechies 4 ウェーブレット
level = 4        # 分解レベル

# ウェーブレット変換
coeffs = pywt.wavedec(data, wavelet, level=level)

# プロットの準備
fig, axes = plt.subplots(nrows=level + 2, sharex=True, figsize=(12, 10))
fig.suptitle('Wavelet Transform of a Sine Wave')

# 元のサイン波をプロット
axes[0].plot(t, data)
axes[0].set_title('Original Sine Wave')
axes[0].set_ylabel('Amplitude')

# ウェーブレット係数をプロット
for i, coeff in enumerate(coeffs):
    axes[i + 1].plot(coeff)
    axes[i + 1].set_title(f'Level {i} coefficients')
    axes[i + 1].set_ylabel('Coefficient')

axes[-1].set_xlabel('Sample index')

plt.tight_layout(rect=[0, 0.03, 1, 0.95])
plt.show()


```


```
import numpy as np
import matplotlib.pyplot as plt
from scipy.fft import fft, fftfreq

# 定義域
x = np.linspace(-2, 2, 400)

# 矩形関数 f(x)
def rect_function(x):
    return np.where(np.abs(x) <= 1, 1, 0)

# フーリエ変換
def fourier_transform(xi):
    if xi == 0:
        return 2  # xi が 0 の場合の処理
    else:
        return 2 * np.sin(xi) / xi

# 矩形関数のプロット
f_x = rect_function(x)
plt.figure(figsize=(12, 6))
plt.subplot(2, 1, 1)
plt.plot(x, f_x, label='$f(x)$')
plt.title('Rectangular Function $f(x)$')
plt.xlabel('$x$')
plt.ylabel('$f(x)$')
plt.legend()
plt.grid()

# フーリエ変換のプロット
xi = np.linspace(-10, 10, 400)
f_hat = np.array([fourier_transform(xi_i) for xi_i in xi])
plt.subplot(2, 1, 2)
plt.plot(xi, f_hat, label='$\\hat{f}(\\xi)$')
plt.title('Fourier Transform $\\hat{f}(\\xi)$')
plt.xlabel('$\\xi$')
plt.ylabel('$\\hat{f}(\\xi)$')
plt.legend()
plt.grid()

plt.tight_layout()
plt.show()

# FFT の計算
N = 400
T = 1.0 / 800.0  # サンプル間隔
x_fft = np.linspace(-2, 2, N)
y_fft = rect_function(x_fft)
yf = fft(y_fft)
xf = fftfreq(N, T)[:N//2]

# FFT のプロット
plt.figure(figsize=(12, 6))
plt.plot(xf, 2.0/N * np.abs(yf[:N//2]), label='FFT')
plt.title('FFT of Rectangular Function')
plt.xlabel('Frequency')
plt.ylabel('Amplitude')
plt.legend()
plt.grid()
plt.show()
```


```
import numpy as np
import matplotlib.pyplot as plt
import pywt
from scipy.signal import stft, hilbert, coherence, find_peaks, lti, lsim, butter, lfilter
from scipy.interpolate import lagrange
from pykalman import KalmanFilter
from sklearn.neural_network import MLPRegressor
from scipy.linalg import householder
from scipy.signal import resample

# サンプル信号の生成
fs = 1000  # サンプリング周波数
t = np.arange(0, 10, 1/fs)
x = np.sin(2 * np.pi * 10 * t) + np.sin(2 * np.pi * 50 * t)  # 基本信号
y = np.sin(2 * np.pi * 10 * t + np.pi / 4) + np.random.randn(len(t))  # 参照信号

# 1. フーリエ変換
from scipy.fft import fft, fftfreq
N = len(x)
yf = fft(x)
xf = fftfreq(N, 1/fs)[:N//2]

# 2. 短時間フーリエ変換 (STFT)
f_stft, t_stft, Zxx = stft(x, fs, nperseg=256)

# 3. ウェーブレット変換
coeffs = pywt.wavedec(x, 'db1', level=4)

# 4. ヒルベルト変換
analytic_signal = hilbert(x)
envelope = np.abs(analytic_signal)
instantaneous_phase = np.unwrap(np.angle(analytic_signal))

# 5. コヒーレンス解析
f_coh, Cxy = coherence(x, y, fs, nperseg=1024)

# 6. ラプラス変換 (概念的な実装: システム応答)
system = lti([1], [1, 2, 1])
t_lap, y_lap, _ = lsim(system, x, t)

# 7. カリマンフィルタ
kf = KalmanFilter(initial_state_mean=0, n_dim_obs=1)
kf = kf.em(x, n_iter=10)
(filtered_state_means, _) = kf.filter(x)

# 8. ラグランジュ補間
data_points = np.array([0, 1, 2, 3])
values = np.sin(data_points)
poly = lagrange(data_points, values)
interpolated_values = poly(t)

# 9. アリアシング
signal_resampled = resample(x, len(x) // 2)
signal_resampled_full = resample(signal_resampled, len(x))

# 10. システム同定 (簡単な線形モデル)
from scipy.optimize import curve_fit
def model(x, a, b):
    return a * x + b
popt, _ = curve_fit(model, t[:100], x[:100])
fitted_y = model(t[:100], *popt)

# 11. リカレントニューラルネットワーク (RNN)
rnn = MLPRegressor(hidden_layer_sizes=(50,), max_iter=1000)
rnn.fit(t.reshape(-1, 1), x)
predicted_y = rnn.predict(t.reshape(-1, 1))

# 12. フィルタバンク
num_bands = 5
bands = np.linspace(0, fs/2, num_bands + 1)
filtered_signals = [lfilter(*butter(4, [bands[i], bands[i+1]], btype='band', fs=fs), x) for i in range(num_bands)]

# 13. ハウスホルダー変換
matrix = np.random.rand(4, 4)
Q, R = householder(matrix)

# 14. 自適応フィルタ
from scipy.signal import lfilter
def adaptive_filter(x, d, mu=0.01, M=32):
    N = len(x)
    w = np.zeros(M)
    y_hat = np.zeros(N)
    e = np.zeros(N)
    for n in range(M, N):
        x_n = x[n-M:n]
        y_hat[n] = np.dot(w, x_n)
        e[n] = d[n] - y_hat[n]
        w = w + 2 * mu * e[n] * x_n
    return e

# 15. マルチレート信号処理
x_resampled = resample(x, len(x) // 2)

# プロット
plt.figure(figsize=(16, 18))

# フーリエ変換のプロット
plt.subplot(5, 3, 1)
plt.plot(xf, np.abs(yf[:N//2]))
plt.title('Fourier Transform')
plt.xlabel('Frequency [Hz]')
plt.ylabel('Magnitude')

# STFTのプロット
plt.subplot(5, 3, 2)
plt.pcolormesh(t_stft, f_stft, np.abs(Zxx), shading='gouraud')
plt.title('Short-Time Fourier Transform (STFT)')
plt.ylabel('Frequency [Hz]')
plt.colorbar()

# ウェーブレット変換のプロット
plt.subplot(5, 3, 3)
plt.plot(coeffs[0], label='Approximation Coefficients')
for i, coeff in enumerate(coeffs[1:], 1):
    plt.plot(coeff, label=f'Detail Coefficients Level {i}')
plt.title('Wavelet Transform Coefficients')
plt.legend()

# ヒルベルト変換のプロット
plt.subplot(5, 3, 4)
plt.plot(t, x, label='Original Signal')
plt.plot(t, envelope, label='Envelope', linestyle='--')
plt.plot(t, instantaneous_phase, label='Instantaneous Phase', linestyle=':')
plt.title('Hilbert Transform')
plt.legend()

# コヒーレンス解析のプロット
plt.subplot(5, 3, 5)
plt.semilogy(f_coh, Cxy)
plt.title('Coherence')
plt.xlabel('Frequency [Hz]')
plt.ylabel('Coherence')
plt.grid()

# ラプラス変換のプロット
plt.subplot(5, 3, 6)
plt.plot(t_lap, y_lap)
plt.title('Laplace Transform (System Response)')
plt.xlabel('Time [s]')
plt.ylabel('Response')

# カリマンフィルタのプロット
plt.subplot(5, 3, 7)
plt.plot(t, x, label='Original Signal')
plt.plot(t, filtered_state_means, label='Kalman Filtered Signal', linestyle='--')
plt.title('Kalman Filter')
plt.legend()

# ラグランジュ補間のプロット
plt.subplot(5, 3, 8)
plt.plot(t, interpolated_values, label='Lagrange Interpolation')
plt.scatter(data_points, values, color='red', zorder=5)
plt.title('Lagrange Interpolation')
plt.legend()

# アリアシングのプロット
plt.subplot(5, 3, 9)
plt.plot(t, x, label='Original Signal')
plt.plot(t, signal_resampled_full, label='Aliased Signal', linestyle='--')
plt.title('Aliasing')
plt.legend()

# システム同定のプロット
plt.subplot(5, 3, 10)
plt.plot(t[:100], x[:100], label='Data')
plt.plot(t[:100], fitted_y, label='Fitted Model', linestyle='--')
plt.title('System Identification')
plt.legend()

# RNNのプロット
plt.subplot(5, 3, 11)
plt.plot(t, x, label='Original Signal')
plt.plot(t, predicted_y, label='RNN Predicted Signal', linestyle='--')
plt.title('RNN')
plt.legend()

# フィルタバンクのプロット
plt.subplot(5, 3, 12)
for i, band in enumerate(filtered_signals):
    plt.plot(t, band, label=f'Band {i+1}')
plt.title('Filter Bank')
plt.legend()

# ハウスホルダー変換はプロット不要（数値結果が主）

# 自適応フィルタのプロット
plt.subplot(5, 3, 13)
adaptive_error = adaptive_filter(x, x)  # シンプルなデモ用に同じ信号を使用
plt.plot(t, adaptive_error)
plt.title('Adaptive Filter')

# マルチレート信号処理のプロット
plt.subplot(5, 3, 14)
plt.plot(t, x, label='Original Signal')
plt.plot(t[:len(x_resampled)], x_resampled, label='Resampled Signal', linestyle='--')
plt.title('Multirate Signal Processing')
plt.legend()

plt.tight_layout()
plt.show()

```



```
import pandas as pd
import numpy as np
import matplotlib.pyplot as plt
from statsmodels.tsa.ar_model import AutoReg
from statsmodels.tsa.arima.model import ARIMA
from statsmodels.tsa.seasonal import seasonal_decompose
from statsmodels.tsa.stattools import adfuller, grangercausalitytests
from sklearn.preprocessing import StandardScaler
from tensorflow.keras.models import Sequential
from tensorflow.keras.layers import LSTM, Dense
from ruptures import detect, rpt
from scipy.fft import fft, fftfreq

# サンプルデータの生成
np.random.seed(0)
data = np.cumsum(np.random.randn(100))  # ランダムな累積和データ
dates = pd.date_range(start='2023-01-01', periods=100)

df = pd.DataFrame(data, index=dates, columns=['Value'])

# 1. 移動平均 (Moving Average)
df['SMA_10'] = df['Value'].rolling(window=10).mean()
df['EMA_10'] = df['Value'].ewm(span=10, adjust=False).mean()

# 2. 自己回帰 (AR: Autoregressive) モデル
ar_model = AutoReg(df['Value'], lags=1)
ar_fitted = ar_model.fit()
df['AR_Prediction'] = ar_fitted.predict(start=len(df), end=len(df)+10)

# 3. 移動平均 (MA: Moving Average) モデル
# MAモデルの適用 (パラメータ設定は例です)
# 詳細な実装には専用のモデルが必要です

# 4. 自己回帰和分移動平均 (ARIMA) モデル
arima_model = ARIMA(df['Value'], order=(1,1,1))
arima_fitted = arima_model.fit()
df['ARIMA_Prediction'] = arima_fitted.predict(start=len(df), end=len(df)+10, typ='levels')

# 5. 季節調整 (Seasonal Decomposition)
decomposition = seasonal_decompose(df['Value'], model='additive')
df['Trend'] = decomposition.trend
df['Seasonal'] = decomposition.seasonal
df['Residual'] = decomposition.resid

# 6. 状態空間モデル (State Space Model)
# カルマンフィルタの実装には、statsmodelsまたはpymc3などが必要です
# ここでは簡略化しています

# 7. 長短期記憶 (LSTM) ネットワーク
# データの前処理
scaler = StandardScaler()
scaled_data = scaler.fit_transform(df[['Value']].values)

# データの準備
X, y = [], []
for i in range(len(scaled_data) - 10):
    X.append(scaled_data[i:i+10])
    y.append(scaled_data[i+10])
X, y = np.array(X), np.array(y)

# モデルの構築
model = Sequential()
model.add(LSTM(50, activation='relu', input_shape=(X.shape[1], 1)))
model.add(Dense(1))
model.compile(optimizer='adam', loss='mse')
model.fit(X, y, epochs=200, verbose=0)

# 予測
X_pred = np.array(scaled_data[-10:]).reshape(1, 10, 1)
lstm_pred = model.predict(X_pred)
lstm_pred = scaler.inverse_transform(lstm_pred)

# 8. 変化点検出 (Change Point Detection)
model = rpt.Pelt(model="l2").fit(df['Value'])
result = model.predict(pen=10)

# 9. スペクトル解析 (Spectral Analysis)
N = len(df['Value'])
T = 1.0 / 1.0
yf = fft(df['Value'])
xf = fftfreq(N, T)[:N//2]

# 10. グレンジャー因果性検定 (Granger Causality Test)
# ここでは2つの時系列が必要ですが、サンプルデータでは1つのみなので省略します

# プロット
plt.figure(figsize=(14, 12))

# 移動平均
plt.subplot(4, 2, 1)
plt.plot(df.index, df['Value'], label='Original Data')
plt.plot(df.index, df['SMA_10'], label='SMA 10')
plt.plot(df.index, df['EMA_10'], label='EMA 10')
plt.title('Moving Averages')
plt.legend()

# 自己回帰モデル
plt.subplot(4, 2, 2)
plt.plot(df.index, df['Value'], label='Original Data')
plt.plot(pd.date_range(start=df.index[-1], periods=11, closed='right'), df['AR_Prediction'], label='AR Prediction', linestyle='--')
plt.title('AutoRegressive Model')
plt.legend()

# ARIMAモデル
plt.subplot(4, 2, 3)
plt.plot(df.index, df['Value'], label='Original Data')
plt.plot(pd.date_range(start=df.index[-1], periods=11, closed='right'), df['ARIMA_Prediction'], label='ARIMA Prediction', linestyle='--')
plt.title('ARIMA Model')
plt.legend()

# 季節調整
plt.subplot(4, 2, 4)
plt.plot(df.index, df['Value'], label='Original Data')
plt.plot(df.index, df['Trend'], label='Trend')
plt.plot(df.index, df['Seasonal'], label='Seasonal')
plt.plot(df.index, df['Residual'], label='Residual')
plt.title('Seasonal Decomposition')
plt.legend()

# LSTM予測
plt.subplot(4, 2, 5)
plt.plot(df.index, df['Value'], label='Original Data')
plt.axvline(df.index[-1], color='gray', linestyle='--')
plt.scatter(df.index[-1] + pd.DateOffset(days=1), lstm_pred, color='red', label='LSTM Prediction')
plt.title('LSTM Prediction')
plt.legend()

# 変化点検出
plt.subplot(4, 2, 6)
plt.plot(df.index, df['Value'], label='Original Data')
for cp in result:
    plt.axvline(df.index[cp], color='red', linestyle='--')
plt.title('Change Point Detection')
plt.legend()

# スペクトル解析
plt.subplot(4, 2, 7)
plt.plot(xf, 2.0/N * np.abs(yf[0:N//2]))
plt.title('Spectral Analysis')

plt.tight_layout()
plt.show()
```
```
import numpy as np
import matplotlib.pyplot as plt

# Define Delta Function
def delta(t):
    return np.where(t == 0, 1, 0)

# Define Constant Function
def constant(t):
    return np.ones_like(t)

# Define Rectangular Pulse
def rectangular_pulse(t, width):
    return np.where(np.abs(t) < width / 2, 1 / width, 0)

# Define Triangular Pulse
def triangular_pulse(t, width):
    return np.where(np.abs(t) <= width / 2, 2 / width * (1 - np.abs(t) / (width / 2)), 0)

# Define Exponential Pulse
def exponential_pulse(t, a):
    return np.where(t >= 0, (1 / a) * np.exp(-t / a), 0)

# Define Gaussian Pulse
def gaussian_pulse(t, width):
    return (1 / np.sqrt(2 * np.pi * width ** 2)) * np.exp(-t ** 2 / (2 * width ** 2))

# Fourier Transforms
def exp_pulse_transform(omega, a):
    return 1 / (a + 1j * omega)

def gaussian_transform(omega, width):
    return np.sqrt(2 * np.pi * width ** 2) * np.exp(-0.5 * width ** 2 * omega ** 2)

# Time and Frequency domains
t = np.linspace(-5, 5, 1000)
omega = np.linspace(-50, 50, 1000)

# Functions
delta_func = delta(t)
constant_func = constant(t)
rect_pulse = rectangular_pulse(t, 2)
triangular_pulse_func = triangular_pulse(t, 2)
exp_pulse = exponential_pulse(t, 1)
gaussian_pulse_func = gaussian_pulse(t, 1)

# Fourier Transforms
delta_transform = np.ones_like(omega)
constant_transform = 2 * np.pi * delta(omega)
rect_transform = np.sinc(omega / (2 * np.pi))
triangular_transform = (2 * (1 - np.cos(omega))) / (omega ** 2)
triangular_transform[omega == 0] = 2
exp_transform = np.abs(exp_pulse_transform(omega, 1))
gaussian_transform_func = gaussian_transform(omega, 1)

# Plot
plt.figure(figsize=(15, 15))

# Delta Function
plt.subplot(3, 2, 1)
plt.plot(t, delta_func, label='Delta Function')
plt.title('Delta Function')
plt.grid(True)

plt.subplot(3, 2, 2)
plt.plot(omega, delta_transform, label='Fourier Transform', color='r')
plt.title('Fourier Transform of Delta Function')
plt.grid(True)

# Constant Function
plt.subplot(3, 2, 3)
plt.plot(t, constant_func, label='Constant Function')
plt.title('Constant Function')
plt.grid(True)

plt.subplot(3, 2, 4)
plt.plot(omega, constant_transform, label='Fourier Transform', color='r')
plt.title('Fourier Transform of Constant Function')
plt.grid(True)

# Rectangular Pulse
plt.subplot(3, 2, 5)
plt.plot(t, rect_pulse, label='Rectangular Pulse')
plt.title('Rectangular Pulse')
plt.grid(True)

plt.subplot(3, 2, 6)
plt.plot(omega, rect_transform, label='Fourier Transform', color='r')
plt.title('Fourier Transform of Rectangular Pulse')
plt.grid(True)

plt.tight_layout()
plt.show()

# Additional plots for Triangular Pulse, Exponential Pulse, and Gaussian Pulse
plt.figure(figsize=(15, 15))

# Triangular Pulse
plt.subplot(3, 2, 1)
plt.plot(t, triangular_pulse_func, label='Triangular Pulse')
plt.title('Triangular Pulse')
plt.grid(True)

plt.subplot(3, 2, 2)
plt.plot(omega, triangular_transform, label='Fourier Transform', color='r')
plt.title('Fourier Transform of Triangular Pulse')
plt.grid(True)

# Exponential Pulse
plt.subplot(3, 2, 3)
plt.plot(t, exp_pulse, label='Exponential Pulse')
plt.title('Exponential Pulse')
plt.grid(True)

plt.subplot(3, 2, 4)
plt.plot(omega, exp_transform, label='Magnitude of Fourier Transform', color='r')
plt.title('Fourier Transform of Exponential Pulse')
plt.grid(True)

# Gaussian Pulse
plt.subplot(3, 2, 5)
plt.plot(t, gaussian_pulse_func, label='Gaussian Pulse')
plt.title('Gaussian Pulse')
plt.grid(True)

plt.subplot(3, 2, 6)
plt.plot(omega, gaussian_transform_func, label='Fourier Transform', color='r')
plt.title('Fourier Transform of Gaussian Pulse')
plt.grid(True)

plt.tight_layout()
plt.show()
```





```
import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import butter, lfilter, get_window

# Sampling parameters
Fs = 1000  # Sampling frequency (Hz)
T = 1.0 / Fs  # Sampling interval (seconds)
L = 1000  # Number of samples
t = np.arange(L) * T  # Time vector

# Generate analog signal (e.g., sine wave) and sample it
f = 50  # Signal frequency (Hz)
amplitude = 1.0
y = amplitude * np.sin(2 * np.pi * f * t)  # Signal data

# Add noise
noise = 0.1 * np.random.normal(size=t.shape)
y_noisy = y + noise

# Bias correction (subtract mean to center around zero)
y_corrected = y_noisy - np.mean(y_noisy)

# Anti-aliasing filter design (e.g., low-pass filter)
def butter_lowpass(cutoff, fs, order=5):
    nyq = 0.5 * fs
    normal_cutoff = cutoff / nyq
    b, a = butter(order, normal_cutoff, btype='low', analog=False)
    return b, a

def butter_lowpass_filter(data, cutoff, fs, order=5):
    b, a = butter_lowpass(cutoff, fs, order=order)
    y = lfilter(b, a, data)
    return y

cutoff_frequency = 100  # Cutoff frequency (Hz)
y_filtered = butter_lowpass_filter(y_corrected, cutoff_frequency, Fs)

# Apply window function (e.g., Hamming window)
window = get_window('hamming', L)
y_windowed = y_filtered * window

# Perform FFT
yf = np.fft.fft(y_windowed)
xf = np.fft.fftfreq(L, T)

# Plot the original sampled signal
plt.figure(figsize=(12, 6))

plt.subplot(2, 1, 1)
plt.plot(t, y_noisy, label='Noisy Signal')
plt.plot(t, y, label='Original Signal', linestyle='--')
plt.title('Time Domain Signal')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.legend()
plt.grid()

# Plot the FFT result
plt.subplot(2, 1, 2)
plt.plot(xf[:L//2], 2.0/L * np.abs(yf[:L//2]))
plt.title('Frequency Domain (FFT)')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Amplitude')
plt.grid()

plt.tight_layout()
plt.show()


```



```

import numpy as np
import matplotlib.pyplot as plt

# 定義: アナログ信号のパラメータ
frequency = 5        # サイン波の周波数 (Hz)
amplitude = 1        # サイン波の振幅 (V)
duration = 1         # 信号の継続時間 (s)
sampling_rate = 100  # サンプリングレート (サンプル/秒)
adc_resolution = 8   # ADC解像度 (ビット)

# アナログ信号を生成 (連続サイン波)
t_analog = np.linspace(0, duration, 1000)  # アナログ信号の時間ベクトル
analog_signal = amplitude * np.sin(2 * np.pi * frequency * t_analog)

# アナログ信号をサンプリング
t_sampled = np.linspace(0, duration, int(sampling_rate * duration))  # サンプリング信号の時間ベクトル
sampled_signal = amplitude * np.sin(2 * np.pi * frequency * t_sampled)

# サンプリング信号を量子化
quantization_levels = 2 ** adc_resolution  # 量子化レベルの数
quantization_step = 2 * amplitude / quantization_levels  # 量子化ステップサイズ
quantized_signal = np.round(sampled_signal / quantization_step) * quantization_step

# フーリエ変換を行い、パワースペクトルを計算
fft_result = np.fft.fft(quantized_signal)
fft_freq = np.fft.fftfreq(len(fft_result), d=1/sampling_rate)
power_spectrum = np.abs(fft_result) ** 2

# パワースペクトルをプロット
plt.figure(figsize=(10, 6))

# パワースペクトルをプロット
plt.plot(fft_freq[:len(fft_freq)//2], power_spectrum[:len(power_spectrum)//2], label='Power Spectrum')

# ラベルと凡例を追加
plt.xlabel('Frequency (Hz)')
plt.ylabel('Power')
plt.title('Power Spectrum of Quantized Signal')
plt.legend()
plt.grid(True)

# プロットを表示
plt.show()

```

```

import numpy as np
import matplotlib.pyplot as plt

# パラメータ設定
n_bits = 8  # ADCのビット数
quantization_levels = 2**n_bits  # 量子化レベル数
amplitude = 1.0  # 入力信号の振幅
frequency = 1000  # 入力信号の周波数 (Hz)
sampling_rate = 10000  # サンプリングレート (Hz)
duration = 1.0  # 信号の継続時間 (秒)

# 時間軸の生成
t = np.arange(0, duration, 1/sampling_rate)

# サイン波の生成
signal = amplitude * np.sin(2 * np.pi * frequency * t)

# 理想的なADC変換
ideal_adc_output = np.round((signal + amplitude) * (quantization_levels / (2 * amplitude))) - 1

# 非理想的なADCの誤差のシミュレーション
# DNLとINLをシミュレート（簡略化したモデル）
dnl = np.random.normal(0, 0.01, quantization_levels)
inl = np.cumsum(dnl) - np.mean(np.cumsum(dnl))

# 実際のADC出力（DNLとINLを含む）
adc_output = ideal_adc_output + dnl[(ideal_adc_output).astype(int)] + inl[(ideal_adc_output).astype(int)]
adc_output = np.clip(adc_output, 0, quantization_levels - 1)

# DNLとINLのプロット
plt.figure(figsize=(14, 8))

plt.subplot(2, 2, 1)
plt.plot(dnl)
plt.title("Differential Non-Linearity (DNL)")
plt.xlabel("Code")
plt.ylabel("DNL (LSB)")

plt.subplot(2, 2, 2)
plt.plot(inl)
plt.title("Integral Non-Linearity (INL)")
plt.xlabel("Code")
plt.ylabel("INL (LSB)")

# SNDRの計算
noise = adc_output - ideal_adc_output
signal_power = np.mean(signal**2)
noise_power = np.mean(noise**2)
snr = 10 * np.log10(signal_power / noise_power)

# SNDR (Signal to Noise and Distortion Ratio)
sndr = 10 * np.log10(signal_power / (noise_power + np.var(dnl) + np.var(inl)))

# SFDR (Spurious-Free Dynamic Range)
sfdr = 10 * np.log10(signal_power / np.max(np.abs(noise)))

# ENOB (Effective Number of Bits)
enob = (sndr - 1.76) / 6.02

print(f"SNR: {snr:.2f} dB")
print(f"SNDR: {sndr:.2f} dB")
print(f"SFDR: {sfdr:.2f} dB")
print(f"ENOB: {enob:.2f} bits")

# ノイズプロット
plt.subplot(2, 2, 3)
plt.plot(noise)
plt.title("Quantization Noise")
plt.xlabel("Sample")
plt.ylabel("Noise")

# 入力信号とADC出力の比較プロット
plt.subplot(2, 2, 4)
plt.plot(t, signal, label='Original Signal')
plt.plot(t, adc_output / (quantization_levels / (2 * amplitude)) - amplitude, label='ADC Output', linestyle='dashed')
plt.title("Original Signal vs ADC Output")
plt.xlabel("Time [s]")
plt.ylabel("Amplitude")
plt.legend()

plt.tight_layout()
plt.show()


```


```




import numpy as np
import matplotlib.pyplot as plt

# サイン波のパラメータ
amplitude = 1.0  # 振幅
frequency = 1000  # 周波数 (Hz)
sampling_rate = 10000  # サンプリングレート (Hz)
duration = 1.0  # 信号の継続時間 (秒)
quantization_levels = 256  # 量子化レベル数（8ビットの場合）
kT = 4.11e-21  # 熱雑音の電力スペクトル密度 (Joules per Hz)

# 時間軸の生成
t = np.arange(0, duration, 1/sampling_rate)

# サイン波の生成
signal = amplitude * np.sin(2 * np.pi * frequency * t)

# 信号エネルギーの計算
signal_energy = np.sum(signal**2) / sampling_rate
print(f"Signal Energy: {signal_energy:.6f} J")

# ノイズの生成（標準正規分布）
noise_std = 0.1  # 標準偏差
noise = np.random.normal(0, noise_std, len(signal))

# ノイズを含む信号
noisy_signal = signal + noise

# SNRの計算
signal_power = np.mean(signal**2)
noise_power = np.mean(noise**2)
snr = 10 * np.log10(signal_power / noise_power)
print(f"SNR: {snr:.2f} dB")

# ENOBの計算 (Effective Number of Bits)
enob = (snr - 1.76) / 6.02
print(f"ENOB: {enob:.2f} bits")

# 熱雑音の計算
bandwidth = sampling_rate / 2  # 有効帯域幅（Nyquist周波数）
thermal_noise_power = kT * bandwidth
print(f"Thermal Noise Power: {thermal_noise_power:.6e} W")

# サンプリングジッタの影響（簡略化）
jitter_std = 1e-12  # ジッタの標準偏差 (秒)
jitter_noise_power = (2 * np.pi * frequency * amplitude * jitter_std)**2
print(f"Jitter Noise Power: {jitter_noise_power:.6e} W")

# 量子化ノイズの計算
quantization_step = 2 * amplitude / quantization_levels
quantization_noise_power = quantization_step**2 / 12
print(f"Quantization Noise Power: {quantization_noise_power:.6e} W")

# 全ノイズ電力の計算
total_noise_power = noise_power + thermal_noise_power + jitter_noise_power + quantization_noise_power
print(f"Total Noise Power: {total_noise_power:.6e} W")

# グラフのプロット
plt.figure(figsize=(10, 6))
plt.plot(t, signal, label='Original Signal')
plt.plot(t, noisy_signal, label='Noisy Signal', linestyle='dashed')
plt.xlabel('Time [s]')
plt.ylabel('Amplitude')
plt.title('Original vs Noisy Signal')
plt.legend()
plt.show()

```

```
import numpy as np
import matplotlib.pyplot as plt
from scipy.fft import fft, fftfreq

# Parameters
fs = 1000  # Sampling frequency (Hz)
T = 1.0    # Duration (seconds)
N = int(T * fs)  # Number of samples
t = np.linspace(0.0, T, N, endpoint=False)

# Waveforms
def sine_wave(frequency, amplitude):
    return amplitude * np.sin(2 * np.pi * frequency * t)

def square_wave(frequency, amplitude):
    return amplitude * np.sign(np.sin(2 * np.pi * frequency * t))

def triangle_wave(frequency, amplitude):
    return amplitude * (2 * np.abs(2 * (t * frequency - np.floor(t * frequency + 0.5))) - 1)

def full_wave_rectified_wave(frequency, amplitude):
    return np.abs(sine_wave(frequency, amplitude))

def unipolar_pulse_wave(frequency, amplitude, duty_cycle):
    return amplitude * ((t % (1 / frequency)) < (duty_cycle / frequency))

def gaussian_noise(std_dev):
    return np.random.normal(0, std_dev, N)

# Parameters for waves
f_sine = 5
f_square = 5
f_triangle = 5
f_rectified = 5
f_pulse = 5
duty_cycle = 0.5
std_dev_noise = 0.5

# Generate waveforms
sine = sine_wave(f_sine, 1)
square = square_wave(f_square, 1)
triangle = triangle_wave(f_triangle, 1)
rectified = full_wave_rectified_wave(f_rectified, 1)
pulse = unipolar_pulse_wave(f_pulse, 1, duty_cycle)
noise = gaussian_noise(std_dev_noise)

# Compute FFT
def compute_fft(signal):
    yf = fft(signal)
    xf = fftfreq(N, 1/fs)
    return xf, np.abs(yf) / N

# Compute metrics
def compute_metrics(signal):
    rms = np.sqrt(np.mean(signal**2))
    average = np.mean(signal)
    abs_mean = np.mean(np.abs(signal))
    peak_to_peak_ratio = np.max(signal) - np.min(signal)
    return rms, average, abs_mean, peak_to_peak_ratio

# Plot waveforms and FFTs
fig, axs = plt.subplots(6, 2, figsize=(14, 18))
axs = axs.flatten()

waveforms = [sine, square, triangle, rectified, pulse, noise]
titles = ['Sine Wave', 'Square Wave', 'Triangle Wave', 'Full-Wave Rectified Wave', 'Unipolar Pulse Wave', 'Gaussian Noise']

for i, (wave, title) in enumerate(zip(waveforms, titles)):
    # Plot waveform
    axs[2*i].plot(t, wave)
    axs[2*i].set_title(f'{title}')
    axs[2*i].set_xlabel('Time [s]')
    axs[2*i].set_ylabel('Amplitude')
    
    # Compute and plot FFT
    xf, yf = compute_fft(wave)
    axs[2*i+1].plot(xf[:N // 2], yf[:N // 2])
    axs[2*i+1].set_title(f'{title} - FFT')
    axs[2*i+1].set_xlabel('Frequency [Hz]')
    axs[2*i+1].set_ylabel('Magnitude')

    # Compute metrics
    rms, average, abs_mean, peak_to_peak_ratio = compute_metrics(wave)
    print(f"{title} Metrics:")
    print(f"  RMS: {rms:.3f}")
    print(f"  Average: {average:.3f}")
    print(f"  Absolute Mean: {abs_mean:.3f}")
    print(f"  Peak-to-Peak Ratio: {peak_to_peak_ratio:.3f}\n")

plt.tight_layout()
plt.show()
```

```

import numpy as np
import matplotlib.pyplot as plt
from scipy.fft import fft, fftfreq

# Define time-domain waveforms
def sine_wave(t, f0):
    return np.sin(2 * np.pi * f0 * t)

def square_wave(t, f0):
    return np.sign(np.sin(2 * np.pi * f0 * t))

def triangular_wave(t, f0):
    return 2 * np.abs(2 * (t * f0 % 1) - 1) - 1

def full_wave_rectified_sine(t, f0):
    return np.abs(np.sin(2 * np.pi * f0 * t))

def half_wave_rectified_sine(t, f0):
    return np.maximum(0, np.sin(2 * np.pi * f0 * t))

# Define Gaussian function for approximation
def gaussian_transform(f, f0, sigma):
    return np.exp(-0.5 * ((f - f0) / sigma) ** 2)

# Define Gaussian approximations
def square_wave_transform(f, f0, sigma, num_harmonics):
    X = np.zeros_like(f)
    for n in range(1, num_harmonics + 1):
        X += gaussian_transform(f, n * f0, sigma)
    return X

def triangular_wave_transform(f, f0, sigma, num_harmonics):
    X = np.zeros_like(f)
    for n in range(1, num_harmonics + 1):
        X += gaussian_transform(f, n * f0, sigma) / n**2
    return X

def full_wave_rectified_sine_transform(f, f0, sigma):
    return (0.5 * (gaussian_transform(f, 2 * f0, sigma) + gaussian_transform(f, -2 * f0, sigma))
            + 0.25 * (gaussian_transform(f, 0, sigma) - gaussian_transform(f, 4 * f0, sigma) - gaussian_transform(f, -4 * f0, sigma)))

def half_wave_rectified_sine_transform(f, f0, sigma):
    return 0.5 * (gaussian_transform(f, f0, sigma) + gaussian_transform(f, -f0, sigma)
                   - 0.25 * (gaussian_transform(f, 2 * f0, sigma) + gaussian_transform(f, -2 * f0, sigma)))

# Parameters
f0 = 5  # Fundamental frequency
sigma = 0.5  # Standard deviation of the Gaussian
num_harmonics = 10  # Number of harmonics

# Frequency range
f = np.linspace(-20, 20, 400)

# Time domain
T = 1 / (2 * f0)  # Sampling period
t = np.linspace(0, 2 * T, 1000)  # Time range

# Generate time-domain waveforms
sine = sine_wave(t, f0)
square = square_wave(t, f0)
triangular = triangular_wave(t, f0)
full_wave_rectified = full_wave_rectified_sine(t, f0)
half_wave_rectified = half_wave_rectified_sine(t, f0)

# Compute FFT
def compute_fft(signal, T):
    N = len(signal)
    yf = fft(signal)
    xf = fftfreq(N, T)[:N//2]
    return xf, np.abs(yf[:N//2])

# FFT results
xf_sine, yf_sine = compute_fft(sine, t[1] - t[0])
xf_square, yf_square = compute_fft(square, t[1] - t[0])
xf_triangular, yf_triangular = compute_fft(triangular, t[1] - t[0])
xf_full_wave_rectified, yf_full_wave_rectified = compute_fft(full_wave_rectified, t[1] - t[0])
xf_half_wave_rectified, yf_half_wave_rectified = compute_fft(half_wave_rectified, t[1] - t[0])

# Plotting Gaussian Approximations
plt.figure(figsize=(14, 10))

plt.subplot(3, 2, 1)
plt.plot(f, gaussian_transform(f, f0, sigma))
plt.title('Gaussian Approximation of Sine Wave')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.subplot(3, 2, 2)
plt.plot(f, square_wave_transform(f, f0, sigma, num_harmonics))
plt.title('Gaussian Approximation of Square Wave')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.subplot(3, 2, 3)
plt.plot(f, triangular_wave_transform(f, f0, sigma, num_harmonics))
plt.title('Gaussian Approximation of Triangular Wave')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.subplot(3, 2, 4)
plt.plot(f, full_wave_rectified_sine_transform(f, f0, sigma))
plt.title('Gaussian Approximation of Full-Wave Rectified Sine Wave')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.subplot(3, 2, 5)
plt.plot(f, half_wave_rectified_sine_transform(f, f0, sigma))
plt.title('Gaussian Approximation of Half-Wave Rectified Sine Wave')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.tight_layout()
plt.show()

# Plotting FFT results
plt.figure(figsize=(14, 10))

plt.subplot(3, 2, 1)
plt.plot(xf_sine, yf_sine)
plt.title('FFT of Sine Wave')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.subplot(3, 2, 2)
plt.plot(xf_square, yf_square)
plt.title('FFT of Square Wave')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.subplot(3, 2, 3)
plt.plot(xf_triangular, yf_triangular)
plt.title('FFT of Triangular Wave')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.subplot(3, 2, 4)
plt.plot(xf_full_wave_rectified, yf_full_wave_rectified)
plt.title('FFT of Full-Wave Rectified Sine Wave')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.subplot(3, 2, 5)
plt.plot(xf_half_wave_rectified, yf_half_wave_rectified)
plt.title('FFT of Half-Wave Rectified Sine Wave')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.tight_layout()
plt.show()

```


```
import numpy as np
import matplotlib.pyplot as plt

# サンプル数とサンプリング周波数を定義
n_samples = 1024
sampling_rate = 1024  # 1kHzのサンプリング

# ホワイトノイズを生成
white_noise = np.random.normal(0, 1, n_samples)

# FFTを計算
fft_result = np.fft.fft(white_noise)
fft_magnitude = np.abs(fft_result)
fft_phase = np.angle(fft_result)
frequencies = np.fft.fftfreq(n_samples, d=1/sampling_rate)

# グラフを描画
plt.figure(figsize=(14, 12))

# 1. 時間領域の波形プロット
plt.subplot(3, 1, 1)
plt.plot(white_noise, color='green')
plt.title('White Noise - Time Domain')
plt.xlabel('Sample')
plt.ylabel('Amplitude')
plt.grid(True)

# 2. FFTのプロット（周波数スペクトル）
plt.subplot(3, 1, 2)
plt.plot(frequencies[:n_samples//2], fft_magnitude[:n_samples//2], color='blue')
plt.title('FFT of White Noise')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

# 3. ボード線図プロット
# 3.1 ゲインプロット (Magnitude)
plt.subplot(3, 1, 3)
plt.semilogx(frequencies[:n_samples//2], 20 * np.log10(fft_magnitude[:n_samples//2]), color='blue', label='Magnitude (dB)')
plt.ylabel('Magnitude (dB)')
plt.xlabel('Frequency (Hz)')
plt.grid(True)
plt.legend(loc='upper right')

# 3.2 位相プロット (Phase)
plt.twinx()
plt.semilogx(frequencies[:n_samples//2], np.degrees(fft_phase[:n_samples//2]), color='red', linestyle='--', label='Phase (degrees)')
plt.ylabel('Phase (degrees)')
plt.grid(True)
plt.legend(loc='lower right')

plt.title('Bode Plot of White Noise')

# レイアウト調整
plt.tight_layout()
plt.show()


```


```


import numpy as np
import matplotlib.pyplot as plt

# パラメータ設定
fs = 1000  # サンプリング周波数 (Hz)
T = 1.0 / fs  # サンプリング間隔 (秒)
L = 2.0  # 信号の長さ (秒)
N = int(L * fs)  # 信号のサンプル数

# 時間ベクトル
t = np.linspace(0.0, L, N, endpoint=False)

# ディラックのデルタ関数をサンプル化した単位デルタ関数列
delta_seq = np.zeros(N)
delta_seq[int(N / 2)] = 1  # 中心に1を配置

# ガウシアン関数を生成
sigma = 0.01  # ガウス関数の標準偏差 (秒)
mu = L / 2  # ガウス関数の中心 (秒)
gaussian = np.exp(-((t - mu) ** 2) / (2 * sigma ** 2))

# 大きな値を持つデルタ関数に近い関数を生成
alpha = 1000000000  # 大きな値を持つデルタ関数に近い関数のスケーリングファクタ
delta_approx = np.zeros(N)
delta_approx[int(N / 2)] = alpha  # 中心に大きな値を配置

# ホワイトノイズ
np.random.seed(0)  # 再現性のためのシード
white_noise = np.random.normal(0, 1, N)

# FFTを計算
fft_delta = np.fft.fft(delta_seq)
fft_gaussian = np.fft.fft(gaussian)
fft_delta_approx = np.fft.fft(delta_approx)
fft_white_noise = np.fft.fft(white_noise)

# 周波数ベクトル
frequencies = np.fft.fftfreq(N, T)

# デルタ関数のフーリエ変換
omega = np.linspace(-10, 10, 1000)
delta_hat = np.ones_like(omega)  # 理論的に全ての周波数で1

# プロット
plt.figure(figsize=(16, 14))

# ディラックのデルタ関数のサンプル化プロット
plt.subplot(4, 2, 1)
plt.plot(t, delta_seq, label='Unit Delta Function Sequence')
plt.title('Unit Delta Function Sequence')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.grid(True)

# ガウシアン関数のプロット
plt.subplot(4, 2, 2)
plt.plot(t, gaussian, label='Gaussian Approximation of Delta Function')
plt.title('Gaussian Approximation of Delta Function')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.grid(True)

# 大きな値を持つデルタ関数に近い関数のプロット
plt.subplot(4, 2, 3)
plt.plot(t, delta_approx, label='Delta Approximation with Large Value', color='green')
plt.title('Delta Approximation with Large Value')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.grid(True)

# ホワイトノイズのプロット
plt.subplot(4, 2, 4)
plt.plot(t, white_noise, label='White Noise', color='orange')
plt.title('White Noise')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.grid(True)

# ディラックのデルタ関数のFFTプロット
plt.subplot(4, 2, 5)
plt.plot(frequencies, np.abs(fft_delta), label='FFT of Delta Sequence')
plt.title('FFT of Delta Sequence')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

# ガウシアン関数のFFTプロット
plt.subplot(4, 2, 6)
plt.plot(frequencies, np.abs(fft_gaussian), label='FFT of Gaussian Approximation')
plt.title('FFT of Gaussian Approximation')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

# 大きな値を持つデルタ関数のFFTプロット
plt.subplot(4, 2, 7)
plt.plot(frequencies, np.abs(fft_delta_approx), label='FFT of Delta Approximation with Large Value', color='green')
plt.title('FFT of Delta Approximation with Large Value')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

# ホワイトノイズのFFTプロット
plt.subplot(4, 2, 8)
plt.plot(frequencies, np.abs(fft_white_noise), label='FFT of White Noise', color='orange')
plt.title('FFT of White Noise')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

# ディラックのデルタ関数のフーリエ変換プロット
plt.figure(figsize=(8, 4))
plt.plot(omega, delta_hat, label=r"$\hat{\delta}(\omega) = 1$")
plt.title(r"Fourier Transform of Dirac Delta Function $\delta(t)$")
plt.xlabel(r"Frequency $\omega$")
plt.ylabel(r"$\hat{\delta}(\omega)$")
plt.axhline(0, color='black', linewidth=0.5)
plt.axvline(0, color='black', linewidth=0.5)
plt.grid(True)
plt.legend()
plt.show()
```

```

import numpy as np
import matplotlib.pyplot as plt
from scipy.signal import lfilter

# パラメータ設定
fs = 1000  # サンプリング周波数 (Hz)
T = 1.0 / fs  # サンプリング間隔 (秒)
L = 2.0  # 信号の長さ (秒)
N = int(L * fs)  # サンプル数

# 時間ベクトル
t = np.linspace(0.0, L, N, endpoint=False)

# ピンクノイズの生成
def generate_pink_noise(N):
    """ Generate pink noise using the Voss-McCartney algorithm """
    def pink_filter(n, beta):
        return np.sin(np.pi * (np.arange(1, n+1) / (n+1)) ** beta) ** 2
    
    white = np.random.randn(N)
    freq = np.fft.fftfreq(N, T)
    filter = pink_filter(N, 1)
    pink = np.fft.ifft(np.fft.fft(white) * filter).real
    return pink

pink_noise = generate_pink_noise(N)

# ノイズシェーピングフィルタ (例えば、簡単な1次IIRフィルタ)
b = [1, -0.9]  # フィルタの係数 (例: 一次IIRフィルタ)
a = [1]  # フィルタの係数
shaped_noise = lfilter(b, a, pink_noise)

# フーリエ変換を計算
fft_pink_noise = np.fft.fftshift(np.fft.fft(pink_noise))
fft_shaped_noise = np.fft.fftshift(np.fft.fft(shaped_noise))
fft_pink_noise_magnitude = np.abs(fft_pink_noise)
fft_shaped_noise_magnitude = np.abs(fft_shaped_noise)
frequencies = np.fft.fftshift(np.fft.fftfreq(N, T))

# プロット
plt.figure(figsize=(16, 12))

# ピンクノイズのプロット
plt.subplot(3, 2, 1)
plt.plot(t, pink_noise, label='Pink Noise')
plt.title('Pink Noise')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.grid(True)

# ノイズシェーピング後の信号のプロット
plt.subplot(3, 2, 2)
plt.plot(t, shaped_noise, label='Shaped Noise')
plt.title('Shaped Noise')
plt.xlabel('Time (s)')
plt.ylabel('Amplitude')
plt.grid(True)

# ピンクノイズのフーリエ変換のプロット
plt.subplot(3, 2, 3)
plt.plot(frequencies, fft_pink_noise_magnitude, label='FFT of Pink Noise')
plt.title('Fourier Transform of Pink Noise')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

# ノイズシェーピング後の信号のフーリエ変換のプロット
plt.subplot(3, 2, 4)
plt.plot(frequencies, fft_shaped_noise_magnitude, label='FFT of Shaped Noise')
plt.title('Fourier Transform of Shaped Noise')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

# ピンクノイズのパワースペクトル
plt.subplot(3, 2, 5)
plt.semilogy(frequencies[1:N//2], np.abs(fft_pink_noise[1:N//2]), label='Power Spectrum of Pink Noise')
plt.title('Power Spectrum of Pink Noise')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

# ノイズシェーピング後の信号のパワースペクトル
plt.subplot(3, 2, 6)
plt.semilogy(frequencies[1:N//2], np.abs(fft_shaped_noise[1:N//2]), label='Power Spectrum of Shaped Noise')
plt.title('Power Spectrum of Shaped Noise')
plt.xlabel('Frequency (Hz)')
plt.ylabel('Magnitude')
plt.grid(True)

plt.tight_layout()
plt.show()
```


```

import numpy as np
import matplotlib.pyplot as plt

def calculate_sndr_enob_sfdr(fft_data, fundamental_freq_bin, fs, fin, fft_points):
    """
    Calculate SNDR, ENOB, and SFDR from FFT data of an ADC.
    
    Parameters:
    fft_data (numpy array): FFT magnitude data.
    fundamental_freq_bin (int): Index of the fundamental frequency in the FFT data.
    fs (float): Sampling frequency in Hz.
    fin (float): Input frequency in Hz.
    fft_points (int): Number of FFT points.

    Returns:
    sndr_db (float): Signal-to-Noise and Distortion Ratio in dB.
    enob (float): Effective Number of Bits.
    sfdr_db (float): Spurious-Free Dynamic Range in dB.
    """
    # Calculate signal power
    signal_power = fft_data[fundamental_freq_bin] ** 2
    
    # Calculate total power
    total_power = np.sum(fft_data ** 2)
    
    # Calculate noise and distortion power
    noise_distortion_power = total_power - signal_power
    
    # Calculate SNDR (dB)
    sndr_db = 10 * np.log10(signal_power / noise_distortion_power)
    
    # Calculate ENOB
    enob = (sndr_db - 1.76) / 6.02
    
    # Calculate SFDR (dB)
    # Find the maximum spurious signal excluding the fundamental frequency
    spurious_power = np.max(np.delete(fft_data ** 2, fundamental_freq_bin))
    sfdr_db = 10 * np.log10(signal_power / spurious_power)
    
    return sndr_db, enob, sfdr_db

# Define parameters
fs = 1e6  # Sampling frequency in Hz (1 MSPS)
fin = 124.511e3  # Input frequency in Hz (124.511 kHz)
fft_points = 2048  # FFT points
t = np.arange(0, fft_points) / fs  # Time vector

# Create a sinusoidal waveform with the given amplitude and frequency
input_amplitude = 0.3  # 0.3 V
waveform = input_amplitude * np.sin(2 * np.pi * fin * t)

# Perform FFT
fft_data = np.abs(np.fft.fft(waveform))[:fft_points // 2]  # Take positive frequency components

# Find fundamental frequency bin
fundamental_freq_bin = int(fin / (fs / fft_points))

# Calculate SNDR, ENOB, and SFDR
sndr_db, enob, sfdr_db = calculate_sndr_enob_sfdr(fft_data, fundamental_freq_bin, fs, fin, fft_points)

print(f"SNDR: {sndr_db:.2f} dB")
print(f"ENOB: {enob:.2f} bits")
print(f"SFDR: {sfdr_db:.2f} dB")

# Plot time-domain waveform
plt.figure(figsize=(12, 6))

plt.subplot(1, 2, 1)
plt.plot(t * 1e3, waveform)
plt.title('Time-Domain Waveform')
plt.xlabel('Time (ms)')
plt.ylabel('Amplitude (V)')

# Plot frequency-domain FFT
freq = np.fft.fftfreq(fft_points, d=1/fs)[:fft_points // 2]  # Frequency vector
plt.subplot(1, 2, 2)
plt.plot(freq / 1e3, 20 * np.log10(fft_data))  # Convert FFT magnitude to dB
plt.title('Frequency-Domain FFT')
plt.xlabel('Frequency (kHz)')
plt.ylabel('Magnitude (dB)')

plt.tight_layout()
plt.show()
```






```
import numpy as np
import matplotlib.pyplot as plt

def calculate_sndr_enob_sfdr(fft_data, fundamental_freq_bin, fs, fin, fft_points):
    """
    Calculate SNDR, ENOB, and SFDR from FFT data of an ADC.
    
    Parameters:
    fft_data (numpy array): FFT magnitude data.
    fundamental_freq_bin (int): Index of the fundamental frequency in the FFT data.
    fs (float): Sampling frequency in Hz.
    fin (float): Input frequency in Hz.
    fft_points (int): Number of FFT points.

    Returns:
    sndr_db (float): Signal-to-Noise and Distortion Ratio in dB.
    enob (float): Effective Number of Bits.
    sfdr_db (float): Spurious-Free Dynamic Range in dB.
    """
    # Calculate signal power
    signal_power = fft_data[fundamental_freq_bin] ** 2
    
    # Calculate total power
    total_power = np.sum(fft_data ** 2)
    
    # Calculate noise and distortion power
    noise_distortion_power = total_power - signal_power
    
    # Calculate SNDR (dB)
    sndr_db = 10 * np.log10(signal_power / noise_distortion_power)
    
    # Calculate ENOB
    enob = (sndr_db - 1.76) / 6.02
    
    # Calculate SFDR (dB)
    # Find the maximum spurious signal excluding the fundamental frequency
    spurious_power = np.max(np.delete(fft_data ** 2, fundamental_freq_bin))
    sfdr_db = 10 * np.log10(signal_power / spurious_power)
    
    return sndr_db, enob, sfdr_db

def DC_evaluation(digital_signal, max_bins=1024):
    """
    Calculate DNL and INL from the given digital signal.

    Parameters:
    digital_signal (numpy array): The digital signal data.
    max_bins (int): Maximum number of bins to be used in the histogram calculation.

    Returns:
    dnl (numpy array): Differential Non-Linearity.
    inl (numpy array): Integral Non-Linearity.
    """
    # Clip digital_signal values to a reasonable range
    digital_signal = np.clip(digital_signal, 0, 2**12 - 1)  # Assuming a 12-bit ADC

    # Calculate histogram with a limited number of bins
    max_signal_value = int(np.max(digital_signal)) + 1
    bins = min(max_bins, max_signal_value + 1)  # Limit bins to max_bins or less
    code_hist, _ = np.histogram(digital_signal, bins=np.arange(bins))

    # Calculate ideal code width
    ideal_code_width = np.mean(code_hist)
    
    # Calculate DNL
    dnl = (code_hist - ideal_code_width) / ideal_code_width
    
    # Calculate INL
    inl = np.cumsum(dnl)
    
    return dnl, inl

# Define parameters for signal and FFT
fs = 1e6  # Sampling frequency in Hz (1 MSPS)
fin = 124.511e3  # Input frequency in Hz (124.511 kHz)
fft_points = 2048  # FFT points
t = np.arange(0, fft_points) / fs  # Time vector

# Create a sinusoidal waveform with the given amplitude and frequency
input_amplitude = 0.3  # 0.3 V
waveform = input_amplitude * np.sin(2 * np.pi * fin * t)

# Quantize waveform to simulate ADC conversion (12-bit ADC)
digital_signal = np.round(((waveform + 1) / 2) * (2**12 - 1))

# Perform FFT
fft_data = np.abs(np.fft.fft(waveform))[:fft_points // 2]  # Take positive frequency components

# Find fundamental frequency bin
fundamental_freq_bin = int(fin / (fs / fft_points))

# Calculate SNDR, ENOB, and SFDR
sndr_db, enob, sfdr_db = calculate_sndr_enob_sfdr(fft_data, fundamental_freq_bin, fs, fin, fft_points)

# Calculate DNL and INL for digital signal
dnl, inl = DC_evaluation(digital_signal)

# Print calculated values
print(f"SNDR: {sndr_db:.2f} dB")
print(f"ENOB: {enob:.2f} bits")
print(f"SFDR: {sfdr_db:.2f} dB")
print(f"DNL: {dnl}")
print(f"INL: {inl}")

# Plot time-domain waveform
plt.figure(figsize=(12, 8))

plt.subplot(2, 2, 1)
plt.plot(t * 1e3, waveform)
plt.title('Time-Domain Waveform')
plt.xlabel('Time (ms)')
plt.ylabel('Amplitude (V)')

# Plot frequency-domain FFT
freq = np.fft.fftfreq(fft_points, d=1/fs)[:fft_points // 2]  # Frequency vector
plt.subplot(2, 2, 2)
plt.plot(freq / 1e3, 20 * np.log10(fft_data))  # Convert FFT magnitude to dB
plt.title('Frequency-Domain FFT')
plt.xlabel('Frequency (kHz)')
plt.ylabel('Magnitude (dB)')

# Plot DNL
plt.subplot(2, 2, 3)
plt.stem(dnl, use_line_collection=True)
plt.title('Differential Non-Linearity (DNL)')
plt.xlabel('Code')
plt.ylabel('DNL (LSB)')

# Plot INL
plt.subplot(2, 2, 4)
plt.stem(inl, use_line_collection=True)
plt.title('Integral Non-Linearity (INL)')
plt.xlabel('Code')
plt.ylabel('INL (LSB)')

plt.tight_layout()
plt.show()

```


```

import numpy as np
import matplotlib.pyplot as plt

# シミュレーション用のパラメータ
dt = 150E-9  # データクロックの周期
t_sample = dt  # サンプリング時間の長さ
t_sample_start = 0  # 初回サンプリングの開始時刻
adc_bit = 16  # データのビット長
FFT_points = 128  # データ数
Vth = 350E-3  # 0/1の閾値電圧
sampling_rate = 1 / dt  # サンプリングレート

# シミュレーション用サイン波のパラメータ
frequency = 1E6  # 周波数 (1MHz)
amplitude = 500E-3  # 振幅 (500mV)
phase = 0  # 位相

# サイン波データを生成する
simulation_time = FFT_points * dt  # シミュレーションの時間
t = np.arange(0, simulation_time, dt)  # 時間配列
sinewave = amplitude * np.sin(2 * np.pi * frequency * t + phase)  # サイン波

# デコード用の変数初期化
target_time = t_sample_start + t_sample + dt / 8
bitcounter = 0
counter = 0
row_out = []

# 結果保存用ファイル名
output_filename = "simulation_output.txt"

# デコード結果を保存しながら、サイン波の電圧値をプロット
fig, ax = plt.subplots()
ax.plot(t, sinewave, label='Input Sine Wave')  # サイン波をプロット
ax.axhline(Vth, color='red', linestyle='--', label='Threshold Voltage (Vth)')  # 閾値をプロット

# ファイルにデコード結果を書き込む
with open(output_filename, "w") as outfile:
    for i, time in enumerate(t):
        data = sinewave[i]  # シミュレーションサイン波のデータを取得

        if time > target_time:
            target_data = data
            if target_data > Vth:
                row_out.append('1')
            else:
                row_out.append('0')

            target_time += dt
            bitcounter += 1

            if bitcounter == adc_bit:
                target_time += t_sample
                # デコード結果をファイルに書き込む
                outfile.write(','.join(row_out) + '\n')
                row_out = []
                bitcounter = 0
                print(f"Frame {counter + 1} decoded.")
                counter += 1

# サイン波のプロット設定
ax.set_xlabel('Time (s)')
ax.set_ylabel('Voltage (V)')
ax.set_title('Input Sine Wave and Threshold Voltage')
ax.legend()
plt.grid(True)
plt.show()

print("Decoding and saving completed.")


```



```
import numpy as np
import matplotlib.pyplot as plt

# パラメータ設定
sampling_rate = 1000  # サンプリング周波数 (Hz)
frequency = 50        # 波の周波数 (Hz)
amplitude = 250       # 振幅
duration = 0.02       # 信号の長さ (秒)

# 時間軸の設定
t = np.linspace(0, duration, int(sampling_rate * duration), endpoint=False)

# サイン波の生成
signal = amplitude * np.sin(2 * np.pi * frequency * t)

# パワースペクトルの計算
signal_fft = np.fft.fft(signal)
power_spectrum = np.abs(signal_fft)**2

# SNDR, ENOB, SFDR の仮の値
sndr = 48.71
enob = 7.8
sfdr = 70.25

# プロットの設定
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(12, 6))

# サイン波のプロット
ax1.plot(t, signal, marker='o')
ax1.set_title("Sorted Wave")
ax1.set_xlabel("Time [sec]")
ax1.set_ylabel("Code")
ax1.grid(True)

# パワースペクトルのプロット
freqs = np.fft.fftfreq(len(signal), 1/sampling_rate)
ax2.plot(freqs[:len(freqs)//2], 10*np.log10(power_spectrum[:len(freqs)//2]))  # パワースペクトルをdBで表示
ax2.set_title("Power Spectrum")
ax2.set_xlabel("f/fs")
ax2.set_ylabel("Power [dB]")
ax2.grid(True)

# SNDR, ENOB, SFDR を図に追加
textstr = f"SNDR = {sndr} dB\nENOB = {enob} bit\nSFDR = {sfdr} dB"
ax2.text(0.75, 0.95, textstr, transform=ax2.transAxes, fontsize=12,
         verticalalignment='top', bbox=dict(boxstyle='round', facecolor='white', alpha=0.5))

plt.tight_layout()
plt.show()




```



```

import numpy as np
import matplotlib.pyplot as plt

# Discrete Fourier Transform (DFT)
def DFT(x):
    N = len(x)
    X = np.zeros(N, dtype=complex)
    for n in range(N):
        for k in range(N):
            X[n] += x[k] * np.exp(-2j * np.pi * k * n / N)
    return X

# Inverse Discrete Fourier Transform (IDFT)
def IDFT(X):
    N = len(X)
    x = np.zeros(N, dtype=complex)
    for n in range(N):
        for k in range(N):
            x[n] += X[k] * np.exp(2j * np.pi * k * n / N)
    return x / N

# Example Data (from image Example 2.4, N=8)
f = np.array([1.00, 0.75, 0.50, 0.25, 0.00, 0.25, 0.50, 0.75])

# Compute DFT
F = DFT(f)

# Compute IDFT
f_reconstructed = IDFT(F)

# Plot original and reconstructed data
plt.figure(figsize=(10, 6))

# Original data plot
plt.subplot(2, 1, 1)
plt.stem(np.arange(len(f)), f, use_line_collection=True)
plt.title("Original Data")
plt.xlabel("Sample Index")
plt.ylabel("Amplitude")

# Reconstructed data plot
plt.subplot(2, 1, 2)
plt.stem(np.arange(len(f_reconstructed)), np.real(f_reconstructed), use_line_collection=True)
plt.title("Reconstructed Data (using IDFT)")
plt.xlabel("Sample Index")
plt.ylabel("Amplitude")

plt.tight_layout()
plt.show()

# Print results
print("Original Data:", f)
print("DFT of Data:", F)
print("Reconstructed Data:", np.real(f_reconstructed))  # Take only the real part for comparison


```