Verilog-AMSの勉強とPython実装(日記)



 Verilog-AMS 発振器モジュール（リスト2.1 統合版）


```
`timescale 100ps / 10ps           // 時間単位：100ps、時間精度：10ps

`include "disciplines.h"         // 電気的特性（discipline）定義ファイルの取り込み
`include "connect.h"             // モジュール間接続ルールの定義

// --- トップモジュール：発振器の基本構成 ---
module top;

  wire a, b;                     // デジタル信号配線

  not #1 g1 (b, a);              // NOTゲート（1単位遅延）
  assign #1 out = b;            // bを1単位遅延でoutに出力

  res (.val(5e3)) r1(b, a);      // 抵抗インスタンス（5kΩ）をbとaの間に接続
  cap (.val(1e-9)) cl(out, a);   // コンデンサインスタンス（1nF）をoutとaの間に接続

endmodule

// --- 抵抗モデルモジュール ---
module res(a, b);

  inout a, b;                   // 双方向ポート定義
  electrical a, b;             // electrical discipline（アナログ信号）定義

  parameter real val = 1e3;     // 抵抗値（デフォルト：1kΩ）

  analog
    V(a, b) <+ val * I(a, b);   // アナログ記述：V = R * I（オームの法則）

endmodule

// --- キャパシタ（コンデンサ）モデルモジュール ---
module cap(a, b);

  inout a, b;
  electrical a, b;

  branch (a, b) cap;            // 電流の流れる経路（ブランチ）定義

  parameter real val = 1e3;     // 容量値（デフォルト：1k、使用時に1nFに上書き）

  analog
    I(cap) <+ val * ddt(V(cap)); // アナログ記述：I = C * dV/dt（キャパシタの基本式）

endmodule

```


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

# --- パラメータ設定 / Parameters ---
R = 5e3           # 抵抗値 [Ohm]
C = 1e-9          # キャパシタ [F]
Vdd = 1.0         # 電源電圧（HIGHレベル）
Vth = 0.5         # NOTゲートの閾値電圧

dt = 1e-11        # 時間刻み [s]
T = 2e-6          # 総時間 [s]
steps = int(T / dt)

# --- 初期化 / Initialization ---
t = np.linspace(0, T, steps)
a = np.zeros(steps)   # ノードa（入力）
b = np.zeros(steps)   # ノードb（出力）

a[0] = 0.0            # 初期値：LOW

# --- シミュレーションループ / Simulation loop ---
for i in range(1, steps):
    # デジタルNOTゲート：aに対する反転出力がb
    b[i-1] = 0.0 if a[i-1] > Vth else Vdd

    # RC回路によるaの更新（アナログ）
    dV = (b[i-1] - a[i-1]) / (R * C) * dt
    a[i] = a[i-1] + dV

# --- プロット / Plotting ---
plt.figure(figsize=(10, 4))
plt.plot(t * 1e6, a, label='Node a (analog)', linewidth=1.5)
plt.plot(t * 1e6, b, label='Node b (digital)', linewidth=1.0, linestyle='--')
plt.xlabel("Time [µs]")
plt.ylabel("Voltage [V]")
plt.title("Oscillator Simulation: NOT + RC Feedback")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

```

Verilog-AMSによるVCO記述（パルス発生型、リスト4.9）
```
`include "disciplines.h"  // アナログ信号のディシプリン定義

module vco(vctrl, vout, vdd, vss);

  inout vctrl, vout, vdd, vss;        // 入出力ポート宣言
  electrical vctrl, vout, vdd, vss;   // 電気信号として定義

  // --- パラメータ宣言 ---
  parameter real f0    = 100e6;  // 基本周波数 100 MHz
  parameter real fgain = 100e6;  // ゲイン（Hz/V）
  parameter real vdead = 1.0;    // 発振が開始する電圧しきい値 [V]
  parameter real tr    = 0.1e-9; // 出力立ち上がり時間 [s]
  parameter real tf    = 0.1e-9; // 出力立ち下がり時間 [s]

  real period;       // 周期（内部変数）
  integer state;     // 出力状態（0 or 1）

  analog begin
    // --- 発振周期の計算 ---
    if (V(vctrl) > vdead)
      period = 1.0 / (f0 + (V(vctrl) - vdead) * fgain);
    else
      period = 1.0 / f0;

    // --- タイマーでトグル動作（パルス出力） ---
    @(timer(period/2, period/2))  // ON時間・OFF時間を同周期で繰り返す
      state = !state;             // 出力トグル（0→1→0...）

    // --- パルス波形生成（0↔Vddの矩形波） ---
    V(vout) <+ V(vdd, vss) * transition(state, 0.0, tr, tf);
    // 出力電圧 = 状態に応じてVdd/vssを切替（transitionで滑らかに）
  end

endmodule

```


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

# --- パラメータ設定 / VCO Parameters ---
f0 = 100e6         # 基本周波数 [Hz]
fgain = 100e6      # ゲイン [Hz/V]
vdead = 1.0        # 発振開始しきい値 [V]
vctrl = 2.0        # 制御電圧 [V]
vdd = 1.0          # 出力電圧（High）
vss = 0.0          # 出力電圧（Low）
tr = 0.1e-9        # 立ち上がり時間 [s]（未使用、波形理想）
tf = 0.1e-9        # 立ち下がり時間 [s]（未使用、波形理想）

# --- 時間軸の設定 / Time Axis ---
dt = 1e-10                   # タイムステップ [s]
Tmax = 1e-6                  # 総シミュレーション時間 [s]
steps = int(Tmax / dt)
time = np.arange(steps) * dt

# --- 初期化 / Initialization ---
vout = np.zeros(steps)      # 出力波形
state = 0                   # 初期状態（0 or 1）
t_next_toggle = 0.0         # 次の反転タイミング [s]

# --- 周期の計算 / Period Calculation ---
if vctrl > vdead:
    period = 1.0 / (f0 + (vctrl - vdead) * fgain)
else:
    period = 1.0 / f0

half_period = period / 2.0  # 半周期（トグル間隔）

# --- シミュレーションループ / Main Simulation Loop ---
for i in range(steps):
    t = i * dt

    if t >= t_next_toggle:
        state = 1 - state                       # トグル（0→1→0…）
        t_next_toggle += half_period            # 次の反転時間更新

    vout[i] = vdd if state == 1 else vss        # 出力電圧の決定

# --- 結果の表示 / Plotting ---
plt.figure(figsize=(10, 4))
plt.plot(time * 1e6, vout, label='VCO Output (vout)', color='blue')
plt.xlabel("Time [µs]")
plt.ylabel("Voltage [V]")
plt.title("Voltage-Controlled Oscillator Output")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

```

[リスト 5.4] Verilog-AMS: ローパス＆ハイパスフィルタ定義例（laplace_nd使用）
```
// --- ローパス・フィルタ（Low-pass Filters） ---
V(low1) <+ laplace_nd(V(in), (1),                    (1, 1));                          // 1次ローパス
V(low2) <+ laplace_nd(V(in), (1),                    (1, 1.4142, 1));                  // 2次ローパス（バターワース）
V(low3) <+ laplace_nd(V(in), (1),                    (1, 2, 2, 1));                    // 3次ローパス
V(low4) <+ laplace_nd(V(in), (1),                    (1, 2.6131, 3.4142, 2.6131, 1));  // 4次ローパス（バターワース）

// --- ハイパス・フィルタ（High-pass Filters） ---
V(high1) <+ laplace_nd(V(in), (0, 1),                (1, 1));                          // 1次ハイパス
V(high2) <+ laplace_nd(V(in), (0, 0, 1),             (1, 1.4142, 1));                  // 2次ハイパス（バターワース）
V(high3) <+ laplace_nd(V(in), (0, 0, 0, 1),          (1, 2, 2, 1));                    // 3次ハイパス
V(high4) <+ laplace_nd(V(in), (0, 0, 0, 0, 1),       (1, 2.6131, 3.4142, 2.6131, 1));  // 4次ハイパス（バターワース）

```


```python
import numpy as np
import matplotlib.pyplot as plt
from scipy import signal

# --- 周波数軸設定 / Frequency range ---
w = np.logspace(0, 6, 1000)  # [rad/s]：1〜1Mの対数スケール

# --- フィルタ定義（laplace_ndと一致） ---
filters = {
    'low1':  ([1], [1, 1]),
    'low2':  ([1], [1, 1.4142, 1]),
    'low3':  ([1], [1, 2, 2, 1]),
    'low4':  ([1], [1, 2.6131, 3.4142, 2.6131, 1]),
    'high1': ([0, 1], [1, 1]),
    'high2': ([0, 0, 1], [1, 1.4142, 1]),
    'high3': ([0, 0, 0, 1], [1, 2, 2, 1]),
    'high4': ([0, 0, 0, 0, 1], [1, 2.6131, 3.4142, 2.6131, 1])
}

# --- プロット設定 / Plot configuration ---
fig_mag, ax_mag = plt.subplots(figsize=(10, 5))
fig_phase, ax_phase = plt.subplots(figsize=(10, 5))

# --- フィルタごとにプロット / Plot each filter ---
for name, (num, den) in filters.items():
    system = signal.TransferFunction(num, den)
    w_, mag, phase = signal.bode(system, w)

    ax_mag.semilogx(w_, mag, label=name)
    ax_phase.semilogx(w_, phase, label=name)

# --- 振幅プロット / Magnitude ---
ax_mag.set_title("Bode Magnitude Plot (Low-pass & High-pass Filters)")
ax_mag.set_xlabel("Frequency [rad/s]")
ax_mag.set_ylabel("Magnitude [dB]")
ax_mag.grid(True, which="both", ls='--')
ax_mag.legend()

# --- 位相プロット / Phase ---
ax_phase.set_title("Bode Phase Plot (Low-pass & High-pass Filters)")
ax_phase.set_xlabel("Frequency [rad/s]")
ax_phase.set_ylabel("Phase [deg]")
ax_phase.grid(True, which="both", ls='--')
ax_phase.legend()

plt.tight_layout()
plt.show()

```

基本素子モデル統合コード（Verilog-AMS）
```
`include "disciplines.h"  // electricalディシプリンの定義

// ------------------------------
// 抵抗モデル / Resistor
// ------------------------------
module resistor(p, n);

  inout p, n;
  electrical p, n;

  parameter real r = 100 from [0:inf);  // 抵抗値 [Ω]

  analog
    V(p, n) <+ r * I(p, n);             // V = R × I

endmodule


// ------------------------------
// キャパシタモデル / Capacitor
// ------------------------------
module capacitor(p, n);

  inout p, n;
  electrical p, n;

  parameter real c = 1e-9 from (0:inf);   // 容量 [F]
  parameter real ic = 0 from [0:inf);     // 初期電荷による電圧

  analog
    I(p, n) <+ c * ddt(V(p, n), ic);      // I = C × dV/dt

endmodule


// ------------------------------
// インダクタモデル / Inductor
// ------------------------------
module inductor(p, n);

  inout p, n;
  electrical p, n;

  parameter real l = 10e-6 from [0:inf);  // インダクタンス [H]
  parameter real ic = 0 from [0:inf);     // 初期電流

  analog
    V(p, n) <+ l * idt(I(p, n), ic);      // V = L × dI/dt

endmodule


// ------------------------------
// ダイオードモデル / Diode
// ------------------------------
module diode(a, c);

  inout a, c;
  electrical a, c;

  parameter real is = 1e-14;  // 逆方向飽和電流 [A]

  analog
    I(a, c) <+ is * (limexp(V(a, c)/$vt) - 1);  // 指数関数特性

endmodule

```


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

# --- パラメータ設定 / Parameters ---
R = 100          # 抵抗 [Ω]
C = 1e-9         # 容量 [F]
L = 10e-6        # インダクタンス [H]
Is = 1e-14       # ダイオード飽和電流 [A]
Vt = 0.025       # 熱電圧 [V]

# --- シミュレーション設定 / Simulation parameters ---
dt = 1e-9                      # タイムステップ [s]
Tmax = 2e-6                    # 総時間 [s]
time = np.arange(0, Tmax, dt) # 時間軸
vin = np.ones_like(time)      # 入力電圧：1Vステップ

# --- RC回路（直列） / RC circuit ---
vc = np.zeros_like(time)
for i in range(1, len(time)):
    dV = (vin[i-1] - vc[i-1]) / (R * C) * dt
    vc[i] = vc[i-1] + dV

# --- RL回路（直列） / RL circuit ---
il = np.zeros_like(time)
vl = np.zeros_like(time)
for i in range(1, len(time)):
    dI = (vin[i-1] - R * il[i-1]) / L * dt
    il[i] = il[i-1] + dI
    vl[i] = L * (dI / dt)  # V = L dI/dt（理論値）

# --- ダイオードモデル / Diode I-V curve ---
vd_range = np.linspace(-0.1, 0.8, 500)
id_diode = Is * (np.exp(vd_range / Vt) - 1)

# --- プロット / Plotting ---
fig, axs = plt.subplots(3, 1, figsize=(10, 10))

# RC回路電圧
axs[0].plot(time * 1e6, vc, label='V_C (RC circuit)', color='blue')
axs[0].set_title("RC Circuit: Capacitor Voltage")
axs[0].set_xlabel("Time [µs]")
axs[0].set_ylabel("Voltage [V]")
axs[0].grid(True)
axs[0].legend()

# RL回路電流
axs[1].plot(time * 1e6, il, label='I_L (RL circuit)', color='green')
axs[1].set_title("RL Circuit: Inductor Current")
axs[1].set_xlabel("Time [µs]")
axs[1].set_ylabel("Current [A]")
axs[1].grid(True)
axs[1].legend()

# ダイオード I-V 曲線
axs[2].semilogy(vd_range, np.abs(id_diode), label='I-V (Diode)', color='red')
axs[2].set_title("Diode I-V Characteristic")
axs[2].set_xlabel("Voltage [V]")
axs[2].set_ylabel("Current [A] (log scale)")
axs[2].grid(True, which='both')
axs[2].legend()

plt.tight_layout()
plt.show()

```


合体版：4ビット逐次比較A-Dコンバータ（SAR ADC）


````
include "disciplines.h"

module ad4 (ain, clk, convert, done, dval);

  // --- ポート定義 ---
  inout ain;                      // アナログ入力
  input clk, convert;             // クロック、変換トリガ
  output done;                    // 変換完了フラグ
  output [3:0] dval;              // 4ビットディジタル出力

  // --- 信号宣言 ---
  electrical ain;                 // アナログ入力として宣言
  reg [3:0] dval, bit, result, dac; // SARレジスタと出力
  reg done;                       // 変換完了信号
  reg track_hold;                 // サンプル&ホールド制御信号

  wire [3:0] dacin = dac;         // DAC制御入力（ビットごと）
  wire comp;                      // コンパレータ出力

  // --- 初期化 ---
  initial begin
    track_hold = 1;              // 初期状態：サンプリング中
    done = 0;
  end

  // --- SAR制御：クロックに同期して変換ステップを進める ---
  always @(posedge clk) begin
    if (convert == 1) begin
      done <= 0;
      bit <= 4'b1000;            // 最上位ビットから順に評価
      result <= 4'b0000;
      track_hold <= 0;           // サンプル開始（ホールド解除）
      dac <= result | bit;       // 試験ビットONしてDAC出力
    end
    else if (!done) begin
      if (comp) begin
        result <= result | bit;  // sample > DAC → ビットを1に確定
      end
      bit <= bit >> 1;           // 次のビットへ

      if (bit == 0) begin
        dval <= result;          // 完了 → 結果格納
        done <= 1;
        track_hold <= 1;         // サンプル保持（ホールドON）
      end
      else begin
        dac <= result | bit;     // 次ビット試験用値
      end
    end
  end

  // --- アナログモジュール呼び出し ---
  ad4_amod amod (ain, track_hold, dacin[3], dacin[2], dacin[1], dacin[0], comp);

endmodule


// --- アナログモジュール：S/H + DAC + コンパレータ ---
module ad4_amod(ain, thold, d3, d2, d1, d0, comp);

  input ain, thold, d3, d2, d1, d0;
  output comp;

  electrical ain, thold, d3, d2, d1, d0, comp;

  // --- パラメータ定義 ---
  parameter real vth = 2.5;           // トラック→ホールド切替しきい値 [V]
  parameter real logic1 = 5.0;        // デジタルHIGHの電圧
  parameter real logic0 = 0.0;        // デジタルLOWの電圧
  parameter real fullscale = 5.0;     // DACフルスケール電圧

  real sample;                        // サンプル保持用
  real dac_out;                       // DAC出力電圧

  analog begin
    // --- サンプル&ホールド動作 ---
    if (V(thold) > vth)
      sample = V(ain);                // トラック→ホールド時に保持

    // --- 4ビットDAC：加重和で出力電圧を生成 ---
    dac_out = (fullscale / logic1) * (
      (V(d3) * 0.5) +
      (V(d2) * 0.25) +
      (V(d1) * 0.125) +
      (V(d0) * 0.0625)
    );

    // --- コンパレータ動作 ---
    if (sample > dac_out)
      V(comp) <+ logic1;              // sample > DAC → HIGH
    else
      V(comp) <+ logic0;              // sample ≤ DAC → LOW
  end

endmodule



`````












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

# --- パラメータ設定 / Parameters ---
V_ref = 5.0       # DACフルスケール電圧 [V]
bits = 4          # 4ビットADC
V_in = 2.7        # 入力アナログ電圧 [V]

# --- SAR ADC 変換関数 / SAR conversion logic ---
def sar_adc(V_in, V_ref, bits):
    dval = 0                     # 最終的な出力値（4ビット）
    result_trace = []            # 各ステップのDAC出力を記録
    compare_trace = []           # 各ビットの比較結果
    step_labels = []             # ステップごとのラベル

    for i in range(bits):
        bit_pos = bits - 1 - i
        test_val = dval | (1 << bit_pos)  # そのビットを仮に1とする
        V_dac = V_ref * test_val / (2 ** bits)

        result_trace.append(V_dac)
        compare_trace.append(V_in > V_dac)
        step_labels.append(f"Bit {bit_pos}")

        if V_in > V_dac:
            dval = test_val  # ビットを1に確定

    return dval, result_trace, compare_trace, step_labels

# --- 実行 / Run ADC ---
dval, dac_trace, comp_result, labels = sar_adc(V_in, V_ref, bits)

# --- 結果表示 / Print Result ---
print(f"Input Voltage: {V_in:.2f} V")
print(f"Digital Output: {dval:04b} (Decimal: {dval})")

# --- 可視化 / Plot the DAC steps ---
plt.figure(figsize=(10, 4))
plt.plot(range(bits), dac_trace, marker='o', label='DAC Output (V)')
plt.axhline(V_in, color='red', linestyle='--', label='Input Voltage')
for i, c in enumerate(comp_result):
    color = 'green' if c else 'gray'
    plt.text(i, dac_trace[i] + 0.1, '1' if c else '0', color=color, ha='center')

plt.xticks(range(bits), labels)
plt.xlabel("SAR Step")
plt.ylabel("Voltage [V]")
plt.title("SAR ADC Bitwise Comparison Trace")
plt.grid(True)
plt.legend()
plt.tight_layout()
plt.show()

```