MATLAB实现黑体辐射谱绘制与普朗克定律数值仿真
2026/9/16 14:56:51 网站建设 项目流程

简介:本资源是一份面向物理专业本科生、研究生及MATLAB初学者的黑体辐射可视化教学实践包,聚焦普朗克定律的数值实现与图像表达,解决理论公式难直观理解、温度—波长—辐射强度关系难动态呈现的问题。压缩包共2个文件(1个MATLAB源码文件plancklow.m + 1个RGB像素数据文本文件),总大小216KB;其中m文件完整实现普朗克辐射谱计算、多温度曲线绘制、坐标标注与图例生成,支持参数修改与结果复现,txt文件提供实测/模拟光谱的RGB参考数据,可用于理论曲线与实际光谱图像的定性比对验证。已有1702人学习下载,资源代码结构清晰、注释友好,附带可直接运行的完整计算逻辑,涵盖普朗克公式编程实现、波长网格设定、指数项数值稳定性处理及多曲线可视化技巧,是开展热辐射基础实验、量子物理课程设计或MATLAB科学绘图训练的实用入门材料。

1. 用 MATLAB 直观呈现黑体辐射谱:普朗克线不是一条“线”,而是温度决定的连续能量分布曲线

很多人第一次看到“普朗克线”这个词,会下意识以为是某条固定位置的参考线——比如像玻尔轨道那样有确定波长。实际上,它根本不是一条线,而是一族由普朗克定律定义的、随温度变化的平滑辐射谱曲线。在 MATLAB 中绘制它,核心不是调用某个现成函数,而是亲手构建物理模型:从波长或频率网格出发,代入普朗克辐射公式,再用plotfplot渲染出峰值位置、形状和积分面积都严格符合热力学要求的曲线。这一步对物理仿真、红外测温标定、光学传感器响应建模甚至天文光谱拟合都构成底层支撑。如果你正在做热辐射建模、课程设计(如《热学》《近代物理实验》)、或需要验证某段红外探测器数据是否符合黑体假设,那么这段代码不是演示,而是可嵌入你 pipeline 的计算模块。它不依赖任何工具箱(基础 MATLAB 即可运行),但参数必须按 SI 单位制严格设置,否则峰值波长会偏移近一个数量级。


2. 从普朗克定律出发:推导 MATLAB 可计算的辐射谱表达式并完成单位一致性校验

普朗克定律描述黑体在温度 $T$ 下单位波长间隔内的光谱辐射出射度(spectral radiance):

$$ B_\lambda(\lambda, T) = \frac{2hc^2}{\lambda^5} \cdot \frac{1}{e^{\frac{hc}{\lambda k_B T}} - 1} $$

其中:

  • $h = 6.62607015 \times 10^{-34}~\text{J·s}$(普朗克常数)
  • $c = 2.99792458 \times 10^8~\text{m/s}$(真空中光速)
  • $k_B = 1.380649 \times 10^{-23}~\text{J/K}$(玻尔兹曼常数)

注意:MATLAB 中所有物理量必须统一为国际单位制(SI)。若输入波长单位为纳米(nm),必须先除以 $10^9$ 转为米;若温度用摄氏度,必须加 273.15 转为开尔文。单位错一位,整个曲线峰值偏移超 10 倍——这是新手最常踩的坑。

2.1 构建波长向量:覆盖可见光到远红外,兼顾分辨率与计算效率

我们不使用linspace(0.2, 20, 1000)这类粗略范围,因为普朗克谱在短波端发散($\lambda^{-5}$),直接线性采样会导致数值溢出;在长波端又趋近于零,浪费计算资源。更合理的方式是采用对数间距(logspace),并在峰值附近加密采样:

% 定义温度(开尔文) T = 5800; % 太阳表面有效温度,用于基准参考 % 计算维恩位移定律预测的峰值波长(单位:米) lambda_peak_theory = 2.897771955e-3 / T; % 单位:m % 构建波长向量:以 lambda_peak_theory 为中心,前后各扩展 2 个数量级 lambda_min = lambda_peak_theory * 1e-2; % 0.01 × peak lambda_max = lambda_peak_theory * 1e2; % 100 × peak % 使用 logspace 生成 2000 个点,避免短波端数值爆炸 lambda = logspace(log10(lambda_min), log10(lambda_max), 2000); % 单位:m % 若需输出常用单位(如微米),可额外定义: lambda_um = lambda * 1e6; % 转为 μm,仅用于横轴标注

这段代码的关键在于:logspace保证了短波(紫外)区域有足够密度防止插值失真,长波(远红外)区域不会因过密采样拖慢速度;lambda_min/max动态绑定T,使不同温度下的绘图范围自动适配——比如画 300 K(室温)物体时,峰值在 9.7 μm,范围自动设为 0.1–1000 μm;画 1000 K 物体时,峰值在 2.9 μm,范围缩至 0.03–300 μm。

2.2 实现普朗克公式:用向量化运算避免 for 循环,显式处理数值稳定性

直接套用公式会出现两个典型问题:
① $\lambda \to 0$ 时,$\exp(hc/\lambda k_B T)$ 溢出为Inf,导致整项为NaN
② $\lambda$ 很大时,指数项趋近于 0,分母 $e^x - 1 \approx x$,但直接计算仍可能因浮点精度丢失导致除零错误。

MATLAB 的稳健写法是引入expm1函数(计算 $e^x - 1$ 的高精度版本),并用条件分支截断极端值:

% 物理常数(SI 单位) h = 6.62607015e-34; c = 2.99792458e8; kB = 1.380649e-23; % 计算指数项 x = hc / (lambda * kB * T) x = (h * c) ./ (lambda * kB * T); % 使用 expm1 避免 e^x - 1 在 x 较小时的精度损失 % 同时对 x > 700 的情况设为 Inf(此时 e^x 已远超 double 表示上限) x(x > 700) = Inf; denominator = expm1(x); % 等价于 exp(x) - 1,但 x 接近 0 时更准 % 主公式:B_lambda = (2*h*c^2 / lambda^5) / (exp(hc/(lambda*kB*T)) - 1) B_lambda = (2 * h * c^2) ./ (lambda.^5) ./ denominator; % 将结果单位转为常用 W·sr⁻¹·m⁻³(即每米波长、每球面度、每平方米面积的功率) % 注意:此即标准光谱辐亮度单位,可直接与仪器标定值比对

提示expm1(x)是 MATLAB 内置函数,专为 $e^x - 1$ 设计。当 $x < 10^{-5}$ 时,exp(x)-1会产生相对误差达 $10^{-12}$ 量级,而expm1(x)保持机器精度。此处x在长波端很小(例如 $\lambda=100~\mu m$ 时 $x \approx 0.001$),必须使用。

2.3 验证单位一致性:用维恩位移定律和斯特藩-玻尔兹曼定律交叉校验

绘图前必须验证计算结果是否自洽。我们用两个经典定律进行双重检验:

  • 维恩位移定律:理论峰值波长 $\lambda_{\max} = b / T$,其中 $b = 2.897771955 \times 10^{-3}~\text{m·K}$
  • 斯特藩-玻尔兹曼定律:总辐射出射度 $M = \sigma T^4$,其中 $\sigma = 5.670374419 \times 10^{-8}~\text{W·m}^{-2}\text{·K}^{-4}$,且 $M = \int_0^\infty B_\lambda(\lambda,T),d\lambda$
% 查找数值峰值位置(注意:lambda 是向量,B_lambda 是对应值) [~, idx_peak] = max(B_lambda); lambda_peak_numeric = lambda(idx_peak); % 单位:m lambda_peak_theory = 2.897771955e-3 / T; fprintf('数值峰值波长: %.4g μm\n', lambda_peak_numeric * 1e6); fprintf('理论峰值波长: %.4g μm\n', lambda_peak_theory * 1e6); fprintf('相对误差: %.2e\n', abs(lambda_peak_numeric - lambda_peak_theory)/lambda_peak_theory); % 数值积分验证总辐射(使用 trapz,注意 dλ 步长) dlambda = diff(lambda); % lambda 是 logspace,步长不等,故用 diff M_numeric = trapz(lambda, B_lambda); % 单位:W·sr⁻¹·m⁻² sigma = 5.670374419e-8; M_theory = sigma * T^4; fprintf('数值积分总辐射: %.4g W·sr⁻¹·m⁻²\n', M_numeric); fprintf('理论总辐射: %.4g W·sr⁻¹·m⁻²\n', M_theory); fprintf('相对误差: %.2e\n', abs(M_numeric - M_theory)/M_theory);

运行后应看到两组误差均小于 $10^{-3}$。若超过 $10^{-2}$,说明波长范围过窄、采样点不足,或单位转换有误(例如忘了把 nm 转 m)。


3. 绘制多温度普朗克线族:叠加标注、动态范围压缩与视觉可读性优化

单条曲线意义有限,实际应用中需对比不同温度下的谱形变化(如 LED 封装热分析、燃烧火焰温度反演)。MATLAB 绘图需解决三个关键问题:
① 多曲线重叠导致低温度曲线被高温度曲线完全遮盖;
② 纵坐标跨度达 $10^{10}$ 以上,线性坐标无法同时显示峰值与长波尾部;
③ 缺乏物理标注(如维恩线、可见光区间)使图像失去解释力。

3.1 用semilogy实现纵轴对数刻度,并手动设置YLim避免自动裁剪

figure('Position', [100, 100, 900, 600]); hold on; T_list = [300, 1000, 3000, 5800, 10000]; % 开尔文 colors = lines(length(T_list)); % 自动配色 for i = 1:length(T_list) T = T_list(i); % 重用前述计算逻辑(此处省略重复代码,实际需封装为函数) lambda = logspace(log10(2.897771955e-3/T*1e-2), ... log10(2.897771955e-3/T*1e2), 2000); x = (h*c) ./ (lambda * kB * T); x(x > 700) = Inf; denominator = expm1(x); B_lambda = (2*h*c^2) ./ (lambda.^5) ./ denominator; % 绘制:横轴用微米,纵轴用对数 plot(lambda*1e6, B_lambda, 'Color', colors(i,:), 'LineWidth', 1.4); end xlabel('波长 \lambda (\mum)', 'FontSize', 12); ylabel('光谱辐亮度 B_\lambda (W·sr^{-1}·m^{-3})', 'FontSize', 12); title('黑体辐射谱:不同温度下的普朗克线族', 'FontSize', 14, 'FontWeight', 'bold'); % 设置 y 轴为对数,并限定显示范围(避免极小值淹没) set(gca, 'YScale', 'log'); ylim([1e4, 1e14]); % 根据 T_list 动态调整,此处覆盖全部曲线 % 添加图例(温度值带单位) legend_str = arrayfun(@(t) sprintf('%d K', t), T_list, 'UniformOutput', false); legend(legend_str, 'Location', 'southwest', 'FontSize', 10);

3.2 标注物理参考线:可见光区间(0.38–0.78 μm)与维恩位移线

单纯曲线不够,必须嵌入物理语境:

% 标注可见光波段(灰色半透明矩形) fill([0.38, 0.38, 0.78, 0.78], ylim, [0.9, 0.9, 0.9], 'FaceAlpha', 0.2, 'EdgeColor', 'none'); text(0.5, ylim(2)*0.8, '可见光', 'HorizontalAlignment', 'center', 'FontSize', 10); % 绘制维恩位移线(λ_max = b/T,用虚线连接各温度峰值) lambda_ve = 2.897771955e-3 ./ T_list; % 单位:m → μm plot(lambda_ve*1e6, zeros(size(lambda_ve)) + ylim(1)*1.5, 'k--o', 'MarkerSize', 4, 'LineWidth', 1); text(lambda_ve(1)*1e6, ylim(1)*1.8, '\leftarrow 维恩位移线', 'FontSize', 9); % 添加网格提升可读性 grid on; box on;

3.3 解决长波端噪声:用smoothdata抑制数值积分残留振荡

由于logspace在长波端采样稀疏,且expm1在 $x \ll 1$ 时仍有微小波动,B_lambda末尾可能出现高频抖动。这不是物理现象,而是数值误差:

% 对每条曲线末尾 30% 数据做移动平均平滑(仅视觉优化,不影响峰值) n_smooth = floor(0.3 * length(lambda)); B_lambda_smooth = smoothdata(B_lambda, 'movmean', n_smooth); plot(lambda*1e6, B_lambda_smooth, 'Color', colors(i,:), 'LineWidth', 1.4);

注意:平滑仅用于绘图,不可用于后续数值积分或拟合。若需高精度积分,应改用quadgk或增加采样密度。


4. 导出高保真矢量图与批量处理:EPS/PDF 兼容性设置及多温度数据导出技巧

科研论文、技术报告对图像质量要求严苛:字体必须嵌入、线条不能锯齿、坐标轴标签需 LaTeX 渲染。MATLAB 默认print命令导出的 EPS 常出现字体缺失或符号错位,根源在于未指定RendererFontEmbedding

4.1 导出无损 EPS/PDF:绕过 OpenGL 渲染器,强制使用 Painters

% 关键设置:禁用硬件加速,启用矢量渲染 set(gcf, 'Renderer', 'painters'); % 必须!否则 EPS 文字变方块 set(gcf, 'PaperPositionMode', 'auto'); % 导出 EPS(兼容 LaTeX \includegraphics) print('-depsc2', '-r600', 'planck_spectrum.eps'); % 导出 PDF(现代期刊首选) print('-dpdf', '-r600', 'planck_spectrum.pdf');

提示-r600指定 600 dpi 光栅化分辨率,仅对含图像元素的图生效;对于纯矢量图(如本例),该参数不影响线条质量,但能确保图例阴影、渐变等效果正确。若导出后文字模糊,请检查系统是否安装了对应字体(推荐使用HelveticaComputer Modern)。

4.2 批量生成多温度数据文件:.mat.csv双格式导出

便于后续用 Python 或 Origin 二次分析:

% 将所有温度对应的 lambda 和 B_lambda 存入结构体 data_struct.T = T_list; data_struct.lambda_um = lambda * 1e6; % 波长(μm) data_struct.B_lambda = zeros(length(T_list), length(lambda)); for i = 1:length(T_list) % ...(同上循环内计算 B_lambda) data_struct.B_lambda(i, :) = B_lambda; end % 导出为 .mat(MATLAB 原生,保留双精度) save('planck_data.mat', 'data_struct'); % 导出为 .csv(首行为波长,后续每行一个温度的 B_lambda) csv_data = [data_struct.lambda_um'; data_struct.B_lambda]; writematrix(csv_data, 'planck_data.csv', 'Delimiter', ',');

4.3 一行命令验证导出文件:用readmatrix快速回读并重绘

% 验证 csv 是否可逆 csv_check = readmatrix('planck_data.csv'); lambda_check = csv_check(1, :); % 第一行是波长 B_check = csv_check(2:end, :); % 后续是各温度数据 % 重绘第一条曲线(300 K) figure; semilogy(lambda_check, B_check(1, :), 'b-', 'LineWidth', 1.5); xlabel('\lambda (\mum)'); ylabel('B_\lambda (W·sr^{-1}·m^{-3})'); title('CSV 回读验证:300 K 黑体谱');

运行后应与原始图完全一致。若出现跳变或截断,说明writematrix默认精度不足,需改用:

writematrix(csv_data, 'planck_data.csv', 'Delimiter', ',', 'Precision', 15);

5. 进阶技巧:用fplot替代离散采样,实现解析式动态绘图与交互式温度调节

前述方法基于离散网格,适合批量计算;但若需实时探索(如教学演示、参数敏感性分析),fplot提供符号化绘图能力——它自动选择采样点,避开奇点,并支持回调更新。

5.1 定义符号普朗克函数并用fplot绘制

syms lambda_real % 符号变量,单位:米 T_sym = 5800; % 符号温度 % 构建符号表达式(注意:所有常数必须用 sym() 转换) h_sym = sym(6.62607015e-34); c_sym = sym(2.99792458e8); kB_sym = sym(1.380649e-23); x_sym = (h_sym * c_sym) / (lambda_real * kB_sym * T_sym); B_sym = (2 * h_sym * c_sym^2) / (lambda_real^5) / (exp(x_sym) - 1); % fplot 自动处理奇点(lambda→0),并优化采样 figure; fplot(B_sym, [1e-7, 3e-5], 'LineWidth', 1.6); % 0.1–30 μm xlabel('\lambda (m)'); ylabel('B_\lambda (W·sr^{-1}·m^{-3})'); title('符号普朗克函数:fplot 自适应绘图');

5.2 构建交互式滑块:拖动实时更新曲线

% 创建 UI(需 R2019a+) fig = uifigure('Name', '普朗克线交互演示'); ax = uiaxes(fig); ax.XScale = 'log'; ax.YScale = 'log'; % 初始温度滑块 slider = uislider(fig, 'Limits', [300, 10000], 'Value', 5800); label = uilabel(fig, 'Text', '温度: 5800 K', 'Position', [20, 40, 120, 22]); % 绘制初始曲线 [lambda_init, B_init] = compute_planck_curve(5800); plot(ax, lambda_init*1e6, B_init, 'LineWidth', 1.8); % 滑块回调 slider.ValueChangedFcn = @(src,~) update_plot(src.Value, ax, label); function update_plot(T_val, ax_handle, label_handle) [lambda_new, B_new] = compute_planck_curve(T_val); plot(ax_handle, lambda_new*1e6, B_new, 'LineWidth', 1.8); label_handle.Text = sprintf('温度: %.0f K', T_val); ax_handle.YLim = [1e4, 1e14]; end % 将 compute_planck_curve 封装为独立函数(含前述全部数值逻辑) function [lambda_out, B_out] = compute_planck_curve(T) h = 6.62607015e-34; c = 2.99792458e8; kB = 1.380649e-23; lambda_min = 2.897771955e-3/T * 1e-2; lambda_max = 2.897771955e-3/T * 1e2; lambda_out = logspace(log10(lambda_min), log10(lambda_max), 2000); x = (h*c) ./ (lambda_out * kB * T); x(x > 700) = Inf; B_out = (2*h*c^2) ./ (lambda_out.^5) ./ expm1(x); end

运行后将弹出带滑块的窗口,拖动即可实时看到峰值移动、曲线展宽、总辐射增强——这是理解“温度升高使辐射向短波迁移”最直观的方式。

本文还有配套的精品资源,点击获取

需要专业的网站建设服务?

联系我们获取免费的网站建设咨询和方案报价,让我们帮助您实现业务目标

立即咨询