如何利用vue实现波谱拟合详解


Posted in Javascript onNovember 05, 2020

主页面-功能介绍

小白初入职场第一篇总结,废话比较多,求轻喷~

如何利用vue实现波谱拟合详解

波谱拟合用来对某种材料或物质的谱图进行识别和分析,每种物质可以有多种成分,每种成分用component1、component2...表示,用Add another component和Remove component来控制每种成分的增加和删除,每种成分由多种原子核构成,即nuclei,用Add nucleus和Remove nucleus来控制每种成分内原子核数量,每新增一个原子核,波谱就会分裂一次,谱峰数量由(1->2->4->8...)依次分裂。另外可以通过更改默认参数,改变波谱形态,成分参数中:Relative amount表示每种成分占绘图分量的百分比,百分比之和不超过100,giso用来计算分裂的中心位置,LineWidth用来控设置谱峰到谱谷的宽度,%Lorentzian表示谱峰形态,一共两种形态,高斯和洛伦兹,两者之和为100;原子核参数:No of equivalent nuclei用来改变原子核个数,如果一种成分内包含很多个一模一样的参数时,就可以通过改变这个参数实现,Nuclear spin用来改变原子核种类,Hyperfine用来设置分裂后两峰之间的宽度。

再来一张图:

如何利用vue实现波谱拟合详解

每种成分数量和参数、每种成分内每种原子核数量和参数设置好后,对数据进行处理,由三种结果,卷积、积分、二重积分,那就来看看数据的处理逻辑吧~

如何利用vue实现波谱拟合详解

从数据流角度,主要进行三步处理:数据->数据裂变->光谱计算->绘图,左边是算法实现所需的参数、右边是对数据及每个步骤的描述。

代码实现

遇到一个坑,一开始写demo的时候用的vue+Ant design of vue,在select等其他组件的使用上都是正常的,但是在input number中就很变态了,给input number绑定的change事件,用户在输入两位以上数据的时候,change事件会触发两次!!!想避免这个问题,于是用blur事件,问题又来了,因为这个页面中组件的生成和删除需要动态渲染,并且根据前面的介绍很容易知道组件的渲染是有两层结构的,那么在用户进行点击或输入操作的时候,就需要传递一个参数(用来定位是哪个component以及每个component下面对应的某一个nucle等等),能力有限( ?□? )目前我没有找到解决办法,于是转elementUI框架。

组件的动态渲染用了一个比较巧妙的办法,一开始我打算用render来写,后来从部门大神那里学到通过遍历列表进行渲染,脑子之间还是有差距的。。。

<div v-for="(Con, i) in componentList" :key="Con[i]"><strong>Component {{i+1}}.</div>

同理原子核的动态渲染也是这么实现的:

<div v-for="(li, j) in nucleusList[i]" :key="li[j]">{{j+1}}. No of equivalent nuclei:</div>

然后每次增加和删除只需要操作数组列表的长度即可~

各参数的绑定:component中参数均使用一维数组,chenge事件需传递一维数组的下标,component内的nucleui均使用二维数组,change事件需传递二维数组的下标。

以上介绍参数定义,接下来是数据处理:

// 首先计算裂变数据
stickspectrum (w) {
   // console.log('组件信息', w)
   const stick = new Array(2) // 返回包含stick[0]的stick光谱数组,stick[1]是位置
   stick[0] = new Array()// 光谱强度
   stick[1] = new Array()// 光谱位置
   stick[1][0] = this.h * this.frequency / (this.r[w].g * this.mu)

   for (var j = 0; j < this.r[w].equiv.length; j++) {
    // console.log('stick[0].length', stick[0].length) //分裂后的光谱数据长度
    for (var i = stick[0].length - 1; i >= 0; i--) {
     stick[0][i] /= Math.pow((2 * this.r[w].spin[j] + 1), this.r[w].equiv[j])
     stick[1][i] -= this.r[w].equiv[j] * this.r[w].spin[j] * this.r[w].hfc[j]

     for (var k = 0; k < 2 * this.r[w].equiv[j] * this.r[w].spin[j]; k++) {
      stick[1].splice(i + k + 1, 0, stick[1][i] + this.r[w].hfc[j] * (k + 1))
      stick[0].splice(i + k + 1, 0, 0)
     }
     for (var k = 0; k < this.r[w].equiv[j]; k++) {
      for (var m = i + 2 * this.r[w].spin[j] * k; m >= i; m--) {
       for (var ii = 0; ii < 2 * this.r[w].spin[j]; ii++) {
        stick[0][m + ii + 1] += stick[0][m]
       }
      }
     }
    }
   }
   return stick
  },
// 再对裂变后的数据进行光谱计算
spectrum (stick) {
   let xmin = Infinity; let xmax = 0
   for (var k = 0; k < this.r.length; k++) {
    xmin = Math.min(Math.min.apply(Math, stick[k][1]) - 10 * this.r[k].width, xmin)
    xmax = Math.max(Math.max.apply(Math, stick[k][1]) + 10 * this.r[k].width, xmax)
   }
   const tmp = xmax - xmin
   xmax += tmp * 0.05
   xmin -= tmp * 0.05
   const step = (xmax - xmin) / (this.No_integers - 1)
   for (let i = 0; i < this.No_integers; i++) {
    this.XY[0][i][0] = xmin + step * i
    this.XY[0][i][1] = 0
    this.XYint[0][i][0] = this.XY[0][i][0]
    this.XYint[0][i][1] = 0
    this.XYdoubleint[0][i][0] = this.XY[0][i][0]
    this.XYdoubleint[0][i][1] = 0
   }

   for (let k = 0; k < this.r.length; k++) { // 分量累加
    const sticks = new Array(this.No_integers)
    for (var i = 0; i < stick[k][0].length; i++) {
     var j = Math.round((stick[k][1][i] - xmin) / step)
     sticks[j] = sticks[j] ? sticks[j] + stick[k][0][i] : stick[k][0][i]
    }

    const tmp = new Array(this.No_integers)// 第一种光谱绘图位置数据
    let ind = 0
    for (var i = 0; i < this.No_integers; i++) {
     if (sticks[i]) { // 建立峰值索引——sticks[i]===1即峰值所在。
      tmp[ind] = i
      ind++
     }
    }
    const tmpint = new Array(this.No_integers) // 用来保存每个分量的积分
    const tmpdoubleint = new Array(this.No_integers) // 用来保存每个分量的二重积分
    for (var i = 0; i < this.No_integers; i++) tmpint[i] = 0
    tmpdoubleint[0] = 0
    const rwid = Number(this.r[k].width)
    const rwid2 = Math.pow(rwid, 2)
    const lortmp = Number(this.r[k].percent) * Number(this.r[k].lor) / 100 * Math.sqrt(3) / Math.PI // 洛伦兹线乘积
    const gaustmp = Number(this.r[k].percent) * (100 - Number(this.r[k].lor)) / 100 * Math.sqrt(2 / Math.PI) // 高斯线乘法器

    for (let i = 0; i < this.No_integers; i++) {
     for (let j = 0; j < ind; j++) {
      const delta = this.XY[0][i][0] - this.XY[0][tmp[j]][0]
      const delta2 = Math.pow(delta, 2)
      if ((rwid > step && Math.abs(-0.5 * rwid - delta) < 0.5 * step) || (rwid < step && -0.5 * rwid - delta > 0 && -0.5 * rwid - delta < step)) {
       this.XY[0][i][1] += sticks[tmp[j]] * (lortmp * 0.5 / rwid2 + gaustmp * 2 / Math.sqrt(Math.E) / rwid2)
      } else if ((rwid > step && Math.abs(0.5 * rwid - delta) < 0.5 * step) || (rwid < step && delta - 0.5 * rwid > 0 && delta - 0.5 * rwid < step)) {
       this.XY[0][i][1] -= sticks[tmp[j]] * (lortmp * 0.5 / rwid2 + gaustmp * 2 / Math.sqrt(Math.E) / rwid2)
      } else {
       this.XY[0][i][1] += sticks[tmp[j]] * (gaustmp * (-4) / rwid / rwid2 * delta * Math.exp(-2 * delta2 / rwid2) + lortmp * (-delta) * rwid / Math.pow((delta2 + 3 / 4 * rwid2), 2)) // 其他情况下的正常计算,高斯+洛伦兹
      }
      this.dataarray = [this.XY, this.XYint, this.XYdoubleint]
      tmpint[i] += sticks[tmp[j]] * (gaustmp * Math.exp(-2 * delta2 / rwid2) / rwid + lortmp / 2 / rwid / (0.75 + delta2 / rwid2)) // 高斯+洛伦兹积分-明确计算以避免积分误差
     }
    }
    for (let j = 1; j < this.No_integers; j++) {
     tmpdoubleint[j] = tmpdoubleint[j - 1] + step * (tmpint[j] + tmpint[j - 1]) / 2
    } // 二重积分
    // console.log('二重积分', tmpdoubleint)

    const mm = tmpdoubleint[this.No_integers - 1] / Number(this.r[k].percent) // 有多少积分高于理论(只发生在非常尖锐的线)
    for (let j = 1; j < this.No_integers; j++) {
     this.XYdoubleint[0][j][1] += mm > 1 ? tmpdoubleint[j] / mm : tmpdoubleint[j] // 第三种频谱数据 如果二重积分高于理论,将其标准化
     this.XYint[0][j][1] += tmpint[j] // 第二种频谱数据
    }
   }
   // console.log('XYint', this.XYint[0])
  },

计算完成的光谱,返回三种数据XY、XYint、XYdouble,然后就是绘图~

到此这篇关于如何利用vue实现波谱拟合的文章就介绍到这了,更多相关vue实现波谱拟合内容请搜索三水点靠木以前的文章或继续浏览下面的相关文章希望大家以后多多支持三水点靠木!

Javascript 相关文章推荐
javascript forEach通用循环遍历方法
Oct 11 Javascript
iframe的onload在Chrome/Opera中执行两次Bug的解决方法
Mar 17 Javascript
容易造成JavaScript内存泄露几个方面
Sep 04 Javascript
jQuery实现右侧显示可向左滑动展示的深色QQ客服效果代码
Oct 23 Javascript
javascript多物体运动实现方法分析
Jan 08 Javascript
JavaScript代码实现左右上下自动晃动自动移动
Apr 08 Javascript
全面了解javascript中的错误处理机制
Jul 18 Javascript
微信小程序 列表的上拉加载和下拉刷新的实现
Apr 01 Javascript
详解webpack+ES6+Sass搭建多页面应用
Nov 05 Javascript
vue生命周期与钩子函数简单示例
Mar 13 Javascript
vue中的面包屑导航组件实例代码
Jul 01 Javascript
electron踩坑之dialog中的callback解决
Oct 06 Javascript
关于Vue中$refs的探索浅析
Nov 05 #Javascript
JavaScript 实现轮播图特效的示例
Nov 05 #Javascript
nuxt 服务器渲染动态设置 title和seo关键字的操作
Nov 05 #Javascript
nuxt 每个页面head标签内容设置方式
Nov 05 #Javascript
JavaScript TAB栏切换效果的示例
Nov 05 #Javascript
nuxt 页面路由配置,主页轮播组件开发操作
Nov 05 #Javascript
JS时间戳与日期格式互相转换的简单方法示例
Jan 30 #Javascript
You might like
PHP 5.3新特性命名空间规则解析及高级功能
2010/03/11 PHP
WordPress迁移时一些常见问题的解决方法整理
2015/11/24 PHP
PHP切割汉字的常用方法实例总结
2019/04/27 PHP
ThinkPHP5+UEditor图片上传到阿里云对象存储OSS功能示例
2019/08/05 PHP
Javascript图像处理—虚拟边缘介绍及使用方法
2012/12/27 Javascript
JS获取农历日期具体实例
2013/11/14 Javascript
JS判断客服QQ号在线还是离线状态的方法
2015/01/13 Javascript
JS点击链接后慢慢展开隐藏着图片的方法
2015/02/17 Javascript
基于jquery实现鼠标左右拖动滑块滑动附源码下载
2015/12/23 Javascript
js replace(a,b)之替换字符串中所有指定字符的方法
2016/08/17 Javascript
详解Js模板引擎(TrimPath)
2016/11/22 Javascript
简单实现Vue的observer和watcher
2016/12/21 Javascript
jQuery实现的滑块滑动导航效果示例
2018/06/04 jQuery
JS实现DOM节点插入操作之子节点与兄弟节点插入操作示例
2018/07/30 Javascript
vue+element实现图片上传及裁剪功能
2020/06/29 Javascript
js实现点击上传图片并设为模糊背景
2020/08/02 Javascript
vue3+typeScript穿梭框的实现示例
2020/12/29 Vue.js
[41:08]TNC vs VG 2018国际邀请赛小组赛BO2 第一场 8.16
2018/08/17 DOTA
讲解Python中的递归函数
2015/04/27 Python
Python批量查询域名是否被注册过
2017/06/21 Python
基于python中的TCP及UDP(详解)
2017/11/06 Python
python用户评论标签匹配的解决方法
2018/05/31 Python
Python爬虫之pandas基本安装与使用方法示例
2018/08/08 Python
我们为什么要减少Python中循环的使用
2019/07/10 Python
浅谈Python2之汉字编码为unicode的问题(即类似\xc3\xa4)
2019/08/12 Python
关于Python中定制类的比较运算实例
2019/12/19 Python
win10下python2和python3共存问题解决方法
2019/12/23 Python
python3 deque 双向队列创建与使用方法分析
2020/03/24 Python
pycharm不以pytest方式运行,想要切换回普通模式运行的操作
2020/09/01 Python
德国百年厨具品牌WMF美国站:WMF美国
2016/09/12 全球购物
Famous Footwear加拿大:美国多品牌运动休闲鞋店
2018/12/05 全球购物
旅游与环境专业求职信
2014/06/05 职场文书
服装设计专业求职信
2014/06/16 职场文书
美容院管理规章制度
2015/08/05 职场文书
Oracle中日期的使用方法实例
2022/07/07 Oracle
VW、VH适配移动端的解决方案与常见问题
2023/05/21 HTML / CSS