だいぶ一般的になっている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とは限らないかららしい。
で、人力でしようとしていたんだけど、どうにもこうにも仕様と合わない、、、クッソー何か間違っているかもしれない。
0 件のコメント:
コメントを投稿