Pico Tech - Peak Fit With Gnuplot Part5

Radiation Detection / Software Projects ... Peak Fit With R ... Peak Fit With Octave ... Peak Fit With Python / 日本語ページインデックス ... English Documents / 掲示板 / Peak Fit With Gnuplot

Peak Fit With Gnuplot Part5 検出器の自動特性調査編

Peak Fit With Gnuplot 最初の一歩とK40編、
Peak Fit With Gnuplot Part2 任意の単一ピーク編、
Peak Fit With Gnuplot Part3 複数ピーク+核種データ編、
Peak Fit With Gnuplot Part4 検出器の特性調査編の続編です。

他に、
Peak Fit With Gnuplot Part6 色々な関数編があります。

Gnuplotの色々な使い方は、以下のページに書いてあります。
Gnuplot Memo
Gnuplot Memo3D
Gnuplot Memo2


今回は、特性調査に使うデータを自動で取得し、その結果も自動的にプロットしよう、というものです。



まず、 Peak Fit With Gnuplot Part2 任意の単一ピーク編で作った準備用スクリプトをそのまま使います。

http://pico.dreamhosters.com/raddata/ft0.plt

次に、単一ピーク用のスクリプトを改造して、連続して複数のピークに対して調査やフィットを行い、
そのデータをGnuplotが読み込める形でファイルに書き出すようにします。

この時、 Peak Fit With Gnuplot Part3 複数ピーク+核種データ編のころから作り始めた、核種データスクリプトを利用します。

http://pico.dreamhosters.com/raddata/nlist.plt

で、単一ピーク用のスクリプトに何をしたか?といいますと、核種のリストでループするようにしたのと、
ピークをフィットする際に、どの範囲でフィットするか?というのが大事なので、それをStatsコマンドで事前調査して、
隣と被っているピークは、狭い幅でフィットし、被ってなかったら広めでフィットする、という作戦です。

尚、このスクリプトは、データの取得部分と、結果の調査、プロット部分に分かれています。
また、サイトにアップロードしてあるスクリプトは、時々改造、改良、改悪して変更されています。

まず、データ取得と書き出し部分。

http://pico.dreamhosters.com/raddata/ft3.plt




 
#======================
#検出器の特性を自動的に調査するためのスクリプト
#あらかじめ、ft0.plt を実行して準備がなされている必要があります。
#Automatic peak info checker and detector profile maker
#ft0.plt が実行されてなかったりして、ファイル名とかが定義してない場合は、ft0.pltをまず呼ぶ。 if(!exists("f") || !exists("fname") ||fname ne f){ load 'ft0.plt' }
#しつこくマクロの使用を宣言して、このスクリプトも @ft3 というコマンドで実行できるようにする。 set macro ft3='load "ft3.plt"'
#Statsコマンドなどで問題が起きない様、レンジ設定を解除 unset xrange unset yrange
#Statsコマンドなどで問題が起きない様、Log表示設定を解除 unset logscale
#何シグマまでフィットするのかを n に数字を入れて指定しますが #n が定義されていなかったり、0だった場合は、暫定的に3にしてみる。 if((!exists("n")) || n==0){ n=3}
#この変数が重要で、ピークの左右の最低地点の何倍までの範囲をフィットするかの変数 #これを変えて、色々試せます。ユーザーが定義しない場合は、0.9になります。 if((!exists("sfac")) || sfac==0){ sfac=0.9}
#核種データを読み込みます。 load 'nlist.plt'
#調査に使う核種と、そのピークを指定します。これを変えると、他の核種でやったり、 #特定のピークを入れたり、省いたり出来ます。 #また、核種データと同じ形式で、架空の名前でリストを作り、それを指定しても良いです。 peak_list='Ra226 5 2 3 4 1 7 10 11 17 21'
#ベースラインの傾きの初期値を適当に設定。 a=-0.001
#フィットの結果を変数に指定するおまじない set fit errorvariables
#調査に使用する核種の名前を変数に読み込み。 ri=word(peak_list,1)
#調査結果を書き込むファイルの名前を定義。 pfn=ri.'-dr.plt'
#ファイルを上書きモードで開き、ヘッダー部分を書き込んでリセット。 set print pfn print '# E (keV) Ig (%) ch FWHM (%) h (cps) Np (cps) a b ns0 ns1'
#調査するピークの数+1を変数にセット。 wn=words(peak_list)
#ピークの数だけループ(2から始めるので) do for[i=2:wn] { #ピーク番号をリストから抽出 nn=word(peak_list,i)
#ピーク名の変数を定義 cmd='peakname="'.ri.'_'.nn.'"' eval cmd
#そのピークのエネルギーをEに入れる。 cmd='E=word('.peakname.',1)' eval cmd
#E0にエネルギーを保存。 E0=E
#放出率をIgに設定。 cmd='Ig=word('.peakname.',2)' eval cmd
#指定されたエネルギー位置のシグマ(分解能)を計算。 s=SigE(E) s0=s
#統計機能を使って、ピークの頂点と最低点を適当に推測。カウント数で入っているデータを秒数で割って、レートで計算。 #print round(E-3*s,2),round(E+3*s,2) stats [E-3*s:E+3*s] f u 1:($2/sec) every ::HL::BGL nooutput b=STATS_min_y h=STATS_max_y-b
#bの初期値がゼロだとこけるので、その場合は、1にしておく。 if (b==0){b=1}
#統計調査の結果から、このピークの部分のおおよその傾きと平均の高さや最低の位置などを取得。 sta=STATS_slope stb=STATS_intercept a=stb stm=STATS_mean_y stmin=STATS_min_y
#ピークの傾きを打ち消す関数 bt(x)=sta*x+stb-(stm-stmin) #plot [E-3*s:E+3*s] f every ::HL::BGL u 1:($2/sec), f every ::HL::BGL u 1:($2/sec-bt($1)+stmin),bt(x),stmin
#傾きをある程度打ち消した状態で、ピークの左側の最低地点を調べる stats [E-3*s:E] f u 1:($2/sec-bt($1)+stmin) every ::HL::BGL nooutput min0x=STATS_pos_min_y min0y=STATS_min_y
#傾きをある程度打ち消した状態で、ピークの右側の最低地点を調べる #check right side for the lowest point stats [E:E+3*s] f u 1:($2/sec-bt($1)+stmin) every ::HL::BGL nooutput min1x=STATS_pos_min_y min1y=STATS_min_y
min(x)=((min1y-min0y)/(min1x-min0x))*(x-min1x)+min1y #plot [E-3*s:E+3*s] f every ::HL::BGL u 1:($2/sec), f every ::HL::BGL u 1:($2/sec-bt($1)+stmin),bt(x),stmin,min(x) #ピークの位置から左右の最低地点までの距離をシグマで割り、係数をかけてフィットする範囲を決定。 ns0=(E-min0x)/s*sfac ns1=(min1x-E)/s*sfac
#フィットの際にも、データ(カウント数)を測定秒数で割って、レートでやります。ピークの高さだけでなく、 #エネルギー位置、分解能、ベースラインの傾きと高さも、全部フィットします。 fit [E-ns0*s:E+ns1*s] g(x) f every ::HL using 1:($2/sec) noerror via h,E,s,a,b
#シグマから、FWHMを計算。 σ(シグマ) = FWHM(チャンネル幅) ÷ 2√(2ln2) なので、 fwhm=s * 2*sqrt(2*log(2)) Pfwhm=fwhm/E
peak_h_err=h_err/h*100 peak_s_err=s_err/s*100
#========================== #フィットした情報から、ピーク部分の計数率(面積)を出してみる #このガウス関数の全域の面積は、単純に、高さとσ(シグマ)から、こうなります。 #           面積 = 高さ x √(2π) x σ #これも、Gnuplotに計算してもらいます。
#σ(シグマ)は、エネルギーではなく、チャンネル数でないとならないので、 #ft0 データファイルのエネルギーのカラムを読んでフィットしたチャンネル勾配を使います。
#ピークのエネルギー位置のチャンネルは、 bE=e2b(E)
#それよりもσ(シグマ)の分だけ左のチャンネルは、 bEs1=e2b(E-s)
#なので、チャンネル数でのσ(シグマ)は、 bsig=bE-bEs1 # print "sigma(channels) = ", bsig
#なお、このシグマの計算の仕方は、厳密なものではありません。 #実用上の問題は無いと思いますが、気になる方は、両側を調べて平均を取るなり、 #両側3σの幅で調べて、6で割るなり、お好きにどうぞ。
#で、高さと定数とσ(シグマ)をかけると rate=h*sqrt(2*pi)*bsig # print "rate = ", rate
#データファイルから読み出しておいた測定秒でピークの計数を求めます。 counts=rate*sec # print "Counts = ", counts
#標準不確かさ U=sqrt(rate/sec) #ファイルを閉じて、画面に情報を書き出します。 unset print print sprintf('%f %f %f %f %f %f %f %f %f %f %f',E0+0,Ig+0,bE,fwhm,Pfwhm,h,rate,a,b,ns0,ns1)
#追加書き込みモードでファイルを開き、データを書き込みます。 set print pfn append print sprintf('%f %f %f %f %f %f %f %f %f %f %f',E0+0,Ig+0,bE,fwhm,Pfwhm,h,rate,a,b,ns0,ns1)
#使われていないプロットの残骸。 if(0){ set xr [E-8*s:E+8*s] plot f u 1:($2/sec) every ::50 with @lt @ftitle ,\ [E-ns0*s:E+ns1*s] g(x) t "Gaussian fit g(x)=h*exp(-((x-E)/s)**2/2)+a*(x-E)+b" lt rgb "red",\ [E-6*s:E-ns0*s] g(x) t "Gaussian fit g(x)=h*exp(-((x-E)/s)**2/2)+a*(x-E)+b" lt rgb "blue",\ [E+ns1*s:E+6*s] g(x) t "Gaussian fit g(x)=h*exp(-((x-E)/s)**2/2)+a*(x-E)+b" lt rgb "blue",\ [E-6*s:E+6*s] a*(x-E)+b t"baseline a*(x-E)+b" lt rgb "black" } }
#全部調査が終わったら、ファイルを閉じます。 unset print
#次の操作の為のマクロを定義して、呼び出します。 ft4='load "ft4.plt"' @ft4



次に、書き出したピークデータを読み込んで、フィットしたり、プロットする部分。
これは、もっと色々追加しても良いし、いちいち画面にプロットせずに、
PNGファイルとかを作っても良いし、校正情報や効率曲線のデータだけとっても良いし、
各自好きなようにしてください。

この例では、エネルギー校正用のフィットとプロットを、直線と二次式でやってみて、
効率曲線のフィットを、ピークの高さと、ピークの面積についてやってみてます。

一つのフィットとプロットの後、ポーズが入っていて、キーボードやマウスで
次のフィットとプロットに進みます。

ここは、基本的に、Part4でやっていたのと同じことで、それをまとめて、
ポーズを入れて、グラフの出し方とかを少し改良したものです。

http://pico.dreamhosters.com/raddata/ft4.plt




 
#フィットに使う一次関数と二次関数を定義 f1(x)=a*x+b f2(x)=a*x**2+b*x+c
#初期値を適当にセット a=0.5 b=1 c=1
#まずは、エネルギーとチャンネル番号をフィット fit f1(x) pfn u 1:3 via a,b
#プロットにグリッドを出したり、見出しを付けて、表示。 set grid set ylabel 'channel' unset yr
#フィットの結果の数値を数式に混ぜて表示。 fitt=sprintf('f1(x) = %f * x + %f',a,b)
#フィット範囲のファクターも差分のところに表示。 difft=sprintf('diff (sfac=%0.2f)',sfac)
#プロットしてポーズ。 plot pfn u 1:3 @ftitle ,f1(x) t fitt,pfn u 1:($3-f1($1)) t difft pause -1
#次は、エネルギー校正を二次式でフィット。これは、多分、平方根でやるのが正しいのかも。 a=-0.00001 b=0.5 c=1
fit f2(x) pfn u 1:3 via a,b,c
fitt=sprintf('f(x) = %f * x**2 + %f * x + %f',a,b,c) plot pfn u 1:3 @ftitle ,f2(x) t fitt,pfn u 1:($3-f2($1)) t difft pause -1
#次は、効率曲線で、ピークの高さでもってやっています。面積でやるより、この方がまとまる場合が多い。 set ylabel 'Peak hight/sec/Ig'
f(x)=(a*x+b)/(x-c) a=0.0001 b=50 c=50 fit f(x) pfn u 1:($6/$2) via a,b,c fitt=sprintf('f(x)=(%f * x + %f)/(x - %f)',a,b,c) plot pfn u 1:($6/$2) @ftitle, f(x) t fitt, pfn u 1:($6/$2-f($1)) t difft pause -1
#今度は、ピークの面積で、効率曲線のフィットをしてますが、その結果を高さに変換したりはまだしていません。 set ylabel 'Peak Rate/sec/Ig'
a=1 fit f(x) pfn u 1:($7/$2) via a,b,c fitt=sprintf('f(x)=(%f * x + %f)/(x - %f)',a,b,c) plot pfn u 1:($7/$2) @ftitle, f(x) t fitt, pfn u 1:($7/$2-f($1)) t difft
#後は、何でも好きな項目を追加したり、変更すればよいでしょう。



sfacの値を大きくしすぎると、フィットに失敗して、良いデータが取れない場合がありますし、
小さすぎても同じです。

小さすぎで上手くいかなかった例 sfac=0.2:
エネルギー校正のフィットは、まずまずですが、効率曲線の方が駄目。

大きすぎて上手くいかなかった例 sfac=2, sfac=3:
2にすると、効率曲線がグダグダ

3だと、最後のピークで大きく失敗し、エネルギー校正も外れます。

大体、0.8から1.5くらいの間でもって、まあまあのデータが取れるようです。
(手動で、一生懸命調整したのと同じ様な結果が自動的に得られます。)

ただし、まだ、いくつもの測定器のスペクトルでテストしたわけではないので、
分解能の違いなどによっては、上手くいかない可能性があります。
(初期値、というか、色々な設定は、標準的なNaI3インチに合わせてありますが、
どうにでも変更可能です。)


Peak Fit With Gnuplot Part6


Last modified : Sun Apr 19 09:19:05 2015 Maintained by nkom AT pico.dreamhosters.com