Commit 1c502780 authored by Anders Wallin's avatar Anders Wallin

ustepper script calculations

parent f2f5cd50
"""
This file is part of the Microstepper project
https://www.ohwr.org/project/microstepper
This simple script computes microstepper output frequency
given DDS frequency tuning words.
released under GPLv3 or later license.
Anders Wallin, 2019-2020
"""
import matplotlib.pyplot as plt
import numpy
import ustep
# nominal F1
F1 = 112535015102874
F2 = 112589990683444
y, y18 = ustep.y_out(F1, F2)
print( ["%02x"%x for x in ustep.split_hex(F1)])
print(y18)
yset = numpy.linspace(-100, 100, 400)
#print(yset)
y18s = []
fs = []
for y in yset:
ftw2 = ustep.f2_from_y( y, F1 )
_, y18 = ustep.y_out( F1, ftw2 )
y18s.append(y18)
fs.append(ftw2)
plt.figure()
fs = numpy.array(fs)
plt.plot(yset, yset, 'r-', label='Ideal')
plt.plot(yset, y18s, '.', label='uStepper')
plt.plot(yset, y18s-yset, 'm.', label='Error')
plt.xlabel('set-point / y18')
plt.ylabel('output / y18')
plt.legend()
plt.grid()
plt.show()
"""
This file is part of the Microstepper project
https://www.ohwr.org/project/microstepper
Library for microstepper related functions
released under GPLv3 or later license.
Anders Wallin, 2019-2020
"""
import bigfloat
import numpy
import requests
dds_clk=1.0e9
ftw_length = pow(2,48)
# nominal F1, F2, for N_div=8, M_div=1024
# these FTWs give output closest to reference frequency, i.e. y approx= 0.
F1 = 112535015102874
F2 = 112589990683444
def ftw_dds(f_hz):
""" return AD9912 DDS Frequency tuning word, given desired frequency in Hz.
Assumes 1GHz SYSCLK
Only even FTWs possible in practice (i.e. LSB is allways zero)
"""
with bigfloat.precision(200):
a = bigfloat.BigFloat.exact(f_hz)
b = bigfloat.BigFloat.exact(ftw_length)
c = bigfloat.BigFloat.exact(dds_clk)
ftw = a*b/c
ftwi = round_to_even(ftw)
return int( ftwi )
def hz_dds(ftw):
""" return DDS output-frequency in Hz, given frequency tuning word
"""
return dds_clk*ftw/ftw_length
def round_to_even(f):
""" AD9912 frequency tuning words are ALLWAYS even
i.e. the LSB is allways zero.
"""
return round(f / 2.) * 2
def y_out(ftw1, ftw2, N_div=8.0, M_div=1024.0):
""" given frequency tuning words, compute fractional frequency of microstepper
F_out / F_REF
"""
with bigfloat.precision(200):
F1term = bigfloat.BigFloat.exact(ftw1 / 4.0)
F2term = bigfloat.BigFloat.exact(ftw2/ (N_div*M_div ))
Fsum = F1term+F2term
y = ftw_length* bigfloat.pow( 10.0*(Fsum), -1.0)-1.0
y18 = y*bigfloat.BigFloat.exact(1e18)
return y, y18
def f2_from_y(y18, ftw1, N_div=8.0, M_div=1024.0):
""" given fractional frequency, compute frequency tuning word for DDS2
y = f_out/f_ref - 1.0
y=0 corresponds to f_out = f_ref
y18 input is in units of 1e-18
"""
with bigfloat.precision(200):
a = bigfloat.BigFloat.exact( pow(2,48) )/ bigfloat.BigFloat.exact( 10.0 )
y = bigfloat.BigFloat.exact( 1.0 ) + y18 / bigfloat.BigFloat.exact( 1e18 )
b = bigfloat.BigFloat.exact( 1.0 ) / y
c = bigfloat.BigFloat.exact( ftw1 )/ bigfloat.BigFloat.exact( 4.0 )
d = bigfloat.BigFloat.exact( N_div*M_div )
ftw2 = d*( a*b - c )
#print(ftw2)
#print(" y - 1 = %.3g" %(y-1.0))
#print(int(ftw2))
ftw2i = round_to_even(ftw2)
return int(ftw2i)
def set_DDS(ftw, DDS=0, IP="192.168.1.18"):
""" use HTTP to set DDS frequency to given frequency tuning word
DDS index can be 0 or 1
"""
hexs = split_hex(ftw)
ftw_string = "%02x:%02x:%02x:%02x:%02x:%02x" % (hexs[0],hexs[1],hexs[2],hexs[3],hexs[4],hexs[5] )
r = requests.get('http://%s/DDS:%s:FTW:%s' % (IP, DDS, ftw_string))
def split_hex(ftw):
""" Split FTW into six 2-digit hex words
"""
mask = 0x0000000000ff
out=[]
for n in range(6):
hexdigits = (ftw & (mask << n*8) ) >> n*8
#print("%x " % hexdigits)
out.append(hexdigits)
return out
......@@ -14,15 +14,27 @@ import numpy
def ftw_dds(f_hz):
""" return AD9912 1GHz SYSCLK FTW
"""
return numpy.round(f_hz*ftw_length/dds_clk,0)
with bigfloat.precision(200):
a = bigfloat.BigFloat.exact(f_hz)
b = bigfloat.BigFloat.exact(ftw_length)
c = bigfloat.BigFloat.exact(dds_clk)
ftw = a*b/c
ftwi = round_to_even(ftw)
return int( ftwi )
def hz_dds(ftw):
""" return f_out [Hz]
"""
return dds_clk*ftw/ftw_length
def round_to_even(f):
""" AD9912 frequency tuning words are ALLWAYS even
i.e. the LSB is allways zero.
"""
return round(f / 2.) * 2
def y_out(ftw1, ftw2, N_div=4.0, M_div=1024.0):
""" fractional frequency of microstepper
""" given frequency tuning words, compute fractional frequency of microstepper
F_out / F_REF
"""
with bigfloat.precision(200):
......@@ -30,20 +42,46 @@ def y_out(ftw1, ftw2, N_div=4.0, M_div=1024.0):
F2term = bigfloat.BigFloat.exact(ftw2/ (N_div*M_div ))
Fsum = F1term+F2term
y = ftw_length* bigfloat.pow( 10.0*(Fsum), -1.0)-1.0
return y
y18 = y*bigfloat.BigFloat.exact(1e18)
return y, y18
def f2_from_y(y18, ftw1, N_div=4.0, M_div=1024.0):
""" given fractional frequency, compute frequency tuning word for DDS2
y = f_out/f_ref - 1.0
y=0 corresponds to f_out = f_ref
y18 input is in units of 1e-18
"""
with bigfloat.precision(200):
a = bigfloat.BigFloat.exact( pow(2,48) )/ bigfloat.BigFloat.exact( 10.0 )
y = bigfloat.BigFloat.exact( 1.0 ) + y18 / bigfloat.BigFloat.exact( 1e18 )
b = bigfloat.BigFloat.exact( 1.0 ) / y
c = bigfloat.BigFloat.exact( ftw1 )/ bigfloat.BigFloat.exact( 4.0 )
d = bigfloat.BigFloat.exact( N_div*M_div )
ftw2 = d*( a*b - c )
#print(ftw2)
#print(" y - 1 = %.3g" %(y-1.0))
#print(int(ftw2))
ftw2i = round_to_even(ftw2)
return int(ftw2i)
dds_clk=1.0e9
ftw_length = pow(2,48)
DDS2_nom = 400e6 # nominal frequency of DDS
N_div = 80.0 # first divider 2/4/8
DDS2_nom = hz_dds( ftw_dds(400e6) ) # nominal frequency of DDS
N_div = 8.0 # first divider 2/4/8
M_div = 1024.0 # second divider 2**10 = 1024
IF = DDS2_nom/(N_div*M_div) # 97656.25 Hz
print("IF = %.3f Hz" % IF)
print("DDS2 nom = ",DDS2_nom)
print("IF2 = %.3f Hz" % IF)
# nominally we get zero output frequency with these
# tuning-wrods:
F1 = ftw_dds(400e6-4.0*IF) # DDS1
IF1 = (100e6-hz_dds(F1)/4.0)
F2 = ftw_dds(N_div*M_div*IF1) # DDS2
F2approx = ftw_dds(N_div*M_div*IF1) # DDS2
print("F1 ", F1)
F2 = f2_from_y(0, F1, N_div=N_div, M_div=M_div)
print("F2 approx = ", F2approx)
print("F2 = ", F2)
#IF2 = hz_dds(F2)/(N_div*M_div)
#F1 = ftw_dds(400e6-4.0*IF2) # DDS1
......@@ -63,7 +101,7 @@ ys =[]
for delta in [-5,-4,-3,-2,-1,0,1,2,3,4,5]:
delta=2*delta
F1x = F1+delta
y1 = y_out(F1x,F2, N_div = N_div)
y1, _ = y_out(F1x,F2, N_div = N_div)
ys.append(y1)
print( "%d\t%d\t%.3g" % ( F1x, delta, y1) )
print( "y change due to 2 steps in FTW1: %.2g" % (min(numpy.diff(ys))) )
......@@ -75,10 +113,18 @@ ys =[]
for delta in [-5,-4,-3,-2,-1,0,1,2,3,4,5]:
delta=2*delta
F2x = F2+delta
y1 = y_out(F1,F2x, N_div = N_div)
y1, _ = y_out(F1,F2x, N_div = N_div)
ys.append(y1)
print( "%d\t%d\t%.3g" % ( F2x, delta, y1) )
print( "y change due to 2 steps in FTW2: %.3g" % (min(numpy.diff(ys))) )
print( 40*"-" )
y18 = 5678
F2 = f2_from_y(y18, F1, N_div=N_div, M_div=M_div)
print("F2 2e-17= ", F2)
yget, yget18 = y_out(F1,F2, N_div=N_div, M_div=M_div)
print(yget18)
print(" y_out = %.6g" % yget )
print(" y(set)-y_out = %d " % (y18-yget*1e18) )
print(" y(set)-yget18 = %.6f " % (y18-yget18) )
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment