Nutubeを理解するためのPythonコード


## はじめに  
オーディオや楽器の世界において、**真空管**は長年にわたり「温かみのある音」や「心地よい歪み」を生み出す重要な電子部品として愛されてきました。真空管アンプの独特な音色は、デジタル機器では再現しきれない魅力を持ち、多くのギタリストやオーディオマニアにとって欠かせない存在です。
しかし、従来の真空管は高電圧が必要で消費電力も大きく、大型で壊れやすいという課題がありました。これらの問題を解決しつつ、真空管ならではの音響特性を維持した新しいデバイスとして登場したのが、**「Nutube」**です。
Nutubeは、コルグとノリタケ伊勢電子が共同開発した次世代真空管で、従来の構造をフラットパネル化することで、小型・低消費電力・高耐久性を実現しました。それでいて、真空管特有の倍音成分やサチュレーション（飽和）といった音質的な特徴をしっかりと保持しています。


リンク一覧
1. **真空管とは | Nutube**  
   [リンクはこちら](https://www.korgnutube.com/tube#:~:text=%E5%BE%93%E6%9D%A5%E3%81%AE%E7%9C%9F%E7%A9%BA%E7%AE%A1%E3%81%8C%E6%95%B0,%E7%89%B9%E6%80%A7%E3%81%A8%E8%A8%80%E3%81%88%E3%82%8B%E3%81%A7%E3%81%97%E3%82%87%E3%81%86%E3%80%82)

2. **Nutube 6P1 第 1 回目**  
   [リンクはこちら](https://www.marutsu.co.jp/sv/files/page/page/MBK6K1/report1.pdf?srsltid=AfmBOoqcGpoWurK2afClMhEiyQQ9SExSIMblepmSERBs0VlBebersfpx)

3. **Nutube を用いたエフェクターの実装と評価**  
   [リンクはこちら](https://www.st.nanzan-u.ac.jp/info/gr-thesis/2018/okumura/pdf/15sc081.pdf)

4. **Nutube を用いたエフェクターへの無線給電回路の実装と評価**  
   [リンクはこちら](https://www.st.nanzan-u.ac.jp/info/gr-thesis/2020/okumura/pdf/17sc028.pdf)

```python

   import numpy as np
import matplotlib.pyplot as plt

# 描画関数 / Function to draw triode structure and electron paths
def draw_triode(Vg):
    fig, ax = plt.subplots(figsize=(8, 5))
    
    # 真空管の構造を描画 / Draw the structure of the triode
    ax.plot([1, 1], [0, 8], color='black', lw=5, label="Plate")
    ax.plot([4, 4], [0, 8], color='gray', lw=10, label="Grid")
    ax.plot([7, 7], [0, 8], color='brown', lw=5, label="Cathode")
    
    # ヒーターの描画（下部） / Heater
    ax.plot([6.5, 7.5], [0.5, 0.5], color='orange', lw=6, label="Heater")
    
    # 電子の流れの描画 / Simulate electron flow from cathode to plate
    y_vals = np.linspace(1, 7, 6)
    for y in y_vals:
        alpha = max(0, 1 - (Vg + 2)/4)  # グリッド電圧が下がると透過性が上がる
        color = (0, 0, 1, alpha)  # 青色電子 with alpha透明度
        ax.annotate("", xy=(1, y), xytext=(7, y),
                    arrowprops=dict(arrowstyle="->", color=color, lw=2))
    
    # ラベルと説明 / Labels
    ax.text(1.2, 7.5, "Plate", fontsize=12)
    ax.text(3.7, 7.5, "Grid", fontsize=12)
    ax.text(6.5, 7.5, "Cathode", fontsize=12)
    ax.text(6.2, 0.2, "Heater", fontsize=10, color='orange')
    
    ax.set_xlim(0, 9)
    ax.set_ylim(0, 8)
    ax.set_title(f"Triode Operation (Grid Voltage = {Vg}V)")
    ax.axis('off')
    plt.show()

# 例：グリッド電圧が-1Vのときの動作 / Example with Grid Voltage -1V
draw_triode(Vg=-1)
# グリッド電圧の範囲 / Grid Voltage range
Vg_vals = np.linspace(-3, 0, 100)

# プレート電流を模擬（指数関数的に減少） / Simulate plate current
Ip_vals = np.exp(Vg_vals)  # 模擬的な特性

# プロット / Plot
plt.figure(figsize=(8, 4))
plt.plot(Vg_vals, Ip_vals)
plt.title("Plate Current vs Grid Voltage")
plt.xlabel("Grid Voltage [V]")
plt.ylabel("Plate Current [mA] (simulated)")
plt.grid(True)
plt.show()
# 時間軸 / Time axis
t = np.linspace(0, 0.01, 1000)
input_signal = -1 + 0.2 * np.sin(2 * np.pi * 1000 * t)  # グリッド電圧変化

# プレート電流（模擬） / Simulated plate current
output_signal = np.exp(input_signal)

# グラフ化 / Plot input and output
plt.figure(figsize=(10, 4))
plt.plot(t * 1000, input_signal, label="Grid Voltage (Input)")
plt.plot(t * 1000, output_signal, label="Plate Current (Output)", linestyle='--')
plt.title("Triode Amplification Simulation")
plt.xlabel("Time [ms]")
plt.ylabel("Voltage / Current")
plt.grid(True)
plt.legend()
plt.show()
```

2. **Nutube 6P1 第 1 回目**  
   [リンクはこちら](https://www.marutsu.co.jp/sv/files/page/page/MBK6K1/report1.pdf?srsltid=AfmBOoqcGpoWurK2afClMhEiyQQ9SExSIMblepmSERBs0VlBebersfpx)




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

def fet_amp_analysis(gm_mS=2, R3_kohm=10):
    """
    FETアンプの出力インピーダンス Z_o と 電圧増幅度 A_v を計算して表示する関数
    Compute and print output impedance Z_o and voltage gain A_v for FET amplifier
    """
    gm = gm_mS * 1e-3     # gm [S] に変換 / Convert gm from mS to S
    R3 = R3_kohm * 1e3    # R3 [Ω] に変換 / Convert R3 from kΩ to Ω

    gmR3 = gm * R3
    Zo = R3 / (1 + gmR3)              # 出力インピーダンス / Output impedance
    Av = gmR3 / (1 + gmR3)            # 電圧増幅度 / Voltage gain
    Av_dB = 20 * np.log10(Av)         # dB表記 / Gain in dB

    print(f"gm = {gm_mS} mS, R3 = {R3_kohm} kΩ")
    print(f"Z_o = {Zo:.2f} Ω")
    print(f"A_v = {Av:.4f} → {Av_dB:.2f} dB")

    return Zo, Av, Av_dB

def vacuum_tube_gain(gm_uS=30, R1_k=400, R2_k=330):
    """
    真空管（三極管）アンプの電圧増幅度 A_v を計算する関数
    Compute voltage gain A_v of vacuum tube (triode) amplifier
    """
    gm = gm_uS * 1e-6               # gm [S] に変換 / Convert gm from μS to S
    R1 = R1_k * 1e3                 # R1 [Ω] に変換
    R2 = R2_k * 1e3                 # R2 [Ω] に変換
    Req = (R1 * R2) / (R1 + R2)     # 並列抵抗 / Parallel resistance

    Av = -gm * Req                  # 電圧増幅度（マイナスは位相反転） / Voltage gain (negative = inversion)
    Av_dB = 20 * np.log10(abs(Av))  # dB表記

    print(f"gm = {gm_uS} μS, R1 = {R1_k}kΩ, R2 = {R2_k}kΩ")
    print(f"並列抵抗 Req = {Req:.2f} Ω")
    print(f"A_v = {Av:.2f} → {Av_dB:.2f} dB")

    return Av, Av_dB

def plot_fet_gain_and_impedance():
    """
    gmの値に対するFETアンプの出力インピーダンスと電圧増幅度をプロット
    Plot FET amplifier's output impedance and gain versus gm
    """
    gm_vals = np.linspace(0.5e-3, 5e-3, 100)  # gm from 0.5 mS to 5 mS
    R3 = 10e3  # 固定値 10kΩ / Fixed value 10kΩ

    Av_vals = (gm_vals * R3) / (1 + gm_vals * R3)
    Zo_vals = R3 / (1 + gm_vals * R3)

    fig, ax1 = plt.subplots(figsize=(8, 5))

    ax1.set_xlabel("gm [mS]")
    ax1.set_ylabel("Voltage Gain A_v", color='blue')
    ax1.plot(gm_vals * 1e3, Av_vals, label="A_v", color='blue')
    ax1.tick_params(axis='y', labelcolor='blue')

    ax2 = ax1.twinx()
    ax2.set_ylabel("Output Impedance Z_o [Ω]", color='red')
    ax2.plot(gm_vals * 1e3, Zo_vals, label="Z_o", color='red')
    ax2.tick_params(axis='y', labelcolor='red')

    plt.title("FET Amplifier: Gain and Output Impedance vs gm")
    plt.grid(True)
    plt.show()

def voltage_divider_ratio(Ra, Rb, show_db=False):
    """
    RaとRbを入力して、Ra/(Ra + Rb) の値、パーセント、およびdB表示（任意）を出力
    Calculate and display Ra / (Ra + Rb), percent, and optional dB representation
    """
    if Ra + Rb == 0:
        print("Ra + Rb cannot be zero.")  # 0割り防止 / Prevent division by zero
        return None

    ratio = Ra / (Ra + Rb)
    percent = ratio * 100
    print(f"Ra = {Ra:.1f} Ω, Rb = {Rb:.1f} Ω")
    print(f"Ratio (Ra / (Ra + Rb)) = {ratio:.4f} ({percent:.2f}%)")

    if show_db:
        db_value = 20 * np.log10(ratio)
        print(f"Ratio in dB = {db_value:.2f} dB")

    return ratio

# 実行例 / Example executions
print("----- FET Amp Analysis -----")
fet_amp_analysis(gm_mS=2, R3_kohm=10)

print("\n----- Vacuum Tube Gain -----")
vacuum_tube_gain(gm_uS=30, R1_k=400, R2_k=330)

print("\n----- FET Gain/Impedance Plot -----")
plot_fet_gain_and_impedance()

print("\n----- Voltage Divider Ratio -----")
voltage_divider_ratio(100e3, 200e3, show_db=True)
```



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

# ===== 基本設定 / Basic parameters =====
fs = 10000         # サンプリング周波数 [Hz] / Sampling frequency
f = 1000           # サイン波の周波数 [Hz] / Sine wave frequency
T = 1              # 信号の長さ [s] / Duration
t = np.linspace(0, T, int(fs*T), endpoint=False)  # 時間軸 / Time vector

# ===== ゲイン設定 / Gain Settings =====
Vin_amp = 0.12                       # 入力振幅 / Input amplitude [V]
G = 0.765 / 0.15                     # 電圧ゲイン / Voltage gain
G_dB = 20 * np.log10(G)              # dBに変換 / Convert to dB

# ===== サイン波生成 / Generate sine waves =====
Vin = Vin_amp * np.sin(2 * np.pi * f * t)     # 入力波 / Input wave
Vout = G * Vin                                # 出力波 / Output wave

print(f"Gain G = {G:.2f}")
print(f"Gain in dB = {G_dB:.2f} dB")

# ===== 入力波形のプロット（全体）/ Input waveform (full) =====
plt.figure(figsize=(10, 3))
plt.plot(t, Vin, color='blue')
plt.title("Input Waveform (Full)")
plt.xlabel("Time [s]")
plt.ylabel("Voltage [V]")
plt.grid(True)
plt.tight_layout()
plt.show()

# ===== 出力波形のプロット（全体）/ Output waveform (full) =====
plt.figure(figsize=(10, 3))
plt.plot(t, Vout, color='red')
plt.title("Output Waveform (Full)")
plt.xlabel("Time [s]")
plt.ylabel("Voltage [V]")
plt.grid(True)
plt.tight_layout()
plt.show()

# ===== 1周期分のプロット / One cycle view =====
cycle_samples = int(fs / f)         # 1周期あたりのサンプル数 / Samples per cycle
t_one = t[:cycle_samples]
Vin_one = Vin[:cycle_samples]
Vout_one = Vout[:cycle_samples]

# 入力1周期
plt.figure(figsize=(10, 3))
plt.plot(t_one * 1e3, Vin_one, color='blue')
plt.title("Input Waveform (One Cycle)")
plt.xlabel("Time [ms]")
plt.ylabel("Voltage [V]")
plt.grid(True)
plt.tight_layout()
plt.show()

# 出力1周期
plt.figure(figsize=(10, 3))
plt.plot(t_one * 1e3, Vout_one, color='red')
plt.title("Output Waveform (One Cycle)")
plt.xlabel("Time [ms]")
plt.ylabel("Voltage [V]")
plt.grid(True)
plt.tight_layout()
plt.show()

# ===== FFT計算関数 / FFT calculation function =====
def compute_fft(signal, fs):
    N = len(signal)
    fft_vals = np.fft.fft(signal)
    fft_freq = np.fft.fftfreq(N, d=1/fs)
    fft_mag = np.abs(fft_vals) / (N/2)
    return fft_freq[:N//2], fft_mag[:N//2]  # 正の周波数のみ返す

# FFTの計算 / Compute FFT
freq_in, mag_in = compute_fft(Vin, fs)
freq_out, mag_out = compute_fft(Vout, fs)

# ===== FFTプロット（入力）/ FFT Plot (Input) =====
plt.figure(figsize=(10, 3))
plt.plot(freq_in, mag_in, color='blue')
plt.title("Input FFT Spectrum")
plt.xlabel("Frequency [Hz]")
plt.ylabel("Magnitude")
plt.grid(True)
plt.xlim(0, 3000)
plt.tight_layout()
plt.show()

# ===== FFTプロット（出力）/ FFT Plot (Output) =====
plt.figure(figsize=(10, 3))
plt.plot(freq_out, mag_out, color='red')
plt.title("Output FFT Spectrum")
plt.xlabel("Frequency [Hz]")
plt.ylabel("Magnitude")
plt.grid(True)
plt.xlim(0, 3000)
plt.tight_layout()
plt.show()
```