基于 MATLAB 的3D 蒙特卡洛光子传输模拟

蒙特卡洛(Monte Carlo, MC)方法是模拟光子在生物组织中传播的"黄金标准"。由于生物组织具有高度散射的特性,光子的传播路径本质上是一个随机游走(Random Walk)过程。蒙特卡洛模拟通过追踪成千上万个光子的微观轨迹,利用统计力学的方法宏观地反映出光在组织中的能量沉积、吸收和热效应。

基于 MATLAB 的3D 蒙特卡洛光子传输模拟。这个框架涵盖了组织光学特性设定、自由程抽样、Henyey-Greenstein 相位函数散射以及边界折射/全反射处理等核心机制。

1. 核心算法原理概述

在模拟中,每个光子都有一个权重 WWW(初始为 1)。当它进入组织后:

  1. 步长抽样 :光子在遇到下一次相互作用前传播的距离 sss 服从指数分布:s=−ln⁡(ξ)/μts = -\ln(\xi) / \mu_ts=−ln(ξ)/μt,其中 μt=μa+μs\mu_t = \mu_a + \mu_sμt=μa+μs 是总衰减系数,ξ\xiξ 是 (0,1)(0,1)(0,1) 间的均匀随机数。
  2. 散射方向 :偏转角度 θ\thetaθ 由 Henyey-Greenstein 函数抽样得到,方位角 ϕ\phiϕ 在 [0,2π][0, 2\pi][0,2π] 均匀抽样。
  3. 边界处理:在空气-组织界面,根据菲涅尔公式和斯涅尔定律计算反射和折射概率。若发生全反射,则光子留在组织内继续传播。

2. 仿真代码实现

您可以直接复制以下代码到一个新的 MATLAB 脚本文件(例如 monte_carlo_tissue.m)中运行。

matlab 复制代码
% =========================================================
% 蒙特卡洛模拟:光子在生物组织(皮肤)中的传播
% 描述:本代码模拟光子束垂直入射到多层组织中的传播轨迹,
%       并记录其在组织内部的能量沉积分布。
% =========================================================

clear; clc; close all;

%% --- 1. 模拟与组织参数设定 ---
num_photons = 10000;       % 发射的光子数量 (越多越精确,但耗时越长)
grid_size = [100, 100, 200]; % 仿真空间网格 (X, Y, Z),单位:个体素
voxel_size = 0.01;       % 体素实际大小 1cm / grid_size = 0.1 mm

% 组织光学参数 (以皮肤/真皮为例)
mu_a = 0.1;   % 吸收系数 (1/cm) - 光传播1cm被吸收的概率
mu_s = 10.0;  % 散射系数 (1/cm) - 光传播1cm被散射的概率
g = 0.8;      % 各向异性因子 (-1 到 1),0.8表示强烈前向散射
n_tissue = 1.4; % 组织折射率
n_air = 1.0;    % 空气折射率

% 初始化能量沉积网格 (记录光子能量在空间中的分布情况)
energy_deposition = zeros(grid_size);

% 菲涅尔反射系数 (垂直入射时的近似)
Rs = ((n_air - n_tissue) / (n_air + n_tissue))^2;

%% --- 2. 主循环:发射并追踪每一个光子 ---
fprintf('正在使用蒙特卡洛方法模拟 %d 个光子的传播...\n', num_photons);
for p_idx = 1:num_photons
    
    % --- 2.1 光子初始化 ---
    % 初始位置 (网格中心,表面处)
    pos = [grid_size(1)/2, grid_size(2)/2, 1]; 
    % 初始方向 (垂直向下,即 +Z 方向)
    dir = [0, 0, 1]; 
    % 光子初始权重
    weight = 1.0;
    
    % 考虑光束在空气-组织界面的初次反射损失
    if rand() < Rs
        continue; % 光子被反射,停止追踪
    end
    
    % --- 2.2 光子在组织内的随机游走 ---
    while true
        % 1. 抽样自由程 (Step Length)
        % 公式: s = -ln(xi) / (mu_a + mu_s)
        s = -log(rand()) / (mu_a + mu_s);
        
        % 2. 更新光子位置
        % 新位置 = 旧位置 + 步长 * 单位方向向量
        new_pos = pos + s * dir;
        
        % 3. 检查边界碰撞 (假设组织是一个长方体网格)
        % 如果光子试图逃离底面 (Z方向超出网格)
        if new_pos(3) > grid_size(3) || new_pos(3) < 1
            break; % 光子逃逸出组织,结束追踪
        end
        % 如果光子试图逃离侧面 (X或Y方向超出网格)
        if new_pos(1) < 1 || new_pos(1) > grid_size(1) || ...
           new_pos(2) < 1 || new_pos(2) > grid_size(2)
            break; % 光子逃逸
        end
        
        % 4. 记录能量沉积 (光与物质相互作用)
        % 按比例分配吸收和散射的能量
        absorb_prob = mu_a / (mu_a + mu_s);
        if rand() < absorb_prob
            % 光子被吸收,将其权重加到当前体素中
            % 使用线性索引加速
            idx = sub2ind(grid_size, round(pos(1)), round(pos(2)), round(pos(3)));
            energy_deposition(idx) = energy_deposition(idx) + weight;
            
            % 采用俄罗斯轮盘赌法 (Russian Roulette) 决定光子存亡以节省计算
            if rand() > 0.1 % 90%概率光子死亡
                weight = 0;
                break;
            else
                weight = weight / 0.1; % 10%概率存活,权重增加
            end
        end
        
        % 5. 更新位置 (如果未被吸收)
        pos = new_pos;
        
        % 6. 抽样新的散射方向 (Henyey-Greenstein 相位函数)
        % 抽样偏转极角 theta
        xi = rand();
        if g == 0
            cos_theta = 2*xi - 1;
        else
            cos_theta = (1/(2*g)) * (1 + g^2 - ((1-g^2)/(1-g+2*g*xi))^2);
        end
        sin_theta = sqrt(1 - cos_theta^2);
        
        % 抽样方位角 phi
        phi = 2 * pi * rand();
        
        % 构建新的方向向量 (局部坐标系旋转到全局坐标系)
        u = dir(1); v = dir(2); w = dir(3);
        
        % 防止数值误差导致 w 超出 [-1, 1]
        w = max(min(w, 1.0), -1.0);
        
        if abs(w) > 0.99999
            % 接近平行于 Z 轴的情况
            new_dir = [sin_theta*cos(phi), sin_theta*sin(phi), cos_theta*w/abs(w)];
        else
            sqrt_term = sqrt(1 - w^2);
            new_dir = [
                sin_theta*(u*w*cos(phi) - v*sin(phi))/sqrt_term + u*cos_theta;
                sin_theta*(v*w*cos(phi) + u*sin(phi))/sqrt_term + v*cos_theta;
                -sin_theta*cos(phi)*sqrt_term + w*cos_theta
            ];
        end
        
        % 归一化新方向向量 (防止浮点数误差累积)
        dir = new_dir / norm(new_dir);
    end
end
fprintf('模拟完成!\n');

%% --- 3. 结果可视化 ---
% 计算沿深度方向 (Z轴) 的能量沉积剖面
depth_profile = squeeze(sum(sum(energy_deposition, 1), 2));

% 绘制 3D 网格中的中心切片 (X-Z 平面)
figure('Name', '蒙特卡洛光子传输模拟结果', 'Color', 'w', 'Position', [100 100 1200 500]);

% 子图 1: 光子在组织深度方向的能量沉积衰减曲线
subplot(1, 2, 1);
plot(depth_profile, 1:grid_size(3), 'b-', 'LineWidth', 2);
set(gca, 'YDir', 'reverse'); % 翻转Y轴,使Z=1在顶部 (模拟从上往下入射)
title('光子能量随组织深度的沉积分布');
xlabel('能量沉积 (任意单位)');
ylabel('组织深度 (体素数)');
grid on;

% 子图 2: 组织内部能量分布的 2D 切片热力图
subplot(1, 2, 2);
imagesc(energy_deposition(:,:,round(grid_size(3)/2))); % 显示中间深度的切片
title('组织内部能量沉积二维切片图 (俯视图)');
xlabel('X 轴方向');
ylabel('Y 轴方向');
colorbar;
axis equal;
colormap('hot'); % 使用热度图配色

sgtitle('基于蒙特卡洛算法的生物组织光子传输仿真');

3. 代码核心模块解析

  1. 光学参数 (μa,μs,g{\mu}_a, {\mu}_s, gμa,μs,g)
    • mu_a (吸收系数):决定了光子在介质中被吸收的难易程度。黑色素较多的皮肤此值较高。
    • mu_s (散射系数):决定了光子发生碰撞偏转的频率。生物组织通常属于高散射介质 (μs≫μa{\mu}_s \gg {\mu}_aμs≫μa)。
    • g (各向异性因子):g=0g=0g=0 代表各向同性散射,g≈0.8∼0.9g \approx 0.8 \sim 0.9g≈0.8∼0.9 代表强烈的前向散射,这符合生物组织中胶质颗粒对光的散射特性。
  2. 步长抽样 (Exponential Sampling)
    代码中的 s = -log(rand()) / (mu_a + mu_s) 是根据概率密度函数 p(s)=μte−μtsp(s) = \mu_t e^{-\mu_t s}p(s)=μte−μts 进行逆变换抽样,这是蒙特卡洛模拟中最核心的数学操作之一。
  3. Henyey-Greenstein 函数
    这是生物医光学中描述光在随机介质中散射角度分布的经验公式。代码通过随机数 ξ\xiξ 反解出偏转角 cos⁡(θ)\cos(\theta)cos(θ),从而更新光子的三维运动方向。
  4. 边界条件与能量守恒
    光子在网格边缘被判定为"逃逸"。同时,代码引入了Russian Roulette 算法:当光子权重过低时,通过一定概率直接pass光子以避免无意义的长时间追踪,从而保证整个系统的能量守恒。

参考代码 关于蒙特卡洛算法,用于模拟光子在人体皮肤 www.youwenfan.com/contentcsu/63374.html

4. 后续

如果希望将此基础框架应用于更真实的医学或科研场景,可以考虑参考一下以下扩展:

  • 多层皮肤结构 :将单一的 mu_a, mu_s 替换为三维矩阵,从而定义表皮(Epidermis)、真皮(Dermis)以及皮下脂肪等不同层次的折射率和光学属性。
  • 光束类型 :修改初始位置 pos 和方向 dir 的生成方式,以模拟高斯光束(激光)或漫反射光源。
  • 相干性模拟:如果需要研究散斑成像(Speckle Imaging)或光学相干断层扫描(OCT),则需要追踪光子的波长(或频率)以及偏振态的变化。
相关推荐
我是唐青枫1 小时前
C#.NET YARP 认证授权实战:在网关层统一接入 JWT
开发语言·c#·.net
故事和你911 小时前
洛谷-【数据结构2-2】线段树2
开发语言·数据结构·算法·动态规划·图论
ghie90901 小时前
MATLAB 随机蛙跳算法 (SFLA) 优化最小二乘回归
算法·matlab·回归
故事和你911 小时前
洛谷-【数据结构2-2】线段树1
开发语言·javascript·数据结构·算法·动态规划·图论
鸠摩智首席音效师1 小时前
如何在 Bash 中通过 Amazon SES 发送电子邮件 ?
开发语言·bash
AI视觉网奇1 小时前
AI 3D建模生成STL文件教程 2026最新版
深度学习·3d
~|Bernard|1 小时前
五,go语言的内存管理
开发语言·后端·golang
Cx330❀2 小时前
从零实现一个 C++ 轻量级日志系统:原理与实践
大数据·linux·运维·服务器·开发语言·c++·搜索引擎
AI玫瑰助手2 小时前
Python流程控制:while循环嵌套与死循环避免技巧
开发语言·python·信息可视化