haniwers.daq#
Data Acquisition from the OSECHI Cosmic Ray Detector.
This module handles communication with the OSECHI detector hardware and collects cosmic ray event data. It converts raw detector signals into structured event records that can be saved to files and analyzed.
What Does This Module Do?
The DAQ (Data Acquisition) module:
Opens a serial connection to the OSECHI detector
Listens for cosmic ray events (charged particles passing through the detector)
Records event data: timestamps, hit information, and environmental sensors
Saves events to CSV files for later analysis
Key Concepts for Beginners
Event: When a cosmic ray passes through the detector and triggers a measurement
Hit: Detection of the particle at one of three layers (top, middle, bottom)
ADC Value: Amplitude of the signal (0-1023 scale)
Environmental Data: Temperature, pressure, humidity from sensors
Main Classes
RealEvent : Represents a single cosmic ray event with all its measurements Stores timestamp, hit patterns, ADC values, and environmental data
Main Functions
run_daq() : Collect events for a specified duration loop_and_save_events() : Continuously collect events and save to file read_event() : Parse raw serial data into an event loop_events() : Stream events one at a time as they arrive
Example Usage
from haniwers.config import Daq
from haniwers.daq import run_daq
daq = Daq() # Load configuration
events = run_daq(daq, duration=60) # Collect for 60 seconds
for event in events:
print(f"Event at {event.timestamp}: {event.top}, {event.mid}, {event.btm}")
Module Contents#
Classes#
実イベント |
Functions#
(削除予定) |
|
データを保存するディレクトリを作成 |
|
(削除予定)データを保存するファイル名を生成する |
|
データを保存するファイル名を生成する(時刻付き) |
|
シリアル通信を開始する |
|
Write threshold to individual channel. |
|
Set threshold to individual channel. |
|
Set threshold with retries |
|
Read single event from the opened port. |
|
イベント取得ループ(回数指定) |
|
イベント取得ループ(時間指定) |
|
イベント保存ループ |
|
測定データをデータフレームに変換する |
|
Run DAQ(回数指定) |
|
Run DAQ(時間指定) |
|
メインのDAQ |
|
(削除予定)測定時間を指定してDAQを走らせます。 |
|
(削除予定)Run threshold scan. |
|
(削除予定)Run threshold scan. |
|
(削除予定)Read serial data from port. |
|
(削除予定) |
|
(削除予定)イベント保存ループ |
|
(削除予定)イベント保存ループ |
|
(削除予定) |
API#
- class haniwers.daq.RealEvent(/, **data: Any)#
Bases:
pydantic.BaseModel実イベント
OSECHIに接続したUSBポートから、シリアル通信で受け取った値を格納するためのデータクラス。 ファイルに書き出したり、
pandas.DataFrameに変換できるように自作メソッドを追加。Initialization
Create a new model by parsing and validating input data from keyword arguments.
Raises [
ValidationError][pydantic_core.ValidationError] if the input data cannot be validated to form a valid model.selfis explicitly positional-only to allowselfas a field name.- timestamp: datetime.datetime#
‘now(…)’
測定時刻。宇宙線イベントが通過した日時。タイムゾーン付きの日付オブジェクト
- top: int#
0
topレイヤーのヒット。0 - 10の値
- mid: int#
0
midレイヤーのヒット。0 - 10の値
- btm: int#
0
btmレイヤーのヒット。0 - 10の値
- adc: int#
0
topレイヤーにヒットがあったときのADC値。0 - 1023の値
- tmp: float#
0.0
BME280で測定した気温。[degC]
- atm: float#
0.0
BME280で測定した気圧。[Pa]
- hmd: float#
0.0
BME280で測定した湿度。[%]
- to_list_string() list[str]#
メンバー変数を文字列にしたリストに変換
- Returns:
list (str): データ文字列のリスト
>>> real_data = RealEvent() >>> read_data.to_list_string() ['2024-05-21 08:44:20.389786+09:00', '0', '0', '0', '0', '0', '0', '0']
- to_csv_string() str#
Comma Separated Values
メンバー変数をCSV形式(カンマ区切り)の文字列に変換します。 OSECHIから受け取ったデータを、ファイルに保存する際に使うことを想定したメソッドです。
- Returns:
str: CSV形式の文字列
>>> real_data = RealEvent() >>> real_data.to_csv_string() '2024-05-21 08:44:20.389786+09:00,0,0,0,0,0,0,0'
- to_tsv_string() str#
Tab Separated Values
メンバー変数をTSV形式(タブ区切り)の文字列に変換します。
- Returns:
str: TSV形式の文字列
>>> real_data = RealEvent() >>> real_data.to_tsv_string() '2024-05-21 08:44:20.389786+09:00 0 0 0 0 0 0 0'
- to_ltsv_string() str#
Labeled Tab-Separated Values
メンバー変数をLTSV形式(ラベルありのタブ区切り)の文字列に変換します。
- Returns:
str: LTSV形式の文字列
>>> real_data = RealEvent() >>> real_data.to_ltsv_string() 'timestamp:2024-05-21 08:44:20.389786+09:00 top:0 mid:0 btm:0 adc:0 tmp:0 atm:0 hmd:0'
- haniwers.daq.init_saved(daq: haniwers.config.Daq) None#
(削除予定)
- haniwers.daq.mkdir_saved(daq: haniwers.config.Daq) None#
データを保存するディレクトリを作成
データを保存するディレクトリを初期化します。 ディレクトリが存在しない場合は、新しく作成します。 ディレクトリが存在する場合は、そのままにします。
- Args:
daq(Daq): DAQ設定オブジェクト
- Returns:
None
- haniwers.daq.get_savef(args: haniwers.config.Daq, fid: int | str) pathlib.Path#
(削除予定)データを保存するファイル名を生成する
保存するファイル名を生成します。 DAQ設定の接頭辞(
prefix)と拡張子(suffix)の値を使って{prefix}_{連番:06}.{suffix}の形式で生成します。- Args:
args(Daq): DAQ設定オブジェクト
prefix: ファイルの接頭辞
suffix: ファイルの拡張子
n(int): ファイル番号
- Example:
osechi_data_000000.csv osechi_data_000001.csv osechi_data_000002.csv
- haniwers.daq.get_savef_with_timestamp(args: haniwers.config.Daq, fid: int | str) pathlib.Path#
データを保存するファイル名を生成する(時刻付き)
作成日を含んだファイル名を生成する。 ファイル名は、DAQ設定の接頭辞(
prefix)、ファイルを開いた時刻(pendulum.now)と 拡張子(suffix)の値を使って生成する。時刻のフォーマットは、ファイル名が分かりやすいように独自フォーマットにした。
- Args:
args (Daq): Daqオブジェクトfid (int|str): ファイル識別子
- Returns:
savef (Path): ファイル名(Pathオブジェクト)
- Examples:
ファイル数の上限を指定して、Pathオブジェクトを生成
max_files = 100 for nfile in range(max_files): savef = get_savef_with_timestamp(daq, nfile) # savefを使ったファイル処理
- Examples:
DAQを走らせると生成されるファイル名のサンプル
20240520/osechi_data_2024-05-20T12h34m56s_000000.csv 20240520/osechi_data_2024-05-20T13h53m24s_000001.csv 20240520/osechi_data_2024-05-20T14h46m23s_000000.csv // DAQを走らせ直すとリセット 20240520/osechi_data_2024-05-20T14h36m32s_000001.csv
- haniwers.daq.open_serial_connection(daq: haniwers.config.Daq) serial.Serial#
シリアル通信を開始する
シリアル通信(UART)に使うポートを準備します。
with構文で使う想定です。通信に使うUSBポート名(
device)、 ボーレート(baudrate)、 通信開始/書き込みのタイムアウト秒(timeout)は DAQ用の設定ファイルで変更できるようにしてあります。- Args:
daq (Daq): DAQ設定オブジェクトdevice: USBポート名baudrate: ボーレート(通信速度)[bps]timeout: タイムアウト秒 [sec]
- Returns:
port (serial.Serial): 通信を開始したSerialオブジェクト
- Example:
with open_serial_connection(daq) as port: # データ測定の処理 success = write_vth(port, ch, vth)
- haniwers.daq.write_vth(port: serial.Serial, ch: int, vth: int) bool#
Write threshold to individual channel.
シリアル通信(UART)を使って、チャンネルに閾値を書き込みます。 ESP32のバッファサイズの制限から、閾値は2回に分割して転送しています。
val1は vth を右に6ビットシフト(=64で割る)して、head を足した値val2は vth を左に2ビットシフト(=4をかける)して、下位8ビットを取り出した値
詳細はこの関数のソースコードを確認してください。
閾値を書き込んだあとに、値が読み出せるかを確認します。 読み出した値が
dameとなっている場合は書き込みに失敗しています。 その場合は、もういちど設定し直すよう警告を表示します。- Args:
port (serial.Serial): 接続ポート(Serialオブジェクト)ch (int): 閾値を設定するチャンネル番号vth (int): 閾値
- Returns:
success (bool): 閾値を書き込んだ結果
- Examples:
チャンネルごとに閾値を設定
success = write_vth(port, 1, 270) success = write_vth(port, 2, 281) success = write_vth(port, 3, 297)
- TODO:
ユーザーが直接あつかわない関数でよいので、 内部変数(の命名規則)に変更する(write_vth -> _write_vth)
- haniwers.daq.set_vth(daq: haniwers.config.Daq, ch: int, vth: int) bool#
Set threshold to individual channel.
シリアル通信を開始し、チャンネル番号を指定して閾値を設定します。 チャンネル番号は1 - 3 の範囲で指定してください。 閾値は1 - 1023 の範囲で指定してください。
書き込みに成功すると
success=Trueを返します。 書き込みに失敗した場合は、警告メッセージを表示します。 このとき、設定済みの閾値はそのままになります。- Args:
daq (Daq): DAQ設定オブジェクトch (int): チャンネル番号。1 - 3の範囲で指定してくださいvth (int): 閾値の値。1 - 1023の範囲で指定してください
- Returns:
success (bool): 閾値を書き込んだ結果
- Exceptions:
チャンネル番号が範囲外の場合は終了
閾値が範囲外の場合は終了
serial.SerialException: シリアル通信ができなかった場合は終了Exception: その他の予期せぬエラーの場合も終了
- Examples:
success = set_vth(daq, 1, 280) success = set_vth(daq, 2, 280) success = set_vth(daq, 4, 280) # チャンネル番号が範囲外 success = set_vth(daq, 1, 2000) # 閾値が範囲外
- haniwers.daq.set_vth_retry(daq: haniwers.config.Daq, ch: int, vth: int, max_retry: int) bool#
Set threshold with retries
閾値の書き込みに失敗した場合、成功するまで
max_retry回繰り返します。- Args:
daq (Daq): Daqオブジェクトch (int): チャンネル番号vth (int): スレッショルド値max_retry (int): リトライする最大回数
- Returns:
success (bool): 閾値を書き込んだ結果
- Examples:
# 5回繰り返す success = set_vth_retry(daq, 1, 280, 5) # 10回繰り返す success = set_vth_retry(daq, 2, 290, 10)
- haniwers.daq._read_event(port: serial.Serial) haniwers.daq.RealEvent#
Read single event from the opened port.
シリアル接続しているポートから1イベント分のデータを読み出します。 引数に指定するポートは、接続済みのポートを渡してください。 読み出したデータは適切な型に変換して、
RealEventオブジェクトに代入します。- Note:
run_daqやtime_daqでデータを取得するために使います。
- Args:
port (serial.Serial): 接続済みのSerialオブジェクト
- Returns:
event (RealEvent): 1イベント分のデータ。読み出した時刻も自動で追加される。
- Examples:
with open_serial_connection() as port: event = _read_event(port) print(event) # [pendulum.now(), top, mid, btm, adc, tmp, atm, hmd]
- haniwers.daq._loop_events_for_rows(port: serial.Serial, max_rows: int) Generator[haniwers.daq.RealEvent, None, None]#
イベント取得ループ(回数指定)
測定回数を指定してデータを読み出します。 ジェネレーター関数になっています。
- Args:
port (serial.Serial): 接続済みのSerialオブジェクトmax_rows (int): 測定回数
- Yields:
event (RealEvent): 1イベント分の測定データ(RealEventオブジェクト)
- Example:
# 100回測定する for event in _loop_events_for_rows(port, 100): print(event.to_ltsv_string())
- haniwers.daq._loop_events_for_duration(port: serial.Serial, max_duration: int) Generator[haniwers.daq.RealEvent, None, None]#
イベント取得ループ(時間指定)
測定時間を指定してデータを読み出します。 ジェネレーター関数になっています。
- Args:
port (serial.Serial): 接続済みのSerialオブジェクトmax_duration (int): 測定時間(秒)
- Yields:
event (RealEvent): 1イベント分の測定データ(RealEventオブジェクト)
- Example:
# 10秒間測定する for event in _loop_events_for_rows(port, 10): print(event.to_ltsv_string())
- haniwers.daq.loop_and_save(fname: pathlib.Path, generator: Generator) list[haniwers.daq.RealEvent]#
イベント保存ループ
指定したファイルに、1イベントずつファイルに書き足して保存します。
保存形式はファイル名の拡張子で判定します。 有効な拡張子は
[".csv", ".dat", ".tsv", ".json", ".jsonl"]です。イベントの取得方法は
generatorで指定します。 有効なジェネレーターは_loop_events_for_rowsと_loop_events_for_durationです。- Args:
fname (Path): データを追記するファイル名generator (Generator): データの取得方法。[_loop_events_for_rows,_loop_events_for_duration]から選択。
- Returns:
events (list[RealEvent]): 測定したデータのリスト
- haniwers.daq.events_to_dataframe(events: list[haniwers.daq.RealEvent]) pandas.DataFrame#
測定データをデータフレームに変換する
測定データは、データを取得するたびにファイルに書き出してますが、 同時にRealEventオブジェクトのリストとしてもストアしています。 このままだと使いにくいので、データフレームに変換できるようにしました。 そのときに、
preprocess.add_hitとpreprocess.add_hit_typeの処理もしています。 測定時刻の調整やリサンプル処理はしていません。- Args:
events (list[RealEvent]): 測定データ(RealEventオブジェクト)のリスト
- Returns:
data (pd.DataFrame): 測定データのデータフレーム
- Notes:
- haniwers.daq.run_daq(port: serial.Serial, daq: haniwers.config.Daq) None#
Run DAQ(回数指定)
OSECHIを接続したUSBポートとシリアル通信をして、データ取得する。 指定したファイル数と行数をでループ処理する。
- Args:
port (serial.Serial): 接続するポート(Serialオブジェクト)daq (Daq): 設定(Daqオブジェクト)
- Returns:
None: 測定時間が長くなると、メモリリークするかもしれないため、 1イベントのデータをファイルに書き出したあとは潔く破棄している
- Example:
run_daq(port, daq)
- haniwers.daq.scan_daq(args: haniwers.config.Daq, fname: str, duration: int) pandas.DataFrame#
Run DAQ(時間指定)
1回のランあたりの測定時間を指定してデータを取得する。 スレッショルド測定するために作ったDAQ関数です。
- Args:
args (Daq): Daqオブジェクトduration (int): 測定時間を秒で指定
- Returns:
data (pd.DataFrame): 測定結果のデータフレーム。 データフレームを次の処理に渡したいため。
- Example:
data = scan_daq(daq, fname, duration)
- haniwers.daq.run(port: serial.Serial, args: haniwers.config.Daq)#
メインのDAQ
run_daqのラッパー。例外処理などで囲んだもの。
- Versionadded:
0.6.0.
- haniwers.daq.time_daq(args: haniwers.config.Daq, duration: int) pandas.DataFrame#
(削除予定)測定時間を指定してDAQを走らせます。
- Args:
args (Daq): Daqオブジェクト
duration (int): 測定時間を秒で指定
- Returns:
data (pd.DataFrame): 測定結果のデータフレーム
- haniwers.daq.scan_ch_vth(daq: haniwers.config.Daq, duration: int, ch: int, vth: int) list#
(削除予定)Run threshold scan.
- Args:
daq (Daq): Daqオブジェクト
duration (int): 測定時間(秒)
ch (int): 測定するチャンネル番号
vth (int): スレッショルド値
- Returns:
data (list): [測定時刻、チャンネル番号、スレッショルド値、イベント数]のリストを返します。
- haniwers.daq.scan_ch_thresholds(daq: haniwers.config.Daq, duration: int, ch: int, thresholds: list[int]) list[list]#
(削除予定)Run threshold scan.
- Args:
daq (Daq): Daqオブジェクト
duration (int): 測定時間(秒)
ch (int): チャンネル番号
thresholds (list[int]): スレッショルド値のリスト
- Returns:
rows (list[list]): [測定時刻、チャンネル番号、スレッショルド値、イベント数]のリスト
- haniwers.daq._read_serial_data_as_list(port: serial.Serial) list#
(削除予定)Read serial data from port.
OSECHIが接続されているポートからデータを読み出します。 引数に指定するポートは、あらかじめ開いたものを渡してください。
run_daqやtime_daqでデータを取得するために使います。- Args:
port (serial.Serial): Serialオブジェクト
- Returns:
row (list): 読み出した時刻を追加したデータのリスト
- Examples:
>>> with open_serial_connection() as port: >>> row = read_serial_data(port) >>> row [日付, top, mid, btm, adc, tmp, atm, hmd]
- haniwers.daq.read_serial_data(port: serial.Serial) list#
(削除予定)
- haniwers.daq._loop_and_save_events(fname: pathlib.Path, port: serial.Serial, max_rows: int, suffix: str = '.csv') list#
(削除予定)イベント保存ループ
- Args:
f (typing.TextIO): 開いたファイルオブジェクトport (serial.Serial): 接続済みのSerialオブジェクトmax_rows (int): 1ファイルあたりの行数の最大値suffix (str): ファイルの拡張子
- Return:
events (list): 複数イベントの測定データ
- haniwers.daq.loop_and_save_events(f: TextIO, daq: haniwers.config.Daq, port: serial.Serial) list[str]#
(削除予定)イベント保存ループ
- Args:
f (TextIO): データを書き込むファイルオブジェクト
daq (Daq): Daqオブジェクト
port (serial.Serial): 接続済みのSerialオブジェクト
- haniwers.daq.save_serial_data(f, daq: haniwers.config.Daq, port: serial.Serial) list#
(削除予定)
- Args:
f: ファイルポインタ
daq (Daq): Daqオブジェクト
port (serial.Serial): Serialオブジェクト
- Return:
rows (list[list]): 取得したデータのリスト
- TODO:
Daqオブジェクトに依存しない関数にしたい(ジェネレーターにするのがいいのかな?)
pd.DataFrameを返した方がいいかもしれない?