Added helper script for pll parameter test

This commit is contained in:
Sebastian 2023-08-18 12:09:49 +02:00
parent 24753c8252
commit c8cd7ce46c
2 changed files with 165 additions and 0 deletions

128
scripts/calc_pll_errpr.py Normal file
View File

@ -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()

37
scripts/ssb_filter.py Normal file
View File

@ -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()