[C3.3]ヒストグラムクラス

ヒストグラムは実験データの解析の中で非常に重要な役割を果たす コンポーネントです。生データや解析の結果としての数値を用いて ヒストグラムを作っていきます。この機能をどのようにモデル化し、 クラスとして実装していくかを考えてみましょう。

[現在の実装はこう なっています。]

1.ヒストグラムを扱うモデル

まず、ヒストグラムはイベントレコードの解析を経てフィルされます。 例えば一次元のヒストグラムを考えてみましょう。横軸としてADCのチャンネル をとって、縦軸は頻度をあらわします。この場合、ヒストグラムはADCチャンネル によって規定されます。ADCチャンネルはそのヒストグラム固有のものでは なく、他のヒストグラムの規定にも使えるわけですから、このことから軸は 別個のオブジェクトとして規定することが適当であることがわかります。

ヒストグラムには配列などの記憶域と、その横軸の意味するもの、ビン、 エントリー数、オーバーフローやアンダーフローなど色々な情報が 含まれます。そのうちの「横軸の意味するもの」について考えて 見ましょう。これはある値を取るものです。それは例えばイベント データの中に含まれるADCの値です。このことから、データ収集部分で 述べたデータリストを構成するものとも関係付けられます。

同じ情報が例えばフィルするかどうかの判断に使えます。ADCの値が この範囲の時のTDCの値などを求めるとき、同じ枠組みでデータを 検査し、フィルの判断に用いることが出来ます。このように、 解析で使われる物理データとしてのオブジェクトを導入し、それを 用いてデータセレクションやヒストグラミングを行なうことにします。

イベントデータはそこに多くの物理データを含みます。そこから どのようなヒストグラムをフィルしていくかを考えてみましょう。 同じデータがいくつものヒストグラムをフィルする場合があります。 物理データとヒストグラムは1対1対応する訳ではありません。また、 物理データがいくつか取り出され、そこから相関を得てフィルが 行なわれる場合もあります。物理データとヒストグラムの他に、 データを取り出してフィルをする機能が外に存在しなければならない ことになります。「ヒストグラムをフィルするもの」という クラスを用意することが必要です。

アナリシスによっては、大量のヒストグラムを生成する必要がある ことがあります。その場合、合理的効率的にヒストグラムを管理する ことが重要になってきます。階層化された構造の中に保管したり、 意味のわかる名前で検索できたりすることが出来るようになっていなければ なりません。

1.1.ヒストグラムの規定

簡単のために一次元のヒストグラムを考えてみましょう。この場合、 ある物理量をもってフィルすることになります。物理データオブジェクトが 必要です。この物理データがはきだす物理データ要素を数値として フィルする訳ですが、ヒストグラムの最小値・最大値・ビン幅などの 情報が必要です。これは上述の議論からもわかるようにヒストグラムの 軸に伴う属性です。場合によっては複数のヒストグラムで同じ軸を 使うこともあります。このことから、ヒストグラム軸をオブジェクトと 考えるべきです。

ヒストグラムはある意味でデータ集計表です。集計表の次元としては いくつでも可能ですが、現実的な記憶域との関係から高い次元のものは 作りにくいので、当面1から3次元くらいのものを考えましょう。この ことからヒストグラム本体は

といった情報を保持する必要があります。現在の実装では、 ヒストグラムは に分類されて構成されています。各々は入出力が可能なように、 KonoeStreamableObjectを継承して定義されています。

1.1.1.ヒストグラム記憶域

ヒストグラム記憶域は例えば単純な線形記憶域と考えることもできますし、 より複雑な実装も可能ですが、要するに一定のサイズを持ったメモリー です。整数型の記憶でも実数型の記憶でも操作方法は共通で、結果と して得られるビンの蓄積した量が実数かどうかで精度がかわるという ことです。

現在の実装では次のように継承関係が与えられています。

1.1.2.物理量スケール

記憶域は単純な連続したビンのならびですが、そのビン毎に物理量の ある値の範囲を割り当てることで蓄積された値に意味を持たせます。 例えばリニアなスケールもあればログスケールを扱うこともある でしょう。いずれの場合もある物理量の値がきまるとスケールによって ビンのオフセットが計算されます。オフセットが一度決まると、あとは 1を加えたり、ある重さで値をセットしたりする行為は記憶域にまかせ ます。

現在の実装では次のように継承関係が与えられています。

1.1.3.ヒストグラム全体の定義

一次元のヒストグラムはですから、一つの記憶域と一つのスケールで 定義できます。それ以外に、ヒストグラムに名前を付けたり、 コメントを加えたりします。

現在の実装では次のように継承関係が与えられています。

1.2.ブッキング

実際の解析ではたくさんのヒストグラムを定義する必要が出てきます。 この場合、どのようにしてそれらのヒストグラムを管理するべきでしょうか。 もっとも単純にはおのおのに名前や番号を付けてそれで管理することも 考えられますが、決して使いよいとは言えません。

解析では、おもに用いる物理データによってヒストグラムをグループに 分けることが考えられます。また、それらは相互の関係から、例えば ディレクトリ構造に配置されることが好ましいでしょう。

ディレクトリ構造をクラスとして扱うKonoeDirectoryクラステンプレートを 利用して実装します。

1.3.ヒストグラムのフィル

おのおののヒストグラム(の軸)はそれぞれ対応する物理データオブジェクト を持っています。新しい物理データが出現したとき(新しいイベントデータを 受け取ったとき)どのようにしてヒストグラムをフィルするのが効率的か 考えてみましょう。

物理データが導出されると、そのデータを使ってヒストグラムをフィルする 段階に入ります。このとき、物理データが自分のフィルすべきヒストグラムを 知っていればそれぞれをフィルしてまわればいいのですが、物理データ自身に ヒストグラムの情報を覚えさせるのは好ましくありません。そうすると、 ヒストグラムを一つ一つ調べていって必要ならフィルするのも効率的とは 言えません。また、逆にヒストグラムの方から必要な物理データを呼び出して フィルする方法もありますが、この場合、例えば相関をとるときなど 同じ処理を繰り返すことになったりして、やはり効率的でないと考えられます。

物理データでヒストグラムをフィルするという発想をそのまま受け入れると すれば、第三者が最も効率的な手順でそれを行なうというモデルが適して いるように思えます。このことにより、物理データとヒストグラムが 強く相関し過ぎることを避けることが出来ます。物理データにしてみれば ヒストグラムの実装には興味がありません。ヒストグラムにしてみれば 自分をフィルするのに最小限の情報を知りたいと思っているので、物理 データの実装の詳細は知りたくありません。

フィルをする主体は、物理データとヒストグラムの両方について 知っていなければなりません。物理データが出そろったところで、フィル 主体が起動されます。フィル主体は物理データからフィルデータセットを 抽出し、ヒストグラムのフィルメソッドを読みだします。

フィルデータセットの抽出は解析の上で非常に重要な作業です。抽出という 作業の中には、値に関する演算と、その結果を用いた論理操作・判断が 含まれます。また、それらはいくつものステップが一連の操作として カスケードに行なわれていきます。それらの手順が記述されなければ なりません。

以上の議論をもとに、次のような登場人物を考えることが出来ます。

最初の4つは物理データカテゴリーの産物で、最終的にも物理データと して渡されます。その意味ではヒストグラムフィル主体は、 を知っておればよいことになります。

プログラミングの詳細に行く前に問題を良く分析することが必要なことは いうまでもありません。特にオブジェクト指向プログラミングの場合 そこにある「もの」をいかに的確に認識するかということがポイントに なります。プログラミングが問題解決の方法であると考えると、問題の うらに隠れている「もの」の発見がソフトウエア設計(クラス設計)の もっとも重要な仕事になります。

2.実装

現在の実装については こちら を見てください。

2.1.ヒストグラムの定義

2.2.ヒストグラムブッキング

ヒストグラムのブッキングは

2.3.フィル機構

ヒストグラムカテゴリーにあってフィル機構を実現するために必要なクラスは 次のようになります。

2.3.1.KonoeFillData

これはヒストグラムのフィルメソッドに渡されるデータを表すものです。 現在の実装ではKonoePhysicalValueのオブジェクトがfillの渡されて いますが、上述の議論でこれはあまりスマートではありません。それで このクラスを導入します。

class	KonoeFillData	{
public :
	KFloat	getX( );
	KFloat	getY( );
	KFloat	getZ( );
};

これを用いて、
class	KonoeHistogramBase : ... {
public :
	virtual KInt	fill( KonoeFillData * ) = 0;
	...
}:
という風にしたいのです。

2.3.2.KonoeFillDataExtractor

物理データからフィルデータを抽出するクラスです。例えば単純な 物理データオブジェクトはいくつかのデータ要素を持っています。 データ要素は例えばADCデータのように、アドレスとデータを持っています。 extractorは、一次元のヒストグラムを埋めるにはデータだけをXの 値にいれて順に返します。二次元の場合、Xにアドレス、Yにデータを いれて順に返すかも知れません。また、多重度を返して欲しい場合も あるでしょう。
class	KonoeFillDataExtractor	{
public :
	KonoeFillDataExtractor( KonoePhysicalValue * value, KInt manner );
	KInt	getDataCount( );
	KonoeFillData	* next( );
};
とかを考えてみましょう。コンストラクタで物理量と振る舞いを指定しています。 フィルの際、順にフィルデータを取り出す機構が想像できると思います。

2.3.3.KonoeHistogramFiller

ヒストグラムをフィルする主体です。
class	KonoeHistogramFiller	{
public :
	KonoeHistogramFille( KonoeHistogramBase * histogram,
		KonoeFillDataExtractor * extractor );
	KInt	fill( );
};
コンストラクタで抽出器とヒストグラムを結び付けます。そうすると fillメソッドを呼ぶだけでヒストグラムがフィルされます。

抽出器やフィル主体は必要な情報をコンストラクタで得ています。それによって 最初にコンフィギュレーションをおこなうだけで、ユーザはフィルを直接 記述する必要がなくなります。汎用性のあるコードを意識しています。

2.3.4.KonoeHistoFillerList

フィル主体一つは一つのヒストグラムをフィルします。もちろん複数を 扱うものを考えても構いませんが。さて、フィル操作はどうやって 起動されるかと言うと、例えばイベントレコードがソケットやファイルから 読み込まれ、KonoeSectionAnalyzerが解析をおこなってKonoePhysicalValue に変換し終わったタイミングでフィルにいきます。この時に呼ばれるべき フィル主体のリストを用意します。単純なリストで構わないので、 KonoeListを継承します。
class	KonoeHistoFillerList
		: public KonoeTree < KonoeHistogramFiller * > {
public :
	KInt	fill( );
};
まずFillerListを生成し、個別のFillerをaddしていきます。これで準備は 終わりです。フィルすべきタイミングでこのリストのfillメソッドを 呼ぶと、一つづつとりだしてfillを呼ぶことになります。


[classes/histogram.html] Last Modified : 05-Feb-1998.

KONOEコラボレーション konoe-req@konoe.kek.jp