Added helper script for pll parameter test
This commit is contained in:
parent
24753c8252
commit
c8cd7ce46c
|
@ -0,0 +1,128 @@
|
|||
#!/bin/env python3
|
||||
|
||||
from fractions import Fraction
|
||||
from math import floor, nan
|
||||
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
|
||||
BANDS = [
|
||||
(1_810_000, 2_000_000),
|
||||
(3_500_000, 3_800_000),
|
||||
(5_351_500, 5_366_500),
|
||||
(7_000_000, 7_200_000),
|
||||
(10_100_000, 10_150_000),
|
||||
(14_000_000, 14_350_000),
|
||||
(18_068_000, 18_168_000),
|
||||
(21_000_000, 21_450_000),
|
||||
(24_890_000, 24_990_000),
|
||||
(28_000_000, 29_700_000)
|
||||
]
|
||||
|
||||
|
||||
XTAL_FREQ = 25_000_000
|
||||
|
||||
TARGET_PHASE = 90.0
|
||||
|
||||
# Official limit is 600MHz, however https://rfzero.net/tutorials/si5351a/ claims that 420Mhz is also okay
|
||||
PLL_MIN = 420_000_000
|
||||
PLL_MAX = 900_000_000
|
||||
|
||||
|
||||
def calc_pll_params(in_freq, out_freq):
|
||||
MAX_DENOM = 0x0FFFFF
|
||||
|
||||
divider = Fraction(floor(in_freq), floor(out_freq))
|
||||
divider = divider.limit_denominator(MAX_DENOM)
|
||||
|
||||
a = floor(divider.numerator / divider.denominator)
|
||||
b = divider.numerator % divider.denominator
|
||||
c = divider.denominator
|
||||
|
||||
return a, b, c
|
||||
|
||||
|
||||
def calc_error(freq, offset):
|
||||
phase_offset_sec = 1.0 / freq * TARGET_PHASE / 360.0
|
||||
target_pll_freq = offset / (4 * phase_offset_sec)
|
||||
|
||||
if target_pll_freq >= PLL_MIN and target_pll_freq <= PLL_MAX:
|
||||
#print("\tVCO target for %d: %f" % (offset, target_pll_freq / 10**6))
|
||||
|
||||
pll_a, pll_b, pll_c = calc_pll_params(XTAL_FREQ, target_pll_freq)
|
||||
pll_actual_freq = XTAL_FREQ / (pll_a + pll_b/pll_c)
|
||||
|
||||
#print("\tVCO actual for %d: %f" % (offset, target_pll_freq / 10**6))
|
||||
|
||||
ms_a, ms_b, ms_c = calc_pll_params(target_pll_freq, freq)
|
||||
ms_actual_freq = pll_actual_freq / (ms_a + ms_b/ms_c)
|
||||
|
||||
err = ms_actual_freq - freq
|
||||
#print("\tError: %f" % (ms_actual_freq - freq))
|
||||
|
||||
return err, target_pll_freq
|
||||
|
||||
return None, None
|
||||
|
||||
|
||||
def main():
|
||||
freqs = []
|
||||
errs = []
|
||||
pll_freqs = []
|
||||
phases = []
|
||||
|
||||
for start, end in BANDS:
|
||||
print("Band %d - %d" % (start, end))
|
||||
|
||||
min_err = None
|
||||
min_err_phase = None
|
||||
for phase in range(1,128):
|
||||
err_sum = 0
|
||||
for freq in range(start, end, 100):
|
||||
err, pll_freq = calc_error(freq, phase)
|
||||
if pll_freq is None:
|
||||
break
|
||||
err_sum += err
|
||||
|
||||
if min_err is None or err_sum <= min_err:
|
||||
min_err = err_sum
|
||||
min_err_phase = phase
|
||||
|
||||
if min_err_phase is None:
|
||||
print("\tNo suitable PLL freq found for %d" % freq)
|
||||
continue
|
||||
|
||||
print("Minimal error phase offset for band: %d" % (min_err_phase))
|
||||
|
||||
for freq in range(start, end, 1):
|
||||
err, pll_freq = calc_error(freq, min_err_phase)
|
||||
if pll_freq is None:
|
||||
print("\tNo suitable PLL freq found for %d" % freq)
|
||||
break
|
||||
|
||||
freqs += [freq]
|
||||
pll_freqs += [pll_freq]
|
||||
phases += [min_err_phase]
|
||||
errs += [err]
|
||||
|
||||
freqs += [nan]
|
||||
pll_freqs += [nan]
|
||||
phases += [nan]
|
||||
errs += [nan]
|
||||
|
||||
|
||||
freqs = np.array(freqs) / 10**6
|
||||
pll_freqs = np.array(pll_freqs) / 10**6
|
||||
phases = np.array(phases)
|
||||
errs = np.abs(np.array(errs))
|
||||
|
||||
fig, (ax1, ax2, ax3) = plt.subplots(3, 1)
|
||||
ax1.plot(freqs, phases)
|
||||
ax2.plot(freqs, pll_freqs)
|
||||
ax3.plot(freqs, errs)
|
||||
plt.show()
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
|
@ -0,0 +1,37 @@
|
|||
#!/usr/bin/env python3
|
||||
|
||||
from scipy import signal
|
||||
import matplotlib.pyplot as plt
|
||||
import numpy as np
|
||||
|
||||
|
||||
def main():
|
||||
fs = 6400.0
|
||||
coeffs = signal.firls(63, (0, 1150, 1200, fs/2), (1, 1, 0, 0), fs=fs)
|
||||
|
||||
freq_space = np.linspace(-fs/2 / (fs/2)*np.pi, fs/2 / (fs/2)*np.pi, 512)
|
||||
freqs, response = signal.freqz(coeffs, worN=freq_space)
|
||||
response = 10 * np.log(abs(response))
|
||||
plt.plot(fs/2*freqs/(np.pi), response)
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
f0 = (1200 + 50) / fs
|
||||
complex_coeffs = []
|
||||
for n in range(0, len(coeffs)):
|
||||
complex_coeffs += [coeffs[n] * np.exp(1j * 2 * np.pi * f0 * n)]
|
||||
complex_coeffs = np.array(complex_coeffs)
|
||||
|
||||
print(complex_coeffs)
|
||||
|
||||
freq_space = np.linspace(-fs/2 / (fs/2)*np.pi, fs/2 / (fs/2)*np.pi, 512)
|
||||
freqs, response = signal.freqz(complex_coeffs, worN=freq_space)
|
||||
response = 10 * np.log(abs(response))
|
||||
plt.plot(fs/2*freqs/(np.pi), response)
|
||||
plt.grid()
|
||||
plt.show()
|
||||
|
||||
|
||||
|
||||
if __name__ == '__main__':
|
||||
main()
|
Loading…
Reference in New Issue