VHDLで二相発振器を実装する / IIRフィルターによる方法 / 整数化する

sin、cos を再帰的に求める / 加法定理による方法 & IIR フィルターによる方法 / Python / それに意味のないとき - Qiita」のときに計算手順だけ確かめておいたのを今度は実際にVHDLFPGAに実装してみたい。まずは整数化して計算できることをPythonで確かめておく。

うまい端数処理のしかたがわからない。

import math
import matplotlib.pyplot as plt

def scale_int(x, in_min, in_max, out_min, out_max):
    return int(((x - in_min) * (out_max - out_min)) / (in_max - in_min)) + out_min

def SinCos(Δθ):
    res_out  = (1 << 10) - 1 #最大出力値(DACへ与える最大値)
    shif_val = 16 #整数化の手段として2の何乗倍にするか
    res      = 1 << shif_val
    sin_     = math.sin(Δθ)
    cos_     = math.cos(Δθ)
    
    A = int(2 * cos_ * res)
    S = int(    sin_ * res)
    C = int(   -cos_ * res)
    u = [0, int(res_out/2)] #内部計算での[sinの初期値, cosの初期値]
    def sincos():
        sin_temp   =         int(S * u[0]) >> shif_val
        cos_temp   = u[1] + (int(C * u[0]) >> shif_val)
        u[0], u[1] = u[1],  (int(A * u[1]) >> shif_val) - u[0]
        
        #return sin_temp, cos_temp
        #↑一旦端数を全部切り捨ててsin、cosの最小値、最大値を求めてから、下のように無理矢理スケーリングする。
        return scale_int(sin_temp, -520, 509 , 0, res_out), scale_int(cos_temp, -515, 514, 0, res_out)

    return sincos

########
# test #
########
Δθ    = math.pi/32
sin_cos = SinCos(Δθ) # 初期値をセットした状態でクロージャを開いて、
θList  = []
sinList = []
cosList = []

for i in range(200):
    sin, cos = sin_cos() # 外に出した函数を実行し続ける。実行するたびに sin、cos の値が更新される。

    θList.append(i * Δθ)
    sinList.append(sin)
    cosList.append(cos)
    #print("θ: %.2f, sin: %.6f, cos: %.6f, amp: %.16f" % (i*Δθ, sin, cos, math.sqrt(sin**2 + cos**2)))

print(min(sinList), max(sinList))
print(min(cosList), max(cosList))

plt.plot(θList,sinList,
         θList,cosList)
plt.xlabel("radian")
plt.ylabel("amplitude")
plt.grid(color="lightblue")
plt.show()

f:id:ti-nspire:20220116101554p:plain:w400