Python Script that Tells You the RMS Cycle-to-Cycle Jitter of Your Oscillator
$ python3 script.py phas_noi_export.csv f_center [f_lower or 0] [f_higher] # if specify only f_higher, then use 0 for arg2
import numpy as np
import pandas as pd
import sys
def read_phase_noise_file(filename):
with open(filename, 'r') as f:
first_line = f.readline()
try:
float(first_line.split(',')[0])
df = pd.read_csv(filename, header=None)
except ValueError:
df = pd.read_csv(filename)
freq = df.iloc[:, 0].values
L_dbc_per_hz = df.iloc[:, 1].values
return freq, L_dbc_per_hz
def calc_cycle_to_cycle_jitter(freq, L_dbc_per_hz, f0, f_min=None, f_max=None):
# Apply frequency limits
mask = np.ones_like(freq, dtype=bool)
if f_min is not None:
mask &= freq >= f_min
if f_max is not None:
mask &= freq <= f_max
freq = freq[mask]
L_dbc_per_hz = L_dbc_per_hz[mask]
if len(freq) == 0:
raise ValueError("No data points within specified frequency range.")
# Convert to linear
L_linear = 10 ** (L_dbc_per_hz / 10.0)
# Weighting for cycle-to-cycle jitter
w = 2 * np.sin(np.pi * freq / f0)
integrand = (w ** 2) * L_linear
# Integration and conversion (fixed warning)
jitter_power = 2 * np.trapezoid(integrand, freq)
sigma_ccj = np.sqrt(jitter_power) / (2 * np.pi * f0)
return sigma_ccj
if __name__ == "__main__":
if len(sys.argv) < 3:
print("Usage: python3 ccjitter.py <phase_noise.csv> <f0_Hz> [f_min_Hz f_max_Hz]")
sys.exit(1)
csv_file = sys.argv[1]
f0 = float(sys.argv[2])
f_min = float(sys.argv[3]) if len(sys.argv) > 3 else None
f_max = float(sys.argv[4]) if len(sys.argv) > 4 else None
try:
freq, L = read_phase_noise_file(csv_file)
jitter = calc_cycle_to_cycle_jitter(freq, L, f0, f_min, f_max)
print(f"Cycle-to-cycle RMS jitter: {jitter * 1e12:.2f} ps")
except Exception as e:
print("Error:", e)
sys.exit(1)
Comments
Post a Comment