Open28
Red Pitaya の調べ物
Red Pitaya
- (教育用の)シングルボードコンピュータ
- 加速キッチンの宇宙線測定で利用している
Qick Start
- 型番を確認する。電源はちゃんと確保したほうがよい
- Red Pitayaをルーターに接続する。DHCPでIPが振られる
- OSをセットアップ。SDカードでインストールする
- ケースを組み立てる(任意)
ドキュメント迷子
- ドキュメントを探すのが結構大変・・・
- とりあえず上のドキュメントが参考になった
- 2.3.5 List of supported SCPI & API commandから使えそうなAPIを名前から推測する
- このサンプル( 2.3.6.4.1. Triggering with a threshold on channel}})をベースにAPIを手当たりしだい試す
- 一般的なDAQの手順がわかっていれば、思った通りに動く印象
加速キッチン
- 素粒子物理学の研究者たちではじめた、中高生向けの教育支援プロジェクト
- 参加希望者に小型の宇宙線検出器(Cosmic Watch + RedPitaya)を配布し、生徒の希望に沿った実験・実習をサポートする
- 研究者や大学生メンターが定期的にサポートする体制
- (不定期だけど毎年数回?)宇宙線測定体験会を実施している
Red Pitaya STEMlab の使い方
- アナログ信号入力: 2ch / 125Msps / 10bit / ADC AD9608
- アナログ信号出力: 2ch / 125Msps / 10bit / DAC AD9767
- FPGA
- LAN接続
- OS: RedPitaya OS
- Python (Jupyter) 内蔵
Red Pitaya の Pythonパッケージ
- 7年くらい前に作られたパッケージのよう。ビルドの仕方が古い
- Sphinxみたいなドキュメントもない
-
docs
フォルダはあるので、その中の.rst
ファイルを見ればよさそう
PYNQ
- Python productivity for Zynq
- FPGAを操作するPythonパッケージ?
- RedPitayaのコードの参考になるかも
- 最近はあまり開発されてないっぽい?
オシロスコープの信号を取得する
- 上のサンプルを読んでみる
- Red Pitayaで生成した信号を output から出力し、inputで受け取るセットアップ
- 信号生成は別のスクリプト
from redpitaya.overlay.mercury import mercury as overlay
fpga = overlay()
- 最初にやること
-
mercuryクラスを
overlay
という名前で読み込む -
fpga = overlay()
でmercury
オブジェクトを作成する
osc
)オブジェクトを作成する
オシロスコープ(osc = [fpga.osc(ch, 1.0) for ch in range(2)]
- チャンネルごとにインスタンスを作成する
-
osc
->osciloscopes
とかinputs
のようにリストであることが分かるように複数形で書くのが好み
-
fpga.osc(index: int, input_range: float)
# index: チャンネル番号;0か1を指定できる
# input_range: 入力レンジの設定;lo or hi を切り替える
- 当該ソースは以下の部分
オシロスコープのチャンネルを初期化する
for ch in osc:
# data rate decimation
ch.decimation = 1
# trigger timing [sample periods]
N = ch.buffer_size
ch.trigger_pre = 0
ch.trigger_post = N
# osc[0] is controlling both channels
ch.sync_src = fpga.sync_src["osc0"]
- チャンネルごとに初期化する
-
ch
はoscクラスオブジェクト
-
- デシメーションを1に設定(デフォルトは0になってるみたい)
- ch.decimation (redpitaya.drv.osc_fli)
- サンプリングレート (redpitaya.drv.osc)をダウンサンプルするのに使われる(アップサンプルも指定はできるのかな?)
- バッファーサイズのデフォルトは
2**14
- トリガー前後のサンプル数を設定する
- trigger_pre (redpitaya.drv.acq): トリガー前のサンプル数を0以上の整数値で設定する。(エラー処理あり)
- trigger_post (redpitaya.drv.acq): トリガー後のサンプル数を0以上の整数値で設定する。(エラー処理あり)
- チャンネルの動作の基準を
fpga.sync_src["osc0"]
にする
トリガーを設定する
# trigger level [V], edge ['neg', 'pos']
# hysteresis is used to avoid triggering on wrong edge with noisy signals
# trigger on 0.5V but do not trigger again
# unless signal first falls below 0.45V
osc[0].level = [0.45, 0.5]
osc[0].edge = 'pos'
# trigger on -0.2V but do not trigger again
# unless signal first rises above -0.15V
osc[1].level = [-0.2, -0.15]
osc[1].edge = 'neg'
- それぞれのチャンネルのトリガーレベルを設定する
- トリガーの値
- トリガーする向き(
neg
=立ち下がり orpos
=立ち上がり)
for ch in osc:
ch.trig_src = fpga.trig_src["osc1"]
- トリガーの基準とするチャンネルを設定する
測定する(シングルイベント)
# reset and start
osc[0].reset()
osc[0].start()
# wait for data
while (osc[0].status_run()): pass
print ("triggered")
- マスターとしたチャンネルに対して
reset()
→start()
を実行する - トリガーがかかるまで
while
ループする - トリガーがかかったら
triggerd
と表示される -
osc
オブジェクトに波形データが保存されている-
osc.data()で波形データを取得できる(
NDArray
型で保存されているっぽい) - 引数にバッファーサイズ(=サンプリング数)を設定できる
-
osc.data()で波形データを取得できる(
波形データを描画する
import matplotlib.pyplot as plt
# show only the part of the buffer requested by pre/post trigger timing
for ch in osc:
data = ch.data(N)
plt.plot(data)
plt.show()
-
osc
オブジェクトにある波形データをチャンネルごとに描画する-
ch.data() -> np.array
なので、Pandasに食べさせてもよさそう - CSVまたはJSON形式で保存する
-
- ここでは描画に
matplotlib
を使っている
波形データを保存する
names = ["x", "y"]
fname_prefix = "measured_測定日時"
for ch in osc:
_data: np.array = ch.data()
data: pd.DataFrame = pd.DataFrame(_data, columns=names)
fname = f"{fname_prefix}_{ch}.csv"
data.to_csv(fname, index=False)
fname = f"{fname_prefix}_{ch}.json"
data.to_json(fname, orient="records")
- チャンネルごとに波形データをファイルに保存する
-
ch.data()
がnp.arrayなので、そのままpd.DataFrameに変換する - カラム名は
x
とy
にする(よりデータに適した名前にする)
-
- CSVとJSONに変換する
- 測定日時をデータにも入れておく?
_data1: np.array = osc[0].data
_data2: np.array = osc[1].data
ch1 = pd.DataFrame(_data1, columns=["x", "ch1"])
ch2 = pd.DataFrame(_data2, columns=["x", "ch2"])
merged = pd.merge(ch1, ch2, on="x")
merged["datetime"] = 測定日時
merged.to_csv(ファイル名, index=False)
merged.to_json(ファイル名, orient="records")
- 2chしかないので、ループを回すより、直で書いてしまってもよいかも
-
["datetime", "x", "ch1", "ch2"]
というカラム名のファイルができるはず
プリセットされた設定値
入/出力チャンネルの設定
/**
* Type representing Input/Output channels.
*/
typedef enum {
RP_CH_1 = 0, //!< Channel A
RP_CH_2 = 1, //!< Channel B
RP_CH_3 = 2, //!< Channel C
RP_CH_4 = 3 //!< Channel D
} rp_channel_t;
トリガーチャンネルの設定値
/**
* Type representing Input/Output channels in trigger.
*/
typedef enum {
RP_T_CH_1 = 0, //!< Channel A
RP_T_CH_2 = 1, //!< Channel B
RP_T_CH_3 = 2, //!< Channel C
RP_T_CH_4 = 3, //!< Channel D
RP_T_CH_EXT = 4
} rp_channel_trigger_t;
デシメーションの設定値
/**
* Type representing decimation used at acquiring signal.
*/
typedef enum {
RP_DEC_1 = 1, //!< Decimation 1
RP_DEC_2 = 2, //!< Decimation 2
RP_DEC_4 = 4, //!< Decimation 4
RP_DEC_8 = 8, //!< Decimation 8
RP_DEC_16 = 16, //!< Decimation 16
RP_DEC_32 = 32, //!< Decimation 32
RP_DEC_64 = 64, //!< Decimation 64
RP_DEC_128 = 128, //!< Decimation 128
RP_DEC_256 = 256, //!< Decimation 256
RP_DEC_512 = 512, //!< Decimation 512
RP_DEC_1024 = 1024, //!< Decimation 1024
RP_DEC_2048 = 2048, //!< Decimation 2048
RP_DEC_4096 = 4096, //!< Decimation 4096
RP_DEC_8192 = 8192, //!< Decimation 8192
RP_DEC_16384 = 16384, //!< Decimation 16384
RP_DEC_32768 = 32768, //!< Decimation 32768
RP_DEC_65536 = 65536 //!< Decimation 65536
} rp_acq_decimation_t;
トリガーソースの設定値
/**
* Type representing different trigger sources used at acquiring signal.
*/
typedef enum {
RP_TRIG_SRC_DISABLED = 0, //!< Trigger is disabled
RP_TRIG_SRC_NOW = 1, //!< Trigger triggered now (immediately)
RP_TRIG_SRC_CHA_PE = 2, //!< Trigger set to Channel A threshold positive edge
RP_TRIG_SRC_CHA_NE = 3, //!< Trigger set to Channel A threshold negative edge
RP_TRIG_SRC_CHB_PE = 4, //!< Trigger set to Channel B threshold positive edge
RP_TRIG_SRC_CHB_NE = 5, //!< Trigger set to Channel B threshold negative edge
RP_TRIG_SRC_EXT_PE = 6, //!< Trigger set to external trigger positive edge (DIO0_P pin)
RP_TRIG_SRC_EXT_NE = 7, //!< Trigger set to external trigger negative edge (DIO0_P pin)
RP_TRIG_SRC_AWG_PE = 8, //!< Trigger set to arbitrary wave generator application positive edge
RP_TRIG_SRC_AWG_NE = 9, //!< Trigger set to arbitrary wave generator application negative edge
RP_TRIG_SRC_CHC_PE = 10,//!< Trigger set to Channel C threshold positive edge
RP_TRIG_SRC_CHC_NE = 11,//!< Trigger set to Channel C threshold negative edge
RP_TRIG_SRC_CHD_PE = 12,//!< Trigger set to Channel D threshold positive edge
RP_TRIG_SRC_CHD_NE = 13 //!< Trigger set to Channel D threshold negative edge
} rp_acq_trig_src_t;
トリガー状態の設定値
/**
* Type representing different trigger states.
*/
typedef enum {
RP_TRIG_STATE_TRIGGERED, //!< Trigger is triggered/disabled
RP_TRIG_STATE_WAITING, //!< Trigger is set up and waiting (to be triggered)
} rp_acq_trig_state_t;
import rp
- Red Pitaya OS 2.0からAPIがごろっと変わったみたい(たぶん)
-
import rp
でAPIが使えるようになった - メソッド名は
rp_*
ではじまるらしい- これまで調べた内容との互換性はよく分からない
import rp
print(f"Red Pitaya: {rp.rp_GetVersion()}")
print("Initialize Red Pitaya")
rp.rp_Init()
-
import rp
モジュールを読み込んだあとは、とりあえずrp.rp_Init()
する
トリガーの設定
triggers = {
rp.RP_T_CH_1: 0.35,
rp.RP_T_CH_2: 0.35,
}
for ich, iv in trigger.items():
rp.rp_AcqSetTriggerLevel(ich, iv)
check = rp.rp_AcqGetTriggerLevel(ich)[1]
- チャンネルごとに、トリガーレベルを設定できた
- データ取得用のチャンネル変数と、トリガー用のチャンネル変数が、名前がことなる点に注意する
- 実体は Enum変数なので、直接、整数値で設定してもいいのかもしれない
- 変数名を変えたのはなぜなんだろう?
- セッターとゲッターのメソッド名はペアになっている
- ゲッターは
[0, 返り値]
のようにリストで返ってくることが多いみたい - ゲッターの末尾の
[1]
は大事だった
- ゲッターは
トリガーソースの設定
# ソースを設定する
trigger_source = rp.RP_TRIG_SRC_CHA_PE # Ch1 / 立ち上がり
# trigger_source = rp.RP_TRIG_SRC_CHB_PE # Ch2 / 立ち上がり
# DAQを開始する
rp.rp_AcqStart()
time.sleep(0.1)
# DAQを開始してからトリガーソースを設定する
rp.rp_AcqSetTriggerSrc(trigger_source)
check = rp.rp_AcqGetTriggerSrc()[1]
- トリガー設定(チャンネルとレベルの設定)とトリガーソースの設定は別のもの
- トリガーソースでは「チャンネル」と「立ち上がり/立ち下がり」のトリガー条件を決める
- これもトリガーソースの変数名が別になっている
- トリガーソースはDAQを開始(
rp_AcqStart
)したあとで設定しないといけない- サンプルコードに書いてあった
ファイルシステムをリサイズする
redpitaya> $ df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 6.6G 5.2G 1.1G 84% /
tmpfs 231M 0 231M 0% /dev/shm
tmpfs 93M 4.0M 89M 5% /run
tmpfs 5.0M 0 5.0M 0% /run/lock
none 5.0M 16K 5.0M 1% /var/log
/dev/mmcblk0p1 484M 308M 177M 64% /boot
- 32GBのmicroSDカードを使っているのに、8GBくらいしか利用できなかった
-
/dev/root
が 6.6GBしか認識されてない
-
- ドキュメントを読んだらリサイズが必要と書いてあった
- これまで取得したデータをバックアップして、リサイズした
-
rsync
は使えずscp -r
するしかなかった
-
# /opt/redpitaya/sbin/resize.sh
Welcome to fdisk (util-linux 2.37.2).
Changes will remain in memory only, until you decide to write them.
Be careful before using the write command.
This disk is currently in use - repartitioning is probably a bad idea.
It's recommended to umount all file systems, and swapoff all swap
partitions on this disk.
Command (m for help):
Disk /dev/mmcblk0: 28.89 GiB, 31016878080 bytes, 60579840 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x4fbf5bff
Device Boot Start End Sectors Size Id Type
/dev/mmcblk0p1 8192 999423 991232 484M e W95 FAT16 (LBA)
/dev/mmcblk0p2 999424 15155199 14155776 6.8G 83 Linux
Command (m for help): Partition number (1,2, default 2):
Partition 2 has been deleted.
Command (m for help): Partition type
p primary (1 primary, 0 extended, 3 free)
e extended (container for logical partitions)
Select (default p): Partition number (2-4, default 2): First sector (2048-60579839, default 2048): Last sector, +/-sectors or +/-size{K,M,G,T,P} (999424-60579839, default 60579839):
Created a new partition 2 of type 'Linux' and of size 28.4 GiB.
Partition #2 contains a ext4 signature.
Command (m for help):
Disk /dev/mmcblk0: 28.89 GiB, 31016878080 bytes, 60579840 sectors
Units: sectors of 1 * 512 = 512 bytes
Sector size (logical/physical): 512 bytes / 512 bytes
I/O size (minimum/optimal): 512 bytes / 512 bytes
Disklabel type: dos
Disk identifier: 0x4fbf5bff
Device Boot Start End Sectors Size Id Type
/dev/mmcblk0p1 8192 999423 991232 484M e W95 FAT16 (LBA)
/dev/mmcblk0p2 999424 60579839 59580416 28.4G 83 Linux
Command (m for help): The partition table has been altered.
Syncing disks.
Root partition has been resized. The filesystem will be enlarged upon the next reboot
- 最初のほうに、ディスクを使用中なのでよく考えたほうがよい、みたいな警告が表示された
- しかし、途中で確認のプロンプトなど表示されす、お構いなしに最後まで実行された
- この時点では、まだリサイズされていないことを確認した
# df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 6.6G 5.2G 1.1G 84% /
tmpfs 231M 0 231M 0% /dev/shm
tmpfs 93M 4.0M 89M 5% /run
tmpfs 5.0M 0 5.0M 0% /run/lock
none 5.0M 16K 5.0M 1% /var/log
/dev/mmcblk0p1 484M 308M 177M 64% /boot
-
reboot
して、再接続する
(redpitaya) # reboot
(redpitaya) # Connection to rp-f0ad2a.local closed by remote host.
(laptop) $ Connection to rp-f0ad2a.local closed.
(laptop $ ssh rp-f0ad2a.local -l root
(redpitaya) #
// ログイン情報の表示(省略)
(redpitaya) # df -h
Filesystem Size Used Avail Use% Mounted on
/dev/root 28G 5.3G 22G 20% /
tmpfs 231M 0 231M 0% /dev/shm
tmpfs 93M 4.0M 89M 5% /run
tmpfs 5.0M 0 5.0M 0% /run/lock
none 5.0M 8.0K 5.0M 1% /var/log
/dev/mmcblk0p1 484M 308M 177M 64% /boot
-
/dev/root/
が28GBになった- 4GBくらいがシステムで使われると公式ドキュメントのどこかに書いてあった気がするので、合わせて32GBで、あってる
念のためにデータのバックアップを取得したが、問題なくそのままだった