将 fnOS 从 eMMC/TF 卡无损迁移至外部存储(NVMe/USB/SATA/TF)的完整方案 —— 适用于瑞芯微 RK 系列平台(含小容量盘适配)

news2026/4/13 2:47:11
将 fnOS 从 eMMC 无损迁移至 NVMe SSD日常用 ARM 设备总习惯把固件刷进 eMMC 或者 TF 卡。eMMC 读写慢寿命有限用久了总觉得差口气。我手头有块 NanoPC-T4给它刷了 Arm 飞牛固件简单体验了一下就琢磨要是能把系统挪到 NVMe 上应该会爽很多。NanoPC-T4 正好有个 NVMe M.2 插槽把系统装到外部存储上就能绕过 eMMC 这个瓶颈。我去翻了友善官方的eflasher-multiple-os固件说明它确实可以把根文件系统写到 NVMe 或 USB 设备里但我不确定它能不能兼容飞牛的 rootfs。而且官方固件内核太老了4.19新特性和 Docker 完整支持都享受不到。好在 ARM 设备的引导思路是相通的自己研究了一下把飞牛系统迁移到了 NVMe 硬盘上。下面就是完整的折腾记录。先搞清楚 ARM 板子是怎么启动的以 RK3399 为例芯片内部固化了一段不可更改的启动 ROMBootROM。上电后BootROM 会按顺序扫描可启动设备一般是 SD 卡 → eMMC → SPI Flash找到有效的 U-Boot 就加载执行。U-Boot 负责初始化内存、时钟等然后从某个设备通常是 eMMC 或 SD 卡的分区加载内核kernel和设备树dtb。内核跑起来之后再根据root参数去挂载根文件系统。关键点RK3399 的 BootROM 不认识 NVMe。U‑Boot 和内核镜像必须放在 eMMC 或 SD 卡上但根文件系统可以放在任何内核能驱动的地方——当然也包括 NVMe。顺着这个思路整个方案可以拆成两步准备 rootfs在 NVMe 上建好分区把 eMMC 上的根文件系统完整复制过去并处理好 UUID 冲突。修改 PARTUUID修改 eMMC 上的内核引导参数让系统从 NVMe 的 PARTUUID 启动。基于这个原理我们决定用“eMMC 引导 NVMe 系统”的分离架构eMMC只放引导文件U‑Boot、内核、DTB几乎只读寿命无限NVMe放完整的根文件系统所有读写都在这儿享受高速低延迟这个方案既能绕过 RK3399 的引导限制又能把 eMMC 的寿命省下来同时把 NVMe 的性能用满。而且这种“引导介质与 rootfs 分离”的思路并不局限于 NVMe——如果 eMMC 损坏了或者板子根本没有 eMMC甚至你想把系统挪到 USB 3.0 硬盘、SATA 盘、另一张 TF 卡上本质都是一样的只要 BootROM 能从某个介质比如 TF 卡把 U‑Boot 和内核拉起来内核就能从任何它认得到的设备上挂载 rootfs。后面你会看到我们只改了一个rootPARTUUID参数这个参数指向哪里系统就从哪里启动。我手里的东西开发板NanoPC-T4RK3399引导盘板载 eMMC14.6 GB系统盘Intel Optane M10 16GB NVMe实际可用只有 13.4 GB系统fnOS 1.1.24内核Linux 6.12.41文件系统Btrfs引导方式U-Boot 脚本boot.scrfnEnv.txt注意本文所有操作都假设 NVMe 设备名为nvme0n1。你的可能是nvme1n1或别的请用lsblk确认后替换。一上来就碰了个硬钉子量了一下傲腾 M10 虽然标称 16GB实际可用只有 13.4 GB而 eMMC 上的根分区占了 14.1 GB。用dd直接克隆肯定不行目标盘比源盘还小得换个思路——不能用块设备克隆只能用文件级复制挑着有用的文件搬过去。一步步开干1. 先看看设备lsblk我的输出rootNanoPC-T4:/# lsblkNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS mmcblk2179:0014.6G0disk ├─mmcblk2p1179:10285M0part /boot └─mmcblk2p2179:2014.1G0part / mmcblk2boot0179:3204M1disk mmcblk2boot1179:6404M1disk zram0252:001.9G0disk[SWAP]nvme0n1259:0013.4G0disk └─nvme0n1p1259:1013.4G0part └─md09:0013.4G0raid1 └─trim_08a0334e_a652_40cb_a25e_151bd2290a7e-0253:0013.4G0lvm注意我的傲腾 M10 之前在飞牛上挂载过残留了 LVM 和 RAID 的配置得先清理干净。2. 清理 NVMe 上的旧配置如果不清理干净后面分区格式化会出各种奇怪问题——比如明明已经分区了但lsblk还是能看到旧的分区结构。# 强制卸载所有可能相关的挂载点根据你的实际情况改umount-l/vol12/dev/null||trueumount-l/dev/md02/dev/null||trueumount-l/dev/nvme0n1p12/dev/null||true# 停止 LVM 和 RAID 服务替换成你实际的 LVM 名称lvchange-an-fftrim_08a0334e_a652_40cb_a25e_151bd2290a7e-02/dev/null||truemdadm--stop/dev/md02/dev/null||truedmsetup remove trim_08a0334e_a652_40cb_a25e_151bd2290a7e-02/dev/null||true# 擦除分区表头扇区让内核认为这盘是空的ddif/dev/zeroof/dev/nvme0n1bs512count100convfsync# 通知内核重新读取分区表partprobe /dev/nvme0n1执行完后lsblk应该只看到一个光秃秃的nvme0n1rootNanoPC-T4:/# lsblkNAME MAJ:MIN RM SIZE RO TYPE MOUNTPOINTS mmcblk2179:0014.6G0disk ├─mmcblk2p1179:10285M0part /boot └─mmcblk2p2179:2014.1G0part / mmcblk2boot0179:3204M1disk mmcblk2boot1179:6404M1disk zram0252:001.9G0disk[SWAP]nvme0n1259:0013.4G0disk3. 确认 eMMC 上的文件系统类型blkid /dev/mmcblk2p2我得到rootNanoPC-T4:/# blkid /dev/mmcblk2p2/dev/mmcblk2p2:LABELrootfsUUID48b0a7cb-68bc-4337-b9ad-fc605dbb31bfUUID_SUBf29b6a03-37ca-4e05-987e-a2b5d5e05154BLOCK_SIZE4096TYPEbtrfsPARTUUIDafe747ae-13c5-4540-8cd0-94fb975662e5是 Btrfs记下这个 UUID后面要用。4. 给 NVMe 分区第一步准备 rootfs 的开始# 彻底清一下残留元数据wipefs-a/dev/nvme0n1 partprobe /dev/nvme0n1# 创建 GPT 分区表parted/dev/nvme0n1 mklabel gpt# 输入 yes 确认# 创建 Boot 分区285MB和 eMMC 保持一致parted/dev/nvme0n1 mkpart primary ext4 1MiB 286MiB# 创建 Root 分区占满剩余空间(此时建立了一个ext4分区,后面会格式化成btrfs)parted/dev/nvme0n1 mkpart primary ext4 286MiB100%# 刷新分区表partprobe /dev/nvme0n1# 检查分区结果lsblk /dev/nvme0n15. 格式化# Boot 分区用 ext4兼容性最好mkfs.ext4 /dev/nvme0n1p1# Root 分区用 btrfs和源系统一致mkfs.btrfs-f-Lrootfs_nvme /dev/nvme0n1p2格式化完顺手记一下新分区的 UUID 和 PARTUUIDblkid /dev/nvme0n1p26. 挂载并复制数据继续准备 rootfs# 创建临时挂载点mkdir-p/mnt/dst_boot /mnt/dst_root# 挂载目标分区mount/dev/nvme0n1p1 /mnt/dst_bootmount/dev/nvme0n1p2 /mnt/dst_root# 检查空间够不够df-h/# 源已用空间df-h/mnt/dst_root# 目标可用空间# 必须确保 源已用 目标可用确认空间足够后开始复制。因为目标盘比源盘小不能用dd只能用rsync做文件级复制。# 复制 Boot 分区rsync-avHAX/boot/ /mnt/dst_boot/# 复制根文件系统排除虚拟文件系统和外部挂载点rsync-avHAX\--exclude/proc/*\--exclude/sys/*\--exclude/dev/*\--exclude/run/*\--exclude/mnt/*\--exclude/tmp/*\--exclude/lostfound/*\--exclude/vol*/\--exclude/media/*\/ /mnt/dst_root/等几分钟看到类似这样的输出就成功了sent5,244,244,907 bytes received1,572,046 bytes62,080,674.00 bytes/sec total size is5,241,423,994 speedup is1.007. 修改 NVMe 分区的 UUID关键步骤属于准备 rootfs 的收尾现在遇到一个新问题我们用rsync把文件原样复制过去了但 Btrfs 文件系统的 UUID 也被原样复制了。也就是说NVMe 上的新 rootfs 和 eMMC 上的旧 rootfs 有完全相同的 UUID。内核在挂载时看到两个相同 UUID 的 Btrfs 卷就会混乱——它不知道该用哪一个。所以必须给 NVMe 上的 rootfs 生成一个新的 UUID。先卸载 root 分区btrfstune要求分区不能处于挂载状态umount/mnt/dst_root然后生成新 UUIDbtrfstune-u/dev/nvme0n1p2工具会问你是否确认输入yNew fsid: ff743428-987f-4649-b87e-3a94a65c94c6 Set superblock flag CHANGING_FSID Change fsidinextent tree Change fsidinchunk tree Clear superblock flag CHANGING_FSID Fsid change finished记录下新旧 UUID 和 PARTUUIDOLD_UUID$(blkid-sUUID-ovalue /dev/mmcblk2p2)NEW_UUID$(blkid-sUUID-ovalue /dev/nvme0n1p2)NEW_PARTUUID$(blkid-sPARTUUID-ovalue /dev/nvme0n1p2)echo旧 UUID (eMMC):$OLD_UUIDecho新 UUID (NVMe):$NEW_UUIDecho新 PARTUUID (NVMe):$NEW_PARTUUID我的输出旧 UUID(EMMC): 48b0a7cb-68bc-4337-b9ad-fc605dbb31bf 新 UUID(NVMe): ff743428-987f-4649-b87e-3a94a65c94c6 新 PARTUUID(NVMe): 871c986b-5385-45ae-a241-2e875a3ecc438. 修改 NVMe 里的 /etc/fstab让新 rootfs 引用自己的 UUIDNVMe 上的 rootfs 里还有一个/etc/fstab文件它里面写的是旧的 UUID指向 eMMC。如果不改即使内核从 NVMe 启动了后续挂载/时又会因为 UUID 不匹配而出错。所以得把它也换成新的 UUID。重新挂载 NVMe 的 root 分区mount/dev/nvme0n1p2 /mnt/dst_root备份并替换 UUIDcp/mnt/dst_root/etc/fstab /mnt/dst_root/etc/fstab.baksed-is/$OLD_UUID/$NEW_UUID/g/mnt/dst_root/etc/fstab验证一下cat/mnt/dst_root/etc/fstab应该看到/分区已经指向新的 UUIDrootNanoPC-T4:/# cat /mnt/dst_root/etc/fstab.......UUIDff743428-987f-4649-b87e-3a94a65c94c6 / btrfs defaults,noatime,errorsremount-ro01UUIDcf2ecdac-946c-4790-a894-19c10b526a1a /boot ext4 defaults,noatime,errorsremount-ro02tmpfs /tmp tmpfs defaults,nosuid00确认无误后卸载umount/mnt/dst_rootumount/mnt/dst_boot至此第一步“准备 rootfs”完成NVMe 上已经有了一个独立、可用的根文件系统UUID 也改好了。9. 修改 eMMC 上的引导配置第二步修改 PARTUUID现在NVMe 上的系统已经准备好了但内核还不知道要去 NVMe 上找 root。因为 RK3399 的 BootROM 只认识 eMMC/SD 卡所以我们还是从 eMMC 启动内核但要让内核把根文件系统挂载到 NVMe 上。这就需要修改内核启动参数。另外如果直接使用文件系统的 UUID 来指定 root可能会遇到问题在早期引导阶段内核不一定能正确解析 Btrfs 的 UUID尤其当有多个相同类型的文件系统时。更可靠的办法是用 PARTUUID——这是分区表的属性在分区创建时就固定了不会因为文件系统格式化而改变而且内核在很早期的阶段就能识别它。编辑 eMMC 上的/boot/fnEnv.txtvim/boot/fnEnv.txt原来的内容大概是这样verbosity1bootlogofalseconsolebothextraargscma256Mfdtfilerockchip/rk3399-nanopc-t4.dtbkernelfilevmlinuz-6.12.41-trim我们需要在extraargscma256M后面追加rootPARTUUIDxxxx-xxxx-xxxx-xxxx。注意PARTUUID后面不要加双引号cma256M和root...之间必须有一个空格。修改后verbosity1bootlogofalseconsolebothextraargscma256MrootPARTUUID871c986b-5385-45ae-a241-2e875a3ecc43fdtfilerockchip/rk3399-nanopc-t4.dtbkernelfilevmlinuz-6.12.41-trim为什么用 PARTUUID 而不是 UUIDPARTUUID 是分区表的属性不会因为文件系统重新格式化而改变在早期引导阶段更可靠。而且这个rootPARTUUID参数是通用的——如果你的 eMMC 坏了你可以把同样的参数指向另一张 TF 卡上的根分区如果你想用 USB 3.0 硬盘启动只要内核能识别该硬盘改一下 PARTUUID 就行。整个方案的精髓就在这一行。10. 重启验证建议再检查一遍/boot/fnEnv.txt里的 PARTUUID 是否和blkid /dev/nvme0n1p2输出一致。syncreboot验证一下是否真的跑在 NVMe 上重启后登录系统执行df-hT/ lsblkmount|grep / 我的结果可以看到/已经挂载在/dev/nvme0n1p2上了eMMC 的mmcblk2p2没有被使用。性能测试傲腾到底有多快Intel Optane M10 是一块很有意思的小硬盘。它的容量不大16GB但用的是 3D XPoint 介质延迟极低读写磨损均衡做得特别好。普通 TLC 固态的 4K 随机读写通常只有几万 IOPS而傲腾可以轻松跑到六位数。在 NanoPC-T4 上虽然 PCIe 2.0 x4 的带宽限制了顺序读写理论上限约 1.6 GB/s实际更少但傲腾真正的杀手锏——4K 随机读写和超低延迟——几乎不受影响。跑数据库、Docker 容器、频繁读写小文件的场景这块小傲腾能带来脱胎换骨的体验。先装fiosudoaptupdatesudoaptinstallfio-y然后跑几个测试# 4K 随机读fio--namerandread--ioenginelibaio--iodepth1--rwrandread--bs4k--direct1--size256M--numjobs1--runtime60--group_reporting--filename/tmp/fio_test_read# 4K 随机写fio--namerandwrite--ioenginelibaio--iodepth1--rwrandwrite--bs4k--direct1--size256M--numjobs1--runtime60--group_reporting--filename/tmp/fio_test_write# 混合读写70% 读 30% 写典型服务器负载fio--namemixed--ioenginelibaio--iodepth4--rwrandrw--rwmixread70--bs4k--direct1--size256M--numjobs2--runtime60--group_reporting--filename/tmp/fio_mixed# 清理rm/tmp/fio_test_* /tmp/fio_mixed_*2/dev/null我的测试结果测试项目速度/性能延迟评价顺序写入611 MB/s-吃满 PCIe 2.0 带宽顺序读取800 MB/s-含内存缓存加速4K 随机读137,000 IOPS6.16 μs企业级性能4K 随机写135,000 IOPS6.13 μs读写几乎一致混合读写读 181k / 写 77.8k IOPS29 μs低负载依然极低延迟傲腾在 RK3399 上跑出了 13 万 IOPS延迟只有 6 微秒——系统响应飞快Docker 容器启动也明显流畅了。这个方案能走多远回过头看这次迁移的核心其实就两步先在目标盘上准备好一个独立的根文件系统再改一下 eMMC 上fnEnv.txt里的rootPARTUUID参数。这个思路并不绑定 NVMe也不依赖 eMMC 必须完好。引导介质可以是 eMMC也可以是 TF 卡。万一哪天 eMMC 彻底写坏了只要把同样的引导文件U‑Boot、内核、dtb和fnEnv.txt拷到一张 TF 卡上插上去就能照样启动。而rootPARTUUID后面那个参数你想指向哪里就指向哪里——NVMe 可以USB 3.0 硬盘可以SATA 盘可以甚至另一张 TF 卡也可以。只要内核能驱动那个设备系统就能从那儿跑起来。所以这套方法不仅救活了我这块小容量傲腾也适用于任何想把瑞芯微 ARM 设备的系统从慢速存储迁到高速外部介质的场景。如果你的 eMMC 还没坏它可以作为提速方案如果已经坏了它更是一条复活路径。LECREATE2026 年 3 月 22 日

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/2511647.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

SpringBoot-17-MyBatis动态SQL标签之常用标签

文章目录 1 代码1.1 实体User.java1.2 接口UserMapper.java1.3 映射UserMapper.xml1.3.1 标签if1.3.2 标签if和where1.3.3 标签choose和when和otherwise1.4 UserController.java2 常用动态SQL标签2.1 标签set2.1.1 UserMapper.java2.1.2 UserMapper.xml2.1.3 UserController.ja…

wordpress后台更新后 前端没变化的解决方法

使用siteground主机的wordpress网站,会出现更新了网站内容和修改了php模板文件、js文件、css文件、图片文件后,网站没有变化的情况。 不熟悉siteground主机的新手,遇到这个问题,就很抓狂,明明是哪都没操作错误&#x…

网络编程(Modbus进阶)

思维导图 Modbus RTU(先学一点理论) 概念 Modbus RTU 是工业自动化领域 最广泛应用的串行通信协议,由 Modicon 公司(现施耐德电气)于 1979 年推出。它以 高效率、强健性、易实现的特点成为工业控制系统的通信标准。 包…

UE5 学习系列(二)用户操作界面及介绍

这篇博客是 UE5 学习系列博客的第二篇,在第一篇的基础上展开这篇内容。博客参考的 B 站视频资料和第一篇的链接如下: 【Note】:如果你已经完成安装等操作,可以只执行第一篇博客中 2. 新建一个空白游戏项目 章节操作,重…

IDEA运行Tomcat出现乱码问题解决汇总

最近正值期末周,有很多同学在写期末Java web作业时,运行tomcat出现乱码问题,经过多次解决与研究,我做了如下整理: 原因: IDEA本身编码与tomcat的编码与Windows编码不同导致,Windows 系统控制台…

利用最小二乘法找圆心和半径

#include <iostream> #include <vector> #include <cmath> #include <Eigen/Dense> // 需安装Eigen库用于矩阵运算 // 定义点结构 struct Point { double x, y; Point(double x_, double y_) : x(x_), y(y_) {} }; // 最小二乘法求圆心和半径 …

使用docker在3台服务器上搭建基于redis 6.x的一主两从三台均是哨兵模式

一、环境及版本说明 如果服务器已经安装了docker,则忽略此步骤,如果没有安装,则可以按照一下方式安装: 1. 在线安装(有互联网环境): 请看我这篇文章 传送阵>> 点我查看 2. 离线安装(内网环境):请看我这篇文章 传送阵>> 点我查看 说明&#xff1a;假设每台服务器已…

XML Group端口详解

在XML数据映射过程中&#xff0c;经常需要对数据进行分组聚合操作。例如&#xff0c;当处理包含多个物料明细的XML文件时&#xff0c;可能需要将相同物料号的明细归为一组&#xff0c;或对相同物料号的数量进行求和计算。传统实现方式通常需要编写脚本代码&#xff0c;增加了开…

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器的上位机配置操作说明

LBE-LEX系列工业语音播放器|预警播报器|喇叭蜂鸣器专为工业环境精心打造&#xff0c;完美适配AGV和无人叉车。同时&#xff0c;集成以太网与语音合成技术&#xff0c;为各类高级系统&#xff08;如MES、调度系统、库位管理、立库等&#xff09;提供高效便捷的语音交互体验。 L…

(LeetCode 每日一题) 3442. 奇偶频次间的最大差值 I (哈希、字符串)

题目&#xff1a;3442. 奇偶频次间的最大差值 I 思路 &#xff1a;哈希&#xff0c;时间复杂度0(n)。 用哈希表来记录每个字符串中字符的分布情况&#xff0c;哈希表这里用数组即可实现。 C版本&#xff1a; class Solution { public:int maxDifference(string s) {int a[26]…

【大模型RAG】拍照搜题技术架构速览:三层管道、两级检索、兜底大模型

摘要 拍照搜题系统采用“三层管道&#xff08;多模态 OCR → 语义检索 → 答案渲染&#xff09;、两级检索&#xff08;倒排 BM25 向量 HNSW&#xff09;并以大语言模型兜底”的整体框架&#xff1a; 多模态 OCR 层 将题目图片经过超分、去噪、倾斜校正后&#xff0c;分别用…

【Axure高保真原型】引导弹窗

今天和大家中分享引导弹窗的原型模板&#xff0c;载入页面后&#xff0c;会显示引导弹窗&#xff0c;适用于引导用户使用页面&#xff0c;点击完成后&#xff0c;会显示下一个引导弹窗&#xff0c;直至最后一个引导弹窗完成后进入首页。具体效果可以点击下方视频观看或打开下方…

接口测试中缓存处理策略

在接口测试中&#xff0c;缓存处理策略是一个关键环节&#xff0c;直接影响测试结果的准确性和可靠性。合理的缓存处理策略能够确保测试环境的一致性&#xff0c;避免因缓存数据导致的测试偏差。以下是接口测试中常见的缓存处理策略及其详细说明&#xff1a; 一、缓存处理的核…

龙虎榜——20250610

上证指数放量收阴线&#xff0c;个股多数下跌&#xff0c;盘中受消息影响大幅波动。 深证指数放量收阴线形成顶分型&#xff0c;指数短线有调整的需求&#xff0c;大概需要一两天。 2025年6月10日龙虎榜行业方向分析 1. 金融科技 代表标的&#xff1a;御银股份、雄帝科技 驱动…

观成科技:隐蔽隧道工具Ligolo-ng加密流量分析

1.工具介绍 Ligolo-ng是一款由go编写的高效隧道工具&#xff0c;该工具基于TUN接口实现其功能&#xff0c;利用反向TCP/TLS连接建立一条隐蔽的通信信道&#xff0c;支持使用Let’s Encrypt自动生成证书。Ligolo-ng的通信隐蔽性体现在其支持多种连接方式&#xff0c;适应复杂网…

铭豹扩展坞 USB转网口 突然无法识别解决方法

当 USB 转网口扩展坞在一台笔记本上无法识别,但在其他电脑上正常工作时,问题通常出在笔记本自身或其与扩展坞的兼容性上。以下是系统化的定位思路和排查步骤,帮助你快速找到故障原因: 背景: 一个M-pard(铭豹)扩展坞的网卡突然无法识别了,扩展出来的三个USB接口正常。…

未来机器人的大脑:如何用神经网络模拟器实现更智能的决策?

编辑&#xff1a;陈萍萍的公主一点人工一点智能 未来机器人的大脑&#xff1a;如何用神经网络模拟器实现更智能的决策&#xff1f;RWM通过双自回归机制有效解决了复合误差、部分可观测性和随机动力学等关键挑战&#xff0c;在不依赖领域特定归纳偏见的条件下实现了卓越的预测准…

Linux应用开发之网络套接字编程(实例篇)

服务端与客户端单连接 服务端代码 #include <sys/socket.h> #include <sys/types.h> #include <netinet/in.h> #include <stdio.h> #include <stdlib.h> #include <string.h> #include <arpa/inet.h> #include <pthread.h> …

华为云AI开发平台ModelArts

华为云ModelArts&#xff1a;重塑AI开发流程的“智能引擎”与“创新加速器”&#xff01; 在人工智能浪潮席卷全球的2025年&#xff0c;企业拥抱AI的意愿空前高涨&#xff0c;但技术门槛高、流程复杂、资源投入巨大的现实&#xff0c;却让许多创新构想止步于实验室。数据科学家…

深度学习在微纳光子学中的应用

深度学习在微纳光子学中的主要应用方向 深度学习与微纳光子学的结合主要集中在以下几个方向&#xff1a; 逆向设计 通过神经网络快速预测微纳结构的光学响应&#xff0c;替代传统耗时的数值模拟方法。例如设计超表面、光子晶体等结构。 特征提取与优化 从复杂的光学数据中自…