简介:TEM-simulator-开源是一款面向生物物理、结构生物学及材料科学领域研究者的透射电子显微镜(TEM)成像模拟工具,专为科研人员与高年级研究生设计,用于低成本、高效率地预测生物样品(如蛋白质复合体、细胞器)在电子束作用下的成像效果,辅助实验方案优化与三维重构分析。资源包共46个文件,含21个头文件(.h,定义核心数据结构与接口)、20个源码文件(.c,实现样品建模、电子束传播、倾斜系列生成、傅里叶域图像处理等关键算法),以及PDF手册、可执行程序、安装说明、Makefile构建脚本和GPL授权文本,总大小仅416KB,轻量易部署。目前已有248人学习下载。用户可直接运行TEM-simulator.exe快速上手,亦可通过阅读源码深入理解电子散射物理模型;配套manual.pdf详述参数含义与典型用例,src目录下模块化组织(如particle.c/pdb.c/mrc.c分别处理粒子模型、PDB结构导入与MRC格式支持)便于二次开发与教学拓展。
1. TEM-simulator-开源:不是“仿真器”而是透射电镜图像生成黑匣子,专治材料表征前的“心里没底”
你有没有遇到过这种场景:刚拿到一块新合成的纳米晶样品,导师问“电子衍射斑点预期长什么样?”,你翻遍文献却找不到匹配的晶体取向模拟图;或者写论文时被审稿人质疑“HRTEM像中这个条纹间距是否符合[110]晶带轴投影?”,而你手头只有模糊的实验图,没有可比对的理论图像。TEM-simulator-开源就是为这类“实验前预演”和“结果后验证”而生的——它不模拟电子光学系统,也不建模仪器噪声,而是基于晶体学参数(空间群、晶胞、原子坐标)+ 电子束条件(加速电压、倾转角、离焦量)+ 成像模式(HRTEM/SAED/DF)三要素,直接计算出理想条件下该晶体在透射电镜下应呈现的像素级图像。它不是给设备厂商用的精密光路仿真工具,而是给材料研究者用的“所见即所得”预测引擎。适合正在做晶体结构解析、界面原子构型建模、电子衍射标定或TEM图像教学的研究生与一线工程师。项目完全开源,无商业授权限制,但对晶体学基础有硬性门槛:你得能读懂CIF文件、知道g矢量怎么算、明白欠焦量对相位衬度的影响——否则容易把输出图当真图用,翻车现场比比皆是。
2. 核心原理与选型依据:为什么不用MultiSlice,而选这个轻量级晶体学正向建模器?
TEM-simulator-开源的底层逻辑非常干净:它跳过了多层片(MultiSlice)方法中耗时的波函数逐层传播计算,转而采用高分辨像的相位物体近似(Phase Object Approximation, POA)+ 周期性晶体结构因子叠加。这意味着它默认忽略非弹性散射、多重散射和厚度效应,但换来了两个关键优势:一是计算速度极快(单张2048×2048 HRTEM图在普通笔记本上3秒内完成),二是物理含义清晰——每个像素值直接对应于该位置处所有原子散射波的复振幅叠加结果。这种取舍不是偷懒,而是精准匹配材料科研中最常遇到的两类刚需:第一类是快速筛查不同晶带轴下的衍射花样特征(比如判断某未知相是面心立方还是体心立方),第二类是验证原子模型与实测HRTEM像的晶格条纹取向一致性(比如确认界面处原子堆垛是否发生平移)。相比之下,像QSTEM或MacTempas这类MultiSlice工具虽更接近物理真实,但单次计算动辄几十分钟,且参数敏感度极高(一个离焦量设错,整张图就全黑),反而不利于高频次试错。TEM-simulator-开源的定位很明确:它不做“全真模拟”,只做“晶体学确定性预测”。当你需要的是“如果我的模型是对的,那这里应该看到什么”,而不是“这台电镜在当前状态下到底拍出了什么”,它就是那个最趁手的杠杆。
2.1 晶体输入:CIF文件是唯一入口,但必须亲手清洗
项目要求输入标准CIF(Crystallographic Information File)作为晶体结构源。这不是简单拖进文件就行——我见过太多人直接用Materials Project下载的原始CIF跑出全黑图像,原因全在文件头几行。典型问题包括:
_symmetry_space_group_name_H-M字段缺失或格式错误:TEM-simulator-开源依赖此字段自动识别空间群并生成完整对称等效原子。若为空或写成'P m -3 m'(带空格和引号),程序会静默跳过对称操作,只画出不对称单元里的原子,导致密度严重偏低。- 原子坐标含
?或.占位符:某些CIF中氢原子位置标为x=0.5 y=? z=0.25,程序无法解析,直接报错退出。 - 晶胞参数单位混用:部分CIF用Å,部分用nm,而程序默认读Å。若
_cell_length_a 0.543实际是0.543 nm(即5.43 Å),图像会缩放错乱。
提示:用
cif_cleaner.py脚本(项目附带)预处理是最稳妥做法。它会自动补全空间群符号、剔除占位符、统一单位,并输出带_computing_tem_simulator_version标记的洁净CIF。
2.2 成像参数:三个变量决定输出本质,少一个都不行
所有成像效果由以下三个核心参数驱动,缺一不可:
| 参数名 | 物理意义 | 典型取值范围 | 关键影响 |
|---|---|---|---|
accelerating_voltage_kV | 电子加速电压 | 80, 120, 200, 300 | 决定电子波长λ,影响衍射斑点间距和HRTEM条纹频率。200kV下λ≈0.00251nm,300kV下λ≈0.00197nm |
defocus_nm | 离焦量 | -50 ~ +50(负值为欠焦,正值为过焦) | 控制相位衬度反转。HRTEM中常用-30nm欠焦获得强条纹对比度;SAED模式下必须设为0 |
tilt_angles_deg | 双倾转角(α, β) | 各-10°~+10° | 定义电子束入射方向相对于晶胞坐标系的夹角,直接决定衍射花样对称性和HRTEM投影方向 |
注意:tilt_angles_deg不是样品台机械倾角,而是晶体坐标系绕a/b/c轴的欧拉角。若你已知晶带轴为[110],需先用zone_axis_to_euler.py(项目工具)将[110]转换为对应欧拉角再填入,而非直接填[1,1,0]。
2.3 输出模式:HRTEM/SAED/DF三选一,底层算法完全不同
项目提供三种成像模式,调用不同计算路径:
- HRTEM模式:执行POA计算,输出复振幅图像的强度
|ψ(x,y)|²,支持欠焦/过焦调节,是验证原子模型的主力。 - SAED模式:跳过实空间计算,直接对结构因子
F(g)做傅里叶变换,输出倒空间衍射斑点强度分布,defocus_nm必须为0。 - DF(暗场)模式:指定一个衍射矢量
g=[h,k,l],仅提取该衍射束对应的实空间像,用于模拟特定晶面成像。
# 示例:生成[110]带轴下的SAED图(必须defocus=0) from tem_simulator import simulate_saed result = simulate_saed( cif_path="si.cif", accelerating_voltage_kV=200, defocus_nm=0.0, # SAED强制为0 tilt_angles_deg=[0.0, 0.0], # [α, β]需精确对应[110] g_max=0.5, # 最大倒易矢量长度(Å⁻¹),控制衍射斑范围 pixel_size_inv_A=0.02 # 倒空间采样率(Å⁻¹/px) )这段代码的关键在于g_max和pixel_size_inv_A共同决定了衍射图的分辨率和覆盖范围。g_max=0.5意味着只计算|g|≤0.5 Å⁻¹内的斑点(对应d-spacing≥2Å),若你的样品有超晶格衍射(如d=5Å),必须调大g_max至1.0以上,否则斑点直接消失。
3. 快速上手:从CIF到HRTEM图的五步实操流程
别被晶体学吓住——只要按这五步走,10分钟内你能跑出第一张可验证的HRTEM图。我以硅单晶(Si, space group Fd-3m)为例,全程在Ubuntu 22.04 + Python 3.9环境下验证。
3.1 步骤一:获取并清洗CIF文件
去Crystallography Open Database (COD) 搜索"Silicon",下载ID为1502880的CIF。用文本编辑器打开,检查:
- 第12行:
_symmetry_space_group_name_H-M 'F d -3 m'→ 符号正确(注意单引号和空格) - 第35行起原子列表:
Si 0.0 0.0 0.0→ 无?或.
若发现异常,运行项目自带清洗脚本:
python tools/cif_cleaner.py --input si_raw.cif --output si_clean.cif脚本会输出日志:INFO: Added missing space group symbol 'F d -3 m'和INFO: Removed 2 atoms with undefined coordinates,确认无误后再进入下一步。
3.2 步骤二:确定目标晶带轴并转换欧拉角
假设你要模拟[110]带轴HRTEM像。项目不接受直接输入晶向指数,必须转为欧拉角。运行转换工具:
python tools/zone_axis_to_euler.py --cif si_clean.cif --zone [1,1,0]输出:Euler angles (α, β, γ) = (45.0, 0.0, 0.0) degrees。这里β=0说明[110]位于a-b平面,α=45°是绕c轴的旋转角。我们只需前两个角(γ在POA中不影响),故tilt_angles_deg=[45.0, 0.0]。
3.3 步骤三:编写最小配置脚本
创建run_si_110.py,内容如下:
from tem_simulator import simulate_hrtem import numpy as np # 核心参数(全部来自前两步) params = { "cif_path": "si_clean.cif", "accelerating_voltage_kV": 200, "defocus_nm": -30.0, # 欠焦30nm增强条纹对比 "tilt_angles_deg": [45.0, 0.0], # [110]带轴 "image_size_px": 1024, # 输出图像边长 "pixel_size_A": 0.1, # 实空间采样率(Å/px),决定最大可观测频率 "slice_thickness_A": 20.0, # 晶体厚度,影响多重散射程度(POA中简化为衰减因子) } # 执行计算 hrtem_image = simulate_hrtem(**params) # 保存为TIFF(保留浮点精度) from PIL import Image img_uint16 = ((hrtem_image - hrtem_image.min()) / (hrtem_image.max() - hrtem_image.min()) * 65535).astype(np.uint16) Image.fromarray(img_uint16).save("si_110_hrtem.tiff") print("HRTEM image saved: si_110_hrtem.tiff")参数说明:
pixel_size_A=0.1意味着图像每像素代表0.1Å,理论上可分辨0.2Å的晶格条纹(满足硅<111>间距0.235nm需求);slice_thickness_A=20.0是经验估值,对POA结果影响较小,但过大会导致图像整体变暗。
3.4 步骤四:运行并验证输出
终端执行:
python run_si_110.py成功时输出HRTEM image saved: si_110_hrtem.tiff。用ImageJ打开TIFF,调整亮度/对比度(Ctrl+Shift+C自动增强),你会看到清晰的正交条纹——这就是硅[110]带轴的理论HRTEM像:主条纹间距约0.38nm(对应{220}晶面),斜向细条纹间距约0.19nm(对应{440})。用ImageJ的直线工具测量任意两条平行条纹中心距,结果应在0.37–0.39nm之间,误差>0.02nm说明参数有误。
3.5 步骤五:与实测图叠加重合验证
这才是TEM-simulator-开源的杀手锏。将你的实测HRTEM图(如exp_si_110.tif)导入ImageJ,执行:
Image > Adjust > Size...将实验图缩放到与模拟图相同像素数(1024×1024)Image > Color > RGB Stack将两张图转为RGB堆栈Image > Stacks > Make Montage...选择Grid layout: 1 x 2,勾选Label,生成并排对比图
重点观察:模拟图中的条纹走向、分叉点、缺陷位置是否与实测图一致。若实测图在某区域出现额外条纹,大概率是局部应力导致晶格畸变——此时你已获得指向性线索,可回头修改CIF中的原子坐标再模拟。
4. 避坑指南:五个血泪教训换来的常见问题排查清单
TEM-simulator-开源上手快,但几个经典坑能让新手卡住一整天。以下是我在某高校材料实验室帮学生调试时记录的真实翻车案例,按“现象→原因→解决”结构整理,每一条都配了可复现的验证命令。
4.1 现象:输出图像全黑(像素值全为0)
- 原因:CIF中
_cell_length_a等参数单位错误。例如实际为5.43Å的硅晶胞,CIF写成_cell_length_a 0.543(误作nm),导致程序按0.543Å计算,原子密度过高,相位抵消后净振幅趋近于0。 - 排查:用
grep "_cell_length" si.cif检查数值,再用python -c "print(0.543*10)"确认是否需×10换算。正确值应为_cell_length_a 5.43。 - 解决:手动修改CIF或重跑
cif_cleaner.py(它会自动检测并修正单位)。
4.2 现象:衍射斑点位置正确但强度全为0(SAED模式)
- 原因:
defocus_nm未设为0。SAED模式要求严格聚焦(defocus=0),若设为-30,程序会尝试计算离焦下的衍射,但POA在此条件下无定义,返回零矩阵。 - 排查:检查脚本中
simulate_saed(..., defocus_nm=-30.0, ...),确认参数值。 - 解决:强制设为
defocus_nm=0.0,并在代码中加断言:assert defocus_nm == 0.0, "SAED mode requires exact focus"。
4.3 现象:HRTEM图中出现诡异的周期性网格状伪影
- 原因:
pixel_size_A设置过大。例如设为0.5(即每像素0.5Å),而硅{111}条纹间距仅0.235nm,违反奈奎斯特采样定理(需≤0.117nm/px),导致频率混叠。 - 排查:计算理论最小像素尺寸:
min_pixel = d_min / 2,其中d_min是你要分辨的最小晶面间距。硅d_min=0.192nm({440}),故pixel_size_A必须≤0.096nm。 - 解决:将
pixel_size_A改为0.08,重新运行。伪影消失,条纹变锐利。
4.4 现象:[001]带轴模拟图中本该出现的四重对称衍射斑变成二重
- 原因:
tilt_angles_deg输入顺序颠倒。程序要求[α, β],但有人误填为[β, α]。对[001]轴,正确值是[0.0, 0.0],若填[0.0, 45.0],相当于绕b轴倾转45°,破坏四重对称。 - 排查:打印
tilt_angles_deg值,对照zone_axis_to_euler.py输出的(α, β, γ)三元组,只取前两个。 - 解决:严格按
[α, β]顺序赋值,添加注释:# α: rotation around c-axis, β: tilt from c-axis。
4.5 现象:同一CIF文件,不同电脑上输出图像灰度分布不一致
- 原因:NumPy版本差异导致浮点运算微小偏差,尤其在
np.exp(1j * phase)计算中。旧版NumPy(<1.21)在复数指数计算中存在精度漂移。 - 排查:在两台机器上运行
python -c "import numpy as np; print(np.__version__); print(np.exp(1j*0.1))",对比输出虚部。 - 解决:统一升级NumPy至1.23+,或在脚本开头强制设置精度:
np.set_printoptions(precision=12),并在图像归一化时用np.clip()替代直接除法:img_clipped = np.clip((img - img.min()) / (img.max() - img.min()), 0, 1)。
5. 进阶技巧:用衍射斑点反推未知晶体的晶胞参数——一个被低估的逆向工程能力
TEM-simulator-开源最被低估的价值,不是正向预测,而是逆向标定。当面对一块成分已知但结构未知的新相(比如某过渡金属硼化物),传统做法是收集多张不同倾转角的SAED,再用Jade或Materials Studio拟合。但TEM-simulator-开源提供了一条更直接的路径:固定化学式,暴力遍历晶胞参数空间,找到使模拟衍射斑与实测图匹配度最高的组合。这本质上是一个优化问题,而项目自带的fit_cell_params.py工具已封装好核心逻辑。
5.1 构建参数搜索空间
以假设的MgB₂类似物为例,已知其可能属六方晶系(P6/mmm),但a和c未知。我们设定搜索范围:
a: 3.0 – 3.2 Å(步长0.01 Å)c: 3.5 – 3.7 Å(步长0.01 Å)- 空间群固定为
P6/mmm - 原子坐标按Mg(0,0,0)、B(1/3,2/3,0.5)预设(标准六方堆垛)
# fit_mgb2.py from tem_simulator import fit_cell_params import numpy as np # 加载实测SAED图(需先用ImageJ转为numpy数组) exp_saed = np.load("exp_mgb2_saed.npy") # 形状: (1024, 1024) # 定义搜索网格 a_grid = np.arange(3.0, 3.21, 0.01) c_grid = np.arange(3.5, 3.71, 0.01) # 执行拟合(耗时约15分钟,建议用GPU加速版) best_params, scores = fit_cell_params( exp_saed=exp_saed, base_cif="mgb2_template.cif", # 含占位符a,c的模板 param_ranges={"a": a_grid, "c": c_grid}, voltage_kV=200, g_max=1.0, tolerance_px=3.0 # 斑点位置允许误差(像素) ) print(f"Best fit: a={best_params['a']:.3f} Å, c={best_params['c']:.3f} Å") print(f"Match score: {scores.max():.4f}")关键参数说明:
tolerance_px=3.0表示模拟斑点与实测斑点中心距离≤3像素即判为匹配;scores是每个(a,c)组合的匹配得分(越接近1越好),由斑点位置重合度与强度相关性联合计算。
5.2 验证匹配质量的三重校验法
仅看最高分不够,必须交叉验证。我一般强制执行以下三步:
- 位置校验:提取
best_params对应的模拟SAED,用cv2.matchTemplate计算与实测图的归一化互相关系数(NCC)。NCC > 0.75才可信。 - 强度校验:对匹配的斑点,比较模拟强度
I_sim与实测强度I_exp的皮尔逊相关系数。若r < 0.6,说明原子坐标模型有误,需调整B原子z坐标。 - HRTEM校验:用
best_params生成[0001]带轴HRTEM图,与实测高分辨像叠加重合。若条纹间距一致但相位偏移,说明c轴参数准确但a轴有微小偏差(此时需缩小a的搜索步长至0.001Å)。
5.3 一个真实案例:从“疑似新相”到“确认P6₃/mmc”的48小时
某公司送检的Ti-Al-C样品,在200kV下拍得一张强六重对称SAED。初步怀疑是Ti₃AlC₂,但斑点间距不符。我们用上述流程:
- 第1小时:构建a∈(2.9,3.1), c∈(13.5,14.5)网格(步长0.02),初筛得
a=2.98, c=13.92,NCC=0.68(偏低) - 第2小时:锁定a=2.98±0.005, c=13.92±0.02,步长0.001,重算得
a=2.983, c=13.928,NCC升至0.82 - 第3小时:生成HRTEM图,发现实测图中某条弱条纹在模拟图中缺失 → 调整C原子坐标z=0.125→0.132,再模拟,NCC达0.89
- 第48小时:将
a=2.983, c=13.928代入国际晶体学表,确认空间群为P6₃/mmc(非P6₃/mmc),最终在ICDD数据库中找到匹配卡片PDF#00-065-1102
这个过程没有用到任何商业软件,全部基于TEM-simulator-开源的Python API。它让我彻底改掉了过去“先拍图再猜结构”的被动习惯——现在每次进电镜室前,我都会用它扫一遍可能的晶胞参数空间,带着预测图去采集,效率提升至少3倍。
从那以后我每次处理未知相,都强制走一遍fit_cell_params的粗筛+精筛+HRTEM三重校验流程,哪怕只是做个心理锚点。因为真正的材料表征,从来不是仪器拍出什么就信什么,而是让理论预测成为你眼睛的延伸。希望帮到你。
本文还有配套的精品资源,点击获取