如何利用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 相关文章推荐
jquery判断checkbox(复选框)是否被选中的代码
Oct 20 Javascript
自写的一个jQuery圆角插件
Oct 26 Javascript
仅IE不支持setTimeout/setInterval函数的第三个以上参数
May 25 Javascript
Javascript继承(上)——对象构建介绍
Nov 08 Javascript
基于Jquery和html5的7款个性化地图插件
Nov 17 Javascript
理解jquery事件冒泡
Jan 03 Javascript
JS创建事件的三种方法(实例代码)
May 12 Javascript
微信小程序 MD5的方法详解及实例代码
Mar 10 Javascript
浅谈Angular4中常用管道
Sep 27 Javascript
vue中axios处理http发送请求的示例(Post和get)
Oct 13 Javascript
Element Table的row-class-name无效与动态高亮显示选中行背景色
Nov 30 Javascript
原生js实现简单轮播图
Oct 26 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 版获取重定向后的地址(代码)
2013/06/26 PHP
浅析PHP安装扩展mcrypt以及相关依赖项(PHP安装PECL扩展的方法)
2013/07/05 PHP
Codeigniter发送邮件的方法
2015/03/19 PHP
PHP递归遍历指定文件夹内的文件实现方法
2016/11/15 PHP
PHP实现统计所有字符在字符串中出现次数的方法
2017/10/17 PHP
PHP实现打包zip并下载功能
2018/06/12 PHP
php下的原生ajax请求用法实例分析
2020/02/28 PHP
jQuery学习基础知识小结
2010/11/25 Javascript
导航跟随滚动条置顶移动示例代码
2013/09/11 Javascript
javascript中this的四种用法
2015/05/11 Javascript
详解vue-validator(vue验证器)
2017/01/16 Javascript
JS随机排序数组实现方法分析
2017/10/11 Javascript
js设置随机切换背景图片的简单实例
2017/11/12 Javascript
Vue 实现树形视图数据功能
2018/05/07 Javascript
node使用Mongoose类库实现简单的增删改查
2018/11/08 Javascript
JS实现根据数组对象的某一属性排序操作示例
2019/01/14 Javascript
微信小程序批量监听输入框对按钮样式进行控制的实现代码
2019/10/12 Javascript
countUp.js实现数字滚动效果
2019/10/18 Javascript
多页vue应用的单页面打包方法(内含打包模式的应用)
2020/06/11 Javascript
python获取指定目录下所有文件名列表的方法
2015/05/20 Python
python使用urllib2提交http post请求的方法
2015/05/26 Python
python实现的简单FTP上传下载文件实例
2015/06/30 Python
python中星号变量的几种特殊用法
2016/09/07 Python
Python浅复制中对象生存周期实例分析
2018/04/02 Python
在pytorch中为Module和Tensor指定GPU的例子
2019/08/19 Python
html5 冒号分隔符对齐的实现
2019/07/31 HTML / CSS
英国领先的酒类网上商城:TheDrinkShop
2017/03/16 全球购物
自荐信的五个重要部分
2013/10/29 职场文书
学校元旦晚会方案
2014/02/19 职场文书
飘柔洗发水广告词
2014/03/14 职场文书
法人授权委托书范本
2014/04/04 职场文书
高二学生评语大全
2014/04/25 职场文书
艺术设计专业求职自荐信
2014/05/19 职场文书
MySQL 自动填充 create_time 和 update_time
2022/05/20 MySQL
Python+pyaudio实现音频控制示例详解
2022/07/23 Python
Java使用HttpClient实现文件下载
2022/08/14 Java/Android