欢迎光临
我们一直在努力

数字孪生与仿真——构建温湿度环境数字镜像

从静态监控到动态映射;用 Spring Boot + WebSocket + Three.js 实现温湿度数字孪生体

🧭 本文属于专栏《Java × 工业智能》第 11 篇 | GitHub 源码:github.com/iweidujiang/java-industrial-smart

温湿度是几乎所有工业环境的基础指标:

  • 机房:高温导致服务器宕机;
  • 仓库:高湿引发货物霉变;
  • 温室:精准调控提升作物产量。

本篇将构建一个温湿度数字孪生演示平台,实现:

  • 实时接收模拟温湿度数据;
  • 3D 场景中动态渲染环境状态(颜色 + 粒子效果)

一、什么是数字孪生?——不只是3D模型,而是“活”的虚拟镜像

在工业智能化浪潮中,“数字孪生”(Digital Twin)已成为高频热词。但很多人误以为:只要有个3D模型,能旋转、能缩放,就是数字孪生。这其实是一种误解。

真正的数字孪生,不是“看得见”,而是“同步得上、算得准、控得住”。

1、数字孪生的核心定义

数字孪生是物理实体在信息空间中的动态、高保真、可交互的数字化映射。它必须满足三个基本特征:

特征说明反例
实时性 虚拟体状态随物理体同步更新(秒级甚至毫秒级) 静态3D展示,数据每天手动导入
双向性 不仅“感知”物理状态,还能“反控”物理行为 仅监控,无法下发指令
模型驱动 基于物理/数据模型,支持仿真、预测、优化 纯UI动画,无底层逻辑支撑

简单说:数字孪生 = 实时数据 + 行为模型 + 可视化交互

2、为什么工业需要数字孪生?

在工厂、电站、仓库等场景中,设备一旦停机,损失可能高达每分钟数万元。而传统运维方式存在三大痛点:

  • 看不见:设备内部状态(如温度场、应力分布)无法直接观测;
  • 难预测:故障往往突发,缺乏预警窗口;
  • 试错贵:调整参数需停机试验,成本高、风险大。
  • 数字孪生正是为解决这些问题而生:

    • 远程诊断:专家通过虚拟镜像查看设备运行状态,无需亲临现场;
    • 故障预演:在数字空间模拟“如果冷却失效,10分钟后会怎样?”;
    • 操作培训:新员工在虚拟环境中练习启停流程,零风险。

    3、数字孪生 ≠ 3D可视化

    很多项目把“三维建模”等同于数字孪生,导致投入大量资源做酷炫动画,却无法解决实际问题。关键区别如下:

    维度3D可视化数字孪生
    目标 展示外观 映射行为
    数据源 静态模型文件 实时传感器流
    交互能力 视角切换、点击高亮 参数调整、仿真推演
    技术栈 Three.js / Unity 物理引擎 + 时序数据库 + 控制算法

    没有实时数据驱动的3D模型,只是“数字尸体”;

    没有行为模型支撑的数据看板,只是“高级图表”。

    四、本篇实践:从最简单的温湿度开始

    本篇选择温湿度这一通用工业感知维度,构建一个轻量但完整的数字孪生原型:

    • 物理侧:用 Java 模拟器生成符合规律的温湿度数据流;
    • 虚拟侧:Three.js 渲染环境状态(颜色 + 雾气);
    • 连接层:WebSocket 实现毫秒级同步;
    • 扩展性:预留 Redis 接口,未来可替换为真实传感器。

    这虽是一个“最小可行孪生体”(Minimum Viable Digital Twin),但它具备了实时映射、状态反馈、异常告警三大核心能力。

    接下来,我们将一步步用 Spring Boot + Vue 3 + Three.js 实现这个温湿度数字孪生体。

    五、系统目标与架构

    功能清单

    功能描述
    3D 环境模型 简易机房/仓库场景(含温湿度传感器图标)
    实时数据流 后端每秒生成模拟温湿度数据
    视觉反馈 温度 → 背景色渐变;湿度 → 雾气粒子密度
    异常告警 温度 > 35℃ 或湿度 > 80% 时闪烁红框

    技术栈

    • 后端:Spring Boot 3.2 + JDK 21 + WebSocket + Redis
    • 前端:Vue 3 + Three.js + STOMP over WebSocket
    • 部署:Docker Compose

    六、后端核心实现

    1. 数据模型:EnvironmentData.java

    /**
    * 温湿度环境数据实体
    * 用于在 WebSocket 和 Redis 中传递
    */

    @Data
    @AllArgsConstructor
    @NoArgsConstructor
    public class EnvironmentData {

    private double temperature;
    private double humidity;
    private long timestamp;
    private boolean alert;
    }

    2. 仿真引擎:EnvironmentSimulator.java

    /**
    * 温湿度模拟器
    * 生成符合物理规律的连续数据流(非随机)
    */

    @Component
    public class EnvironmentSimulator {
    private double currentTemp = 25.0; // 初始温度(℃)
    private double currentHumidity = 60.0; // 初始湿度(%)
    private final Random random = new Random();

    /**
    * 生成下一时刻的环境数据
    *
    * @return 包含温度、湿度、时间戳和告警状态的数据对象
    */

    public EnvironmentData generateNext() {
    // 温度变化:缓慢上升趋势 + 小幅随机波动
    currentTemp += (random.nextDouble() 0.3) * 0.5;
    // 限制温度在合理范围 [10, 45]℃
    currentTemp = Math.max(10.0, Math.min(45.0, currentTemp));

    // 湿度变化:与温度负相关 + 随机扰动
    currentHumidity = 80.0 (currentTemp 20.0) * 1.2 + (random.nextDouble() 0.5) * 5.0;
    // 限制湿度在合理范围 [20, 90]%
    currentHumidity = Math.max(20.0, Math.min(90.0, currentHumidity));

    // 判断是否触发告警
    boolean isAlert = currentTemp > 35.0 || currentHumidity > 80.0;

    return new EnvironmentData(currentTemp, currentHumidity, System.currentTimeMillis(), isAlert);
    }
    }

    3. WebSocket 广播服务:EnvironmentBroadcaster.java

    /**
    * 温湿度数据广播器
    * 通过 WebSocket 向所有前端推送最新数据
    */

    @Slf4j
    @Service
    public class EnvironmentBroadcaster {
    private final SimpMessagingTemplate messagingTemplate;

    public EnvironmentBroadcaster(SimpMessagingTemplate messagingTemplate) {
    this.messagingTemplate = messagingTemplate;
    }

    /**
    * 广播环境数据到指定主题
    *
    * @param data 要广播的环境数据
    */

    public void broadcast(EnvironmentData data) {
    try {
    messagingTemplate.convertAndSend("/topic/environment", data);
    log.debug("已成功推送环境数据 – 温度: {}℃, 湿度: {}%",
    data.getTemperature(), data.getHumidity());
    } catch (Exception e) {
    log.error("推送环境数据到 WebSocket 时发生异常", e);
    }
    }
    }

    4. 定时任务:启动仿真

    @Scheduled(fixedDelay = 1000) // 每秒执行一次
    public void simulateAndBroadcast() {
    EnvironmentData data = simulator.generateNext();
    // 保存到 Redis(供其他服务使用)
    redisTemplate.opsForValue().set("env:latest", data, Duration.ofSeconds(10));
    // 推送至前端
    broadcaster.broadcast(data);
    }

    七、前端核心实现

    1. 初始化 Three.js 场景

    // 创建基础场景
    const scene = new THREE.Scene();
    scene.background = new THREE.Color(0x000033); // 深蓝背景

    // 添加雾效(随湿度变化)
    scene.fog = new THREE.Fog(0xffffff, 10, 30);

    2. 监听 WebSocket 数据

    function initWebSocket() {
    if (client) return;

    client = new Client({
    brokerURL: 'ws://' + window.location.host + '/ws',
    connectHeaders: {},
    debug: (str) => console.log('STOMP Debug:', str),
    reconnectDelay: 5000,
    heartbeatIncoming: 4000,
    heartbeatOutgoing: 4000,

    onConnect: (frame) => {
    console.log('✅ WebSocket 连接成功');
    client.subscribe('/topic/environment', (message) => {
    const data = JSON.parse(message.body);
    updateEnvironmentVisual(data);
    });
    },

    onStompError: (frame) => {
    console.error('❌ WebSocket 错误:', frame.headers['message']);
    }
    });

    try {
    client.activate();
    } catch (e) {
    console.error('WebSocket 激活失败:', e);
    }
    }

    3. 动态更新视觉状态

    function updateEnvironmentVisual(data) {
    // 1. 温度 → 背景色(蓝→红)
    const tempRatio = Math.min(1, (data.temperature 20) / 20);
    const bgColor = new THREE.Color().setHSL(0.66 * (1 tempRatio), 0.7, 0.2 + tempRatio * 0.3);
    scene.background = bgColor;

    // 2. 湿度 → 雾气密度
    scene.fog.density = data.humidity / 200; // 湿度越高,雾越浓

    // 3. 告警 → 红色边框闪烁
    if (data.alert) {
    document.body.style.border = '5px solid red';
    setTimeout(() => document.body.style.border = '', 300);
    }
    }

    ✅ 效果:

    • 温度升高 → 背景由蓝变红;
    • 湿度升高 → 场景雾气加重;
    • 超限时 → 页面边缘红色闪烁。

    八、部署说明

    使用 docker compose 部署,具体方法可见我的上一篇博文:

    手摸手教你部署工业监控大屏项目——Docker 与 Kubernetes 双方案实战

    Java x 工业智能第 10 篇

    这里只贴出 docker-compose.yml 文件:

    version: '3.8'

    services:
    redis:
    image: redis:7alpine
    container_name: industrialredis11
    ports:
    "6379:6379"
    volumes:
    E:/docker_service_data/java_industrial_redis_11:/data
    command:
    "redis-server"
    "–requirepass"
    "devRed1s"
    "–appendonly"
    "yes"
    restart: unlessstopped

    backend:
    image: digitaltwinbackend:local
    container_name: digitaltwinbackend
    depends_on:
    redis
    environment:
    REDIS_HOST=redis
    restart: always

    frontend:
    image: digitaltwinfrontend:local
    container_name: digitaltwinfrontend
    depends_on:
    backend
    ports:
    "80:80"
    restart: always

    在 11-digital-twin-environment 根目录,执行:

    docker compose up -d

    启动后,验证:访问 http://localhost,应看到 3D 场景随温湿度数据动态变化。

    没有告警时,页面显示如图所示:

    当数据出现异常时,出发告警,页面显示如下:

    九、小结:数字孪生的核心是“状态映射”

    本篇通过温湿度这一简单维度,展示了数字孪生的基本范式:

    • 物理状态(温度/湿度)→ 数字状态(颜色/雾气);
    • 实时同步(WebSocket)→ 即时反馈(视觉变化)

    最后,按惯例提醒:

    完整源码已开源: 📁 模块路径:11-digital-twin-environment

    🔗 仓库地址:github.com/iweidujiang/java-industrial-smart

    欢迎 Star & 提 Issue!


    本文属于专栏 《Java × 工业智能》第 11 篇

    如果你对这个系列感兴趣,记得关注我哦!

    赞(0)
    未经允许不得转载:171主机测评 » 数字孪生与仿真——构建温湿度环境数字镜像
    分享到: 更多 (0)

    评论 抢沙发

    • 昵称 (必填)
    • 邮箱 (必填)
    • 网址