だいぶ一般的になっているBLEについて。すごく概念的なことはあちこちに書いてある。が、下から上まで(むしろ下だけ)知りたいのに、資料少なすぎ。なので自力で調べる無茶な挑戦。第2回=アドバタイズ波形を復号する
さて、前回アドバタイズ波形を観測してAccess Addressっぽいの得られたので、残り全部を数字に変えていく。
今回のBLEモジュールは1Mbpsでデータを送っているはずで、サンプリングが56MS/sなので、56回に1回データを取得すればいいことになる。で、その56カウントのゼロをどこから開始するのかってのが課題となるけど、まぁ業界の人はささっとやっちゃうんだろう。で、方針は
・適当にカウントを初めて、エッジが来たところでカウンタをゼロにする
・カウンタがTOP値になったらカウンタをゼロにする
・カウンタのTOP値は56-1なので(ゼロもカウントするから)、その半分の値int((56-1)/2)で値を保存する※
(※実際はint((56-1)/2)になる配列番号を抽出して、その番号の値を取り出す...numpyらしいやり方)
で、コードはこんな感じ(前回のコードに対して、2値化を反転して、値を抽出するってのを追加した)
で、コンソールへの出力はこうなる
・カウンタのTOP値は56-1なので(ゼロもカウントするから)、その半分の値int((56-1)/2)で値を保存する※
(※実際はint((56-1)/2)になる配列番号を抽出して、その番号の値を取り出す...numpyらしいやり方)
で、コードはこんな感じ(前回のコードに対して、2値化を反転して、値を抽出するってのを追加した)
-
import numpy as np
-
import matplotlib.pyplot as plt
-
from scipy import signal
-
-
f_sym=1e6 #
-
rx=np.load('o_rx_t.npy')
-
t=np.load('o_t.npy')
-
#rx=rx[235500:248000]
-
#t=t[235500:248000]
-
#rx=rx[208500:228500]
-
#t=t[208500:228500]
-
rx=rx[32800:54800]
-
t=t[32800:54800]
-
t=t-t[0]
-
t_0=t[:-1:]
-
t_1=t[1::]
-
t_samp=np.mean(t_1-t_0)
-
f_samp=1/t_samp
-
print(f_samp/1e6) # should be 56MHz
-
-
# フィルター係数生成
-
freq_cutoff=f_sym*2
-
w_cutoff=freq_cutoff/(f_samp/2)
-
b,a=signal.butter(1,w_cutoff,'lowpass')
-
-
# フィルター適用
-
rx=signal.lfilter(b,a,rx)
-
-
# demod
-
rx_t0=rx[:-1:]
-
rx_t1=rx[1::]
-
rx_dem=-1*np.angle(rx_t1/rx_t0)
-
rx_dem=np.append(0,rx_dem)
-
# normalization
-
rx_dem=rx_dem/(f_sym/f_samp*np.pi*1)
-
# digitization
-
rx_dig=np.where(rx_dem>0,0,1)
-
-
# counter top value
-
counter_top=56-1
-
counter_half=int(counter_top/2)
-
cnt_list=[]
-
cnt_list.append(int(0))
-
for i in range(rx_dig.size-1):
-
dig_pres=rx_dig[i+1]
-
dig_prev=rx_dig[i]
-
if (dig_pres!=dig_prev):
-
cnt_list.append(int(0))
-
else:
-
if (cnt_list[i]<counter_top):
-
cnt_list.append(cnt_list[i]+int(1))
-
else:
-
cnt_list.append(int(0))
-
cnt=np.array(cnt_list)
-
smp_pos=np.where(cnt==counter_half)[0]
-
rd_dig_smp=rx_dig[smp_pos]
-
print(rd_dig_smp)
-
-
fig=plt.figure()
-
fig.add_subplot(3,1,1)
-
plt.plot(np.real(rx))
-
plt.plot(np.imag(rx))
-
fig.add_subplot(3,1,2)
-
plt.plot(rx_dem)
-
plt.ylim(-1,1)
-
fig.add_subplot(3,1,3)
-
plt.plot(rx_dig)
-
plt.plot(smp_pos,rd_dig_smp,linestyle='',marker='.')
-
plt.ylim(-0.5,1.5)
-
fig.tight_layout()
-
plt.show()
[1 1 1 1 1 1 1 1 1 1 0 1 0 1 0 1 0 1 0 1 1 0 1 0 1 1 0 1 1 1 1 1 0 1 1 0 0
1 0 0 0 1 0 1 1 1 0 0 0 1 1 0 1 1 0 0 0 1 1 1 0 0 1 1 1 1 1 0 1 1 1 0 0 0
1 0 0 0 0 0 1 0 0 1 1 0 0 0 0 1 1 0 1 1 1 0 0 1 1 1 0 1 1 0 0 0 0 0 0 0 1
1 0 0 1 1 1 0 1 1 1 0 0 0 0 0 1 1 0 0 1 1 1 0 1 0 0 0 1 0 0 1 1 0 1 0 1 0
0 0 1 0 0 1 0 0 1 1 1 1 0 0 1 0 0 1 0 1 1 0 0 1 0 0 1 0 1 1 1 0 1 0 0 0 0
1 0 0 0 0 0 1 0 0 0 1 1 1 0 1 1 0 0 0 1 1 1 0 0 0 1 0 0 0 1 0 0 0 1 0 1 1
0 0 1 1 0 1 1 0 1 1 1 0 1 0 1 1 0 1 1 0 1 0 1 0 0 1 0 1 1 0 0 1 1 0 0 1 0
1 0 1 0 0 1 1 1 1 0 1 0 0 0 1 0 0 1 0 0 0 0 1 0 1 1 1 1 1 0 0 0 1 1 1 0 1
1 1 1 1 0 0 0 1 1 0 1 1 0 0 0 1 0 1 0 0 1 0 1 1 0 1 1 0 1 0 1 0 1 0 0 0 1
1 0 0 1 0 0 1 0 1 0 1 0 0 0 1 1 0 1 0 1 0 0]
で、グラフはこうなる
一番下のグラフが2値化した波形と、そのどの時点を値として取り込んだのかを示していて、拡大すると、こうなっている
まぁうまくいってそう。で、これをさらに8bitごとにLSBファーストで16進数化すればいいんだけど、どこまでがプリアンブルなのかとかを自動検出するコードを書くのがメンドクサイ(今回はプリアンブルとAccess
Addressの相関が最大となる位置を探すだけなんだけど、それすらメンドクサイおじさんなのです)ので、この後は人力でやる。ちなみに8bitのことを1byteっていうことがあるけど、Bluetoothの世界では1octっていうらしい。byteはシステム依存で1byte=8bitとは限らないかららしい。
で、人力でしようとしていたんだけど、どうにもこうにも仕様と合わない、、、クッソー何か間違っているかもしれない。
コメントをお書きください