第2章:赤外・ラマン分光法

振動分光で探る分子構造と化学結合

📚 シリーズ: 分光分析入門 ⏱️ 学習時間: 100分 🎯 難易度: 初級〜中級

イントロダクション

赤外分光(Infrared Spectroscopy, IR)とラマン分光(Raman Spectroscopy)は、分子の振動情報を通じて化学結合、官能基、結晶構造を解明する相補的な手法です。IRは赤外光の吸収を測定し、Ramanは散乱光の周波数シフトを観測します。両者は異なる選択則に従うため、IRで活性な振動がRamanで不活性、またはその逆という相補性を持ちます。

IRとRamanの使い分け

1. 分子振動の基礎

1.1 調和振動子モデル

2原子分子の振動は調和振動子で近似できます。ポテンシャルエネルギーはHookeの法則に従います:

$$V(r) = \frac{1}{2}k(r - r_e)^2$$

ここで、$k$ は力の定数(N/m)、$r_e$ は平衡核間距離です。振動周波数 $\nu$ は以下で与えられます:

$$\nu = \frac{1}{2\pi}\sqrt{\frac{k}{\mu}}$$

$\mu = \frac{m_1 m_2}{m_1 + m_2}$ は換算質量です。振動エネルギー準位は量子化され、

$$E_v = h\nu \left(v + \frac{1}{2}\right), \quad v = 0, 1, 2, \ldots$$

調和振動子近似では、選択則は $\Delta v = \pm 1$ です(基本振動のみ許容)。実際の分子では非調和性により $\Delta v = \pm 2, \pm 3, \ldots$(倍音)も弱く観測されます。

コード例1: 調和振動子のエネルギー準位と振動周波数計算

import numpy as np
import matplotlib.pyplot as plt

# 物理定数
h = 6.62607015e-34  # J·s
c = 2.99792458e8    # m/s
u = 1.66053906660e-27  # kg (atomic mass unit)

def vibrational_frequency(k, m1, m2):
    """
    2原子分子の振動周波数(Hz)と波数(cm^-1)を計算

    Parameters:
    -----------
    k : float
        力の定数(N/m)
    m1, m2 : float
        原子の質量(amu)

    Returns:
    --------
    freq_Hz : float
        振動周波数(Hz)
    wavenumber : float
        波数(cm^-1)
    """
    # 換算質量
    mu = (m1 * m2) / (m1 + m2) * u  # kg

    # 振動周波数
    freq_Hz = (1 / (2 * np.pi)) * np.sqrt(k / mu)

    # 波数に変換
    wavenumber = freq_Hz / (c * 100)  # cm^-1

    return freq_Hz, wavenumber

def energy_levels(v_max, freq_Hz):
    """
    調和振動子のエネルギー準位

    Parameters:
    -----------
    v_max : int
        最大振動量子数
    freq_Hz : float
        振動周波数(Hz)

    Returns:
    --------
    v : array
        振動量子数
    E : array
        エネルギー(eV)
    """
    v = np.arange(0, v_max + 1)
    E_J = h * freq_Hz * (v + 0.5)
    E_eV = E_J / 1.602176634e-19
    return v, E_eV

# 典型的な化学結合の計算
bonds = {
    'C-H': {'k': 500, 'm1': 12, 'm2': 1},
    'C=O': {'k': 1200, 'm1': 12, 'm2': 16},
    'C-C': {'k': 400, 'm1': 12, 'm2': 12},
    'O-H': {'k': 750, 'm1': 16, 'm2': 1}
}

print("=" * 70)
print("典型的な化学結合の振動周波数")
print("=" * 70)
print(f"{'結合':<8} {'力の定数 (N/m)':<18} {'周波数 (Hz)':<18} {'波数 (cm⁻¹)':<15}")
print("-" * 70)

for bond, params in bonds.items():
    freq_Hz, wavenumber = vibrational_frequency(params['k'], params['m1'], params['m2'])
    print(f"{bond:<8} {params['k']:<18} {freq_Hz:.3e} {wavenumber:<15.1f}")

# C=O伸縮振動のエネルギー準位図
freq_Hz_CO, wn_CO = vibrational_frequency(1200, 12, 16)
v, E = energy_levels(5, freq_Hz_CO)

fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

# エネルギー準位図
ax1.hlines(E, 0, 1, colors='#f093fb', linewidths=3)
for i, (vi, Ei) in enumerate(zip(v, E)):
    ax1.text(1.1, Ei, f'v={vi}', fontsize=11, va='center')
    if i < len(v) - 1:
        # 遷移の矢印
        ax1.annotate('', xy=(0.5, E[i+1]), xytext=(0.5, E[i]),
                    arrowprops=dict(arrowstyle='->', color='red', lw=2))

ax1.set_xlim(-0.2, 1.5)
ax1.set_ylim(E[0] - 0.05, E[-1] + 0.1)
ax1.set_ylabel('エネルギー (eV)', fontsize=12)
ax1.set_title('C=O伸縮振動のエネルギー準位', fontsize=14, fontweight='bold')
ax1.set_xticks([])
ax1.grid(axis='y', alpha=0.3)

# 同位体効果
masses_C = np.array([12, 13, 14])
wavenumbers = []
for m_C in masses_C:
    _, wn = vibrational_frequency(1200, m_C, 16)
    wavenumbers.append(wn)

ax2.bar([f'$^{{{int(m)}}}$C=O' for m in masses_C], wavenumbers,
        color=['#f093fb', '#f5576c', '#4ecdc4'], alpha=0.7, edgecolor='black')
ax2.set_ylabel('波数 (cm⁻¹)', fontsize=12)
ax2.set_title('同位体効果:C=O伸縮振動', fontsize=14, fontweight='bold')
ax2.grid(axis='y', alpha=0.3)

for i, (m, wn) in enumerate(zip(masses_C, wavenumbers)):
    ax2.text(i, wn + 20, f'{wn:.0f}', ha='center', fontsize=11, fontweight='bold')

plt.tight_layout()
plt.savefig('vibrational_fundamentals.png', dpi=300, bbox_inches='tight')
plt.show()

print(f"\nC=O伸縮振動の波数: {wn_CO:.1f} cm⁻¹")
print(f"基底状態(v=0)のゼロ点エネルギー: {E[0]:.4f} eV")
print(f"v=0 → v=1 遷移エネルギー: {E[1] - E[0]:.4f} eV")

1.2 多原子分子の振動モード

$N$ 原子からなる分子は $3N$ 個の自由度を持ち、そのうち3つは並進、(非線形分子では)3つは回転、残りの $3N - 6$(線形分子では $3N - 5$)が振動の自由度です。

flowchart TD A[全自由度 3N] --> B[並進 3] A --> C[回転] A --> D[振動] C --> C1[非線形分子: 3] C --> C2[線形分子: 2] D --> D1[非線形: 3N-6] D --> D2[線形: 3N-5] D1 --> E[H₂O: 3モード
CO₂: 4モード
ベンゼン: 30モード] style A fill:#f093fb,color:#fff style D fill:#f5576c,color:#fff style E fill:#a8e6cf,color:#000

振動モードは伸縮振動(stretching)変角振動(bending)に分類されます:

コード例2: H₂O分子の3つの振動モードシミュレーション

import numpy as np
import matplotlib.pyplot as plt
from matplotlib.animation import FuncAnimation
from IPython.display import HTML

def h2o_normal_modes():
    """
    H2O分子の3つの振動モード(対称伸縮、非対称伸縮、変角)の可視化

    Returns:
    --------
    fig : matplotlib figure
        振動モードの図
    """
    fig, axes = plt.subplots(1, 3, figsize=(15, 5))

    # 平衡位置(O原子を原点)
    O = np.array([0, 0])
    H1 = np.array([-0.76, 0.59])  # 左のH
    H2 = np.array([0.76, 0.59])   # 右のH

    modes = [
        {
            'name': '対称伸縮 (νₛ)',
            'freq': '3657 cm⁻¹',
            'displacements': {
                'O': np.array([0, 0]),
                'H1': np.array([-0.1, 0.08]),
                'H2': np.array([0.1, 0.08])
            }
        },
        {
            'name': '変角振動 (δ)',
            'freq': '1595 cm⁻¹',
            'displacements': {
                'O': np.array([0, 0]),
                'H1': np.array([-0.05, -0.1]),
                'H2': np.array([0.05, -0.1])
            }
        },
        {
            'name': '非対称伸縮 (νₐₛ)',
            'freq': '3756 cm⁻¹',
            'displacements': {
                'O': np.array([0, 0]),
                'H1': np.array([-0.1, 0.08]),
                'H2': np.array([0.1, -0.08])
            }
        }
    ]

    for ax, mode in zip(axes, modes):
        # 平衡位置
        ax.plot(*O, 'ro', markersize=15, label='O')
        ax.plot(*H1, 'bo', markersize=10, label='H')
        ax.plot(*H2, 'bo', markersize=10)
        ax.plot([O[0], H1[0]], [O[1], H1[1]], 'k-', linewidth=2)
        ax.plot([O[0], H2[0]], [O[1], H2[1]], 'k-', linewidth=2)

        # 振動の変位(拡大表示)
        scale = 2
        O_disp = O + scale * mode['displacements']['O']
        H1_disp = H1 + scale * mode['displacements']['H1']
        H2_disp = H2 + scale * mode['displacements']['H2']

        ax.plot(*O_disp, 'ro', markersize=15, alpha=0.3)
        ax.plot(*H1_disp, 'bo', markersize=10, alpha=0.3)
        ax.plot(*H2_disp, 'bo', markersize=10, alpha=0.3)
        ax.plot([O_disp[0], H1_disp[0]], [O_disp[1], H1_disp[1]], 'k--', linewidth=2, alpha=0.3)
        ax.plot([O_disp[0], H2_disp[0]], [O_disp[1], H2_disp[1]], 'k--', linewidth=2, alpha=0.3)

        # 変位ベクトル
        ax.arrow(*O, *mode['displacements']['O'], head_width=0.08, head_length=0.05, fc='red', ec='red')
        ax.arrow(*H1, *mode['displacements']['H1'], head_width=0.08, head_length=0.05, fc='blue', ec='blue')
        ax.arrow(*H2, *mode['displacements']['H2'], head_width=0.08, head_length=0.05, fc='blue', ec='blue')

        ax.set_xlim(-1.2, 1.2)
        ax.set_ylim(-0.5, 1)
        ax.set_aspect('equal')
        ax.set_title(f"{mode['name']}\n{mode['freq']}", fontsize=12, fontweight='bold')
        ax.axis('off')

    plt.tight_layout()
    plt.savefig('h2o_normal_modes.png', dpi=300, bbox_inches='tight')
    plt.show()

    return fig

# 実行
fig = h2o_normal_modes()

# 振動モードの特徴
print("=" * 60)
print("H₂O分子の3つの基本振動モード")
print("=" * 60)
print("1. 対称伸縮 (νₛ): 3657 cm⁻¹")
print("   - 両方のO-H結合が同時に伸縮")
print("   - IRで強い吸収(双極子モーメント変化大)")
print("")
print("2. 変角振動 (δ): 1595 cm⁻¹")
print("   - H-O-H角が変化")
print("   - 最も低い振動数(弱い力の定数)")
print("")
print("3. 非対称伸縮 (νₐₛ): 3756 cm⁻¹")
print("   - 一方のO-Hが伸びるとき、他方は縮む")
print("   - IRで最も強い吸収")

2. 赤外分光法(IR)

2.1 IR吸収の選択則

IRで振動が活性(IR active)であるためには、振動に伴って双極子モーメント $\boldsymbol{\mu}$ が変化する必要があります:

$$\left(\frac{\partial \boldsymbol{\mu}}{\partial Q}\right)_0 \neq 0$$

ここで、$Q$ は振動の規準座標です。対称分子(CO₂など)の対称伸縮振動はIR不活性ですが、非対称伸縮や変角振動はIR活性です。

2.2 官能基と特性吸収

有機化合物の官能基は特定の波数領域に特性吸収を示します。これにより、IRスペクトルから分子構造を推定できます。

官能基 振動モード 波数(cm⁻¹) 強度
O-H(アルコール) 伸縮 3200-3600 強、幅広
N-H 伸縮 3300-3500
C-H(脂肪族) 伸縮 2850-2960
C≡N 伸縮 2210-2260
C=O(カルボニル) 伸縮 1650-1750 非常に強
C=C 伸縮 1620-1680 弱〜中
C-O 伸縮 1000-1300
芳香環 面外変角 690-900

コード例3: IRスペクトルシミュレーション(エタノール)

import numpy as np
import matplotlib.pyplot as plt

def lorentzian_peak(x, center, intensity, width):
    """Lorentzian線形関数"""
    return intensity * (width**2 / ((x - center)**2 + width**2))

def simulate_ir_spectrum(peaks, x_range=(4000, 400)):
    """
    IRスペクトルのシミュレーション

    Parameters:
    -----------
    peaks : list of dict
        各ピークの情報 [{'center': cm-1, 'intensity': 0-1, 'width': cm-1, 'label': str}, ...]
    x_range : tuple
        波数範囲(cm⁻¹)

    Returns:
    --------
    wavenumbers : array
        波数軸
    transmittance : array
        透過率(%)
    """
    wavenumbers = np.linspace(x_range[0], x_range[1], 2000)
    absorbance = np.zeros_like(wavenumbers)

    for peak in peaks:
        absorbance += lorentzian_peak(wavenumbers, peak['center'],
                                       peak['intensity'], peak['width'])

    transmittance = 100 * np.exp(-absorbance)
    return wavenumbers, transmittance, peaks

# エタノール (CH₃CH₂OH) のIRスペクトル
ethanol_peaks = [
    {'center': 3350, 'intensity': 1.5, 'width': 100, 'label': 'O-H伸縮'},
    {'center': 2970, 'intensity': 0.8, 'width': 20, 'label': 'C-H伸縮(CH₃)'},
    {'center': 2930, 'intensity': 0.7, 'width': 20, 'label': 'C-H伸縮(CH₂)'},
    {'center': 1450, 'intensity': 0.4, 'width': 30, 'label': 'C-H変角'},
    {'center': 1380, 'intensity': 0.3, 'width': 20, 'label': 'C-H変角'},
    {'center': 1050, 'intensity': 1.0, 'width': 40, 'label': 'C-O伸縮'},
    {'center': 880, 'intensity': 0.5, 'width': 25, 'label': 'C-C伸縮'},
]

wavenumbers, transmittance, peaks = simulate_ir_spectrum(ethanol_peaks)

# プロット
fig, ax = plt.subplots(figsize=(12, 6))

ax.plot(wavenumbers, transmittance, linewidth=1.5, color='#f093fb')
ax.fill_between(wavenumbers, transmittance, 100, alpha=0.2, color='#f5576c')

# ピークのラベル
for peak in peaks:
    idx = np.argmin(np.abs(wavenumbers - peak['center']))
    y_pos = transmittance[idx]
    if y_pos < 50:
        ax.annotate(peak['label'], xy=(peak['center'], y_pos),
                   xytext=(peak['center'], y_pos - 15),
                   fontsize=9, ha='center', rotation=90,
                   arrowprops=dict(arrowstyle='->', color='black', lw=0.8))

ax.set_xlabel('波数 (cm⁻¹)', fontsize=12)
ax.set_ylabel('透過率 (%)', fontsize=12)
ax.set_title('エタノール (CH₃CH₂OH) のIRスペクトル(シミュレーション)',
             fontsize=14, fontweight='bold')
ax.set_xlim(4000, 400)
ax.set_ylim(0, 105)
ax.invert_xaxis()  # IRスペクトルは通常高波数側が左
ax.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('ethanol_ir_spectrum.png', dpi=300, bbox_inches='tight')
plt.show()

# ピーク帰属表
print("=" * 70)
print("エタノールのIRスペクトル帰属")
print("=" * 70)
print(f"{'波数 (cm⁻¹)':<15} {'強度':<10} {'帰属':<30}")
print("-" * 70)
for peak in sorted(peaks, key=lambda x: x['center'], reverse=True):
    intensity_str = '強' if peak['intensity'] > 1.0 else ('中' if peak['intensity'] > 0.5 else '弱')
    print(f"{peak['center']:<15} {intensity_str:<10} {peak['label']:<30}")

2.3 FTIR(フーリエ変換赤外分光法)

現代のIR分光計はマイケルソン干渉計を用いたFTIR(Fourier Transform Infrared Spectroscopy)が主流です。干渉計で得られたインターフェログラム(時間領域信号)をフーリエ変換して周波数領域のスペクトルを得ます。

FTIRの利点

コード例4: FTIRのインターフェログラムとフーリエ変換

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

def generate_interferogram(wavenumbers_cm, intensities, mirror_displacement_max=0.05):
    """
    IRスペクトルからインターフェログラムを生成(簡略化版)

    Parameters:
    -----------
    wavenumbers_cm : array
        波数(cm⁻¹)
    intensities : array
        各波数の強度
    mirror_displacement_max : float
        ミラー移動距離の最大値(cm)

    Returns:
    --------
    displacement : array
        ミラー変位
    interferogram : array
        インターフェログラム
    """
    # ミラー変位
    n_points = 2048
    displacement = np.linspace(-mirror_displacement_max, mirror_displacement_max, n_points)

    # インターフェログラム(各波数成分の干渉パターンの和)
    interferogram = np.zeros_like(displacement)
    for wn, intensity in zip(wavenumbers_cm, intensities):
        # 波数をcm^-1からcm単位の波長に変換
        # cos(2π * wavenumber * displacement)
        interferogram += intensity * np.cos(2 * np.pi * wn * displacement)

    # DC成分追加
    interferogram += np.sum(intensities)

    return displacement, interferogram

def fourier_transform_spectrum(displacement, interferogram):
    """
    インターフェログラムをフーリエ変換してスペクトルを復元

    Parameters:
    -----------
    displacement : array
        ミラー変位(cm)
    interferogram : array
        インターフェログラム

    Returns:
    --------
    wavenumbers : array
        波数(cm⁻¹)
    spectrum : array
        復元されたスペクトル
    """
    # フーリエ変換
    N = len(interferogram)
    spectrum_complex = fft(interferogram)
    spectrum = np.abs(spectrum_complex[:N//2])

    # 波数軸(cm⁻¹)
    delta_x = displacement[1] - displacement[0]
    wavenumbers = fftfreq(N, delta_x)[:N//2]

    return wavenumbers, spectrum

# シミュレーション:3つのIRピーク
true_wavenumbers = np.array([1000, 1700, 2900])  # cm^-1
true_intensities = np.array([0.5, 1.0, 0.7])

# インターフェログラム生成
displacement, interferogram = generate_interferogram(true_wavenumbers, true_intensities)

# フーリエ変換でスペクトル復元
wavenumbers_ft, spectrum_ft = fourier_transform_spectrum(displacement, interferogram)

# 可視化
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))

# インターフェログラム
ax1.plot(displacement, interferogram, linewidth=1.5, color='#f093fb')
ax1.set_xlabel('ミラー変位 (cm)', fontsize=12)
ax1.set_ylabel('インターフェログラム強度', fontsize=12)
ax1.set_title('FTIRインターフェログラム(時間領域)', fontsize=14, fontweight='bold')
ax1.grid(True, alpha=0.3)
ax1.axvline(x=0, color='red', linestyle='--', linewidth=2, alpha=0.5, label='Zero Path Difference')
ax1.legend()

# フーリエ変換後のスペクトル
ax2.plot(wavenumbers_ft, spectrum_ft, linewidth=1.5, color='#f5576c')
ax2.set_xlabel('波数 (cm⁻¹)', fontsize=12)
ax2.set_ylabel('強度 (a.u.)', fontsize=12)
ax2.set_title('フーリエ変換後のIRスペクトル(周波数領域)', fontsize=14, fontweight='bold')
ax2.set_xlim(0, 4000)
ax2.grid(True, alpha=0.3)

# 真のピーク位置をマーク
for wn, intensity in zip(true_wavenumbers, true_intensities):
    ax2.axvline(x=wn, color='green', linestyle='--', alpha=0.7, linewidth=1.5)
    ax2.text(wn, max(spectrum_ft) * 0.9, f'{wn} cm⁻¹',
            rotation=90, va='bottom', fontsize=10, color='green')

plt.tight_layout()
plt.savefig('ftir_interferogram.png', dpi=300, bbox_inches='tight')
plt.show()

print("=" * 60)
print("FTIR測定の原理")
print("=" * 60)
print("1. マイケルソン干渉計でミラーを移動")
print("2. 干渉パターン(インターフェログラム)を記録")
print("3. フーリエ変換で周波数領域のスペクトルを復元")
print("")
print("真のピーク位置: ", true_wavenumbers, " cm⁻¹")
print("復元されたピーク: フーリエ変換後のスペクトルで確認")

3. ラマン分光法

3.1 Raman散乱の原理

Raman散乱は、光と分子の相互作用により、入射光(周波数 $\nu_0$)が分子の振動エネルギー(周波数 $\nu_m$)だけシフトした散乱光として観測される現象です:

Raman散乱の選択則は、振動に伴って分極率 $\alpha$ が変化することです:

$$\left(\frac{\partial \alpha}{\partial Q}\right)_0 \neq 0$$

この選択則はIRとは異なり、対称振動がRaman活性、非対称振動がRaman不活性となる場合が多いです(相補則)。

コード例5: RamanスペクトルとStokes/Anti-Stokesの比

import numpy as np
import matplotlib.pyplot as plt

def boltzmann_population(E_vib_cm, T=300):
    """
    Boltzmann分布による振動励起状態の占有率

    Parameters:
    -----------
    E_vib_cm : float
        振動エネルギー(cm⁻¹)
    T : float
        温度(K)

    Returns:
    --------
    ratio : float
        v=1とv=0の占有率比 n₁/n₀
    """
    k_B = 1.380649e-23  # J/K
    h = 6.62607015e-34  # J·s
    c = 2.99792458e8    # m/s

    E_J = h * c * E_vib_cm * 100  # cm^-1 to J
    ratio = np.exp(-E_J / (k_B * T))
    return ratio

def raman_spectrum_simulation(laser_wavelength=532):
    """
    Ramanスペクトル(Stokes/Anti-Stokes)のシミュレーション

    Parameters:
    -----------
    laser_wavelength : float
        励起レーザー波長(nm)

    Returns:
    --------
    fig : matplotlib figure
    """
    # 振動モード
    vibrations = [
        {'mode': 'C-C伸縮', 'shift': 1000, 'intensity': 0.8},
        {'mode': 'C=O伸縮', 'shift': 1700, 'intensity': 1.0},
        {'mode': 'C-H伸縮', 'shift': 2900, 'intensity': 0.6}
    ]

    # レーザー周波数
    laser_freq = 1e7 / laser_wavelength  # cm^-1

    # Raman shift軸(通常は-3500 ~ +3500 cm^-1)
    raman_shift = np.linspace(-3500, 3500, 3000)

    # スペクトル初期化
    spectrum = np.zeros_like(raman_shift)

    # 各振動モードのピーク
    for vib in vibrations:
        shift = vib['shift']
        intensity = vib['intensity']

        # Stokesピーク(正のシフト)
        stokes = intensity * np.exp(-(raman_shift - shift)**2 / (2 * 30**2))
        spectrum += stokes

        # Anti-Stokesピーク(負のシフト)
        # Boltzmann因子で強度が減少
        boltzmann_ratio = boltzmann_population(shift, T=300)
        anti_stokes = intensity * boltzmann_ratio * np.exp(-(raman_shift + shift)**2 / (2 * 30**2))
        spectrum += anti_stokes

    # Rayleigh散乱(中心、非常に強い)
    rayleigh = 100 * np.exp(-(raman_shift)**2 / (2 * 20**2))

    # プロット
    fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))

    # 全スペクトル(Rayleigh含む)
    ax1.plot(raman_shift, spectrum + rayleigh, linewidth=1.5, color='#f093fb')
    ax1.fill_between(raman_shift, spectrum + rayleigh, alpha=0.3, color='#f5576c')
    ax1.axvline(x=0, color='red', linestyle='--', linewidth=2, label='Rayleigh散乱')
    ax1.set_xlabel('Raman Shift (cm⁻¹)', fontsize=12)
    ax1.set_ylabel('強度 (a.u.)', fontsize=12)
    ax1.set_title(f'Ramanスペクトル全体(レーザー: {laser_wavelength} nm)',
                 fontsize=14, fontweight='bold')
    ax1.legend()
    ax1.grid(True, alpha=0.3)
    ax1.set_yscale('log')
    ax1.set_ylim(0.01, 150)

    # Stokes領域の拡大(実用的な測定範囲)
    ax2.plot(raman_shift, spectrum, linewidth=1.5, color='#f5576c')
    ax2.fill_between(raman_shift, spectrum, alpha=0.3, color='#f093fb')
    ax2.set_xlabel('Raman Shift (cm⁻¹)', fontsize=12)
    ax2.set_ylabel('強度 (a.u.)', fontsize=12)
    ax2.set_title('Ramanスペクトル(Rayleigh除去後)', fontsize=14, fontweight='bold')
    ax2.axvline(x=0, color='gray', linestyle='--', alpha=0.5)
    ax2.grid(True, alpha=0.3)

    # ピーク帰属
    for vib in vibrations:
        shift = vib['shift']
        ax2.text(shift, vib['intensity'] * 1.1, vib['mode'],
                ha='center', fontsize=10, rotation=45)
        ax2.text(-shift, vib['intensity'] * boltzmann_population(shift) * 1.1,
                vib['mode'] + '\n(Anti-Stokes)',
                ha='center', fontsize=9, rotation=45, alpha=0.7)

    plt.tight_layout()
    plt.savefig('raman_spectrum_stokes_antistokes.png', dpi=300, bbox_inches='tight')
    plt.show()

    # Boltzmann比の温度依存性
    print("=" * 70)
    print("Stokes/Anti-Stokes強度比の温度依存性")
    print("=" * 70)
    print(f"{'振動モード':<20} {'Raman shift (cm⁻¹)':<25} {'I(Anti-Stokes)/I(Stokes) at 300K':<30}")
    print("-" * 70)
    for vib in vibrations:
        ratio = boltzmann_population(vib['shift'], T=300)
        print(f"{vib['mode']:<20} {vib['shift']:<25} {ratio:<30.4f}")

    return fig

# 実行
fig = raman_spectrum_simulation(laser_wavelength=532)

# 温度依存性の計算
temperatures = np.linspace(100, 800, 50)
raman_shift_1000 = 1000  # cm^-1

ratios = [boltzmann_population(raman_shift_1000, T) for T in temperatures]

plt.figure(figsize=(10, 6))
plt.plot(temperatures, ratios, linewidth=2, color='#f093fb')
plt.xlabel('温度 (K)', fontsize=12)
plt.ylabel('I(Anti-Stokes) / I(Stokes)', fontsize=12)
plt.title('Raman強度比の温度依存性(1000 cm⁻¹モード)', fontsize=14, fontweight='bold')
plt.grid(True, alpha=0.3)
plt.axhline(y=boltzmann_population(1000, 300), color='red', linestyle='--',
           label='室温 (300 K)')
plt.legend()
plt.tight_layout()
plt.savefig('raman_temperature_dependence.png', dpi=300, bbox_inches='tight')
plt.show()

3.2 IRとRamanの相補則

中心対称分子(例: CO₂、ベンゼン)では、IRとRamanの選択則が相補的です:

相互排他則(Mutual Exclusion Rule)
中心対称分子において、IR活性な振動はRaman不活性、Raman活性な振動はIR不活性となります。これは対称性による選択則の違いから生じます。
振動モード 対称性 IR活性 Raman活性
CO₂対称伸縮 Σg 不活性 活性
CO₂非対称伸縮 Σu 活性 不活性
CO₂変角振動 Πu 活性 不活性

3.3 Raman分光の応用

コード例6: 結晶性評価のためのRamanピークフィッティング

import numpy as np
import matplotlib.pyplot as plt
from scipy.optimize import curve_fit

def crystallinity_analysis(raman_shift, intensity):
    """
    Ramanスペクトルから結晶化度を評価(ポリマーの例)

    Parameters:
    -----------
    raman_shift : array
        Raman shift(cm⁻¹)
    intensity : array
        Raman強度

    Returns:
    --------
    crystallinity : float
        結晶化度(%)
    fit_params : dict
        フィッティングパラメータ
    """
    def two_peak_model(x, A1, c1, w1, A2, c2, w2):
        """結晶ピークと非晶ピークの2成分モデル"""
        peak1 = A1 * np.exp(-(x - c1)**2 / (2 * w1**2))  # 結晶ピーク
        peak2 = A2 * np.exp(-(x - c2)**2 / (2 * w2**2))  # 非晶ピーク
        return peak1 + peak2

    # 初期推定値
    p0 = [100, 1095, 10, 80, 1080, 15]

    # フィッティング
    popt, pcov = curve_fit(two_peak_model, raman_shift, intensity, p0=p0)

    # 個別ピーク
    crystal_peak = popt[0] * np.exp(-(raman_shift - popt[1])**2 / (2 * popt[2]**2))
    amorphous_peak = popt[3] * np.exp(-(raman_shift - popt[4])**2 / (2 * popt[5]**2))

    # 結晶化度(ピーク面積比)
    crystal_area = popt[0] * popt[2] * np.sqrt(2 * np.pi)
    amorphous_area = popt[3] * popt[5] * np.sqrt(2 * np.pi)
    crystallinity = crystal_area / (crystal_area + amorphous_area) * 100

    fit_params = {
        'crystal_center': popt[1],
        'crystal_width': popt[2],
        'amorphous_center': popt[4],
        'amorphous_width': popt[5],
        'crystal_peak': crystal_peak,
        'amorphous_peak': amorphous_peak,
        'fitted_curve': two_peak_model(raman_shift, *popt)
    }

    return crystallinity, fit_params

# 合成データ(半結晶性ポリマーのC-C伸縮領域)
raman_shift = np.linspace(1050, 1130, 300)
crystal_peak_true = 70 * np.exp(-(raman_shift - 1095)**2 / (2 * 8**2))
amorphous_peak_true = 50 * np.exp(-(raman_shift - 1080)**2 / (2 * 12**2))
intensity = crystal_peak_true + amorphous_peak_true + np.random.normal(0, 2, len(raman_shift))

# 結晶化度解析
crystallinity, fit_params = crystallinity_analysis(raman_shift, intensity)

# プロット
fig, (ax1, ax2) = plt.subplots(1, 2, figsize=(14, 6))

# ピーク分離
ax1.plot(raman_shift, intensity, 'k.', markersize=4, alpha=0.5, label='実験データ')
ax1.plot(raman_shift, fit_params['fitted_curve'], 'r-', linewidth=2, label='フィッティング')
ax1.plot(raman_shift, fit_params['crystal_peak'], 'b--', linewidth=2, label='結晶成分')
ax1.plot(raman_shift, fit_params['amorphous_peak'], 'g--', linewidth=2, label='非晶成分')
ax1.fill_between(raman_shift, fit_params['crystal_peak'], alpha=0.3, color='blue')
ax1.fill_between(raman_shift, fit_params['amorphous_peak'], alpha=0.3, color='green')
ax1.set_xlabel('Raman Shift (cm⁻¹)', fontsize=12)
ax1.set_ylabel('強度 (a.u.)', fontsize=12)
ax1.set_title('ピーク分離による結晶化度解析', fontsize=14, fontweight='bold')
ax1.legend()
ax1.grid(True, alpha=0.3)

# 結晶化度の表示
ax2.bar(['結晶成分', '非晶成分'],
       [crystallinity, 100 - crystallinity],
       color=['#4ecdc4', '#ffe66d'], edgecolor='black', linewidth=2)
ax2.set_ylabel('割合 (%)', fontsize=12)
ax2.set_title(f'結晶化度: {crystallinity:.1f}%', fontsize=14, fontweight='bold')
ax2.set_ylim(0, 100)
ax2.grid(axis='y', alpha=0.3)

for i, (label, value) in enumerate(zip(['結晶成分', '非晶成分'],
                                        [crystallinity, 100 - crystallinity])):
    ax2.text(i, value + 3, f'{value:.1f}%', ha='center', fontsize=12, fontweight='bold')

plt.tight_layout()
plt.savefig('raman_crystallinity_analysis.png', dpi=300, bbox_inches='tight')
plt.show()

# 結果の出力
print("=" * 60)
print("Raman結晶化度解析結果")
print("=" * 60)
print(f"結晶ピーク中心: {fit_params['crystal_center']:.1f} cm⁻¹")
print(f"結晶ピーク幅(FWHM): {2.355 * fit_params['crystal_width']:.1f} cm⁻¹")
print(f"非晶ピーク中心: {fit_params['amorphous_center']:.1f} cm⁻¹")
print(f"非晶ピーク幅(FWHM): {2.355 * fit_params['amorphous_width']:.1f} cm⁻¹")
print(f"\n結晶化度: {crystallinity:.1f}%")
print(f"非晶化度: {100 - crystallinity:.1f}%")

4. 群論と振動選択則

4.1 分子の対称性と既約表現

分子の振動モードは、分子の対称性(点群)によって分類されます。各振動モードは点群の既約表現に対応し、その対称性から選択則(IR活性、Raman活性)が決まります。

主要な点群と既約表現の例

コード例7: H₂O分子の振動モードと対称性

import numpy as np
import matplotlib.pyplot as plt

def h2o_symmetry_analysis():
    """
    H₂O分子(C2v点群)の振動モードと選択則

    Returns:
    --------
    table : dict
        振動モードの情報
    """
    # H2O分子の3つの基本振動モード
    modes = {
        'mode1': {
            'name': '対称伸縮',
            'symmetry': 'A₁',
            'wavenumber': 3657,
            'IR_active': True,
            'Raman_active': True,
            'description': '両O-H結合が同時に伸縮、対称'
        },
        'mode2': {
            'name': '変角振動',
            'symmetry': 'A₁',
            'wavenumber': 1595,
            'IR_active': True,
            'Raman_active': True,
            'description': 'H-O-H角が変化'
        },
        'mode3': {
            'name': '非対称伸縮',
            'symmetry': 'B₁',
            'wavenumber': 3756,
            'IR_active': True,
            'Raman_active': True,
            'description': '一方のO-Hが伸びる時、他方が縮む'
        }
    }

    # 表形式で表示
    print("=" * 80)
    print("H₂O分子(C₂v点群)の振動モードと選択則")
    print("=" * 80)
    print(f"{'モード':<12} {'対称性':<10} {'波数 (cm⁻¹)':<15} {'IR活性':<10} {'Raman活性':<12} {'説明':<30}")
    print("-" * 80)

    for mode_id, mode in modes.items():
        ir_str = '○' if mode['IR_active'] else '×'
        raman_str = '○' if mode['Raman_active'] else '×'
        print(f"{mode['name']:<12} {mode['symmetry']:<10} {mode['wavenumber']:<15} "
              f"{ir_str:<10} {raman_str:<12} {mode['description']:<30}")

    print("\n" + "=" * 80)
    print("C₂v点群の指標表(Character Table)")
    print("=" * 80)
    print("  C₂v | E   C₂  σv  σv' | 基底関数")
    print("-" * 80)
    print("  A₁  | 1   1   1   1   | z, x², y², z²")
    print("  A₂  | 1   1  -1  -1   | Rz")
    print("  B₁  | 1  -1   1  -1   | x, Ry")
    print("  B₂  | 1  -1  -1   1   | y, Rx")
    print("\n選択則:")
    print("  IR活性: μx, μy, μz(双極子モーメント)が基底に含まれる")
    print("  Raman活性: αxx, αyy, αzz, αxy, αxz, αyz(分極率テンソル)が基底に含まれる")
    print("\nH₂Oの場合、A₁とB₁はいずれもIRとRaman両方で活性")

    # 可視化:エネルギーレベル図
    fig, ax = plt.subplots(figsize=(10, 8))

    # 基底状態と励起状態
    y_ground = 0
    modes_sorted = sorted(modes.items(), key=lambda x: x[1]['wavenumber'])

    colors = ['#f093fb', '#f5576c', '#4ecdc4']

    for i, (mode_id, mode) in enumerate(modes_sorted):
        y_excited = mode['wavenumber'] / 100  # スケーリング
        ax.hlines(y_excited, i*0.5, i*0.5 + 0.4, colors=colors[i], linewidths=5,
                 label=f"{mode['name']} ({mode['symmetry']})")
        ax.text(i*0.5 + 0.45, y_excited, f"{mode['wavenumber']} cm⁻¹",
               va='center', fontsize=10)

        # 遷移矢印
        ax.annotate('', xy=(i*0.5 + 0.2, y_excited), xytext=(i*0.5 + 0.2, y_ground),
                   arrowprops=dict(arrowstyle='->', color=colors[i], lw=2))

    ax.hlines(y_ground, -0.2, 1.5, colors='black', linewidths=3, label='基底状態 (v=0)')
    ax.set_xlim(-0.3, 1.6)
    ax.set_ylim(-2, 40)
    ax.set_ylabel('相対エネルギー (cm⁻¹ / 100)', fontsize=12)
    ax.set_title('H₂O分子の振動励起エネルギー準位', fontsize=14, fontweight='bold')
    ax.set_xticks([])
    ax.legend(loc='upper left', fontsize=10)
    ax.grid(axis='y', alpha=0.3)

    plt.tight_layout()
    plt.savefig('h2o_symmetry_modes.png', dpi=300, bbox_inches='tight')
    plt.show()

    return modes

# 実行
modes = h2o_symmetry_analysis()

4.2 選択則の決定

既約表現に対応する振動モードがIR活性またはRaman活性であるかは、以下の規則で判定されます:

5. 実践的なスペクトル解析

コード例8: IRとRamanの統合解析ワークフロー

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

class VibrationalSpectroscopyAnalyzer:
    """IR・Ramanスペクトルの統合解析クラス"""

    def __init__(self):
        # 官能基データベース(簡略版)
        self.functional_groups = {
            'O-H': {'IR': (3200, 3600), 'Raman': (3200, 3600), 'intensity_IR': 'strong'},
            'N-H': {'IR': (3300, 3500), 'Raman': (3300, 3500), 'intensity_IR': 'medium'},
            'C-H': {'IR': (2850, 3000), 'Raman': (2850, 3000), 'intensity_IR': 'strong'},
            'C=O': {'IR': (1650, 1750), 'Raman': (1650, 1750), 'intensity_IR': 'very strong'},
            'C=C': {'IR': (1620, 1680), 'Raman': (1620, 1680), 'intensity_Raman': 'strong'},
            'C-C': {'IR': (800, 1200), 'Raman': (800, 1200), 'intensity_Raman': 'medium'},
        }

    def identify_functional_groups(self, wavenumbers, intensity, threshold=0.3):
        """
        スペクトルから官能基を同定

        Parameters:
        -----------
        wavenumbers : array
            波数(cm⁻¹)
        intensity : array
            強度
        threshold : float
            ピーク検出の閾値(最大値に対する相対値)

        Returns:
        --------
        identified_groups : list
            同定された官能基のリスト
        """
        # ピーク検出
        peaks, properties = find_peaks(intensity, prominence=threshold * np.max(intensity))

        identified_groups = []

        for peak in peaks:
            peak_wn = wavenumbers[peak]

            # 官能基データベースと照合
            for group, ranges in self.functional_groups.items():
                ir_range = ranges['IR']
                if ir_range[0] <= peak_wn <= ir_range[1]:
                    identified_groups.append({
                        'functional_group': group,
                        'wavenumber': peak_wn,
                        'intensity': intensity[peak]
                    })

        return identified_groups

    def complementary_analysis(self, ir_spectrum, raman_spectrum):
        """
        IRとRamanの相補的解析

        Parameters:
        -----------
        ir_spectrum : dict
            {'wavenumbers': array, 'intensity': array}
        raman_spectrum : dict
            {'wavenumbers': array, 'intensity': array}

        Returns:
        --------
        analysis_result : dict
            統合解析結果
        """
        # IRで検出された官能基
        ir_groups = self.identify_functional_groups(ir_spectrum['wavenumbers'],
                                                     ir_spectrum['intensity'])

        # Ramanで検出された官能基
        raman_groups = self.identify_functional_groups(raman_spectrum['wavenumbers'],
                                                        raman_spectrum['intensity'])

        # 統合
        all_groups = set([g['functional_group'] for g in ir_groups] +
                        [g['functional_group'] for g in raman_groups])

        analysis_result = {
            'IR_only': [g for g in ir_groups if g['functional_group'] not in
                       [rg['functional_group'] for rg in raman_groups]],
            'Raman_only': [g for g in raman_groups if g['functional_group'] not in
                          [ig['functional_group'] for ig in ir_groups]],
            'Both': list(all_groups.intersection(set([g['functional_group'] for g in ir_groups]),
                                                 set([g['functional_group'] for g in raman_groups])))
        }

        return analysis_result

# 実行例:アセトン(CH₃COCH₃)のIR・Raman統合解析
analyzer = VibrationalSpectroscopyAnalyzer()

# 合成IRスペクトル
wn_ir = np.linspace(4000, 400, 2000)
ir_intensity = (
    1.5 * np.exp(-(wn_ir - 2970)**2 / (2 * 20**2)) +  # C-H伸縮
    2.0 * np.exp(-(wn_ir - 1715)**2 / (2 * 30**2)) +  # C=O伸縮
    0.5 * np.exp(-(wn_ir - 1360)**2 / (2 * 25**2)) +  # C-H変角
    0.3 * np.random.random(len(wn_ir))  # ノイズ
)

# 合成Ramanスペクトル
wn_raman = np.linspace(3500, 100, 2000)
raman_intensity = (
    0.8 * np.exp(-(wn_raman - 2970)**2 / (2 * 20**2)) +  # C-H伸縮
    1.2 * np.exp(-(wn_raman - 1715)**2 / (2 * 30**2)) +  # C=O伸縮
    1.5 * np.exp(-(wn_raman - 900)**2 / (2 * 25**2)) +   # C-C伸縮
    0.2 * np.random.random(len(wn_raman))  # ノイズ
)

# 統合解析
ir_spec = {'wavenumbers': wn_ir, 'intensity': ir_intensity}
raman_spec = {'wavenumbers': wn_raman, 'intensity': raman_intensity}

result = analyzer.complementary_analysis(ir_spec, raman_spec)

# 可視化
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))

# IRスペクトル
ax1.plot(wn_ir, ir_intensity, linewidth=1.5, color='#f093fb', label='IRスペクトル')
ax1.fill_between(wn_ir, ir_intensity, alpha=0.3, color='#f5576c')
ax1.set_xlabel('波数 (cm⁻¹)', fontsize=12)
ax1.set_ylabel('吸光度 (a.u.)', fontsize=12)
ax1.set_title('アセトンのIRスペクトル', fontsize=14, fontweight='bold')
ax1.invert_xaxis()
ax1.legend()
ax1.grid(True, alpha=0.3)

# Ramanスペクトル
ax2.plot(wn_raman, raman_intensity, linewidth=1.5, color='#4ecdc4', label='Ramanスペクトル')
ax2.fill_between(wn_raman, raman_intensity, alpha=0.3, color='#ffe66d')
ax2.set_xlabel('Raman Shift (cm⁻¹)', fontsize=12)
ax2.set_ylabel('強度 (a.u.)', fontsize=12)
ax2.set_title('アセトンのRamanスペクトル', fontsize=14, fontweight='bold')
ax2.legend()
ax2.grid(True, alpha=0.3)

plt.tight_layout()
plt.savefig('acetone_ir_raman_complementary.png', dpi=300, bbox_inches='tight')
plt.show()

# 解析結果の表示
print("=" * 70)
print("IRとRamanの統合解析結果(アセトン)")
print("=" * 70)
print("\nIRのみで検出:")
for group in result['IR_only']:
    print(f"  {group['functional_group']}: {group['wavenumber']:.0f} cm⁻¹")

print("\nRamanのみで検出:")
for group in result['Raman_only']:
    print(f"  {group['functional_group']}: {group['wavenumber']:.0f} cm⁻¹")

print("\n両方で検出:")
for group in result['Both']:
    print(f"  {group}")

print("\n結論:")
print("  - C=O伸縮: IRで非常に強い、Ramanでも観測")
print("  - C-H伸縮: IR・Raman両方で強い")
print("  - C-C伸縮: Ramanで強く観測(IRでは弱い)")
print("  → IRとRamanを組み合わせることで、分子構造の全体像を把握")

演習問題

演習問題(クリックして展開)

Easy レベル(基本計算)

問題1: C-O結合(力の定数 $k = 1000$ N/m)の振動周波数(cm⁻¹)を計算してください。炭素の質量は12 amu、酸素の質量は16 amuです。

解答を見る

解答:

# コード例1の関数を使用
freq_Hz, wavenumber = vibrational_frequency(k=1000, m1=12, m2=16)
print(f"C-O伸縮振動の波数: {wavenumber:.1f} cm⁻¹")
# 出力: 約1270 cm⁻¹

問題2: H₂O分子(非線形、3原子)の振動自由度の数を求めてください。

解答を見る

解答:

$$3N - 6 = 3 \times 3 - 6 = 3$$

H₂Oは3つの振動モード(対称伸縮、変角振動、非対称伸縮)を持ちます。

問題3: IRスペクトルで1715 cm⁻¹に強いピークが観測されました。この官能基は何ですか?

解答を見る

解答: カルボニル基(C=O)の伸縮振動。1650-1750 cm⁻¹の領域はC=Oの特性吸収です。

Medium レベル(実践的計算)

問題4: 同位体効果を考慮し、¹²C=O と ¹³C=O の振動周波数の比を計算してください(力の定数は同じと仮定)。

解答を見る

解答:

_, wn_12C = vibrational_frequency(1200, 12, 16)
_, wn_13C = vibrational_frequency(1200, 13, 16)

ratio = wn_12C / wn_13C
print(f"¹²C=O波数: {wn_12C:.1f} cm⁻¹")
print(f"¹³C=O波数: {wn_13C:.1f} cm⁻¹")
print(f"比率: {ratio:.4f}")
# 出力: 比率 ≈ 1.017(約1.7%のシフト)

問題5: Raman散乱において、室温(300 K)でStokes線とAnti-Stokes線の強度比を計算してください。振動モードは1500 cm⁻¹とします。

解答を見る

解答:

# コード例5のboltzmann_population関数を使用
ratio = boltzmann_population(1500, T=300)
print(f"I(Anti-Stokes) / I(Stokes) = {ratio:.4f}")
# 出力: 約0.023(Anti-StokesはStokesの約2.3%)

問題6: CO₂分子(線形、3原子)の振動自由度を求め、各振動モードの対称性(Σg⁺, Σu⁺, Πu)とIR/Raman活性を答えてください。

解答を見る

解答:

$$3N - 5 = 3 \times 3 - 5 = 4$$

モード対称性波数(cm⁻¹)IR活性Raman活性
対称伸縮Σg1340不活性活性
非対称伸縮Σu2349活性不活性
変角振動(2重縮退)Πu667活性不活性

CO₂は中心対称分子なので、相互排他則が成立します。

Hard レベル(高度な解析)

問題7: 下記の実測IRスペクトルデータから、FTIRのインターフェログラムを逆算してください。その後、フーリエ変換で元のスペクトルが復元されることを確認してください。

解答を見る(完全なコード)
# コード例4の関数を利用
true_wavenumbers = np.array([1000, 1500, 2000, 2900])
true_intensities = np.array([0.6, 1.0, 0.8, 0.7])

# インターフェログラム生成
displacement, interferogram = generate_interferogram(true_wavenumbers, true_intensities,
                                                     mirror_displacement_max=0.1)

# フーリエ変換でスペクトル復元
wavenumbers_ft, spectrum_ft = fourier_transform_spectrum(displacement, interferogram)

# 検証プロット
fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(12, 10))

ax1.plot(displacement, interferogram, linewidth=1.5, color='#f093fb')
ax1.set_xlabel('ミラー変位 (cm)', fontsize=12)
ax1.set_ylabel('干渉強度', fontsize=12)
ax1.set_title('実測IRスペクトルから逆算したインターフェログラム', fontsize=14, fontweight='bold')
ax1.grid(True, alpha=0.3)

ax2.plot(wavenumbers_ft, spectrum_ft, linewidth=1.5, color='#f5576c')
for wn in true_wavenumbers:
    ax2.axvline(x=wn, color='green', linestyle='--', alpha=0.7)
ax2.set_xlabel('波数 (cm⁻¹)', fontsize=12)
ax2.set_ylabel('強度 (a.u.)', fontsize=12)
ax2.set_title('フーリエ変換で復元されたスペクトル', fontsize=14, fontweight='bold')
ax2.set_xlim(0, 4000)
ax2.grid(True, alpha=0.3)

plt.tight_layout()
plt.show()

print("真のピーク位置:", true_wavenumbers)
print("復元成功: フーリエ変換により元のスペクトルが再現されました")

問題8: ベンゼン(D6h点群)の振動モード(30個)のうち、IR活性なモードとRaman活性なモードの数を推定してください。対称性に基づいて考察してください。

解答を見る

解答:

ベンゼンは中心対称分子(D6h)なので、相互排他則が成立します。30個の振動モードのうち:

  • IR活性: u(ungerade)対称性のモード → 約4個のE1uモード
  • Raman活性: g(gerade)対称性のモード → 約7個のA1g, E1g, E2gモード
  • 残りのモードは不活性(A2g, A2u, B1u, B2uなど)

詳細な指標表による解析が必要ですが、IR活性モードとRaman活性モードは互いに排他的です。

問題9: ポリエチレンの結晶化度をRamanスペクトルから評価する際、結晶ピーク(1130 cm⁻¹)と非晶ピーク(1080 cm⁻¹)の強度比が2:1でした。ピーク面積比から結晶化度を計算してください(ピーク幅はそれぞれ10 cm⁻¹、15 cm⁻¹とします)。

解答を見る

解答:

# Gaussian近似でピーク面積を計算
I_crystal = 2.0  # 強度比
I_amorphous = 1.0
width_crystal = 10  # cm^-1
width_amorphous = 15  # cm^-1

# 面積 = 強度 × 幅 × sqrt(2π)(Gaussian近似)
area_crystal = I_crystal * width_crystal * np.sqrt(2 * np.pi)
area_amorphous = I_amorphous * width_amorphous * np.sqrt(2 * np.pi)

crystallinity = area_crystal / (area_crystal + area_amorphous) * 100
print(f"結晶ピーク面積: {area_crystal:.1f}")
print(f"非晶ピーク面積: {area_amorphous:.1f}")
print(f"結晶化度: {crystallinity:.1f}%")
# 出力: 約51.3%

問題10: H₂O分子のC2v点群における3つの振動モード(A₁, A₁, B₁)が、なぜすべてIRとRaman両方で活性なのかを、指標表を用いて説明してください。

解答を見る

解答:

C2v点群の指標表より:

  • A₁対称性: 基底関数にz(双極子モーメント)とx², y², z²(分極率テンソル)が含まれる → IR活性かつRaman活性
  • B₁対称性: 基底関数にx(双極子モーメント)とxz(分極率テンソル)が含まれる → IR活性かつRaman活性

したがって、H₂Oの3つの振動モード(対称伸縮A₁、変角A₁、非対称伸縮B₁)はすべてIRとRaman両方で観測されます。中心対称分子ではないため、相互排他則は適用されません。

学習目標の確認

この章で学んだ内容を振り返り、以下の項目を確認してください。

基本理解

実践スキル

応用力

参考文献

  1. Raman, C. V., Krishnan, K. S. (1928). A new type of secondary radiation. Nature, 121(3048), 501-502. DOI: 10.1038/121501c0 - Raman散乱効果の発見を報告した歴史的原著論文
  2. Nakamoto, K. (2008). Infrared and Raman Spectra of Inorganic and Coordination Compounds (6th ed.). Wiley, pp. 25-31 (IR theory), pp. 78-95 (Raman theory), pp. 115-140 (group theory applications). - IR・Ramanスペクトルの包括的教科書と官能基帰属表
  3. Long, D. A. (2002). The Raman Effect: A Unified Treatment of the Theory of Raman Scattering by Molecules. Wiley, pp. 50-68 (classical theory), pp. 95-115 (quantum theory), pp. 145-160 (selection rules). - Raman散乱の量子力学的理論と選択則
  4. Wilson, E. B., Decius, J. C., Cross, P. C. (1980). Molecular Vibrations: The Theory of Infrared and Raman Vibrational Spectra. Dover Publications, pp. 25-42 (normal modes), pp. 65-85 (group theory), pp. 95-110 (selection rules). - 分子振動の古典的名著、群論と選択則
  5. Colthup, N. B., Daly, L. H., Wiberley, S. E. (1990). Introduction to Infrared and Raman Spectroscopy (3rd ed.). Academic Press, pp. 100-125 (functional group frequencies), pp. 180-210 (spectral interpretation), pp. 220-240 (peak assignment). - 実践的なスペクトル解釈とピーク帰属
  6. Savitzky, A., Golay, M. J. E. (1964). Smoothing and differentiation of data by simplified least squares procedures. Analytical Chemistry, 36(8), 1627-1639. DOI: 10.1021/ac60214a047 - Savitzky-Golay平滑化フィルタの原著論文(コード例で使用)
  7. SciPy 1.11 Signal Processing Documentation. scipy.signal.find_peaks, scipy.signal.savgol_filter. Available at: https://docs.scipy.org/doc/scipy/reference/signal.html - Pythonによるスペクトルデータ処理
  8. Smith, E., Dent, G. (2019). Modern Raman Spectroscopy: A Practical Approach (2nd ed.). Wiley, pp. 15-28 (instrumentation), pp. 45-65 (sampling techniques), pp. 72-80 (data processing). - 現代Raman分光法の実践的技術
  9. Cotton, F. A. (1990). Chemical Applications of Group Theory (3rd ed.). Wiley, pp. 250-275 (point groups), pp. 285-305 (vibrational modes), pp. 310-320 (selection rules). - 群論の化学応用と振動スペクトルの対称性解析

次のステップ

第2章では、赤外・ラマン分光法の原理、選択則、官能基同定、群論による対称性解析を学びました。調和振動子モデル、FTIRの原理、Stokes/Anti-Stokes散乱、結晶化度評価など、実践的なデータ解析スキルも習得しました。

第3章では、UV-Vis(紫外可視)分光法を学びます。電子遷移、Lambert-Beer則の応用、Tauc plotによるバンドギャップ測定、配位子場理論、Python実践による吸収スペクトル解析など、半導体・有機材料の電子状態解析の全てをカバーします。