Pythonによるローカルアプリ開発
Cosmo-Zには標準でPython2(2.7.15)とPython3(3.6.5)がインストールされています。
このページではPython3でctypesというライブラリを使って、Cosmo-Zのローカルで動作するアプリを作成する方法について解説します。
インストール
最初に cosmoz-python-api.tgzをダウンロードし解凍して libcosmoz.so と、cszapi.pyを取得します。
wget https://cosmoz.jp/files/cosmoz-python-api.tgz
tar -zxvf cosmoz-python-api.tgz
※これらのファイルは 2023/8/13 時点ではβ版であり、Cosmo-Z APIの一部の関数しか実装されていません。将来大幅に更新される可能性があります。
最初のプログラム
最初に以下のようなプログラムを作成し、csztest.pyという名前で保存します。
import ctypes INTERFACE_ZYNQ = 1 csz = ctypes.cdll.LoadLibrary("./libcosmoz.so") csz.csz_xadc_tempe.restype = ctypes.c_double print ("Open status = %d" % csz.csz_open(INTERFACE_ZYNQ,None)) print ("Temperature = %f " % csz.csz_xadc_tempe())
作成したcsztest.pyとlibcosmoz.soを同じディレクトリに配置し、python3の引数として実行します。
python3 csztest.py
結果は以下のように表示されます。
root@cszmini:/home/share# python3 csztest.py Open status = 1 Temperature = 63.120428
ADコンバータの値を読む
次にADコンバータの値を単純に読みだして表示するプログラムを作成します。
import ctypes INTERFACE_ZYNQ = 1 csz = ctypes.cdll.LoadLibrary("./libcosmoz.so") # 関数の引数と戻り値の型指定 csz.csz_xadc_tempe.argtype = None csz.csz_xadc_tempe.restype = ctypes.c_double csz.csz_adc_val.argtype = ctypes.c_int csz.csz_adc_val.restype = ctypes.c_uint32 # Cosmo-Zをオープンする csz.csz_open(INTERFACE_ZYNQ,None) for ch in range(4): print ("CH%d" % (ch + 1),end="\t") print () # 計測値を表示 for ch in range(4): print ("%d" % csz.csz_adc_val(ch + 1),end="\t") print () # ドライバを閉じる csz.csz_close();
このプログラムではcsz_adc_val(ch)という関数を使用しています。この関数は指定されたチャネルのADCの値を読むことができます。
前のプログラムと同様に
python3 csztest.py
で実行します。実行結果は次のとおりです。
root@cszmini:/home/share# python3 csztest.py CH1 CH2 CH3 CH4 8599 8712 7962 4573
ADC値の換算方法
csz_adc_valで返される値は生のADC値です。ADCが12bitの場合は0~4095、14bitの場合は0~16383、16bitの場合は0~65535となります。これを電圧に換算するには、
計測電圧 = (ADC値/分解能) * (最大電圧 - 最小電圧) + 最小電圧
とします。
また、標準のハードウェアでは最大電圧は通常は0.5、最小電圧は通常は-0.5です。電圧レンジを変更している場合はこの限りではありません。
ADC値と同時に電圧を表示するように改良したプログラムの例を示します。
for ch in range(4): print ("CH%d" % (ch + 1),end="\t") print () # 計測の実行 adcval = [0 for i in range (4)] for ch in range(4): adcval[ch] = csz.csz_adc_val(ch + 1) #生ADC値表示 for ch in range(4): print ("%d" % adcval[ch],end="\t") print ("[ADC]") #電圧表示 for ch in range(4): print ("%.3f" % (adcval[ch] / 16384. - 0.5),end="\t") print ("[V]")
実行結果は以下のようになります。
root@cszmini:/home/share# python3 csztest.py CH1 CH2 CH3 CH4 8596 8716 11759 7574 [ADC] 0.025 0.032 0.218 -0.038 [V]
連続同時サンプリング
前の節で使用したcsz_adc_val()は、関数を呼び出した時点でADCの値をサンプリングしているため、複数チャネルの同時サンプリングはできません。関数を呼び出した適当なタイミングでサンプリングされるので、サンプリングされた時刻もわかりません。
同時サンプリングを行うにはcsz_capture_execute関数を使用します。この関数はデータのキャプチャを開始し、キャプチャが完了すると制御を戻します。データの取り出しにはcsz_capture_datacopy関数を使用します。csz_capture_executeとcsz_capture_datacopyの説明はC/C++によるローカルアプリ開発の説明をご覧ください。
この関数の戻り値と引数にはCAPTURE_INFOという構造体を使いますが、構造体の定義がPythonのプログラム中に入ると可読性が下がるため、cszapi.pyという別ファイルに記述しました。プログラムの先頭で
import cszapi
を実行することで、以下の関数をはじめとするCosmo-Z APIの関数が使えるようになります。
- cszapi.open・・・Cosmo-Zをオープンする
- cszapi.adc_freq・・・ADCのサンプリング周波数を変更する
- cszapi.close・・・Cosmo-Zのドライバをクローズする
- cszapi.capture_excute・・・キャプチャの開始を指示する
- cszapi.capture_datacopy・・・キャプチャしたデータをユーザの配列にコピーする
以下にサンプルプログラムを示します。
from ctypes import * import cszapi import time import datetime cszapi.open(cszapi.INTERFACE_ZYNQ, None) cszapi.adc_freq(2) time.sleep(0.1) length = 10000 info = cszapi.capture_execute(0xff, length, cszapi.CAPTRIG_AUTO, 1) data1 = (c_uint16 * length).from_buffer(bytearray(length * 2)) data2 = (c_uint16 * length).from_buffer(bytearray(length * 2)) data3 = (c_uint16 * length).from_buffer(bytearray(length * 2)) data4 = (c_uint16 * length).from_buffer(bytearray(length * 2)) cszapi.capture_datacopy(info, 1, data1); cszapi.capture_datacopy(info, 2, data2); cszapi.capture_datacopy(info, 3, data3); cszapi.capture_datacopy(info, 4, data4); print ("Capture result=%d" % info.result) print ("chmask=0x%x" % info.chmask) print ("chcount=%d" % info.chcount) print ("length=%d" % info.length) print ("trig=%d" % info.trig) print ("start_time=%s" % datetime.datetime.fromtimestamp(info.start_time)) print ("end_time=%s" % datetime.datetime.fromtimestamp(info.end_time)) print ("sampling_rate=%.0f[MHz]" % info.sampling_rate) print ("adc_freq=%d[MHz]" % info.adc_freq) print ("adc_div=%d" % info.adc_div) for i in range (10): print ("%.1f" % float(i * 12.5), end="\t") print ("%d" % data1[i], end="\t") print ("%d" % data2[i], end="\t") print ("%d" % data3[i], end="\t") print ("%d" % data4[i], end="\n") cszapi.close()
実行結果は以下のようになります。
root@cszmini:/home/share# python3 csztest.py Capture result=0 chmask=0xff chcount=8 length=10000 trig=0 start_time=2023-08-13 01:38:31 end_time=2023-08-13 01:38:31 sampling_rate=2[MHz] adc_freq=80[MHz] adc_div=40 0.0 8600 8713 4708 6013 12.5 8599 8715 5021 7125 25.0 8599 8715 5663 8354 37.5 8605 8710 6581 9597 50.0 8596 8710 7682 10715 62.5 8600 8713 8863 11613 75.0 8600 8713 10000 12195 87.5 8600 8712 10988 12402 100.0 8597 8714 11728 12218 112.5 8603 8712 12151 11658 ・・・
このプログラムを
python3 csztest.py > result.txt
として実行結果をファイルに出力し、それをWindowsのエクスプローラで開いてテキストエディタで開いてコピーペーストして、Excelに貼り付ければ波形をグラフ化できます。