昨年末、Raspberry Pi PicoでOZ1JHMタイプのCW解読器を作ろうと思い、ArduinoのプログラムをmicroPythonに移植したのですが、まったく動きませんでした。
このタイプで利用されているCWトーン検出のためのアルゴリズム、Goetzel AlgorithmをまずArduinoで確認しました。記事はこちら。
この実験で、Goetzel Algorithmで帯域幅約200Hzのオーディオフィルタを実現していることが分かりました。
これと同じ実験をRaspberry Pi Picoでやってみました。回路図です。
ADC0を利用しますので、GPIO26に信号を入力します。
Arduinoの記事に掲載したプログラムをPico用のmicroPythonに移植したのですが、ターゲット周波数どころかどこにもmagnitudeのピークが現れません。
そこで、サンプリング周波数とターゲット周波数の関係を良く見ると、
sampling_freq=8928.0(Hz)
target_freq=558.0(Hz)
sampling_freq/target_freq=8928/558=16
ですから、ターゲットの信号1周期あたり、1000000us/8928Hz=112usごとに、16回サンプリングすることになります。
サンプル数は、n=48ですから3周期分サンプリングします。
ところで、Raspberry Pi PicoのAD変換にかかる時間を測定してみると約30usでした。ということは、サンプリング(AD変換)間隔を110usにするためには、数10usの待ち時間をとればよいのではないかと考えました。
そこで、サンプル周波数とターゲット周波数を上記のままにして、AD変換の後に40,50,60,70,80usの待ち時間を入れて、それぞれについて周波数100Hz~1000Hzの間でmagnitudeがどのように変化するかを測定してみました。
それぞれの待ち時間でmagnitudeのピークが現れました。その中で最も特性が良さそうなのが、60usの時で、特性は次のようになりました。
Arduinoの場合と同等かそれ以上に良い特性だと思います。
テストしたスクリプトです。
--------------------------------------------------------------------------------------
from machine import Pin,ADC
import utime
import math
a=ADC(0)
Q1=0
Q2=0
sampling_freq=8928.0
target_freq=558.0
n=48.0
Pi=3.14152965
testData=[0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,
0,0,0,0,0,0,0,0,0,0,0,0,0,0,0,0]
#Basic goertzel Calcuration
k=int(0.5+(n*target_freq)/sampling_freq)
omega=(2.0*Pi*k)/n
sine=math.sin(omega)
cosine=math.cos(omega)
coeff=2.0*cosine
while True:
for i in range(n):
testData[i]=a.read_u16()
utime.sleep_us(60)
for i in range(n):
Q0=coeff*Q1-Q2+testData[i]
Q2=Q1
Q1=Q0
magnitudeSquared=(Q1*Q1)+(Q2*Q2)-Q1*Q2*coeff
magnitude=math.sqrt(magnitudeSquared)
Q1=0.0
Q2=0.0
print(magnitude//100)
utime.sleep(1)
--------------------------------------------------------------------------------------
これで、Picoでトーン検出ができるようになりました。
CW解読器として、動くように仕上げていくことにします。
余談ですが、今年は雪が多く、除雪などで疲れてしまって、マイコン遊びに戻ってくるまで1か月かかってしまいました。
これからまた少しずつPIC,Arduinoやラズパイ関係の記事を書いていきたいと思います。よろしくお願いします。