🌐 EN | 🇯🇵 JP | Last sync: 2025-11-16

Chapter 3: Magnetic Measurements

VSM/SQUID Magnetometry, M-H Curve Analysis, Magnetic Anisotropy Evaluation, PPMS Integrated Measurements

📖 Reading Time: 50-60 minutes 📊 Difficulty: Intermediate to Advanced 💻 Code Examples: 7

Magnetic measurements are techniques for quantitatively evaluating the magnetic properties of materials (magnetization, magnetic moment, magnetic anisotropy). In this chapter, we will learn the principles of VSM (Vibrating Sample Magnetometer) and SQUID (Superconducting Quantum Interference Device), M-H curve analysis (saturation magnetization, coercivity, remanence), fitting with Curie-Weiss law and Langevin function, temperature-dependent measurements (FC/ZFC), and integrated measurement techniques using PPMS (Physical Property Measurement System), and perform practical magnetic data analysis with Python.

Learning Objectives

By reading this chapter, you will be able to:

3.1 Fundamentals of Magnetism

3.1.1 Relationship Between Magnetization and Magnetic Field

Magnetization $M$ is the magnetic moment per unit volume:

$$ M = \frac{\sum \mu_i}{V} $$

where $\mu_i$ is the magnetic moment of individual atoms/molecules, and $V$ is the volume.

Magnetic susceptibility $\chi$ is the response of magnetization to magnetic field $H$:

$$ M = \chi H $$

Types of magnetic fields:

3.1.2 Classification of Magnetism

Magnetism Susceptibility $\chi$ Temperature Dependence Characteristics Material Examples
Diamagnetism $\chi < 0$
(~$-10^{-5}$)
Almost none Weak magnetization
opposing external field
Cu, Au, H₂O
Superconductors
Paramagnetism $\chi > 0$
(~$10^{-5}$-$10^{-3}$)
$\chi \propto 1/T$
(Curie's law)
Weak magnetization
in field direction
Al, Pt, O₂
Rare earth ions
Ferromagnetism $\chi \gg 1$
(~$10^2$-$10^5$)
Large for T < T$_C$
Paramagnetic for T > T$_C$
Spontaneous
magnetization
Hysteresis
Fe, Co, Ni
NdFeB, SmCo
Antiferromagnetism $\chi > 0$
(small)
Peak at T = T$_N$ Adjacent spins
antiparallel
MnO, Cr, FeO
Ferrimagnetism $\chi \gg 1$ Similar to
ferromagnetism
Unequal antiparallel
spin arrangement
Fe₃O₄ (Magnetite)
Ferrites
flowchart TD A[External Field H] --> B{Material Magnetic Response} B --> C[Diamagnetic
M ↓ H] B --> D[Paramagnetic
M ↑ H
M ∝ H/T] B --> E[Ferromagnetic
Spontaneous
magnetization
M >> H] E --> F[Saturation M_s] E --> G[Coercivity H_c] E --> H[Remanence M_r] style A fill:#99ccff,stroke:#0066cc,stroke-width:2px style C fill:#ffeb99,stroke:#ffa500,stroke-width:2px style D fill:#99ff99,stroke:#00cc00,stroke-width:2px style E fill:#f093fb,stroke:#f5576c,stroke-width:2px,color:#fff

3.2 VSM (Vibrating Sample Magnetometer)

3.2.1 VSM Measurement Principle

VSM (developed by Simon Foner in 1956) is a method that vibrates the sample and measures the voltage induced in detection coils by its magnetic moment.

Measurement principle:

  1. Place the sample in a uniform magnetic field and vibrate it vertically at frequency $f$ (typically 10-100 Hz)
  2. When the sample's magnetic moment $\mu$ vibrates, a time-varying magnetic flux $\Phi(t)$ is generated around the detection coils
  3. According to Faraday's law of electromagnetic induction, induced voltage $V(t)$ is generated in the coils: $$ V(t) = -\frac{d\Phi}{dt} \propto \mu \cdot f $$
  4. Lock-in detection extracts the component at vibration frequency $f$ to quantify the magnetic moment

VSM characteristics:

Code Example 3-1: Curie-Weiss Law Fitting

# Requirements:
# - Python 3.9+
# - matplotlib>=3.7.0
# - numpy>=1.24.0, <2.0.0

import numpy as np
import matplotlib.pyplot as plt
from lmfit import Model

def curie_weiss(T, C, theta):
    """
    Curie-Weiss law: χ = C / (T - θ)
    
    Parameters
    ----------
    T : array-like
        Temperature [K]
    C : float
        Curie constant
    theta : float
        Curie-Weiss temperature (Weiss constant) [K]
    
    Returns
    -------
    chi : array-like
        Magnetic susceptibility
    """
    return C / (T - theta)

# Generate simulation data (paramagnetic material)
T_range = np.linspace(100, 400, 30)  # [K]
C_true = 1.5  # Curie constant
theta_true = -10  # Curie-Weiss temperature [K] (negative → antiferromagnetic interaction)

chi_data = curie_weiss(T_range, C_true, theta_true)
chi_data_noise = chi_data * (1 + 0.05 * np.random.randn(len(T_range)))  # 5% noise

# Fitting
model = Model(curie_weiss)
params = model.make_params(C=1.0, theta=0)
result = model.fit(chi_data_noise, params, T=T_range)

print("Curie-Weiss Law Fitting Results:")
print(result.fit_report())

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

# Left: χ vs T
ax1.scatter(T_range, chi_data_noise, s=80, alpha=0.7, edgecolors='black', linewidths=1.5, label='Measured data', color='#f093fb')
ax1.plot(T_range, result.best_fit, linewidth=2.5, label=f'Fit: C={result.params["C"].value:.2f}, θ={result.params["theta"].value:.1f} K', color='#f5576c')
ax1.set_xlabel('Temperature T [K]', fontsize=12)
ax1.set_ylabel('Magnetic Susceptibility χ', fontsize=12)
ax1.set_title('Curie-Weiss Law: χ vs T', fontsize=14, fontweight='bold')
ax1.legend(fontsize=11)
ax1.grid(alpha=0.3)

# Right: 1/χ vs T (Curie-Weiss plot)
ax2.scatter(T_range, 1/chi_data_noise, s=80, alpha=0.7, edgecolors='black', linewidths=1.5, label='Data (1/χ)', color='#ffa500')
T_fit_extended = np.linspace(0, 450, 100)
chi_fit_extended = curie_weiss(T_fit_extended, result.params['C'].value, result.params['theta'].value)
ax2.plot(T_fit_extended, 1/chi_fit_extended, linewidth=2.5, label='Linear fit (extended)', color='#f5576c')

# Highlight θ
theta_fit = result.params['theta'].value
ax2.axvline(theta_fit, color='red', linestyle='--', linewidth=2, label=f'θ = {theta_fit:.1f} K')
ax2.scatter([theta_fit], [0], s=200, c='red', edgecolors='black', linewidth=2, marker='X', zorder=5)

ax2.set_xlabel('Temperature T [K]', fontsize=12)
ax2.set_ylabel('1/χ', fontsize=12)
ax2.set_title('Curie-Weiss Plot: 1/χ vs T', fontsize=14, fontweight='bold')
ax2.legend(fontsize=11)
ax2.grid(alpha=0.3)
ax2.set_xlim(0, 450)
ax2.set_ylim(bottom=0)

plt.tight_layout()
plt.show()

print(f"\nPhysical Interpretation:")
print(f"  Curie constant C = {result.params['C'].value:.2f}")
print(f"  Curie-Weiss temperature θ = {result.params['theta'].value:.1f} K")
if result.params['theta'].value < 0:
    print(f"  θ < 0 → Dominant antiferromagnetic interactions")
elif result.params['theta'].value > 0:
    print(f"  θ > 0 → Dominant ferromagnetic interactions")
else:
    print(f"  θ ≈ 0 → Ideal paramagnetism (no interactions)")

3.3 SQUID (Superconducting Quantum Interference Device)

3.3.1 SQUID Measurement Principle

SQUID (Superconducting Quantum Interference Device) is an ultra-high sensitivity magnetic sensor using superconducting rings and Josephson junctions.

Measurement principle:

  1. When magnetic flux $\Phi$ penetrates a superconducting ring, quantized superconducting current flows
  2. The critical current through the Josephson junction changes periodically with magnetic flux: $$ I_c(\Phi) = I_0 \left|\cos\left(\frac{\pi\Phi}{\Phi_0}\right)\right| $$ where $\Phi_0 = h/(2e) \approx 2.07 \times 10^{-15}$ Wb is the magnetic flux quantum
  3. Minute changes in magnetic flux are detected with extremely high sensitivity as changes in critical current

SQUID characteristics:

Code Example 3-2: Langevin Function Fitting (Paramagnetism)

# Requirements:
# - Python 3.9+
# - matplotlib>=3.7.0
# - numpy>=1.24.0, <2.0.0

import numpy as np
import matplotlib.pyplot as plt
from lmfit import Model

def langevin(H, M_s, T, mu):
    """
    Langevin function (classical paramagnetism)
    
    Parameters
    ----------
    H : array-like
        Magnetic field [A/m or Oe]
    M_s : float
        Saturation magnetization [emu/g or Am^2/kg]
    T : float
        Temperature [K]
    mu : float
        Magnetic moment per particle [Bohr magneton units]
    
    Returns
    -------
    M : array-like
        Magnetization [emu/g]
    """
    mu_B = 9.274e-24  # Bohr magneton [J/T]
    mu_0 = 4 * np.pi * 1e-7  # Vacuum permeability [H/m]
    k_B = 1.38065e-23  # Boltzmann constant [J/K]
    
    # Convert field to SI units (Oe → T)
    H_T = H * 1e-4  # 1 Oe = 10^-4 T
    
    # Langevin parameter
    xi = mu * mu_B * H_T / (k_B * T)
    
    # Langevin function: L(ξ) = coth(ξ) - 1/ξ
    L = np.where(np.abs(xi) < 1e-3, xi/3, 1/np.tanh(xi) - 1/xi)  # Avoid divergence for small ξ
    
    M = M_s * L
    return M

# Generate simulation data (superparamagnetic nanoparticles)
H_range = np.linspace(-10000, 10000, 100)  # [Oe]
M_s_true = 50  # Saturation magnetization [emu/g]
T_true = 300  # Temperature [K]
mu_true = 5000  # Particle magnetic moment [μ_B]

M_data = langevin(H_range, M_s_true, T_true, mu_true)
M_data_noise = M_data + 0.5 * np.random.randn(len(H_range))  # Add noise

# Fitting
model = Model(langevin)
params = model.make_params(M_s=40, T=300, mu=3000)
params['T'].vary = False  # Fix temperature

result = model.fit(M_data_noise, params, H=H_range)

print("Langevin Function Fitting Results:")
print(result.fit_report())

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

# Left: M vs H
ax1.scatter(H_range, M_data_noise, s=50, alpha=0.6, edgecolors='black', linewidths=1, label='Data (with noise)', color='#f093fb')
ax1.plot(H_range, result.best_fit, linewidth=2.5, label=f'Fit: M_s={result.params["M_s"].value:.1f} emu/g, μ={result.params["mu"].value:.0f} μ_B', color='#f5576c')
ax1.axhline(M_s_true, color='green', linestyle='--', linewidth=1.5, label=f'True M_s = {M_s_true} emu/g')
ax1.axhline(-M_s_true, color='green', linestyle='--', linewidth=1.5)
ax1.set_xlabel('Magnetic Field H [Oe]', fontsize=12)
ax1.set_ylabel('Magnetization M [emu/g]', fontsize=12)
ax1.set_title('Langevin Function Fit (Paramagnetism)', fontsize=14, fontweight='bold')
ax1.legend(fontsize=10)
ax1.grid(alpha=0.3)

# Right: Temperature dependence (Langevin curves at different temperatures)
T_list = [50, 100, 200, 300, 400]
colors = plt.cm.plasma(np.linspace(0, 0.9, len(T_list)))

for T, color in zip(T_list, colors):
    M_T = langevin(H_range, result.params['M_s'].value, T, result.params['mu'].value)
    ax2.plot(H_range, M_T, linewidth=2.5, label=f'T = {T} K', color=color)

ax2.set_xlabel('Magnetic Field H [Oe]', fontsize=12)
ax2.set_ylabel('Magnetization M [emu/g]', fontsize=12)
ax2.set_title('Temperature Dependence of Langevin Curve', fontsize=14, fontweight='bold')
ax2.legend(fontsize=10, loc='lower right')
ax2.grid(alpha=0.3)

plt.tight_layout()
plt.show()

print(f"\nPhysical Interpretation:")
print(f"  Saturation magnetization M_s = {result.params['M_s'].value:.1f} emu/g")
print(f"  Particle magnetic moment μ = {result.params['mu'].value:.0f} μ_B")
print(f"  Lower temperature approaches saturation at lower field (reduced thermal fluctuation)")

Disclaimer