3D fan visualization system based on HTML5 WebGL

Foreword

  For many centuries, wind turbines, like hydraulic machinery, have replaced human and animal power as a power source and have played an important role in the development of productivity. The widespread application of modern electromechanical power and the discovery of oil fields in the Middle East in the 1950s slowed the development of wind turbine generators.

In the early 1970s, due to the "oil crisis", there was a problem of energy shortage. People recognized the instability and limited nature of conventional fossil energy supply, so the search for clean renewable energy became an important issue in the modern world. As a renewable and pollution-free natural energy source, wind energy has once again attracted people's attention.

Now I hope that through this fan demo, the various functions of the wind turbine can be displayed to everyone at a close distance so that everyone can understand the wind turbine more.

This demo uses the  HT for Web  product to lighten the HTML5 / WebGL modeling solution.

Demo link: https://hightopo.com/demo/fan3d-magic/

 

 

Introduction of main functions of fan

effect:

  

 

Surrounding environment function:

  1. Wind speed value.

  Fictitious a wind speed value, the wind speed value will affect the power generation efficiency of the wind turbine and the change of the pitch system.

 

  2. Statistics .

  

  The graph percentages of ambient temperature, cabin temperature, gearbox temperature and wind speed will change with time.

  3. Environmental monitoring .

  

  On the left, the various parameters of the fan are monitored, and on the right is a line chart of the wind speed change.

 

  4. Data monitoring .  

  

  The abnormal situation occurred in the process of generating electricity by the fan, the location of the fault occurred and the time when the fault occurred. The collection of abnormal information is conducive to people to conduct abnormal analysis and abnormal handling.

  5. Yaw system .

  

  The yaw system, also known as the wind device, is part of the wind turbine nacelle. Its function is to quickly and smoothly align the wind direction when the direction of the wind speed vector changes, so that the wind wheel can obtain the maximum wind energy.

 

  6. Pitch system .

  

  As one of the core parts of the control system of large-scale wind turbines, the pitch control system plays an important role in the safe, stable and efficient operation of the unit. Stable pitch control has become one of the hotspots and difficulties in the research of large-scale wind turbine control technology.

  The pitch control technology is simply to change the angle of attack of the blade by adjusting the pitch angle of the blade to control the aerodynamic torque and aerodynamic power captured by the wind wheel.

 

Button control function:

 

  Fan start and stop:

  

  Wireframe mode:

  

  Aircraft cabin perspective:

  

  Power generation process:

  

 

Organize ideas:

    Scene part :

  Here, 3D is used as a background and nested in a 2D scene.

   In this way, when the drawings are initialized, the 2D drawings can be directly deserialized.

 

  Event section :

  There are many buttons in 2D drawings, and they are used to control some animations in 3D.

  The realization idea is to mount the 2D and 3D models and view objects on the window when deserializing the drawings   , so that the corresponding data model can be obtained in different scenarios.

 

  Environmental part:

  Wind speed, wind direction, and pitch angle will be displayed in 2D and 3D, so you can put them in the data pool for easy management.

 

Specific code implementation:

Scene construction: As mentioned above, we nest 3D as the background in 2D, so we only need to serialize the 2D, which requires some code for background judgment.

Related pseudocode :

graphView.deserialize('displays/demo/风力发电机/风力发电机结构查看.json', function (json, dm, gv, datas) {
  if (json.title) document.title = json.title
        if (json.a['json.background']) {
            var bgJSON = json.a['json.background']
            if (bgJSON.indexOf('displays') === 0) {
                var bgGv = new ht.graph.GraphView()
                bgGv.deserialize(bgJSON)
                bgGv.addToDOM()
                graphView.addToDOM(bgGv.getView())
            }
            else if (bgJSON.indexOf('scenes') === 0) {
                var bgG3d = new ht.graph3d.Graph3dView()
                bgG3d.deserialize(bgJSON)
                bgG3d.addToDOM()
                graphView.addToDOM(bgG3d.getView())
            }
            graphView.handleScroll = function () { }
        }
 })

 

Simulated wind speed: Every 30s, a value is randomly generated as the wind speed value.

Related pseudocode :

// 模拟风速
mockWindSpeed() {
  return 8 + Math.random() * 12
}

 

Data statistics: every 30s, random transformation.

effect:

Related pseudocode :

// 指针和扇叶旋转的角度 进行变化
var oldPointerValue = pitchSystem.a('pointer') || 0

// 风机扇叶和变桨系统的旋转角度
var newRotateAngular = (this.windSpeed - 8) * 7.5 * translateAngularRadian.radian
var addPointerValue = newRotateAngular - oldPointerValue

var oldWindSpeedClip = environmentalData.a('windSpeedClip') || 0
var newWindSpeedClip = (this.windSpeed - 8) / 12
var addWindSpeedClip = newWindSpeedClip - oldWindSpeedClip

var anim = {
  duration: 1e3,
  easing: (v) => {
    return v * v
   },
  action: (v) => {
    var windSpeed = Number(this.windSpeed.toFixed(2))
    var Max = Number(MaxValue.toFixed(2))
    var average = Number(Aver.toFixed(2))
    var windSpeedClip = oldWindSpeedClip + (addWindSpeedClip * v)
    // 设置发电参数随机数据
     generator.a({ windSpeed })
    // 设置环境监测随机数据
    environmentalData.a({ windSpeed, windSpeedClip })
    // 设置统计参数随机数据
    statisticalParam.a({ average, Max, windSpeed })
    // 设置变航系统的指针角度
    pitchSystem.a('pointer', oldPointerValue + (addPointerValue * v))
  }
}

ht.Default.startAnim(anim)

This involves the conversion of angles and radians. 1 ° = Math.PI / 180 °, 1rad = 180 ° / Math.PI , because the scene uses the radian system, so you need to convert the random angle value into radians.

Explain the code here to get the current value first. Then add the random value-the current value. For example, the current value is 16, and the random value has two cases, 1: greater than the current value. 2: It is smaller than the current value.

If it is greater than the current value, such as 18, then this is 16 + (18-16) * v (the value after the easing function)

If it is smaller than the current value, such as 13, then this is 16 + (13-16) * v (the value after the easing function)

In this way, when random, it will smoothly change from the current value to the target value.

 

Statistics : Every 30s, monitor the current fault information of the fan.

effect: 

 The table.json  file is used here  , and real-time information is added by modifying the  ht.dataSource  property.

 Related pseudocode :

var checkInternals = () => {
  /**
   * 故障信息
   * 变桨系统 主轴 偏航系统 齿轮箱 油冷装置 发电机 风冷装置
   */
    var FailureStatus = {
        // 正常状态
        status1: new Map([
            [0, ['舱内温度正常,变桨角度正常。', 'i10']],
            [1, ['舱内温度正常,主轴转速正常。', 'i9']],
            [2, ['偏航系统精确。', 'i8']],
            [3, ['齿轮箱温度正常。', 'i1']],
            [4, ['油冷装置温控表正常。', 'i3']],
            [5, ['发电机功率正常。', 'i5']],
            [6, ['风冷装置正常。', 'i2']]
        ]),

        // 异常状态
        status2: new Map([
            [0, ['变桨角度异常。', 'i10']],
            [1, ['主轴转速偏高。', 'i9']],
            [2, ['偏航系统出现偏移。', 'i8']],
            [3, ['齿轮箱温度偏高。', 'i1']],
            [4, ['油冷装置内积尘过多。', 'i3']],
            [5, ['发电机电流过大。', 'i5']],
            [6, ['风冷装置散热不足。', 'i2']]
        ]),
    }

    // 返回设备正常的状况 status 1: 正常 2: 不正常
    var mockQquipmentFailure = (status) => {
        var { rangeRandom } = common
        var index = rangeRandom(7)

        // 返回随机出来的设备情况
        return FailureStatus[`status${status}`].get(index)
    }

      var info = randomInfo[0]
      var targetTag = randomInfo[1]

      this.tableArr = table.a('ht.dataSource')
      var currentTimeFormat = DateUtil.formatHourTime(new Date())

  // 默认是正常 如果找到故障关键字的话 赋值为 异常
  var status = 'normal'
  var time = 0
 this.tableArr.push({ status, info, time: currentTimeFormat })
}

We need two  Map  arrays to facilitate the value operation. One is the normal information array, and the other is the abnormal information array. Use the random value as an index, and then get the corresponding state information and add it to the  table  .

If the current  status  is  normal, it means normal information, otherwise it is abnormal information. If there is any abnormal information, you can   modify the color of the table.json  rendering callback function  "drawCell": function (g, text, rect, option) {} to highlight it.

 

Yaw system: During the rotation of the fan, the direction of the yaw system changes as the wind position varies.

 effect:

   

 Related pseudocode :

/**
  * 随机偏航系统
  * @param { * }
  */
  randomYawSystem() {
    var { dm } = this
    var { d2d } = window
    var { rangeRandom } = common

    var poll = () => {
       // 随机数 30 - 50
        var random = 30 + rangeRandom(20)
        var cabin = dm.getDataByTag('cabin')

        // 将角度度换算成弧度 然后乘以随机数 实现随机风向
        var randomDegrees = translateAngularRadian.radian * random
        var defaultDegress = translateAngularRadian.radian * 180

         ht.Default.startAnim({
           duration: 1e3,
           action: (v) => {
             var oldValue = cabin.getRotationY()
             var newValue = randomDegrees
             var addValue = newValue - oldValue

           cabin.setRotationY(oldValue + addValue * v)
         }
      })
    }
 }

 The above mentioned the conversion of angles and radians. Here, the random angle is converted into radians, and then assigned to rotate.

 

 Pitch system: The change in wind speed affects the angle of the fan blades.

 effect:

Related pseudocode:

var old3Value = whiteShell3Line.getRotationX()
var old4Value = whiteShell4Line.getRotationX()
var old5Value = whiteShell5Line.getRotationX()

// 指针和扇叶旋转的角度 进行变化
var oldPointerValue = pitchSystem.a('pointer') || 0
// 风机扇叶和变桨系统的旋转角度
var newRotateAngular = (this.windSpeed - 8) * 7.5 * translateAngularRadian.radian
var addPointerValue = newRotateAngular - oldPointerValue

whiteShell3Line.setRotationX(old3Value + ((newRotateAngular - oldPointerValue)))
whiteShell4Line.setRotationX(old4Value + ((newRotateAngular - oldPointerValue)))
whiteShell5Line.setRotationX(old5Value + ((newRotateAngular - oldPointerValue)))

 First obtain the current X-axis rotation value of each fan blade, and then obtain the angle value that needs to be rotated and assign it.

 

 Fan start and stop: Fan start and stop

 Related pseudocode:

var fanWireframe = d3d.getDataByTag('fanWireframe')
fanWireframe.setRotationMode('zxy')
this.allAnimManage = new Map([['fanRotate', null]])

var fanRotating = (easeType) => {
  anim = ht.Default.startAnim({
    duration: 5e3,
    easing: (t) => easeIn(t),
    action: (v) => {
      fanWireframe.setRotationZ(fanWireframe.getRotationZ() + speed)

        // 风机轮毂旋转
        if (fanWireframe.getRotationZ() <= -6.28) {
          fanWireframe.setRotationZ(0)
        }

        // 风机扇叶 uv 偏移
        for (let i = 1; i < 17; i++) {
          var node = d3d.getDataByTag(`q${i}`)
          node.s('shape3d.uv.offset', fanOffsetData(v)[i - 1])
        }

        // 暂停命令
        if (isStop) {
          stopFanRotate(fanWireframe.getRotationZ())
          anim.pause()
          anim = null
        }
    },
      finishFunc: () => {
        fanRotating(false)
      }
    })

    this.allAnimManage.set('fanRotate', anim)
}

 Because it can be started and stopped, then we can achieve the effect by controlling   the resume  and  pause  of the returned object of  ht.Default.startAnim () .

 So I added the animation of the fan rotation to the global object for easy calling.

 The setRotationMode ('zxy')  method is to set the three-dimensional rotation mode, the order is  z-> x-> y, first perform the z-axis rotation, then the x-axis rotation, and finally the y-axis rotation. The purpose of setting is to avoid the influence of external rotation of the coordinate axis.

 

 Wind direction: According to the angle of the wind, determine where the wind is currently.

 effect:

 Related pseudocode:

// 判断风向
var windDirection = (rotate) => {
    let direction

    switch (true) {
    case rotate === 0:
        direction = '南'
        break
    case rotate === 90:
        direction = '东'
        break
    case rotate === 180:
        direction = '北'
        break
    case rotate === 240:
        direction = '西'
        break
    case rotate > 0 && rotate < 90:
        direction = '东南'
        break
    case rotate > 90 && rotate < 180:
        direction = '东北'
        break
    case rotate > 180 && rotate < 270:
        direction = '西北'
        break
    case rotate > 270 && rotate < 360:
        direction = '西南'
        break
    default:
        direction = '没有找到风向'
    }

    return direction
}
// 判断是哪个方向
var angular = randomDegrees * translateAngularRadian.angular
var direction = windDirection(angular)

 Put the pointer angle of the compass on the  switch  to judge, and return if the corresponding wind direction is found.

 

to sum up

Wind power is a typical example of the industrial Internet. We can analyze the wind turbine model or monitoring data to reduce the complexity of our work and help us quickly understand the internal structure and function of power generation.

What HT  can do is much more than that, which requires our rich imagination and our own excellent technology. I hope that through this article, we can convey a kind of energy to everyone, so that everyone can be more interested, burst out more fresh ideas, and do more fun things.

Published 314 original articles · Like 138 · Visit 390,000+

Guess you like

Origin blog.csdn.net/u013161495/article/details/104433373