Open28

Red Pitaya の調べ物

shotakahashotakaha

Red Pitaya

https://redpitaya.com/

  • (教育用の)シングルボードコンピュータ
  • 加速キッチンの宇宙線測定で利用している
shotakahashotakaha

ドキュメント迷子

https://redpitaya.readthedocs.io/en/latest/appsFeatures/remoteControl/remoteAndProg.html

shotakahashotakaha

加速キッチン

https://accel-kitchen.com/

  • 素粒子物理学の研究者たちではじめた、中高生向けの教育支援プロジェクト
  • 参加希望者に小型の宇宙線検出器(Cosmic Watch + RedPitaya)を配布し、生徒の希望に沿った実験・実習をサポートする
  • 研究者や大学生メンターが定期的にサポートする体制
  • (不定期だけど毎年数回?)宇宙線測定体験会を実施している
shotakahashotakaha

Red Pitaya STEMlab の使い方

https://content.redpitaya.com/blog/getting-started-with-red-pitaya-stemlab

  • アナログ信号入力: 2ch / 125Msps / 10bit / ADC AD9608
  • アナログ信号出力: 2ch / 125Msps / 10bit / DAC AD9767
  • FPGA
  • LAN接続
  • OS: RedPitaya OS
  • Python (Jupyter) 内蔵
shotakahashotakaha

Red Pitaya の Pythonパッケージ

https://github.com/RedPitaya/jupyter

  • 7年くらい前に作られたパッケージのよう。ビルドの仕方が古い
  • Sphinxみたいなドキュメントもない
  • docsフォルダはあるので、その中の.rstファイルを見ればよさそう
shotakahashotakaha

オシロスコープの信号を取得する

https://github.com/RedPitaya/jupyter/blob/master/examples/osc_sync_two_channel.ipynb

  • 上のサンプルを読んでみる
  • Red Pitayaで生成した信号を output から出力し、inputで受け取るセットアップ
    • 信号生成は別のスクリプト
shotakahashotakaha
from redpitaya.overlay.mercury import mercury as overlay
fpga = overlay()
  • 最初にやること
  • mercuryクラスoverlayという名前で読み込む
  • fpga = overlay()mercuryオブジェクトを作成する
shotakahashotakaha

オシロスコープ(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 を切り替える
  • 当該ソースは以下の部分

https://github.com/RedPitaya/jupyter/blob/master/redpitaya/overlay/mercury.py#L120-L140

shotakahashotakaha

オシロスコープのチャンネルを初期化する

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"]
shotakahashotakaha

トリガーを設定する

# 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=立ち下がり or pos=立ち上がり)
for ch in osc:
    ch.trig_src = fpga.trig_src["osc1"]
  • トリガーの基準とするチャンネルを設定する
shotakahashotakaha

測定する(シングルイベント)

# 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型で保存されているっぽい)
    • 引数にバッファーサイズ(=サンプリング数)を設定できる
shotakahashotakaha

波形データを描画する

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を使っている
shotakahashotakaha

波形データを保存する

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に変換する
    • カラム名はxyにする(よりデータに適した名前にする)
  • CSVとJSONに変換する
  • 測定日時をデータにも入れておく?
shotakahashotakaha
_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"]というカラム名のファイルができるはず
shotakahashotakaha
shotakahashotakaha

入/出力チャンネルの設定

/**
 * 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;
shotakahashotakaha

トリガーチャンネルの設定値

/**
 * 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;
shotakahashotakaha

デシメーションの設定値

/**
 * 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;
shotakahashotakaha

トリガーソースの設定値

/**
 * 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;
shotakahashotakaha

トリガー状態の設定値

/**
 * 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;
shotakahashotakaha
import rp
  • Red Pitaya OS 2.0からAPIがごろっと変わったみたい(たぶん)
  • import rpでAPIが使えるようになった
  • メソッド名はrp_*ではじまるらしい
    • これまで調べた内容との互換性はよく分からない
shotakahashotakaha
import rp
print(f"Red Pitaya: {rp.rp_GetVersion()}")
print("Initialize Red Pitaya")
rp.rp_Init()
  • import rpモジュールを読み込んだあとは、とりあえずrp.rp_Init()する
shotakahashotakaha

トリガーの設定

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]は大事だった
shotakahashotakaha

トリガーソースの設定

# ソースを設定する
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)したあとで設定しないといけない
    • サンプルコードに書いてあった
shotakahashotakaha

ファイルシステムをリサイズする

https://redpitaya.readthedocs.io/en/latest/quickStart/SDcard/SDcard.html#resize-file-system

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で、あってる
shotakahashotakaha

念のためにデータのバックアップを取得したが、問題なくそのままだった