过夜设计:下班前说目标,早上看最好的几条路
优化跑一次几秒到几分钟,可「这个设计还能怎么走」往往要试很多条路:放开厚度、换玻璃、加一片、减一片、换个种子再做全局搜索…… 过夜设计把这些交给后台:下班前说清目标和时间,它整夜一条一条地试,每条路的结果存成一个设计分支(一份完整的 .lens), 早上给出「试了 N 条路,最好的 5 条」——每条带评价函数、像质、良率、总长、证据 id,一条命令切换过去(可撤销)。
lb overnight cooke.lens --hours 8 # 整夜,目标用设计自己的评价函数与 spec
lb overnight cooke.lens --hours 10 --goal "rms<10um, mtf@50>0.3" --max-length 62
lb overnight-report cooke.lens # 早上:试了 N 条路,最好的 5 条
lb branch-list cooke.lens # 全部分支
lb branch-show cooke.lens b1-06 # 一个分支的来历、数与证据
lb branch-diff cooke.lens b1-06 # 与当前设计对比(一阶量、处方、像质、文本 diff)
lb branch-switch cooke.lens b1-06 --dry-run # 先看 diff,去掉 --dry-run 切过去(lb undo 回来)AI 经 MCP 调 overnight 时加 background=true:立即返回任务句柄,job_status 的 stage 写着在跑第几条路线、已经存了几个分支, job_cancel 取消(照样收尾、给出早报)。
目标怎么说
设计自己的评价函数(没有时用默认评价函数
default spot centroid rings=3 arms=6,同 改进探索)与设计里的 spec:评价函数决定每条路往哪儿优化;spec 原来通过的,哪条路都不许让它变成不通过。另加的目标(
--goal,逗号隔开;不进优化,只用来排名——达成几条,排名就先看几条):写法 意思 rms<10um最差视场的复色 RMS 弥散斑(µm,同 lb spot的默认)不超过 10 µmwave<0.07RMS 波前随视场的最大值(λ,同 lb rms-field --data wavefront)mtf@50>0.350/mm 处各视场子午、弧矢 MTF 的最差值不低于 0.3 ttl<60mm总长 yield>80%良率(见下面「怎么排」) 硬约束:焦距、孔径、视场、波长不动(同改进探索);总长不超过起点的 1.05 倍,或
--max-length给的值;--keep-glass不换玻璃 (加片也只用设计里已有的玻璃);--vendor CDGM第 1 轮另加一条「全部换成 CDGM 的等效牌号(同lb glass-replace)再优化」—— 国产替代的那条路;--moves只做其中几类(thickness放开厚度、glass试换玻璃、global全局搜索、split拆片、meniscus加弯月片、remove减片)。时间:
--hours(默认 8),试跑用--minutes。时间到了停在一条路的边界上(那条路照常做完、存盘),再留一点时间给收尾。
整夜试什么
每条路是一串动作,从起点或某个已有的分支出发:
- 第 1 轮(都从起点出发):放开半径与厚度;再试换玻璃;再加全局搜索(就是
lb improve的四步);另一个种子的全局搜索; 给了--vendor时全部换成那个厂商的等效牌号;拆开最强的一片、光阑旁加一片弱弯月、去掉最弱的一片(各接放开半径 → 厚度 → 全局搜索)。 - 之后每一轮:接着路线分最高的 3 个分支各跑一次换了种子的全局搜索(轮数逐轮翻倍,最多到第一轮的 16 倍;偶数轮先试换玻璃); 从起点再跑一个新种子的全局搜索;再做一个还没做过的加减片(第 2 强的一片、光阑另一侧、第 2 弱的一片……都做过了,就在最好的那个 分支上再拆 / 再减一片)。
- 连续三轮没有新分支、或者没有可试的了,就提前收尾。
同一个种子(--seed)、同样的设置,路线计划逐条相同;每条路的结果在没撞上时间的情况下逐位相同。一夜试几条路与机器快慢有关。
加一片、减一片怎么做
| 动作 | 做法 |
|---|---|
| 拆开最强的一片 | 按近轴光焦度挑最强的球面单片,拆成同一种玻璃的两片,各取原来一半的曲率(薄透镜下各一半的光焦度、同样的弯曲);每片中心厚至少 1 mm、边厚留够 1 mm,两片之间空气中心至少 0.5 mm、边缘至少 0.5 mm;多出来的长度从后面(或前面)那段空气里扣 |
| 光阑旁加一片弱弯月 | 在光阑后(下一次在光阑前)离光阑最近、放得下的空气间隔正中插一片:两面同半径 R = 2 × 焦距、凹面朝光阑(薄透镜光焦度为零),中心厚 max(1.5 mm, 2 % × 焦距),两边各至少留 1 mm 空气,玻璃取设计里阿贝数最高的那种 |
| 去掉最弱的一片 | 光焦度最弱的那片(单片或胶合组;光阑所在的那片不去,只剩一片时不去):删掉它的面,前一段空气接上它的厚度与后一段空气,其余各片位置不动 |
改完以后:要能构建,不新增装夹违例与薄边(做不了就如实写「做不了」,例如 Cooke 三片式去掉前片,后面两片会撞上);焦距差 25 % 以内(物在无穷远时)先按比例缩放整个镜头找回焦距,再交给改进探索——焦距与总长上限仍按原设计算,改过结构的那一版本身不满足时, 第一版满足的就留下。变量(var)、solve / pickup 的面号跟着改;注释留在原来的面上。
评价函数、spec、公差里有按面号引用的行(如 op CTGT 3、tol 行、let、自定义表达式的 spec)时不做加减片:面号一变就对不上了。 多重结构、坐标断点、反射镜也不做。
每条路都要过的门槛
同 改进探索 的门槛,比的是原设计:能构建;焦距不变(0.1 %);总长不超上限;装夹违例、薄边(< 0.5 mm)各不比原设计多; 原设计能到像面的探测光线照样能到;原设计通过的 spec 一条也不能变成不通过。没过门槛的路不存分支,早报里列出原因;与已有分支逐字相同的 路、没找到比出发点更好的路也不重复存。
怎么排
先看目标有几条没达成(spec 与 --goal,少的在前),再看路线分(高的在前),再看评价函数。路线分 0–100,五项加权平均 (没算出的项不进分母):
| 项 | 权重 | 这一项的分 |
|---|---|---|
| 像质 | 40 | 100 × (1 − 这一版的评价函数 ÷ 起点评价函数),限在 0–100:评价函数比起点降了百分之几就是几分(降一半 50 分,没降 0 分) |
| 良率 | 30 | 100 × 蒙特卡洛良率 |
| 可制造性 | 15 | 100 − 每处装夹违例 40 − 每片边厚 < 0.5 mm 20 − 每条加工规则(检验规则库 MFG 类)警告 10 |
| 玻璃供货 | 10 | 100 − 每种停产玻璃 40 − 每种特殊熔炼 / 询价 15 |
| 总长 | 5 | 50 + 1000 × (起点总长 − 总长) ÷ 起点总长,限在 0–100:起点 50 分,每短 1 % 加 10 分 |
良率同 体检:默认公差模板(--grade,默认常规)的蒙特卡洛,合格 = 补偿后的判据不超过起点名义值的 1.5 倍(--limit 给绝对值), 所有分支同一个界限、同一个种子。整夜每条路用小样本(--trials,默认 20 次)估;收尾时排名前 top + 3 的分支与起点再用大样本 (--final-trials,默认 100 次)重算,定最终排名。小样本的统计误差大(20 次约 ±10 个百分点),早报里写着每个良率是多少次试验算的。
设计分支存在哪、怎么用
分支放在镜头旁边(同改动日志的 .lensbench/),每次运行一个目录:
<镜头目录>/.lensbench/branches/<名字>/run-1/run.json 这次运行:目标、设置、起点、每条路(计划、状态、结果)、排名
<镜头目录>/.lensbench/branches/<名字>/run-1/base.lens 运行开始时的设计(各分支的起点)
<镜头目录>/.lensbench/branches/<名字>/run-1/b1-06.lens 分支:第 1 次运行第 6 条路的结果,完整的 .lens
<镜头目录>/.lensbench/branches/<名字>/run-1/b1-06.json 分支的来历(起点 / 哪个分支、一路做了什么)、评价函数、像质与证据 id、良率、玻璃、可制造性、目标、路线分lb branch-list:全部分支,按排名;当前打开的就是哪个分支时标「当前」。lb branch-show <分支>:一路做了什么(加减片的具体做法)、各项的数与证据 id;--text连.lens全文一起给。lb branch-diff <分支>:与当前设计对比(同lb compare,面数不同时多出 / 少了的面整行列出),再附文本 diff;lb compare的版本引用也认 分支号(lb compare cooke.lens "" b1-06)。lb branch-switch <分支>:当前设计整段换成分支的文本,同样先--dry-run看 diff、进撤销栈、记进改动日志(lb undo回来)。- 证据 id 与在那个分支上直接跑
lb spot/lb rms-field --data wavefront/lb mtf/lb tolerance --template commercial --mode montecarlo --trials 20 --seed 0登记的相同,可以复算核对。
早报
lb overnight 跑完直接给出早报;之后随时 lb overnight-report(不重算,读存下的结果;还在跑的运行也能看,看到的是到上一条路为止的): 起点一行、最好的 top 条(--top,默认 5)——排名、分支号、路线、评价函数、比起点、最差 RMS 弥散斑、各频率的最差 MTF、良率(几次)、 总长、路线分、目标达成情况——每条的加减片做法与证据 id、切换命令,没成的路与原因。--out 把早报写成文件:overnight.md(报告)、 overnight.json(全部数据)、base.lens 与前几名分支的 .lens。
中断与续跑
每条路做完就写盘。机器重启、进程崩了、取消了:lb overnight cooke.lens --resume last --hours 4 接着跑——做完的路不重做,计划接着往下排 (目标与路线的设置照原来的,只换时间预算);被取消打断的那条路整条重做,结果与一口气跑完的相同。跑完的运行也能续(再加几轮)。
档位
- 个人高级版起:过夜设计本身(
overnight;「各档有什么」里「自动优化与长任务」那一行)。新设备第一次登录的 7 天全功能试用里可以试。 - 个人基础版起:早报文件(
overnight-report --out,交付件)、切换到分支(branch-switch,同「打开改进版」:档位不够时照常给出分支的数, 只是不给 diff 与应用)。 - 免费:看早报(
overnight-report不带--out)、列出 / 查看 / 对比分支——你自己的文件,试用期跑出来的分支到期后照样能看。
一个例子
Cooke 三片式(examples/cooke_triplet.lens,没有评价函数、用默认的),lb overnight cooke_triplet.lens --minutes 5(一台工作站, 前一分多钟是加载内核、起进程与起点的良率;10-20 实测,良率是收尾时 100 次蒙特卡洛的):
| 排名 | 分支 | 路线 | 评价函数 | 比起点 | RMS 最差 µm | MTF@25/50/100 最差 | 良率 | 总长 mm | 路线分 |
|---|---|---|---|---|---|---|---|---|---|
| — | 起点 | (原设计) | 0.011554 | — | 17.73 | 0.229 / 0.054 / 0.005 | 76 % | 60.18 | 48.8 |
| 1 | b1-06 | 光阑后加一片弱弯月 → 半径、厚度 → 全局搜索 | 0.004016 | −65.2 % | 5.71 | 0.687 / 0.306 / 0.011 | 95 % | 60.55 | 80.3 |
| 2 | b1-03 | 放开厚度 + 试换玻璃 + 全局搜索(同 lb improve) | 0.007373 | −36.2 % | 10.68 | 0.530 / 0.112 / 0.007 | 73 % | 54.46 | 66.4 |
| 3 | b1-05 | 拆开最强的一片 → 半径、厚度 → 全局搜索 | 0.005067 | −56.1 % | 7.31 | 0.632 / 0.228 / 0.057 | 48 % | 59.24 | 62.1 |
| 4 | b1-04 | 全局搜索(另一个种子) | 0.008877 | −23.2 % | 12.88 | 0.377 / 0.122 / 0.001 | 63 % | 54.26 | 56.7 |
| 5 | b1-02 | 放开厚度 + 试换玻璃 | 0.010214 | −11.6 % | 15.80 | 0.406 / 0.103 / 0.009 | 75 % | 59.91 | 53.4 |
- 5 分钟试了 6 条路,都过了门槛。最好的是四片的:在光阑后加的那片弱弯月被优化成一片有光焦度的弯月(面 5–6),评价函数低 65 %、 良率反而从 76 % 升到 95 %。
- 拆开中间那片负透镜的方案像质也好(低 56 %),但良率只有 48 %——两片薄的负透镜对偏心很敏感,所以排在第 3;只看评价函数的话它是第 2。
- 这 5 分钟还没轮到第 7 条「去掉最弱的一片」;跑到它时:去掉 Cooke 的前片,后面两片会撞上,早报里如实列为「做不了」。时间再长, 下一轮会接着前三名换种子搜、试换玻璃,再试别的加减片。
双高斯(examples/double_gauss.lens,同样没有评价函数——它不是照默认评价函数优化出来的,所以每条路都能降很多)只做加减片 (--minutes 4 --moves split,meniscus,remove):4 分钟 5 条路都过了门槛——光阑后 / 前加弯月(−91.3 % / −91.2 %)、拆后组单片 / 前组单片 (−90.9 % / −89.3 %)、去掉 7–9 那组胶合透镜(少一组、总长 139.5 → 115.2 mm,评价函数 −50.5 %,排在最后:像质那一项只有 50 分)。 五条的良率都是 100 %(这个设计按常规公差本来就很宽松;时间到了,有一条来不及用 100 次重算,早报里写着它是 20 次的)。
局限
- 加减片只做三种固定的手法(见上),不会凭空想出新的结构形式;拆片只拆球面单片。
- 「最好」是按上面的路线分排的:像质与良率之间怎么取舍,看各项的分,必要时用
--goal把硬要求写出来。 - 良率是蒙特卡洛估计:整夜的小样本只用来挑前几名,定排名用收尾时的大样本;要更准,
--final-trials加大或对选中的分支跑一次体检。 - 多重结构、偏心 / 倾斜系统不支持(同改进探索)。