批量定义功能或如何绘制光谱

埃尔德拉德

我将计算出的光谱存储在包含两列的文件中:第一个是x位置(波数),第二个是高度(强度)。为了模拟真实频谱,我想为每条线(大约60条)放置一个高斯并绘制所有线的总和。如此处所述我从数据文件中读取系数的位置和高度:

g(x,x0,s,I) = I/sqrt(2*pi*s**2)*exp(-(x-x0)**2/(2*s**2))
stats "file.dat" nooutput
nlines=int(STATS_records-1)
paramstr(N) = sprintf('stats "file.dat" every ::%i::%i u (x%i=$1,I%i=$2) nooutput',N,N,N,N)
do for [i=0:nlines] {eval(paramstr(i))}
spectrum(x,s) = sum [i=0:nlines] g(x,value(sprintf('x%i',i)'),s,value(sprintf('I%i',i)))

这样效果很好,并产生了预期的结果。但是,就我而言,这不是一个文件,而是大约30个文件,每个文件包含不同的频谱。这些文件具有系统性的名称,并由“ t”,“ g +”和“ g-”组成的5个符号代码组成,即可能的文件名是ttttt.dat,g + g + ttg-.dat等。

我想批量转换所有这些,但是然后只能以交互方式绘制专门选择的那些。因此,我的想法是为每个文件创建一个单独命名的函数,即ttttt(x​​,s),g + g + ttg-(x,s)等。因为在函数名中不允许+和-,所以我替换了这些分别带有¯和_:

a = '"very/long/path/to/dir/with/files/'
filelist = system('ls '.@a")
conflist = system('ls '.@a"." | sed 's/.dat//' | sed 's/g+/g¯/g' | sed 's/g-/g_/g'")

现在,我将上面显示的代码包装在文件列表中的单词上的循环中。第一次尝试的结果是,所有函数看起来都相同,并且包含按字母顺序排列的最后一个文件的参数,因为每个循环都覆盖了x%i和I%i的值。因此,我必须确保每个函数都通过包含文件名(例如x3替换为xttttt3)来引用其自身的参数。这样,定义了大约3600个变量。

do for [c = 1:words(titlelist)] {
    paramstr(N) = sprintf('stats @a/%s" every ::%i::%i u (x%s%i=$1,I%s%i=$2) nooutput',word(titlelist,c),N,N,word(conflist,c),N,word(conflist,c),N)
    do for [i=0:nlines] {eval(paramstr(i))}
    eval(sprintf("%s(x,s) = sum [i=0:nlines] g(x,value(sprintf('x%s%i',word(conflist,c),i)),s,value(sprintf('I%s%i',word(conflist,c),i)))",word(conflist,c)))
}

但是,在致电时plot ttttt(x,s=5)会收到错误消息undefined variable: c将c设置为1到30之间的某个值后,每个函数显示相同的频谱,即与文件列表的第30个条目相对应的频谱。在这一点上,我的想法不多了。有没有人对如何从类似的命令中获得正确的结果提出建议plot tttg¯t(x,s), tg_g¯ttt(x,s), ttttt(x,s)

编辑:问题是由的错误嵌套引起的sprintf嵌套sprintfs的改组和字符串的仔细串联导致正确的工作调用:

eval(sprintf("%s(x,s) = sum [i=0:nlines] g(x,value('x%s'.i),s,value('I%s'.i))", word(conflist,c),word(conflist,c),word(conflist,c)))

显然,这是写得很差,麻烦,几乎无法理解并且绘图很慢的。我将不胜感激更优雅的解决方案!

埃尔德拉德

同时,我自己想出了一个解决方案。Gnuplot在迭代绘图方面相当慢,这就是为什么用显式和代替高斯的迭代求和是有益的。这是通过将迭代“外包”到来完成的bash,该创建了Spectrum.gpgnuplot的输入文件

#!/bin/bash
for FILE in $(ls *.dat); do
NAME=$(echo $FILE | sed 's/.dat//')
echo "${NAME}(x,s) = \\" >> Spectrum.gp
awk -v str1="g(x," -v str2=",s," -v str3=") + \\" '{print str1 $1 str2 $2 str3}' $FILE | sed '$ s/ + \\//g' >> Spectrum.gp
done

sed -i "1i s = 0.8" Spectrum.gp
sed -i "1i g(x,x0,s,I) = expo(x,x0,s)**2>50 ? 0 : I/sqrt(2*pi*s**2)*exp(-2*expo(x,x0,s)**2)" Spectrum.gp
sed -i "1i expo(x,x0,s) = (x-x0)/(2*s)" Spectrum.gp

生成的文件如下所示(假设我有两个文件molecule1.datmolecule2.dat每个文件有5行:

expo(x,x0,s) = (x-x0)/(2*s)
g(x,x0,s,I) = expo(x,x0,s)**2>50 ? 0 : I/sqrt(2*pi*s**2)*exp(-2*expo(x,x0,s)**2)
s = 0.8
molecule1(x,s) = \
g(x,73.9,s,7.2) + \
g(x,137.37,s,6.2) + \
g(x,218.33,s,3.3) + \
g(x,292.3,s,2.0) + \
g(x,407.94,s,1.0)
molecule2(x,s) = \
g(x,85.3,s,1.2) + \
g(x,150.2,s,5.2) + \
g(x,151.3,s,3.7) + \
g(x,370.3,s,2.3) + \
g(x,401.0,s,9.0)

然后将文件加载到gnuplot中load Spectrum.gp,然后是plot molecule1(x,s)使用这种方法,Spectrum.gp的生成以及绘图只需不到一秒钟的时间。

如果有人对高斯的定义感到疑惑:高斯离中心很远,则接近于零,因此,只要指数内的项大于合理猜想的阈值,总值就将精确设置为零,从而节省了计算量花费一点。

我希望这会帮助那里的任何人。

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章