100 lines
3.4 KiB
Python
100 lines
3.4 KiB
Python
#!/usr/bin/env python3
|
|
import numpy as np
|
|
|
|
################################################################################
|
|
# Define my helper functions.
|
|
def dB20(volt_tf):
|
|
"""Describe signal gain of a transfer function in dB (i.e. 20log(x))"""
|
|
return 20*np.log10(np.abs(volt_tf))
|
|
def ang(volt_tf):
|
|
"""Describe phase of a transfer function in degrees. Not unwrapped."""
|
|
return 180/np.pi*np.angle(volt_tf)
|
|
def ang_unwrap(volt_tf):
|
|
"""Describe phase of a transfer function in degrees. With unwrapping."""
|
|
return 180/np.pi*np.unwrap(np.angle(volt_tf))
|
|
def dB10(pwr_tf):
|
|
"""Describe power gain of a transfer function in dB (i.e. 10log(x))"""
|
|
return 10*np.log10(np.abs(pwr_tf))
|
|
|
|
def dB2Vlt(dB20_value):
|
|
return np.power(10,dB20_value/20)
|
|
|
|
def wrap_rads(angles):
|
|
return np.mod(angles+np.pi,2*np.pi)-np.pi
|
|
def atand(x):
|
|
return 180/np.pi*np.arctan(x)
|
|
|
|
def setLimitsTicks(ax, data, steps):
|
|
targs = np.array([1, 2, 4, 5, 10, 20, 30, 50, 60, 100, 250, 1000])
|
|
lo = np.min(data)
|
|
hi = np.max(data)
|
|
rg = hi-lo
|
|
step_size = rg / steps
|
|
step_size = np.select(targs >= step_size, targs)
|
|
lo = np.floor(lo / step_size)*step_size
|
|
hi = np.ceil(hi / step_size)*step_size
|
|
marks = np.arange(0,steps+1)*step_size + lo
|
|
ax.set_ylim((lo,hi))
|
|
ax.set_yticks(marks)
|
|
|
|
def rms_v_bw(err_sig, bandwidth_scale=1):
|
|
"""compute the rms vs bandwidth assuming a fixed center frequency"""
|
|
# First compute the error power
|
|
err_pwr = np.power(np.abs(err_sig),2)
|
|
steps = len(err_pwr)
|
|
isodd = True if steps%2 != 0 else False
|
|
|
|
# We want to generate the midpoint to the left, and midpoint to the right
|
|
# as two distinct sets.
|
|
pt_rhs_start = int(np.floor(steps/2))
|
|
pt_lhs_stop = int(np.ceil(steps/2))
|
|
|
|
folded = err_pwr[pt_rhs_start:] + np.flip(err_pwr[:pt_lhs_stop],0)
|
|
# Now, we MIGHT have double counted the mid point
|
|
# if the length is odd, correct for that
|
|
if isodd: folded[0]*=0.5
|
|
|
|
# Now we need an array that describes the number of points used to get here.
|
|
# this one turns out to be pretty easy.
|
|
frac_step = np.arange(int(not isodd),steps,2)/(steps-1)
|
|
ind = 2*np.arange(0,frac_step.shape[0])+1+int(not isodd)
|
|
|
|
# Now actually compute the RMS values. First do the running sum
|
|
rms = np.sqrt(np.cumsum(folded,0) / (ind*np.ones((folded.shape[1],1))).T )
|
|
return (frac_step*bandwidth_scale, rms)
|
|
|
|
def delta_rms(signal, reference_delta, wrap_point=2*np.pi):
|
|
"""compute the rms difference between various states and a reference"""
|
|
# First compute the matrix difference including folding
|
|
signal_delta = np.column_stack((
|
|
signal[:,1:]-signal[:,:-1],
|
|
signal[:,0]-signal[:,-1]
|
|
))
|
|
signal_delta = np.where(signal_delta>wrap_point/2, \
|
|
signal_delta-wrap_point, signal_delta)
|
|
signal_delta = np.where(signal_delta<-wrap_point/2, \
|
|
signal_delta+wrap_point, signal_delta)
|
|
signal_error = np.abs(signal_delta)-reference_delta
|
|
|
|
signal_rms = np.sqrt(np.mean(np.power(signal_error,2),1))
|
|
|
|
return signal_rms
|
|
|
|
def gain_error(signal, ref_freq_ind):
|
|
"""compute the gain variation relative to a mean computed at ref_freq_ind"""
|
|
# First compute the matrix difference including folding
|
|
inband_gain = np.mean(signal[ref_freq_ind,:])
|
|
signal_off = signal-inband_gain
|
|
range = np.max(signal_off,1)-np.min(signal_off,1)
|
|
|
|
return range
|
|
|
|
def rms(signal, ref_freq_ind=None):
|
|
"""compute raw RMS"""
|
|
if ref_freq_ind == None:
|
|
offset_signal = signal-np.transpose(\
|
|
np.ones((signal.shape[1],1))*np.mean(signal,1)\
|
|
)
|
|
else:
|
|
offset_signal = signal-np.mean(signal[ref_freq_ind,:])
|
|
return np.sqrt(np.mean(np.power(offset_signal,2),1))
|