如何利用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修改css样式style
Apr 15 Javascript
利用onresize使得div可以随着屏幕大小而自适应的代码
Jan 15 Javascript
JQuery上传插件Uploadify使用详解及错误处理
Apr 27 Javascript
一步一步封装自己的HtmlHelper组件BootstrapHelper(二)
Sep 14 Javascript
JS遍历ul下的li点击弹出li的索引的实现方法
Sep 19 Javascript
利用JS实现页面删除并重新排序功能
Dec 09 Javascript
JS实现的简单轮播图运动效果示例
Dec 22 Javascript
详解微信小程序设置底部导航栏目方法
Jun 29 Javascript
老生常谈Bootstrap媒体对象
Jul 06 Javascript
js实现把时间戳转换为yyyy-MM-dd hh:mm 格式(es6语法)
Dec 28 Javascript
解决webpack无法通过IP地址访问localhost的问题
Feb 22 Javascript
JS轻量级函数式编程实现XDM三
Jun 16 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 checkdate、getdate等日期时间函数操作详解
2010/03/11 PHP
php封装的验证码工具类完整实例
2016/10/19 PHP
Windows平台实现PHP连接SQL Server2008的方法
2017/07/26 PHP
javascript之函数直接量(function(){})()
2007/06/29 Javascript
函数式 JavaScript(一)简介
2014/07/07 Javascript
如何调试异步加载页面里包含的js文件
2014/10/30 Javascript
js实现对table动态添加、删除和更新的方法
2015/02/10 Javascript
浅谈jQuery中replace()方法
2015/05/13 Javascript
vue通过点击事件读取音频文件的方法
2018/05/30 Javascript
Node.js实现简单管理系统
2019/09/23 Javascript
解决vue项目获取dom元素宽高总是不准确问题
2020/07/29 Javascript
[01:14]DOTA2 7.22版本新增神杖效果展示(智力英雄篇)
2019/05/29 DOTA
python测试驱动开发实例
2014/10/08 Python
Python标准异常和异常处理详解
2015/02/02 Python
python批量生成本地ip地址的方法
2015/03/23 Python
Python的Bottle框架中实现最基本的get和post的方法的教程
2015/04/30 Python
python函数形参用法实例分析
2015/08/04 Python
Python数据分析之双色球统计两个红和蓝球哪组合比例高的方法
2018/02/03 Python
pandas 层次化索引的实现方法
2019/07/06 Python
详解python中的数据类型和控制流
2019/08/08 Python
python  logging日志打印过程解析
2019/10/22 Python
Python3.7 读取 mp3 音频文件生成波形图效果
2019/11/05 Python
wxPython实现画图板
2020/08/27 Python
Python-openCV读RGB通道图实例
2020/01/17 Python
一站式跨境收款解决方案:Payoneer(派安盈)
2018/09/06 全球购物
北京华建集团SQL面试题
2014/06/03 面试题
高二化学教学反思
2014/01/30 职场文书
2014年国庆节活动总结
2014/08/26 职场文书
小学班级特色活动方案
2014/08/31 职场文书
教师批评与自我批评(群众路线)
2014/10/15 职场文书
2015关于重阳节的演讲稿
2015/03/20 职场文书
教学质量月活动总结
2015/05/11 职场文书
对Keras自带Loss Function的深入研究
2021/05/25 Python
Python还能这么玩之只用30行代码从excel提取个人值班表
2021/06/05 Python
快速学习Oracle触发器和游标
2021/06/30 Oracle
Python通用验证码识别OCR库ddddocr的安装使用教程
2022/07/07 Python