独立渲染引擎就绪引擎就绪
<!DOCTYPE html>
<html lang="zh-CN">
<head>
<meta charset="UTF-8">
<meta name="viewport" content="width=device-width, initial-scale=1.0">
<title>边缘AI智能工况自适应控制系统 - IFR演示</title>
<style>
:root {
--bg-color: #030712;
--panel-bg: rgba(17, 24, 39, 0.7);
--border-color: rgba(55, 65, 81, 0.5);
--text-main: #E5E7EB;
--text-muted: #9CA3AF;
--accent-cyan: #00F0FF;
--accent-amber: #FFB000;
--accent-green: #00FF66;
--font-ui: 'SF Pro Display', -apple-system, BlinkMacSystemFont, 'Segoe UI', Roboto, Helvetica, Arial, sans-serif;
--font-mono: 'JetBrains Mono', 'Courier New', monospace;
}
body, html {
margin: 0;
padding: 0;
width: 100vw;
height: 100vh;
background-color: var(--bg-color);
background-image:
radial-gradient(circle at 50% 50%, rgba(0, 240, 255, 0.05) 0%, transparent 60%),
linear-gradient(rgba(255, 255, 255, 0.02) 1px, transparent 1px),
linear-gradient(90deg, rgba(255, 255, 255, 0.02) 1px, transparent 1px);
background-size: 100% 100%, 40px 40px, 40px 40px;
overflow: hidden;
font-family: var(--font-ui);
color: var(--text-main);
display: flex;
justify-content: center;
align-items: center;
}
/* 绝对定位的角标文字,严格控制空间占比 */
.overlay-ui {
position: absolute;
z-index: 10;
pointer-events: none;
font-size: 12px;
letter-spacing: 0.5px;
}
.top-left { top: 20px; left: 24px; }
.top-right { top: 20px; right: 24px; text-align: right; }
.bottom-left { bottom: 20px; left: 24px; }
.bottom-right { bottom: 20px; right: 24px; text-align: right; }
.ui-panel {
background: var(--panel-bg);
backdrop-filter: blur(8px);
border: 1px solid var(--border-color);
border-radius: 6px;
padding: 12px 16px;
box-shadow: 0 4px 20px rgba(0,0,0,0.5);
}
.title {
font-size: 14px;
font-weight: 600;
color: var(--accent-cyan);
margin-bottom: 4px;
text-transform: uppercase;
letter-spacing: 1px;
}
.subtitle {
color: var(--text-muted);
font-size: 11px;
}
.status-indicator {
display: flex;
align-items: center;
gap: 6px;
margin-top: 8px;
font-family: var(--font-mono);
}
.dot {
width: 6px;
height: 6px;
border-radius: 50%;
background: var(--accent-green);
box-shadow: 0 0 8px var(--accent-green);
animation: pulse 2s infinite;
}
.data-row {
display: flex;
justify-content: space-between;
gap: 16px;
margin-top: 4px;
font-family: var(--font-mono);
color: var(--accent-amber);
}
/* 核心动画容器 */
#animation-container {
width: 100%;
height: 100%;
max-width: 1200px;
max-height: 800px;
position: relative;
}
svg {
width: 100%;
height: 100%;
display: block;
}
/* SVG 样式与动画 */
.path-line {
fill: none;
stroke: var(--border-color);
stroke-width: 2;
}
.path-flow {
fill: none;
stroke: var(--accent-cyan);
stroke-width: 2;
stroke-dasharray: 8 12;
opacity: 0.3;
animation: flowDash 30s linear infinite;
}
.data-particle {
fill: var(--accent-cyan);
filter: drop-shadow(0 0 5px var(--accent-cyan));
}
.cmd-particle {
fill: var(--accent-amber);
filter: drop-shadow(0 0 5px var(--accent-amber));
}
.node-bg {
fill: rgba(17, 24, 39, 0.8);
stroke: rgba(55, 65, 81, 1);
stroke-width: 1.5;
}
.text-svg {
font-family: var(--font-ui);
font-size: 12px;
fill: var(--text-muted);
text-anchor: middle;
user-select: none;
}
.text-svg-value {
font-family: var(--font-mono);
font-size: 14px;
fill: var(--text-main);
text-anchor: middle;
font-weight: bold;
}
.ai-core-hex {
fill: rgba(0, 240, 255, 0.05);
stroke: var(--accent-cyan);
stroke-width: 2;
transition: all 0.3s ease;
}
.ai-core-glow {
fill: none;
stroke: var(--accent-cyan);
stroke-width: 1;
opacity: 0;
transition: opacity 0.3s;
}
.optimizing .ai-core-hex {
fill: rgba(0, 240, 255, 0.2);
filter: drop-shadow(0 0 20px rgba(0, 240, 255, 0.6));
}
.optimizing .ai-core-glow {
opacity: 1;
animation: pulse-ring 1s cubic-bezier(0.215, 0.61, 0.355, 1) infinite;
}
.bar-bg { fill: rgba(255,255,255,0.05); rx: 2; }
.bar-fill { fill: var(--accent-cyan); rx: 2; transition: height 0.5s ease, y 0.5s ease; }
.actuator-part {
fill: rgba(255, 176, 0, 0.1);
stroke: var(--accent-amber);
stroke-width: 1.5;
transition: transform 1.5s cubic-bezier(0.4, 0, 0.2, 1);
}
@keyframes flowDash {
to { stroke-dashoffset: -1000; }
}
@keyframes pulse {
0%, 100% { opacity: 1; }
50% { opacity: 0.4; }
}
@keyframes pulse-ring {
0% { transform: scale(0.95); stroke-width: 2; opacity: 1; }
100% { transform: scale(1.3); stroke-width: 0; opacity: 0; }
}
</style>
</head>
<body>
<!-- 左上角:标题与状态 -->
<div class="overlay-ui top-left ui-panel">
<div class="title">理想最终解 (IFR) 演示</div>
<div class="subtitle">基于历史数据的参数自适应优化</div>
<div class="status-indicator">
<div class="dot"></div>
<span>边缘 AI 在线监听中</span>
</div>
</div>
<!-- 右上角:约束条件 -->
<div class="overlay-ui top-right ui-panel">
<div class="subtitle" style="color:var(--text-main)">系统约束指标</div>
<div class="data-row">
<span>优化周期:</span>
<span>30 min (加速展示)</span>
</div>
<div class="data-row">
<span>执行器动作限制:</span>
<span>≤ 6次 / 班</span>
</div>
<div class="data-row">
<span>当前班次动作:</span>
<span id="ui-action-count" style="color:var(--accent-green)">2 / 6</span>
</div>
</div>
<!-- 左下角:原理说明 -->
<div class="overlay-ui bottom-left ui-panel" style="max-width: 240px;">
<div class="subtitle">资源利用与机理</div>
<div style="color: var(--text-muted); margin-top: 4px; line-height: 1.4;">
利用现有传感器数据,通过离线贝叶斯优化建立模型,在线下发参数至 PLC。消除人工经验偏差,在极少动作下实现防跑浆。
</div>
</div>
<!-- 中央核心动画区域 -->
<div id="animation-container">
<svg viewBox="0 0 1000 600" preserveAspectRatio="xMidYMid meet">
<defs>
<!-- 滤镜与渐变 -->
<filter id="glow-cyan" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="5" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<filter id="glow-amber" x="-20%" y="-20%" width="140%" height="140%">
<feGaussianBlur stdDeviation="5" result="blur" />
<feComposite in="SourceGraphic" in2="blur" operator="over" />
</filter>
<linearGradient id="grad-bar" x1="0" y1="1" x2="0" y2="0">
<stop offset="0%" stop-color="#0055ff"/>
<stop offset="100%" stop-color="#00F0FF"/>
</linearGradient>
</defs>
<!-- 连线路径 (底层) -->
<g id="connections">
<!-- 传感器到AI -->
<path id="path-s1-ai" class="path-line" d="M 250 150 C 350 150, 400 300, 470 300" />
<path id="path-s2-ai" class="path-line" d="M 250 300 C 350 300, 350 300, 470 300" />
<path id="path-s3-ai" class="path-line" d="M 250 450 C 350 450, 400 300, 470 300" />
<path class="path-flow" d="M 250 150 C 350 150, 400 300, 470 300" />
<path class="path-flow" d="M 250 300 C 350 300, 350 300, 470 300" />
<path class="path-flow" d="M 250 450 C 350 450, 400 300, 470 300" />
<!-- AI到执行器 (PLC接口) -->
<path id="path-ai-a1" class="path-line" d="M 530 300 C 600 300, 650 200, 750 200" />
<path id="path-ai-a2" class="path-line" d="M 530 300 C 600 300, 650 400, 750 400" />
</g>
<!-- 动态粒子容器 -->
<g id="particles-layer"></g>
<!-- 左侧:实时工况传感器 -->
<g id="sensors" transform="translate(100, 0)">
<!-- 密度 -->
<g transform="translate(0, 120)">
<rect x="0" y="0" width="150" height="60" class="node-bg" rx="4"/>
<text x="75" y="22" class="text-svg">泥浆密度 (g/cm³)</text>
<text x="75" y="45" class="text-svg-value" id="val-density" fill="#00F0FF">1.24</text>
<!-- 动态波形条 -->
<rect x="15" y="52" width="120" height="2" fill="rgba(255,255,255,0.1)"/>
<rect id="bar-density" x="15" y="52" width="60" height="2" fill="var(--accent-cyan)"/>
</g>
<!-- 排量 -->
<g transform="translate(0, 270)">
<rect x="0" y="0" width="150" height="60" class="node-bg" rx="4"/>
<text x="75" y="22" class="text-svg">排量 (L/s)</text>
<text x="75" y="45" class="text-svg-value" id="val-flow" fill="#00F0FF">45.2</text>
<rect x="15" y="52" width="120" height="2" fill="rgba(255,255,255,0.1)"/>
<rect id="bar-flow" x="15" y="52" width="80" height="2" fill="var(--accent-cyan)"/>
</g>
<!-- 振动 -->
<g transform="translate(0, 420)">
<rect x="0" y="0" width="150" height="60" class="node-bg" rx="4"/>
<text x="75" y="22" class="text-svg">振动速度 (mm/s)</text>
<text x="75" y="45" class="text-svg-value" id="val-vib" fill="#00F0FF">6.8</text>
<rect x="15" y="52" width="120" height="2" fill="rgba(255,255,255,0.1)"/>
<rect id="bar-vib" x="15" y="52" width="40" height="2" fill="var(--accent-cyan)"/>
</g>
<!-- 装饰性虚线框 -->
<rect x="-15" y="90" width="180" height="420" fill="none" stroke="rgba(255,255,255,0.05)" stroke-dasharray="4 4" rx="8"/>
<text x="75" y="105" class="text-svg" style="font-size: 10px;">实时工况感知层</text>
</g>
<!-- 中央:边缘AI优化器 -->
<g id="ai-module" transform="translate(500, 300)">
<!-- 装饰环 -->
<circle cx="0" cy="0" r="70" fill="none" stroke="rgba(255,255,255,0.05)" stroke-width="1" />
<circle cx="0" cy="0" r="85" fill="none" stroke="rgba(255,255,255,0.02)" stroke-width="20" />
<!-- 发光动效外环 -->
<polygon points="0,-60 52,-30 52,30 0,60 -52,30 -52,-30" class="ai-core-glow" />
<!-- 核心六边形 -->
<polygon points="0,-50 43,-25 43,25 0,50 -43,25 -43,-25" class="ai-core-hex" />
<!-- 内部元素 -->
<circle cx="0" cy="0" r="20" fill="rgba(0, 240, 255, 0.1)" stroke="var(--accent-cyan)" stroke-width="1"/>
<path d="M -10 -5 L 10 0 L -10 5 Z" fill="var(--accent-cyan)" opacity="0.8">
<animateTransform attributeName="transform" type="rotate" from="0" to="360" dur="4s" repeatCount="indefinite"/>
</path>
<text x="0" y="-80" class="text-svg" style="fill: var(--accent-cyan); font-weight: bold;">边缘 AI 优化核心</text>
<text x="0" y="85" class="text-svg" style="font-size:10px;">多目标遗传算法寻优</text>
<!-- 优化状态提示 -->
<g id="opt-status" opacity="0" transform="translate(0, -20)">
<rect x="-40" y="-12" width="80" height="24" rx="12" fill="var(--accent-green)" />
<text x="0" y="4" class="text-svg" style="fill: #000; font-weight: bold; font-size: 11px;">参数更新</text>
</g>
</g>
<!-- 右侧:物理执行器 (PLC控制) -->
<g id="actuators" transform="translate(750, 0)">
<rect x="-20" y="120" width="180" height="340" fill="none" stroke="rgba(255,176,0,0.15)" stroke-dasharray="4 4" rx="8"/>
<text x="70" y="140" class="text-svg" style="fill: var(--accent-amber); font-size: 10px;">PLC 控制执行层</text>
<!-- 堰板抬升机构 -->
<g transform="translate(0, 170)">
<rect x="0" y="0" width="140" height="80" class="node-bg" rx="4"/>
<text x="70" y="20" class="text-svg">最佳堰板高度 (mm)</text>
<text x="70" y="40" class="text-svg-value" id="val-weir" fill="#FFB000">120</text>
<!-- 机械结构示意 -->
<g transform="translate(70, 70)">
<rect x="-30" y="-15" width="60" height="4" fill="rgba(255,255,255,0.2)"/>
<!-- 动态抬升的堰板 -->
<g id="mech-weir" class="actuator-part">
<rect x="-20" y="-15" width="40" height="6" rx="2" />
<path d="M 0 -15 L 0 -25" stroke="var(--accent-amber)" stroke-width="2"/>
</g>
</g>
</g>
<!-- 放液阀门机构 -->
<g transform="translate(0, 360)">
<rect x="0" y="0" width="140" height="80" class="node-bg" rx="4"/>
<text x="70" y="20" class="text-svg">放液开度匹配 (%)</text>
<text x="70" y="40" class="text-svg-value" id="val-valve" fill="#FFB000">45</text>
<!-- 阀门开度示意 -->
<g transform="translate(70, 65)">
<circle cx="0" cy="0" r="15" fill="none" stroke="rgba(255,255,255,0.2)" stroke-width="3"/>
<!-- 动态旋转的阀门 -->
<g id="mech-valve" class="actuator-part">
<line x1="-12" y1="0" x2="12" y2="0" stroke="var(--accent-amber)" stroke-width="4" stroke-linecap="round"/>
</g>
</g>
</g>
</g>
</svg>
</div>
<script>
document.addEventListener("DOMContentLoaded", () => {
// 系统状态变量
const state = {
density: 1.20,
flow: 40.0,
vib: 5.0,
weirHeight: 100, // 初始高度
valveOpen: 30, // 初始开度
actionCount: 2,
maxActions: 6
};
// DOM 元素引用
const els = {
dVal: document.getElementById('val-density'),
fVal: document.getElementById('val-flow'),
vVal: document.getElementById('val-vib'),
dBar: document.getElementById('bar-density'),
fBar: document.getElementById('bar-flow'),
vBar: document.getElementById('bar-vib'),
aiModule: document.getElementById('ai-module'),
optStatus: document.getElementById('opt-status'),
weirVal: document.getElementById('val-weir'),
valveVal: document.getElementById('val-valve'),
mechWeir: document.getElementById('mech-weir'),
mechValve: document.getElementById('mech-valve'),
particles: document.getElementById('particles-layer'),
actionCountUi: document.getElementById('ui-action-count')
};
// SVG 路径长度用于动画
const paths = {
s1: document.getElementById('path-s1-ai'),
s2: document.getElementById('path-s2-ai'),
s3: document.getElementById('path-s3-ai'),
a1: document.getElementById('path-ai-a1'),
a2: document.getElementById('path-ai-a2')
};
// 缓动函数
const lerp = (start, end, amt) => (1 - amt) * start + amt * end;
// 1. 模拟传感器实时数据波动 (每100ms微调)
function updateSensors() {
// 加入随机游走
state.density = Math.max(1.0, Math.min(1.8, state.density + (Math.random() - 0.5) * 0.05));
state.flow = Math.max(20, Math.min(80, state.flow + (Math.random() - 0.5) * 2));
state.vib = Math.max(1, Math.min(15, state.vib + (Math.random() - 0.5) * 0.5));
// 更新UI数值
els.dVal.textContent = state.density.toFixed(2);
els.fVal.textContent = state.flow.toFixed(1);
els.vVal.textContent = state.vib.toFixed(1);
// 更新条形图宽度映射
els.dBar.setAttribute('width', ((state.density - 1) / 0.8) * 120);
els.fBar.setAttribute('width', (state.flow / 80) * 120);
els.vBar.setAttribute('width', (state.vib / 15) * 120);
}
setInterval(updateSensors, 200);
// 2. 数据流粒子系统
function createParticle(pathNode, isCommand = false) {
const circle = document.createElementNS("http://www.w3.org/2000/svg", "circle");
circle.setAttribute("r", isCommand ? "4" : "3");
circle.setAttribute("class", isCommand ? "cmd-particle" : "data-particle");
els.particles.appendChild(circle);
const length = pathNode.getTotalLength();
let start = null;
const duration = isCommand ? 1000 : 1500; // 命令下发更快
function animate(timestamp) {
if (!start) start = timestamp;
const progress = (timestamp - start) / duration;
if (progress < 1) {
const pt = pathNode.getPointAtLength(progress * length);
circle.setAttribute("cx", pt.x);
circle.setAttribute("cy", pt.y);
// 添加拖尾透明度效果
circle.setAttribute("opacity", 1 - Math.pow(progress, 3));
requestAnimationFrame(animate);
} else {
circle.remove();
}
}
requestAnimationFrame(animate);
}
// 持续生成传感器到AI的数据流
setInterval(() => {
createParticle(paths.s1);
createParticle(paths.s2);
createParticle(paths.s3);
}, 800);
// 3. 核心优化周期 (模拟30min触发一次,动画中设为8秒)
function triggerOptimization() {
// A. AI 处理动效
els.aiModule.classList.add('optimizing');
// 状态文本浮现
els.optStatus.style.transition = "opacity 0.3s, transform 0.5s ease-out";
els.optStatus.setAttribute("opacity", "1");
els.optStatus.setAttribute("transform", "translate(0, -40)");
// B. 计算理想解 (简化的规则,代表复杂的遗传算法结果)
// 密度高,排量大 -> 需要更高堰板和更小开度防跑浆
let targetWeir = 100 + (state.density - 1.2) * 100 + (state.flow - 40) * 0.5;
let targetValve = 30 - (state.density - 1.2) * 50 + (state.flow - 40) * 0.2;
// 限制物理边界
targetWeir = Math.max(50, Math.min(250, targetWeir));
targetValve = Math.max(10, Math.min(90, targetValve));
// 检查是否需要动作 (为了满足≤6次的约束,只有差异大于阈值才动作)
const weirDiff = Math.abs(targetWeir - state.weirHeight);
const valveDiff = Math.abs(targetValve - state.valveOpen);
setTimeout(() => {
els.aiModule.classList.remove('optimizing');
els.optStatus.setAttribute("opacity", "0");
els.optStatus.setAttribute("transform", "translate(0, -20)");
if (weirDiff > 10 || valveDiff > 5) {
// 发送控制指令
createParticle(paths.a1, true);
createParticle(paths.a2, true);
// 延迟等待指令到达后执行机械动作
setTimeout(() => executeActuators(targetWeir, targetValve), 1000);
}
}, 1500); // AI处理耗时
}
// 4. 执行器动作
function executeActuators(tWeir, tValve) {
// 更新动作计数 (约束展示)
if (state.actionCount < state.maxActions) {
state.actionCount++;
els.actionCountUi.textContent = `${state.actionCount} / ${state.maxActions}`;
if(state.actionCount === state.maxActions) {
els.actionCountUi.style.color = "var(--accent-amber)";
}
}
// 数值动画
let startWeir = state.weirHeight;
let startValve = state.valveOpen;
let startTime = null;
const duration = 1500;
function animateValues(timestamp) {
if(!startTime) startTime = timestamp;
const progress = Math.min(1, (timestamp - startTime) / duration);
// easeInOutQuad
const ease = progress < 0.5 ? 2 * progress * progress : 1 - Math.pow(-2 * progress + 2, 2) / 2;
state.weirHeight = lerp(startWeir, tWeir, ease);
state.valveOpen = lerp(startValve, tValve, ease);
els.weirVal.textContent = Math.round(state.weirHeight);
els.valveVal.textContent = Math.round(state.valveOpen);
// 物理形态变化映射
// 堰板高度: Y轴负向位移 (-15 是基准,位移量基于数值)
const yOffset = -15 - ((state.weirHeight - 50) / 200) * 20;
els.mechWeir.style.transform = `translateY(${yOffset - (-15)}px)`;
// 阀门开度: 旋转角度映射
const rotAngle = ((state.valveOpen - 10) / 80) * 90; // 0-90度
els.mechValve.style.transform = `rotate(${rotAngle}deg)`;
if(progress < 1) {
requestAnimationFrame(animateValues);
}
}
requestAnimationFrame(animateValues);
}
// 启动循环
setTimeout(() => {
triggerOptimization(); // 首次较快触发
setInterval(triggerOptimization, 8000); // 后续每8秒循环
}, 1000);
});
</script>
</body>
</html>
积分规则:每轮对话扣10分
等待动画代码生成...
