Arduinoによる放射線データ収集(1)

GM管の入手が比較的できるようになってきた。回路の解説はいくつもあり、回路の設計は得意ではないので他にお任せしてArduinoによる活用についてまとめておきたい。
基本的な考え方はGM管に高電圧をかけておくと、放射線によって気体中で電離して生じるイオンが微小な電流として検知できることです。電流が流れることはGM管の電圧変化に表れ、それをLEDや圧電スピーカで知覚できるようにしています。

市販のガイガーカウンタの改造はおすすめせず、キットなど回路が公開されるなどして、パルスの出所がわかることが前提です。
ガイガーカウンタで単に音がなる、LEDが点滅するというレベルから
(0)パルスをカウントして統計を取る
(1)USB(シリアル)でPCに情報を送る
(2)LCDで情報を表示する
(3)ethernetでネットに情報を送る
(4)Xbeeなど無線ネットワークで情報をPCに送る
(5)GPS情報と放射線データをヒモ付する
といったことがArduinoで容易にできます。

私が最初に入手したGM管は”ちっちゃいものくらぶ”さんの
http://tiisai.dip.jp/?p=766
で、そこに提供されているスケッチと、そのもとになったBroHogan氏の
https://sites.google.com/site/diygeigercounter/software
を参考にし、利用改変しています。
この回路はツェナーダイオードで電圧を調節しているため、電圧の微調節が不要で部品さえ入手すれば割と簡単です。(200Vのツェナーは秋葉原にはなさそうです)

Owly Images
ブレッドボードにArduinoの基本回路とシリアルだけつないだものを用意し、ガイガーの出力をD2ピンへつないでいる。

今回は(0),(1)について書きます。

パルスをArduinoでカウントする方法としてはINT0(D2),INT1(D3)の割り込みが使えます。
陰極のパルスを利用する場合はFALLINGの割り込みで、
attachInterrupt(interrupt, function, mode)という関数を利用できます。
interruptとしてはATmega328pでは0(D2),1(D3)の2つが使え、Megaでは4ピンあります。
functionは割り込みが起こったときに呼び出すcallback関数を別に用意しておきます。
modeは割り込みの種類でLOW,CHANGE,RISING,FALLINGのいずれか。
そこでガイガーカウンタからの下向きパルスをD2に接続した場合は
attachInterrupt(0, GetEvent, FALLING);
を起動時(setup)に呼んでおきます。

また、PCでカウント数を見るためにシリアル通信を使います。
まず最低限のプログラムとしては次のようになる。

unsigned long count = 0;

void setup()
{
  Serial.begin(9600);
  Serial.println("### geiger counter started. ###");
  attachInterrupt(0, GetEvent, FALLING);
}

void loop()
{
}

void GetEvent()
{
  count++;
  Serial.println(count);
}

このままではcountがオーバーフローしてしまうので、時間で区切ってやる必要があります。
CPM(count per minitutes)を文字通り測るには60s=60000ms間カウントし、ゼロリセットする必要があります。60秒は長いので短い時間測って予測するということも通常はされますが、count数が3桁とか多い場合はそれで構いません。バックグラウンドの場合は誤差(カウント数の平方根程度)が大きいのでできれば5分測って1分あたりに換算するようにした方がよいと思います。
以下ではPERIODで計測時間を決めています。

#define PERIOD  60000

volatile boolean newEvent = false;
unsigned long count = 0;
unsigned long startTime, startPeriod, samplePeriod;
unsigned long currCnt, CPM, sum;
float average, var, stdev;

void setup()
{
  Serial.begin(9600);
  samplePeriod = PERIOD;
  
  attachInterrupt(0, GetEvent, FALLING);
  startTime = millis();
  startPeriod = startTime;
  Serial.print("### geiger counter started.");
}

void loop()
{
  if (millis() > startPeriod + samplePeriod) ProcCounts();
  if (newEvent) {
    currCnt++;
    newEvent = false;
  }
}

void GetEvent()
{
  newEvent = true;
}

void ProcCounts()
{
  CPM = currCnt;
  currCnt = 0;
  startPeriod = millis();
  Serial.print(startPeriod);
  Serial.print(" ");
  Serial.println(CPM); 
}

統計処理はいろいろな考えがあるが、データを残すためにマイコンでは1分おきのデータを出力し、
それをファイルに落としてパソコン側でやることにしている。
以下はrubyでシリアルポートにアクセスして、MAXDATA=100個データを取ったらファイルに保存するだけのコード。
serialportをgemでインストールしている。

#!/usr/bin/ruby

require 'rubygems'
require 'serialport'

#port = "/dev/cu.usbserial-???"
port = `ls /dev/cu.usbserial*`.chomp // これはmacの場合、環境に合わせる

MAXDATA=100
num = 0
sp = SerialPort.new(port, 9600, 8, 1, SerialPort::NONE)
open("gm.txt", "w") do |fo|
  while num <= MAXDATA && line = sp.gets  do 
    date = Time.now.to_i
    fo.puts "#{date} #{line}"
    puts "#{date} #{line}"
    num += 1
  end
end
sp.close

UNIX timeで記録してあるが、日付に直すには
Time.at(date)でSUN May 29 16:34:46 +0900 2011のような表記に戻せる。
そして取っておいたデータのバラつきを見るために初歩的な統計処理をしてみる。

#!/usr/bin/env ruby
sum, sum2, num=0.0, 0.0, 0
ARGF.each do |f|
  next if /^#/ =~ f
  date, cpm = f.chomp.split //データのフォーマットに合わせる 
  cpm = cpm.to_i
  sum += cpm
  sum2 += cpm*cpm
  num += 1
end
avg = sum/num
var = sum2/num - avg*avg
stdev = Math.sqrt(var)
printf("# of data: %d, average: %7.2f, var: %7.2f, stdev: %7.2f\n", 
       num, avg, var, stdev)

このようにして平均値、分散、標準偏差を求めることができるので、
一度GM管のバラつきをみておいた方がよいと思う。

(追記)
統計処理のフリーソフトでRが最近注目されている。
Rを起動した後、
getwd()で現在のディレクトリを表示。setwd()でディレクトリを移動する。
gm.datというファイルにCPMのデータだけが入っているとして、

x<-read.table("gm.dat")

でxという配列にデータを読み込み、

hist(x[[1]])

でヒストグラムを表示できたりする。
また、平均、標準偏差は

mean(x)
sd(x)

で計算できる。
(例)J408γのあるサンプル10秒間隔の測定を100回のデータを取り、10秒のデータを6倍にしてCPM換算したものと
10秒のデータ6個の和でCPMにしたものを比較
10秒測定でCPMを求めた場合では
98±24
60秒測定でCPMを求めた場合では
97±10
となった。J408γは感度がよい方だが、短時間では誤差が大きいことがわかる。

しかし、10秒測定でも1000個データを取ってみると以下のようにきれいなポアソン分布になっていた。

広告
カテゴリー: Arduino, AVR
Arduinoによる放射線データ収集(1)」への2件のコメント
  1. 根本千恵 より:

    上のコメントを残したものです。メールアドレスが間違っていました。こちらが正しいアドレスです。すみませんでした。

    大学の授業で放射線量を自動で測定し線量マップを作る機械を作っています。
    現在ラジコンに操縦用のarduinoを積んでいて、線量や方向などのデータをその一つのarduinoに集めてXbeeでパソコンに一括で送ろうと考えています。
    geigerduino standardで測った線量もそのarduinoに送る必要があるのですが、
    geigerduino standardともう一つのarduinoをジャンパー線などでつないでデータを送ることは可能でしょうか?もし可能ならやり方を教えていただけないでしょうか。

    • stastaka より:

      geigerduinoのことは正確にはわかりませんが、既に処理されたCPMとかを送るだけなら、
      シリアル通信(UART)で送るのが楽だと思います。geigerduinoのTXともう一台のRXをつないで、
      geigerduino側
      Serial.println(cpm);
      別のarduino側
      int data = Serial.read();
      詳しくは http://arduino.cc/en/Serial/Read
      これだとバイト毎なので、改行まで読み込む
      http://arduino.cc/en/Tutorial/SerialEvent
      とかで送ることはできます。
      しかしXBeeを使っているとすれば、シリアルは塞がってますよね。
      だとすると、
      1. Leonardoだとシリアルが2本ある(SerialとSerial1)あるいはMega
      2. Software Serialを使う
      詳しくは http://arduino.cc/en/Reference/SoftwareSerial
      というのがシリアル通信の場合でしょうか。
      それ以外だとI2CとかSPIという手もありますが、手続はシリアルより低レベルで面倒になります。

コメントを残す

以下に詳細を記入するか、アイコンをクリックしてログインしてください。

WordPress.com ロゴ

WordPress.com アカウントを使ってコメントしています。 ログアウト / 変更 )

Twitter 画像

Twitter アカウントを使ってコメントしています。 ログアウト / 変更 )

Facebook の写真

Facebook アカウントを使ってコメントしています。 ログアウト / 変更 )

Google+ フォト

Google+ アカウントを使ってコメントしています。 ログアウト / 変更 )

%s と連携中

カテゴリー
2011年5月
« 3月   6月 »
 1
2345678
9101112131415
16171819202122
23242526272829
3031  
%d人のブロガーが「いいね」をつけました。