チートシート

OFDMと5G NRヌメロロジーのチートシート

TS 38.211に基づくNRのヌメロロジー、スロット長とサイクリックプレフィックス長、TS 38.101に基づくチャネル帯域幅ごとのリソースブロック数、比較用のLTE、OFDMの諸元を計算するコード。

最終確認 2026年11月15日· 3GPP TS 38.211 V19.5.0, TS 38.101-1 V19.7.0, TS 38.101-2 V19.5.0 (Release 19); NumPy 2.5

このシートは、NRやLTEのキャリアを設定・シミュレーション・復号するエンジニアが、時間・周波数グリッドをひと目で確認するためのものです。ここに載せたNRの数値はすべて、3GPP TS 38.211(NRの物理チャネルと変調)、TS 38.101-1・TS 38.101-2(NR UEの無線送受信、FR1・FR2)、TS 38.104(NR基地局の無線送受信)のRelease 19版と照合しました。直交周波数分割多重(OFDM)の仕組みについては、ゼロから学ぶOFDMのレッスンから始めてください。

OFDMの関係式

量 式 例
サブキャリア間隔 Δf = fs / N_FFT 30.72 Msample/s / 1024 = 30 kHz
有効シンボル長 T_u = 1 / Δf 30 kHzで33.33 µs
サイクリックプレフィックス(CP) チャネルの遅延広がりより長くする必要がある 30 kHzのノーマルCPで2.34 µs
CPオーバーヘッド T_cp / (T_u + T_cp) NRのノーマルCPで約6.6%
占有帯域幅 N_RB × 12 × Δf 273 × 12 × 30 kHz = 98.28 MHz
サンプルレート N_FFT × Δf 4096 × 30 kHz = 122.88 Msample/s

リソースブロックは、周波数方向に連続する12本のサブキャリアです(TS 38.211)。サイクリックプレフィックスはチャネルの線形畳み込みを巡回畳み込みに変えるため、各サブキャリアには1つの複素利得だけがかかります。これが1タップの等化で済む理由です。

NRのヌメロロジー

TS 38.211は基本時間単位Tc = 1 / (480 kHz × 4096)とκ = 64を定義しています。フレームは10 ms、サブフレームは1 msです。ヌメロロジーインデックスμによりΔf = 15 × 2^μ kHzが決まります。

μ Δf CPの種類 サブフレームあたりのスロット数 フレームあたりのスロット数 スロット長 有効シンボル長 ノーマルCP 長いCP(1 msに2回)
0 15 kHz ノーマル 1 10 1 ms 66.67 µs 4.688 µs 5.208 µs
1 30 kHz ノーマル 2 20 0.5 ms 33.33 µs 2.344 µs 2.865 µs
2 60 kHz ノーマル、拡張 4 40 0.25 ms 16.67 µs 1.172 µs 1.693 µs
3 120 kHz ノーマル 8 80 125 µs 8.33 µs 0.586 µs 1.107 µs
4 240 kHz ノーマル 16 160 62.5 µs 4.17 µs 0.293 µs 0.814 µs
5 480 kHz ノーマル 32 320 31.25 µs 2.08 µs 0.146 µs 0.667 µs
6 960 kHz ノーマル 64 640 15.625 µs 1.04 µs 0.073 µs 0.594 µs

1スロットは、ノーマルCPでは14個のOFDMシンボル、拡張CP(60 kHzのみ、拡張CPは4.167 µs)では12個のシンボルです。ノーマルCPは144κ·2^−μ Tcです。0.5 msのハーフサブフレームごとに先頭シンボルには16κ Tcが加わるため、どのμでもスロットが1 msのサブフレームの境界にそろいます。表のスロット長以降の列は、TS 38.211の式から後述のコードで計算した値です。

どこでどのヌメロロジーを使うか

用途 サブキャリア間隔
FR1、データ(TS 38.101-1) 15、30、60 kHz
FR2、データ(TS 38.101-2) 60 kHz・120 kHz、およびオプション扱いの480 kHz・960 kHz
SS/PBCHブロック(TS 38.213のケースA〜G) 15 kHz(A)、30 kHz(B、C)、120 kHz(D)、240 kHz(E)、480 kHz(F)、960 kHz(G)

TS 38.104では、FR1を410 MHz〜7125 MHz、FR2-1を24250 MHz〜52600 MHz、FR2-2を52600 MHz〜71000 MHzと定義しています。SS/PBCHブロックは、時間方向に4個のOFDMシンボル、周波数方向に240本のサブキャリア(20リソースブロック)を占めます。

チャネル帯域幅ごとのリソースブロック数

TS 38.101-1 Table 5.3.2-1(FR1)による最大送信帯域幅構成N_RBです。N/Aはその組み合わせが定義されていないことを示します。

チャネル帯域幅 15 kHz 30 kHz 60 kHz
5 MHz 25 11 N/A
10 MHz 52 24 11
15 MHz 79 38 18
20 MHz 106 51 24
25 MHz 133 65 31
30 MHz 160 78 38
40 MHz 216 106 51
50 MHz 270 133 65
60 MHz N/A 162 79
80 MHz N/A 217 107
100 MHz N/A 273 135

元の表には3、7、35、45、70、90 MHzの行もあります。FR2(TS 38.101-2 Table 5.3.2-1)は次のとおりです。

チャネル帯域幅 60 kHz 120 kHz
50 MHz 66 32
100 MHz 132 66
200 MHz 264 132
400 MHz N/A 264

帯域幅パート(bandwidth part)は、これらのリソースブロックの一部で、独自のヌメロロジーを持ちます。UEはキャリアより狭い帯域幅パートを使うことがあります。

LTEとの比較

TS 36.211(E-UTRAの物理チャネルと変調)では、Ts = 1 / (15000 × 2048) s、307200 Tsからなる10 msのフレーム、0.5 msのスロット2つからなる1 msのサブフレームを使います。LTEのノーマルCPは、スロットの先頭シンボルで160 Ts、残り6シンボルで144 Tsです。拡張CPは512 Tsです。144 Tsは144κ Tcに等しいため、15 kHzではNRのμ = 0と同じ時間長になります。LTEは特殊な用途向けに7.5 kHz、3.75 kHz、1.25 kHzの間隔も定義しています。

コード: TS 38.211の式による時間長

import numpy as np

# TS 38.211 clause 4.1: Tc = 1/(480e3 * 4096) s, kappa = 64
TC = 1 / (480e3 * 4096)
KAPPA = 64

print(" mu  SCS_kHz slots/sf  slot_us  Nu_us  CP_us  CPlong_us  CP_ext_us")
for mu in range(7):
    scs_khz = 15 * 2 ** mu
    nu = 2048 * KAPPA * 2.0 ** -mu * TC          # useful symbol length
    cp = 144 * KAPPA * 2.0 ** -mu * TC           # normal CP, l != 0 and l != 7*2^mu
    cp_long = cp + 16 * KAPPA * TC               # normal CP, l = 0 or l = 7*2^mu
    cp_ext = 512 * KAPPA * 2.0 ** -mu * TC if mu == 2 else float("nan")
    slots = 2 ** mu
    slot_us = 1e3 / slots
    print(f"{mu:3d} {scs_khz:7d} {slots:8d} {slot_us:8.2f} {nu*1e6:6.2f} {cp*1e6:6.3f} {cp_long*1e6:9.3f} {cp_ext*1e6:9.3f}")

# Check: 14 symbols (with two long CPs per half-subframe) fill exactly 0.5 ms per 7*2^mu symbols
for mu in range(7):
    n_half = 7 * 2 ** mu
    total = sum((2048 * KAPPA * 2.0 ** -mu + 144 * KAPPA * 2.0 ** -mu + (16 * KAPPA if l == 0 else 0)) * TC
                for l in range(n_half))
    assert abs(total - 0.5e-3) < 1e-12, (mu, total)
print("each 0.5 ms half-subframe is filled exactly for mu = 0..6")

# Sample rate for a chosen FFT size: fs = N_fft * SCS
for scs_khz, n_fft in [(15, 2048), (30, 4096), (30, 1024), (120, 4096)]:
    print(f"SCS {scs_khz} kHz, FFT {n_fft}: fs = {n_fft * scs_khz / 1e3:.2f} Msample/s")

期待される出力は次のとおりです。

 mu  SCS_kHz slots/sf  slot_us  Nu_us  CP_us  CPlong_us  CP_ext_us
  0      15        1  1000.00  66.67  4.688     5.208       nan
  1      30        2   500.00  33.33  2.344     2.865       nan
  2      60        4   250.00  16.67  1.172     1.693     4.167
  3     120        8   125.00   8.33  0.586     1.107       nan
  4     240       16    62.50   4.17  0.293     0.814       nan
  5     480       32    31.25   2.08  0.146     0.667       nan
  6     960       64    15.62   1.04  0.073     0.594       nan
each 0.5 ms half-subframe is filled exactly for mu = 0..6
SCS 15 kHz, FFT 2048: fs = 30.72 Msample/s
SCS 30 kHz, FFT 4096: fs = 122.88 Msample/s
SCS 30 kHz, FFT 1024: fs = 30.72 Msample/s
SCS 120 kHz, FFT 4096: fs = 491.52 Msample/s

コード: マルチパスチャネルを通る1つのOFDMシンボル

30.72 Msample/sでの30 kHz・1024ポイントのシンボルは、QPSKで変調した612本のサブキャリア(51リソースブロック、30 kHzの20 MHzの欄に相当)を運びます。サンプルはcomplex128です。サイクリックプレフィックスより短い9タップのチャネルは、サブキャリアごとに1回の複素除算で正確に打ち消せます。

import numpy as np

rng = np.random.default_rng(7)
n_fft, n_cp, n_used = 1024, 72, 612          # 30 kHz SCS -> fs = 30.72 Msample/s, 51 RB x 12 = 612 subcarriers
fs = n_fft * 30e3
qpsk = (rng.choice([-1, 1], n_used) + 1j * rng.choice([-1, 1], n_used)) / np.sqrt(2)

grid = np.zeros(n_fft, dtype=np.complex128)
k = np.r_[1:n_used // 2 + 1, n_fft - n_used // 2:n_fft]   # skip DC, fill both edges
grid[k] = qpsk
x = np.fft.ifft(grid) * np.sqrt(n_fft)
tx = np.concatenate([x[-n_cp:], x])                  # prepend cyclic prefix

h = np.array([1.0, 0, 0, 0.5j, 0, 0, 0, 0, 0.25])  # 9-tap channel, shorter than the CP
rx = np.convolve(tx, h)[: tx.size]
y = np.fft.fft(rx[n_cp:]) / np.sqrt(n_fft)
H = np.fft.fft(h, n_fft)
eq = y[k] / H[k]                                    # one-tap equaliser per subcarrier

print(f"fs = {fs/1e6:.2f} Msample/s, CP = {n_cp/fs*1e6:.2f} us, channel span = {(h.size-1)/fs*1e6:.2f} us")
print(f"max error after one-tap equalisation: {np.max(np.abs(eq - qpsk)):.2e}")
print(f"CP overhead: {n_cp / (n_fft + n_cp) * 100:.1f} %")

期待される出力は次のとおりです。

fs = 30.72 Msample/s, CP = 2.34 us, channel span = 0.26 us
max error after one-tap equalisation: 1.02e-15
CP overhead: 6.6 %

30.72 Msample/sでの72サンプルのプレフィックスは、30 kHzにおけるNRのノーマルCPです。hを73タップより長くすると、符号間干渉が入り込むため誤差が急増します。

落とし穴

  • すべてのスロットを1 msとみなすこと。サブフレームあたり1スロットなのはμ = 0だけです。
  • 各ハーフサブフレームの先頭シンボルにある長いCPを忘れること。全体で1種類のCP長を使うと、シンボルの開始時刻が徐々にずれます。
  • 誤った周波数レンジのN_RBを読むこと。FR1とFR2の表は異なります。
  • SS/PBCHブロックのサブキャリア間隔とデータのサブキャリア間隔を混同すること。同じキャリア上でも両者が異なる場合があります。
  • リリースの機能一覧を、ネットワークが実際に運用している内容とみなすこと。通信事業者は機能を選択的に有効にします。

出典

誤りやバージョン変更に気づいたら 訂正の手順をご覧ください。