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に貼り付ければ波形をグラフ化できます。