build_hub.py 30 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397
  1. # -*- coding: utf-8 -*-
  2. """生成 仿真集成台 单文件 HTML: 叙事 + 全部仿真入口 + 内嵌尾流图与动画。"""
  3. import pathlib
  4. import base64
  5. _A = pathlib.Path(__file__).resolve().parent / "assets"
  6. PNG = base64.b64encode((_A/"wake_real.png").read_bytes()).decode()
  7. VIV = base64.b64encode((_A/"pain_viv.png").read_bytes()).decode()
  8. YAWS = base64.b64encode((_A/"pain_yawslip.png").read_bytes()).decode()
  9. PITCH= base64.b64encode((_A/"pain_pitch.png").read_bytes()).decode()
  10. MP4 = base64.b64encode((_A/"wake_anim.mp4").read_bytes()).decode()
  11. G = "http://127.0.0.1:28084"
  12. L = "file:///Users/yuanying/guanlan-rudong-v2/outputs/rudong/windscada/_demo/sim"
  13. ARCH_SVG = '''<svg viewBox="0 0 1290 430" width="100%" style="display:block">
  14. <defs>
  15. <linearGradient id="lgH" x1="0" y1="0" x2="1" y2="0"><stop offset="0" stop-color="#0e6470"/><stop offset="1" stop-color="#0e8898"/></linearGradient>
  16. <linearGradient id="lgD" x1="0" y1="0" x2="1" y2="0"><stop offset="0" stop-color="#1a5f88"/><stop offset="1" stop-color="#2077a8"/></linearGradient>
  17. <marker id="a2" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
  18. <path d="M0 0 L10 5 L0 10 z" fill="#0e8898"/></marker>
  19. <marker id="a3" viewBox="0 0 10 10" refX="9" refY="5" markerWidth="8" markerHeight="8" orient="auto">
  20. <path d="M0 0 L10 5 L0 10 z" fill="#2077a8"/></marker>
  21. </defs>
  22. <!-- 左: 半实物仿真 -->
  23. <rect x="0" y="0" width="600" height="196" rx="14" fill="url(#lgH)"/>
  24. <text x="26" y="34" font-size="12.5" fill="#bfeef4" font-family="monospace" letter-spacing="1.6">HARDWARE IN THE LOOP</text>
  25. <text x="26" y="64" font-size="22" font-weight="600" fill="#fff">半实物仿真</text>
  26. <text x="26" y="90" font-size="14" fill="#d6f2f6">真主控 PLC · 真 IO · 模型在环</text>
  27. <g font-size="12.5" fill="#eaf9fb">
  28. <rect x="26" y="106" width="168" height="30" rx="7" fill="rgba(255,255,255,.16)"/><text x="40" y="126">高速 IO 柜 · 故障注入器</text>
  29. <rect x="204" y="106" width="150" height="30" rx="7" fill="rgba(255,255,255,.16)"/><text x="218" y="126">整机模型在环</text>
  30. <rect x="364" y="106" width="210" height="30" rx="7" fill="rgba(255,255,255,.16)"/><text x="378" y="126">海量连接器 · 换机型只换线</text>
  31. </g>
  32. <text x="26" y="168" font-size="14.5" fill="#fff" font-weight="600">回答:控制器<tspan fill="#ffe9b8">本来该怎么响应</tspan></text>
  33. <!-- 右: 数据 -->
  34. <rect x="690" y="0" width="600" height="196" rx="14" fill="url(#lgD)"/>
  35. <text x="716" y="34" font-size="12.5" fill="#cfe8f7" font-family="monospace" letter-spacing="1.6">DATA IN THE LOOP</text>
  36. <text x="716" y="64" font-size="22" font-weight="600" fill="#fff">数据</text>
  37. <text x="716" y="90" font-size="14" fill="#dcedf8">真实运行记录 · 判据库 · 实测故障事件</text>
  38. <g font-size="12.5" fill="#eaf5fb">
  39. <rect x="716" y="106" width="150" height="30" rx="7" fill="rgba(255,255,255,.16)"/><text x="730" y="126">逐分钟 · 秒级 · 振动谱</text>
  40. <rect x="876" y="106" width="150" height="30" rx="7" fill="rgba(255,255,255,.16)"/><text x="890" y="126">十域判据 · 靶场考过</text>
  41. <rect x="1036" y="106" width="228" height="30" rx="7" fill="rgba(255,255,255,.16)"/><text x="1050" y="126">场级契约 · 换机型只换参数</text>
  42. </g>
  43. <text x="716" y="168" font-size="14.5" fill="#fff" font-weight="600">回答:现场<tspan fill="#ffe9b8">实际发生了什么</tspan></text>
  44. <!-- 接缝 -->
  45. <path d="M600 78 L688 78" stroke="#0e8898" stroke-width="2.2" marker-end="url(#a2)"/>
  46. <path d="M690 120 L602 120" stroke="#2077a8" stroke-width="2.2" marker-end="url(#a3)"/>
  47. <text x="645" y="66" font-size="11" fill="#0e6470" text-anchor="middle">设计意图</text>
  48. <text x="645" y="142" font-size="11" fill="#1a5f88" text-anchor="middle">实测时序</text>
  49. <!-- 下: 四件事 -->
  50. <g>
  51. <rect x="0" y="222" width="312" height="196" rx="12" fill="#fff" stroke="#cbe2eb"/>
  52. <text x="22" y="252" font-size="12" fill="#0e8898" font-family="monospace" letter-spacing="1.4">01</text>
  53. <text x="22" y="278" font-size="17" font-weight="600" fill="#133047">故障测试</text>
  54. <text x="22" y="304" font-size="13" fill="#28536b">硬件层:短路 / 开路 / 电阻电容</text>
  55. <text x="22" y="326" font-size="13" fill="#28536b">软件层:六项失效 · 液压三型</text>
  56. <text x="22" y="348" font-size="13" fill="#28536b">数据层:七种缺陷注入</text>
  57. <text x="22" y="374" font-size="13" fill="#28536b">真实层:实测故障事件库</text>
  58. <text x="22" y="400" font-size="12.5" fill="#61788b">同一个故障,三种来源可互证</text>
  59. <rect x="326" y="222" width="312" height="196" rx="12" fill="#fff" stroke="#cbe2eb"/>
  60. <text x="348" y="252" font-size="12" fill="#0e8898" font-family="monospace" letter-spacing="1.4">02</text>
  61. <text x="348" y="278" font-size="17" font-weight="600" fill="#133047">分析与表现</text>
  62. <text x="348" y="304" font-size="13" fill="#28536b">判据先在已知答案上考过</text>
  63. <text x="348" y="326" font-size="13" fill="#28536b">出的不是图,是清单</text>
  64. <text x="348" y="348" font-size="13" fill="#28536b">定向清单 + 排除清单</text>
  65. <text x="348" y="374" font-size="13" fill="#28536b">工单 → 改后同工况复核</text>
  66. <text x="348" y="400" font-size="12.5" fill="#61788b">每条结论带证伪条件</text>
  67. <rect x="652" y="222" width="312" height="196" rx="12" fill="#fff" stroke="#cbe2eb"/>
  68. <text x="674" y="252" font-size="12" fill="#0e8898" font-family="monospace" letter-spacing="1.4">03</text>
  69. <text x="674" y="278" font-size="17" font-weight="600" fill="#133047">多机型,成本低</text>
  70. <text x="674" y="304" font-size="13" fill="#28536b">硬件侧:柜子共用,换机型只换线</text>
  71. <text x="674" y="326" font-size="13" fill="#28536b">软件侧:换机型 = 换一份参数契约</text>
  72. <text x="674" y="348" font-size="13" fill="#28536b">已有两个功率代际可直接对照</text>
  73. <text x="674" y="374" font-size="13" fill="#28536b">八套原厂包 · 七十一份场级契约</text>
  74. <text x="674" y="400" font-size="12.5" fill="#61788b">不是一个机型建一套台</text>
  75. <rect x="978" y="222" width="312" height="196" rx="12" fill="#f2fafc" stroke="#0e8898"/>
  76. <text x="1000" y="252" font-size="12" fill="#0e8898" font-family="monospace" letter-spacing="1.4">04</text>
  77. <text x="1000" y="278" font-size="17" font-weight="600" fill="#133047">培训四段</text>
  78. <text x="1000" y="304" font-size="13" fill="#28536b"><tspan font-weight="600" fill="#0e6470">机理</tspan> — 它为什么这么动</text>
  79. <text x="1000" y="326" font-size="13" fill="#28536b"><tspan font-weight="600" fill="#0e6470">失效</tspan> — 坏了在信号上什么样</text>
  80. <text x="1000" y="348" font-size="13" fill="#28536b"><tspan font-weight="600" fill="#0e6470">模拟</tspan> — 系统级怎么配合</text>
  81. <text x="1000" y="374" font-size="13" fill="#28536b"><tspan font-weight="600" fill="#0e6470">实操</tspan> — 真控制器上手</text>
  82. <text x="1000" y="400" font-size="12.5" fill="#61788b">前三段软件,人手一份;末段上台</text>
  83. </g>
  84. </svg>'''
  85. def card(title, kind, kcls, model, state, scls, desc, href, meta):
  86. return f'''<a class="sim" href="{href}" target="_blank">
  87. <div class="sim-h"><b>{title}</b><span class="k {kcls}">{kind}</span></div>
  88. <div class="sim-meta"><span class="mm">机型 {model}</span><span class="ms {scls}">{state}</span></div>
  89. <p>{desc}</p><div class="sim-m">{meta}</div></a>'''
  90. SIMS_A = "".join([
  91. card("四系统联调 · 合页","正演","kf","4 MW 海上","参数=实机回读","s-meas",
  92. "偏航、传动链与功率、发电机与热管理、变桨轮毂液压,十七个面板在一页里联动。",
  93. f"{G}/sim/sys/0_四系统合页.html","可拖滑块 · 六项失效注入"),
  94. card("偏航系统","正演","kf","4 MW 海上","参数=实机回读","s-meas",
  95. "风向标滤波 → 对风偏差 → 死区 → 刹车泄压 → 起偏 → 停止容差 → 扭缆累积。",
  96. f"{G}/sim/sys/1_偏航系统.html","注入:静态误差 / 风向标卡死 / 驱动降速"),
  97. card("传动链与功率","正演","kf","4 MW 海上","参数=实机回读","s-meas",
  98. "转速-功率十五点表、桨距调度表、3P 共振禁带,出厂默认与本台整定双曲线同图。",
  99. f"{G}/sim/sys/2_传动链与功率.html","注入:风速仪偏低 / 偏高 / 卡死"),
  100. card("发电机与热管理","正演","kf","4 MW 海上","参数=实机回读","s-meas",
  101. "定子温度与保护裕度、冷却链、告警线,温度条实时跟随。",
  102. f"{G}/sim/sys/3_发电机与热管理.html","注入:散热劣化 / 冷却风机 / 传感器"),
  103. card("变桨与轮毂液压","正演","kf","4 MW 海上","参数=实机回读","s-meas",
  104. "变桨闭环、轮毂压力、蓄能器充放循环,分段增益逐台对比。",
  105. f"{G}/sim/sys/4_变桨轮毂液压.html","注入:润滑 / 跟踪超差 / 校准 / 棘爪"),
  106. card("整机联调台 · 4 MW","正演","kf","4 MW 全功率","控制核心层参数","s-meas",
  107. "主控、变桨、变流器三者配合的联调过程,控制核心层三百七十九项参数完整接入。",
  108. f"{L}/整机联调台_4MW.html","可调风速与转速 · 实时曲线"),
  109. card("整机联调台 · 1.5 MW","正演","kf","1.5 MW 双馈","控制核心层参数","s-meas",
  110. "另一功率代际的联调:主控、变桨、变频器,含状态码、刹车程序与降容逻辑。",
  111. f"{L}/整机联调台_1.5MW.html","可与 4 MW 对照看代际差异"),
  112. ])
  113. SIMS_B = "".join([
  114. card("变桨液压回路仿真台","正演 · 图纸级","kf","4 MW 海上","按原厂图纸搭建","s-meas",
  115. "一个油箱、变桨大站与高速轴制动两条回路、两组蓄能器。可注入失氮、外漏、泵排量下降。",
  116. f"{L}/U6_变桨液压仿真台.html","实时看派生指标与逐循环进油量"),
  117. card("传动链实际运行回放 · 38 台","回放","kr","4 MW 海上","实测 · 一个字节不造","s-meas",
  118. "三十八台机组二十四小时逐分钟真实记录,配十六台在问题窗的真实振动波形与频谱。",
  119. f"{L}/如东传动链实际运行诊断_单文件版.html","同一触发时刻 · 可播放 · 可切机组"),
  120. card("液压公共站健康报告","实测判据","kr","4 MW 海上","实测","s-meas",
  121. "系统总容变分解、两组蓄能器各自的角色、逐台健康分级。",
  122. f"{L}/U6_液压公共站健康报告_客户版.html","仿真台标定判据的产物"),
  123. card("整机综合诊断与风险评估","实测判据","kr","4 MW 海上","实测 · 双模型审","s-meas",
  124. "主轴冲击深挖修订版,逐台逐系统判级。",
  125. f"{L}/如东海上风电场_整机综合诊断与风险评估_主轴冲击深挖修订版V2.1.html","修订版"),
  126. ])
  127. SIMS_D = "".join([
  128. card("涡激共振模拟器","正演 · 教学示范","kf","十二款机型预设","⚠ 频率与阻尼=标度律外推","s-syn",
  129. "可调风速、塔高、叶轮直径、偏航角、转速,实时看塔架与叶片的固有频率、涡脱频率与共振禁带。"
  130. "涵盖塔架涡激、叶片涡激、偏航失速颤振、启动穿越禁带四种情形。"
  131. "<b>核过来源:几何参数取自公开机型库(可信),但固有频率与阻尼比是统一标度律外推、无一机型有实测模态"
  132. "——所以这台只教机理趋势,不可用它的数值下任何结论。</b>",
  133. f"{L}/涡激共振模拟器.html","几何取公开源;无逐机型实测模态 → 只看趋势不看数值"),
  134. card("涡激实测核验","实测","kr","1.5 MW 陆上 × 9 台","实测秒级","s-meas",
  135. "抗涡激动作标志一次未触发。本页回答的是:零触发到底是真没事,还是监测面根本没在工作。",
  136. f"{L}/涡激实测核验.html","每台 43200 秒 · 活通道 vs 死通道对比"),
  137. card("运行形态塌陷 · 动态三维","实测 · 可旋转","kr","4 台 × 18 月 × 15 风速档","实测 + 算法产物","s-meas",
  138. "横轴风速档、纵轴月份、高度是健康裕度。绿色曲面是正常,裕度掉到零平面以下就是形态塌陷 ——"
  139. "在图上表现为从曲面往下扎的一口井。两种算法可切换对照。"
  140. "<b>深度数值不可跨算法比(阈值一个 0.754 一个 0.034),可比的只有位置模式。</b>",
  141. f"{L}/运行形态塌陷_动态三维.html","可旋转缩放 · 四台并排 · 真实最深值如实报"),
  142. card("偏航滑移事件回放","回放","kr","单台机组","实测事件","s-meas",
  143. "制动压不住风载,机舱在无偏航指令下被推着走。可逐事件回放机舱位置与对风偏差。",
  144. f"{L}/偏航滑移事件回放.html","该台全窗四十四次 · 最深一次 42.3°"),
  145. card("变流器故障仿真","注入","ka","1.5 MW 陆上","⚠ 波形为合成","s-syn",
  146. "十千赫兹逐样本算物理量,保护判据真的跑在波形上,越限才爆码,码按事件记录格式列出。"
  147. "改一个定值滑块,爆出来的码就会变。",
  148. f"{L}/变流器故障仿真.html","八类场景 · 电网跌落 / Crowbar 拒动 / IGBT 开路 / 水冷失效"),
  149. card("变桨故障仿真","注入","ka","1.5 MW 陆上","⚠ 波形为合成","s-syn",
  150. "同一套做法用在变桨系统:参数可调、判据在波形上跑、越限爆码。",
  151. f"{L}/变桨故障仿真.html","用于训练判读与验证判据(known-answer)"),
  152. ])
  153. SIMS_C = "".join([
  154. card("整机三维拆装工作台","结构","ks","4 MW 海上","实物结构","s-meas",
  155. "五十八个部件的爆炸图:主轴与轴承、齿轮箱及附件、发电机与冷却、三套集中润滑、"
  156. "变桨泵站与阀块、偏航驱动与轴承、机架、滑环……逐件可拆可看。",
  157. f"{G}/viewer/unit-workbench.html","可旋转 · 可拆解 · 逐件说明"),
  158. card("故障分布三维视图","实测","kr","多台 × 九系统","实测事件统计","s-meas",
  159. "机组 × 系统 × 月份三个维度一起看,气泡大小为停机时长。可旋转、可缩放、可按系统筛。",
  160. f"{L}/故障分布三维视图.html","离线可用(图形库已本地化)"),
  161. card("振动诊断 · CMS","实测","kr","4 MW 海上","实测","s-meas",
  162. "频谱、包络、特征频率与告警分级,逐台逐测点。",
  163. f"{G}/cms/?theme=light","客户版界面"),
  164. card("综合详细分析工作台","实测","kr","4 MW 海上","实测","s-meas",
  165. "全场逐台逐系统的分析结果与证据链。",
  166. f"{G}/detail/v2","在线系统"),
  167. ])
  168. HTML = f'''<!doctype html><html lang="zh-CN"><head><meta charset="utf-8">
  169. <title>风电机组仿真集成台</title>
  170. <style>
  171. :root{{--bg:#edf7f9;--panel:#fff;--ink:#133047;--ink2:#28536b;--ink3:#61788b;
  172. --line:#cbe2eb;--line2:#e1eef3;--spec:#0e8898;--specf:#dff4f4;--meas:#2077a8;--measf:#e5f2fa;
  173. --ok:#23875b;--warn:#d48818;--bad:#d94b43;
  174. --sans:"PingFang SC","Hiragino Sans GB","Microsoft YaHei",ui-sans-serif,system-ui,sans-serif;
  175. --mono:"SF Mono",Menlo,Consolas,monospace}}
  176. *{{box-sizing:border-box;margin:0}}
  177. body{{background:var(--bg);color:var(--ink);font:14.5px/1.7 var(--sans);-webkit-font-smoothing:antialiased}}
  178. a{{color:var(--spec);text-decoration:none}}
  179. .wrap{{max-width:1360px;margin:0 auto;padding:0 32px}}
  180. .top{{background:linear-gradient(110deg,#10384d,#0e6470);color:#fff;padding:14px 0}}
  181. .top .wrap{{display:flex;align-items:center;gap:16px}}
  182. .logo{{width:34px;height:34px;border-radius:9px;background:rgba(255,255,255,.16);display:grid;place-items:center;font-weight:700;font-size:16px}}
  183. .top b{{font-size:15px;letter-spacing:.03em}} .top small{{display:block;font:11px var(--mono);opacity:.72;letter-spacing:.12em}}
  184. .top .r{{margin-left:auto;font:12px var(--mono);opacity:.85}}
  185. .hero{{padding:52px 0 40px;border-bottom:1px solid var(--line)}}
  186. .kick{{font:12px var(--mono);letter-spacing:.16em;color:var(--spec);text-transform:uppercase}}
  187. h1{{font-size:40px;line-height:1.16;font-weight:600;margin:16px 0 14px;letter-spacing:-.01em}}
  188. .lead{{color:var(--ink2);font-size:17px;max-width:760px;text-wrap:pretty}}
  189. section{{padding:40px 0;border-bottom:1px solid var(--line)}}
  190. h2{{font-size:25px;font-weight:600;margin:12px 0 8px}}
  191. .sub{{color:var(--ink3);margin-bottom:24px;max-width:820px}}
  192. .grid{{display:grid;gap:16px}} .g3{{grid-template-columns:repeat(3,minmax(0,1fr))}}
  193. .g2{{grid-template-columns:repeat(2,minmax(0,1fr))}} .g4{{grid-template-columns:repeat(4,minmax(0,1fr))}}
  194. .sim{{display:flex;flex-direction:column;gap:9px;background:var(--panel);border:1px solid var(--line);
  195. border-radius:12px;padding:18px 20px;color:inherit;transition:.16s;box-shadow:0 1px 3px rgba(19,48,71,.05)}}
  196. .sim.nolink{{cursor:default}}
  197. .sim:not(.nolink):hover{{border-color:var(--spec);box-shadow:0 6px 20px rgba(14,136,152,.14);transform:translateY(-2px)}}
  198. .sim-h{{display:flex;align-items:baseline;gap:10px}} .sim-h b{{font-size:15.5px;flex:1 1 auto}}
  199. .sim p{{color:var(--ink2);font-size:13.4px;line-height:1.7}}
  200. .sim-meta{{display:flex;align-items:center;gap:8px;flex-wrap:wrap}}
  201. .mm{{font:11.5px var(--mono);color:var(--ink2);background:#f2fafc;border:1px solid var(--line);border-radius:6px;padding:2px 8px}}
  202. .ms{{font:11.5px var(--mono);border-radius:6px;padding:2px 8px}}
  203. .s-meas{{background:#e6f6ec;color:#1c6e4a;border:1px solid #b6dfc7}}
  204. .s-model{{background:#eef1f6;color:#4a5f75;border:1px solid #cdd8e4}}
  205. .s-syn{{background:#fdf1de;color:#9a6210;border:1px solid #eccb96}}
  206. .sim-m{{margin-top:auto;padding-top:8px;border-top:1px solid var(--line2);font:11.5px var(--mono);color:var(--ink3)}}
  207. .k{{font:11px var(--mono);padding:3px 9px;border-radius:99px;white-space:nowrap}}
  208. .kf{{background:var(--specf);color:var(--spec);border:1px solid #a9dfe4}}
  209. .kr{{background:var(--measf);color:var(--meas);border:1px solid #b3d8ee}}
  210. .ks{{background:#eef1f6;color:#4a5f75;border:1px solid #cdd8e4}}
  211. .ka{{background:#fdf1de;color:#9a6210;border:1px solid #eccb96}}
  212. .card{{background:var(--panel);border:1px solid var(--line);border-radius:12px;padding:20px 22px;box-shadow:0 1px 3px rgba(19,48,71,.05)}}
  213. .card .k2{{font:11px var(--mono);letter-spacing:.12em;color:var(--spec);text-transform:uppercase;margin-bottom:8px}}
  214. .card h3{{font-size:16.5px;font-weight:600;margin-bottom:8px}}
  215. .card p{{color:var(--ink2);font-size:13.6px}}
  216. .num{{font:600 33px/1.1 var(--mono);color:var(--ink)}}
  217. .num span{{font-size:13px;color:var(--ink3);font-weight:400;margin-left:5px}}
  218. figure{{margin:0}} figure img,figure video{{width:100%;display:block;border:1px solid var(--line);border-radius:12px;background:#fff}}
  219. figcaption{{color:var(--ink3);font-size:12.5px;margin-top:10px}}
  220. .note{{border-left:3px solid var(--spec);background:var(--specf);border-radius:0 10px 10px 0;padding:15px 18px;color:var(--ink2);font-size:14px}}
  221. .chap{{display:grid;grid-template-columns:56px 1fr;gap:16px;align-items:start;padding:15px 0;border-bottom:1px solid var(--line2)}}
  222. .chap:last-child{{border-bottom:0}}
  223. .chap .n{{font:600 13px var(--mono);color:var(--spec);background:var(--specf);border:1px solid #a9dfe4;border-radius:8px;padding:6px 0;text-align:center}}
  224. .chap b{{font-size:15.5px}} .chap p{{color:var(--ink2);font-size:13.5px;margin-top:3px}}
  225. .foot{{color:var(--ink3);font:11.5px var(--mono);padding:22px 0 40px}}
  226. @media(max-width:1000px){{.g3,.g4{{grid-template-columns:1fr 1fr}} .g2{{grid-template-columns:1fr}} h1{{font-size:30px}}}}
  227. </style></head><body>
  228. <div class="top"><div class="wrap">
  229. <div class="logo">观</div>
  230. <div><b>观澜 · 风电机组仿真集成台</b><small>GUANLAN SIMULATION HUB</small></div>
  231. <div class="r">离线运行 · 无需网络</div>
  232. </div></div>
  233. <div class="hero"><div class="wrap">
  234. <div class="kick">一个入口,全部仿真</div>
  235. <h1>从图纸到回路,从信号到工单</h1>
  236. <p class="lead">二十一个仿真台、回放台与结构台集中在这一页。每一个都标了它的数从哪来 ——
  237. <b>算出来的</b>(按参数与图纸正演)、<b>测出来的</b>(真实运行记录回放)、还是<b>结构</b>。
  238. 这条分界是所有诊断的第一课。</p>
  239. </div></div>
  240. <section><div class="wrap">
  241. <div class="kick">01 · 整体架构</div>
  242. <h2>两个模块,可分可合,看预算</h2>
  243. <p class="sub"><b>数字仿真</b>回答「现场实际发生了什么」,<b>半实物</b>回答「控制器本来该怎么响应」。
  244. 两个模块<b>各自都能单独成立</b>:只买数字,七篇课里六篇照上;只买半实物,能做控制器测试但培训内容基本是空的。
  245. 组合起来才多出第三个问题的答案——<b>现场的样子和设计的样子,差在哪</b>。这是唯一值得为组合多付钱的理由。</p>
  246. <div class="note" style="margin-bottom:18px">⚠ 组合形态的那条接缝(实测时序 → 测试序列 → 真控制器复现)
  247. <b>至今一次都没跑通过</b>。它是本方案技术风险最高的一环,不应当作既成能力。只买数字模块则不承担此风险。</div>
  248. {ARCH_SVG}
  249. </div></section>
  250. <section><div class="wrap">
  251. <div class="kick">02 · 整体价值</div>
  252. <h2>它把三件看不见的事变成看得见的</h2>
  253. <div class="grid g3" style="margin-top:22px">
  254. <div class="card"><div class="k2">价值一</div><h3>故障在信号上长什么样</h3>
  255. <p>现场三年遇不到的故障,这里可以反复注入观察。蓄能器丢气、外漏、泵磨损 —— 三者签名方向各不相同,
  256. 所以能分得开。<b>已有六项注入全部对应真实告警码</b>,不是编的动画。</p></div>
  257. <div class="card"><div class="k2">价值二</div><h3>手册和真机的差距</h3>
  258. <p>整机参数回读之后才发现,这台机器有二十四项现场整定值和出厂默认不一样,
  259. 其中转速-功率曲线九个点全被改过。<b>手册上那条曲线,它并没有在跑。</b>
  260. 两条曲线同图一画,这件事一屏说完。</p></div>
  261. <div class="card"><div class="k2">价值三</div><h3>判据到底准不准</h3>
  262. <p>判据不是写完就算数。先把已知答案的故障注进真实数据,看它判不判得出、会不会误报 ——
  263. <b>一百六十四个场景考过,才准上机器。</b>这一步别人通常跳过,我们不跳。</p></div>
  264. </div>
  265. <div class="note" style="margin-top:20px">还有一层价值是结构性的:<b>同一套口径能罩住不同厂商、不同功率代际的机器。</b>
  266. 一个场里跑着三家整机厂的机组,没有统一尺子就没法横比、没法排优先级 —— 这正是我们地基那层在解决的问题。</div>
  267. </div></section>
  268. <section><div class="wrap">
  269. <div class="kick">03 · 我们能做什么 · 控制律</div>
  270. <h2>机器是怎么被控制的</h2>
  271. <p class="sub">参数来自整机控制器实机回读。图上同时画出厂默认曲线与本台现场整定曲线,低转速段肉眼可见地分开。</p>
  272. <div class="grid g3">{SIMS_A}</div>
  273. </div></section>
  274. <section><div class="wrap">
  275. <div class="kick">03 · 我们能做什么 · 回路与回放</div>
  276. <h2>按图纸搭回路,用实测验判据</h2>
  277. <p class="sub">判据不是从数据里拟合出来的,是先在物理上算出来、再用整场实测反过来验证的。</p>
  278. <div class="grid g2">{SIMS_B}</div>
  279. </div></section>
  280. <section><div class="wrap">
  281. <div class="kick">03 · 我们能做什么 · 痛点专项</div>
  282. <h2>涡激、偏航滑移、故障爆码,各有各的台子</h2>
  283. <p class="sub">机理归机理、实测归实测、合成归合成 —— 每张卡片都标了机型和数据状态,一眼能分清。</p>
  284. <div class="grid3">{SIMS_D}</div>
  285. </div></section>
  286. <section><div class="wrap">
  287. <div class="kick">03 · 我们能做什么 · 结构与在线</div>
  288. <h2>拆得开,也看得见现在</h2>
  289. <div class="grid g3">{SIMS_C}</div>
  290. </div></section>
  291. <section><div class="wrap">
  292. <div class="kick">03 · 我们能做什么 · 场级</div>
  293. <h2>整个风场一起看</h2>
  294. <p class="sub">单台之外还有场级:机位之间互相遮挡。下面用的是一个真实山地风场的九十台实际机位,
  295. 风向分布来自该场一百二十一万条实测十分钟记录。<b>坐标已做刚性变换脱敏</b> —— 相对几何不变,所以尾流物理为真。</p>
  296. <figure style="margin-bottom:22px">
  297. <img src="data:image/png;base64,{PNG}" alt="真实山地风场尾流图">
  298. <figcaption>主导风向 165°(占全年 33.5%)下的尾流场。标注为该风向下受尾流最深的三台。
  299. 边界:平坦地形假设、推力曲线为通用示意值 → 只看相对形态与排序,不报绝对损失。引擎 PyWake(丹麦技术大学)。</figcaption>
  300. </figure>
  301. <figure>
  302. <video src="data:video/mp4;base64,{MP4}" controls autoplay loop muted playsinline></video>
  303. <figcaption>动态:风向从 90° 扫到 270°(覆盖约九成的时间),看尾流在整个场里横扫。右下风玫瑰为实测分布。</figcaption>
  304. </figure>
  305. </div></section>
  306. <section><div class="wrap">
  307. <div class="kick">03 · 我们能做什么 · 行业痛点</div>
  308. <h2>三个「看着没事、后果很重」的问题</h2>
  309. <p class="sub">共同点是:站在塔下看不出来,在常规报表上也不显眼,但都实打实吃电量、吃寿命,甚至吃安全。
  310. 下面每一张都标了哪部分是实测、哪部分是模型、哪部分引文献。</p>
  311. <figure style="margin-bottom:26px">
  312. <img src="data:image/png;base64,{VIV}" alt="涡激振荡">
  313. <figcaption><b>涡激振荡</b> —— 风吹过塔筒周期性脱落旋涡,脱落频率撞上塔筒固有频率就进入锁频,振动自己放大自己。
  314. 两个反直觉之处:临界风速落在很常见的风速段,不是极端天气;最危险的是吊装期和不带叶片的停机,因为叶轮转动提供的气动阻尼没了。
  315. <b>本图为工程经验模型(涡脱频率 + 锁频带 + Scruton 数),非 CFD、非气弹耦合,参数为通用示意值。</b></figcaption>
  316. </figure>
  317. <figure style="margin-bottom:26px">
  318. <img src="data:image/png;base64,{YAWS}" alt="偏航滑移">
  319. <figcaption><b>偏航滑移</b> —— 制动力矩压不住风载力矩,机舱在没有任何偏航指令的情况下被风推着走。
  320. 上排是五十台机组的实测事件:一半机组一次没滑,问题集中在少数台,最深一次滑了四十二度,而且逐月分布有明显断点。
  321. 下排是三种在信号上长得很像的现象,判滑移必须四门同时成立,缺一就会误判。
  322. <b>上排为实测统计(台号已重编);下排为合成教学信号。</b></figcaption>
  323. </figure>
  324. <figure>
  325. <img src="data:image/png;base64,{PITCH}" alt="变桨角度不一致">
  326. <figcaption><b>变桨角度不一致</b> —— 三个叶片桨距不一致,气动推力不再三重对称,合力矩多出一个每转一圈来一次的分量,
  327. 直接打在轮毂、主轴和塔架上。中间那张是真实机群的塔筒 1P 筛查:四十二台里只挑出两台,这正是机群相对筛查该有的样子。
  328. <b>机理为正演(相对量);筛查为实测;电量与寿命后果因运行数据无载荷通道,全部引文献,本模型不自算。</b></figcaption>
  329. </figure>
  330. </div></section>
  331. <section><div class="wrap">
  332. <div class="kick">04 · 培训编排</div>
  333. <h2>一台机器,一条链走完</h2>
  334. <p class="sub">前置一篇加正课六篇。每一篇的落点是"学员能自己做什么",不是"我们讲了什么"。</p>
  335. <div class="card">
  336. <div class="chap"><div class="n">前置</div><div><b>这些东西各能信到什么程度</b>
  337. <p>放最前面,不是放附录。三个标签贯穿全程:数从哪来、保真到哪一档、结论能用到什么级别。</p></div></div>
  338. <div class="chap"><div class="n">一</div><div><b>认识这台机器</b>
  339. <p>五十八个部件的爆炸图,再叠一层传动链运动学 —— 风轮转一圈,齿轮箱那头转一百一十九圈多。</p></div></div>
  340. <div class="chap"><div class="n">二</div><div><b>它是怎么被控制的</b>
  341. <p>转矩控制怎么追最优叶尖速比、变桨怎么在额定以上稳功率、偏航死区滞环怎么定。</p></div></div>
  342. <div class="chap"><div class="n">三</div><div><b>真实世界里它长什么样</b>
  343. <p>整场逐台回放,配真实振动波形与频谱。教一条最容易踩的口径:同步派生转矩不是扭矩传感器实测。</p></div></div>
  344. <div class="chap"><div class="n">四</div><div><b>它会怎么坏 —— 核心</b>
  345. <p>现场罕见的故障,这里可以反复注入观察。已有六项注入全部对应真实告警码;新增涡激振荡与偏航滑移两个专题。</p></div></div>
  346. <div class="chap"><div class="n">五</div><div><b>怎么判、怎么修、怎么验</b>
  347. <p>判据 → 定向清单加排除清单 → 工单 → 改后同工况复核。排除清单不占改造预算。</p></div></div>
  348. <div class="chap"><div class="n">六</div><div><b>换一台机器怎么办</b>
  349. <p>换一家整机厂、换一个功率代际,这套判据与流程怎么搬过去。</p></div></div>
  350. </div>
  351. </div></section>
  352. <section style="border-bottom:0"><div class="wrap">
  353. <div class="grid g4" style="margin-bottom:22px">
  354. <div class="card"><div class="k2">部件域判据</div><div class="num">10<span>个</span></div>
  355. <p style="margin-top:4px">变桨 · 静态偏航 · 动态偏航 · 部件温度 · 振动频谱 · 液压站 · 限电识别 · 功率曲线 · 欠发归因 · 特性曲线</p></div>
  356. <div class="card"><div class="k2">场级字段契约</div><div class="num">71<span>份</span></div>
  357. <p style="margin-top:4px">每份是一个风场的字段语义定稿,覆盖十九家可辨识整机厂</p></div>
  358. <div class="card"><div class="k2">原厂控制器包</div><div class="num">8<span>套</span></div>
  359. <p style="margin-top:4px">拆到程序、码表、定值一级</p></div>
  360. <div class="card"><div class="k2">判据靶场场景</div><div class="num">164<span>个</span></div>
  361. <p style="margin-top:4px">已知答案的注入与回放场景,判据先在这里考过才准上机</p></div>
  362. </div>
  363. <div class="note">判据先在一百六十四个已知答案上考过,才准上你们的机器。
  364. <b>工具库才是壁垒</b> —— 模型只是调度器。</div>
  365. </div></section>
  366. <div class="wrap foot">观澜 · 风电机组仿真集成台 · 离线单文件 · 本页内所有链接指向本机服务与本地文件</div>
  367. </body></html>'''
  368. _OUT = pathlib.Path(__file__).resolve().parents[2] / "outputs/rudong/windscada/_demo/sim"
  369. pathlib.Path(_OUT/"仿真集成台.html").write_text(HTML, encoding="utf-8")
  370. print("written 仿真集成台.html")