def createFunction(self): wo = self.woCalc() #calculo wo para desnormalizacion pzFunction = signal.ZerosPolesGain(self.zeros, self.poles, 1) coefFunction = pzFunction.to_tf() # num/den den = coefFunction.den num = coefFunction.num for i in range(0, len(den)): den[i] = den[i].real for i in range(0, len(num)): num[i] = num[i].real k = self.kCalc(den, num) #calculo constante self.normFunction = signal.ZerosPolesGain( self.zeros, self.poles, k) #guardo funcion normalizada # desnormalizo segun tipo de filtro if self.type == 'LP': s = c.tf([1, 0], [wo]) elif self.type == 'HP': s = c.tf([wo], [1, 0]) elif self.type == 'BP': s = c.tf([1, 0, wo**2], [1, 0]) / (wo * self.b) elif self.type == 'BR': s = c.tf([1, 0], [1, 0, wo**2]) * wo * self.b ft = c.tf([1], [1]) for i in range(0, len(self.poles)): aux = 1 / (s - self.poles[i]) ft = ft * aux for i in range(0, len(self.zeros)): aux = s - self.zeros[i] ft = ft * aux #creo funcion final self.function = signal.TransferFunction(k * ft.num[0][0], ft.den[0][0]) return
def max_gain_for_stage(self, stage): if stage['zero'] is None: zeros = [] else: zeros = stage['zero']['zeros'] poles = stage['pole']['poles'] gain = 10**(stage['gain_data'] / 20) transfer_function = ss.ZerosPolesGain(zeros, poles, gain) w, mag, phase = ss.bode(transfer_function, n=1000) dmag = np.diff(mag) / np.diff(w) frequencies_to_check = 10 zero_condition = 1.0e-4 gain_needed = 0 for i in range(len(dmag) - frequencies_to_check): values_checked = [] for j in range(frequencies_to_check): values_checked.append(dmag[i + j]) if all([value < zero_condition for value in values_checked]): frequency_to_evaluate = math.floor(i + frequencies_to_check / 2) max_freq = w[frequency_to_evaluate] useless_1, gain_in_passband, useless_2 = ss.bode( transfer_function, [max_freq]) gain_in_passband = 10**(gain_in_passband[0] / 20) gain_needed = gain**2 / gain_in_passband break transfer_function = ss.ZerosPolesGain(zeros, poles, gain_needed) w, mag, phase = ss.bode(transfer_function) return max(mag)
def _denormalised_transfer_function(self) -> ApproximationErrorCode: """ Denormalises the transfer function returned by the approximation used. """ # Unity gain of the normalised transfer function, factor of denormalisation... # moving it between the transition band self.adjust_function_gain(1) wa, aa, wp, ap = self.get_norm_template() relative_adjust = self.denormalisation_factor(wa, aa, wp, ap) new_zeros = self.h_aux.zeros * relative_adjust new_poles = self.h_aux.poles * relative_adjust new_gain = self.h_aux.gain * relative_adjust self.h_aux = ss.ZerosPolesGain(new_zeros, new_poles, new_gain) self.adjust_function_gain(1) # Final normalised transfer function being stored, keep working on auxiliar transfer function self.h_norm = ss.ZerosPolesGain(self.h_aux.zeros, self.h_aux.poles, self.h_aux.gain) self.adjust_function_gain(10**(self.gain / 20)) # Frequency transformation to get the desired filter if self.type == FilterType.LOW_PASS.value: z, p, k = self.denormalise_to_low_pass() elif self.type == FilterType.HIGH_PASS.value: z, p, k = self.denormalise_to_high_pass() elif self.type == FilterType.BAND_PASS.value: z, p, k = self.denormalise_to_band_pass() elif self.type == FilterType.BAND_REJECT.value: z, p, k = self.denormalise_to_band_stop() self.h_denorm = ss.ZerosPolesGain(z, p, k) return ApproximationErrorCode.OK
def GetStagesTransferFunctions(self): funcs = [] for i in range(0, len(self.pairs)): zero, pole1 = self.pairs[i] pole2 = complex(pole1.real, -(pole1.imag)) aux = signal.ZerosPolesGain(zero, [pole1, pole2], 1) funcs.append(aux) for i in range(0, len(self.remainingPoles)): p1 = self.remainingPoles[i] p2 = complex(p1.real, -(p1.imag)) aux = signal.ZerosPolesGain([], [p1, p2], 1) funcs.append(aux) self.stages = funcs
def get_min_max_attenuation(poles, zeros, gain_factor, pass_bands): max_at = -math.inf min_at = math.inf if zeros is not None and poles is not None: filter.Filter.re_add_complex(poles) filter.Filter.re_add_complex(zeros) sys = signal.ZerosPolesGain(zeros, poles, gain_factor) for pass_band in pass_bands: sup_band = pass_band[1] if sup_band == math.inf: sup_band = 10000 * pass_band[0] w = np.logspace(start=math.log10(pass_band[0]), stop=math.log10(sup_band), endpoint=True, base=10) [_, mag, _] = signal.bode(system=sys, w=w) attenuation = -1*mag if min(attenuation) < min_at: min_at = min(attenuation) if max(attenuation) > max_at: max_at = max(attenuation) filter.Filter.add_only_one_complex(poles) filter.Filter.add_only_one_complex(zeros) return [min_at, max_at]
def besselord(omega_p, omega_s, alfa_max, alfa_min, omega_d, max_pc_delay): min_order = 0 # partimos de suponer que al menos será el orden de un Butter o más grande start_order, _ = sig.buttord(omega_p, omega_s, alfa_max, alfa_min + alfa_max, analog=True) # de forma iterativa, intentamos cumplimentar la plantilla for ii in range(start_order, 20): z, p, k = sig.besselap(ii, norm='delay') this_lti = sig.ZerosPolesGain(z, p, k).to_tf() _, mm, pp = sig.bode(this_lti, w=[0, 0.0001, omega_p, omega_d, omega_d + 0.0001]) # attenuation in omega_p, i.e. bandpass end this_ripple = -mm[2] # relative delay this_delay = 1 - np.abs((pp[4] - pp[3]) / (pp[1] - pp[0])) if this_ripple <= alfa_max and this_delay <= max_pc_delay: break min_order = ii return min_order
def calculate_tf(positive_poles, positive_zeros, k): Filter.re_add_complex(positive_poles) Filter.re_add_complex(positive_zeros) sys = signal.ZerosPolesGain(positive_zeros, positive_poles, k) Filter.add_only_one_complex(positive_poles) Filter.add_only_one_complex(positive_zeros) return sys.to_tf()
def plot_stage(self): current_item = self.stages_list.currentItem() stage_index = self.stages_list.row(current_item) if self.accumulative_plot.isChecked(): start = 0 else: start = stage_index poles_list = [] zeros_list = [] total_gain = 1 for i in range(start, stage_index + 1): widget = self.stages_list.itemWidget(self.stages_list.item(i)) if widget.cell_data['zero'] is not None: zeros = [ zero * 2 * np.pi for zero in widget.cell_data['zero']['zeros'] ] else: zeros = [] zeros_list += zeros poles = [ pole * 2 * np.pi for pole in widget.cell_data['pole']['poles'] ] poles_list += poles gain = 10**(widget.cell_data['gain_data'] / 20) gain_needed_to_plot = self.adjust_function_gain(zeros, poles, gain) total_gain *= gain_needed_to_plot tf = ss.ZerosPolesGain(zeros_list, poles_list, total_gain) self.plot_attenuation_for_stages(tf)
def plot_transfer_to_figure(self, figure): n_points = 1000 z = [] p = [] # get a list of all the zeros: for point_pair in self.zero_pairs: for point in point_pair.points: z.append(point) # get a list of all the poles for point_pair in self.pole_pairs: for point in point_pair.points: p.append(point) sys = signal.TransferFunction(signal.ZerosPolesGain(z, p, self.gain)) w, mag, phase = signal.bode(sys) # create and plot title = 'Stage {0} - Frequency Response[dB]'.format(self.id) legend = 'Frequency Response[dB]' # remove axes for axes in figure.axes: figure.delaxes(axes) # create axes axes = figure.add_subplot(111, projection='rectilinear') axes.semilogx(w, mag, label=legend) axes.set_title(title, pad=10) axes.legend() axes.set_xlabel(r'$\omega [rad/seg]$') axes.set_ylabel(r'Mag')
def compute_normalised_by_order(self, ap, n, aa) -> ApproximationErrorCode: """ Generates normalised transfer function prioritising the fixed order """ # Computing needed constants zeros, poles, gain = ss.cheb2ap(n, aa) wa, aa, wp, ap = self.get_norm_template() self.h_aux = ss.ZerosPolesGain(zeros, poles, gain) return ApproximationErrorCode.OK
def _get_tf(self, n: int): """ Returns the normalized transfer function of the Gauss Approximation :param n: Order of the gauss polynomial :return: Scipy signal transfer function """ z, p, k = self._get_zpk(n) transfer_function = ss.ZerosPolesGain(z, p, k) return transfer_function
def compute_normalised_by_order(self, ap, n, aa=None) -> ApproximationErrorCode: """ Generates normalised transfer function prioritising the fixed order """ # Computing needed constants zeros, poles, gain = ss.ellipap(n, ap, aa) self.h_aux = ss.ZerosPolesGain(zeros, poles, gain) return ApproximationErrorCode.OK
def gaussDenGenerator(self): coef = self.gaussPolynomialCoef() auxPoles = np.roots(coef) poles = [] for i in range(0, auxPoles.size): if auxPoles[i].real < 0: poles.append(auxPoles[i]) pzfunc = signal.ZerosPolesGain([], poles, 1) self.normFunction = pzfunc.to_tf() den = self.normFunction.den return den
def filter_from_npz(filename, fs): with np.load(filename) as data: z = data['z'] p = data['p'] k = data['k'] #sos conversion zd, pd, kd = zpk_bilinear(z, p, k, fs) sys_disc = sig.ZerosPolesGain(zd, pd, kd, dt=1 / fs) sos = sig.zpk2sos(sys_disc.zeros, sys_disc.poles, sys_disc.gain) return sos
def H(self): # Generate the transfer function H = signal.ZerosPolesGain([], [0.25, 2 / 3], 0.25, dt=0.1).to_tf() # Generate dicrete frequency response w, h = signal.freqz(H.num, H.den, whole=True) # Shift the angles to [-pi, pi] w = w - np.pi # Shift the gain and phase accordingly # h_ph = np.fft.fftshift(np.angle(h, deg=True)) h = np.abs(np.fft.fftshift(h)) return w, h
def computeCancellationLogic(self, deltaSigmas): STF = [] NTF = [] for df in deltaSigmas: # k is the gain of the system ntf, stf = calculateTF(df.ABCD, k=1.) stf = signal.ZerosPolesGain(*stf) ntf = signal.ZerosPolesGain(*ntf) STF.append(stf.to_tf()) NTF.append(ntf.to_tf()) # Create inverse filter # H1 = STF2 # STF_N H_N = NTF_N-1 H_N-1 for index in range(len(deltaSigmas)): if index == 0: self.H = [STF[1]] else: NTF_over_STF = self.inverseMultiple(NTF[index - 1], STF[index]) self.H.append(self.concatenateSystems(NTF_over_STF, self.H[-1]))
def __init__(self, parent=None, width=5, height=4, dpi=100, s1=signal.ZerosPolesGain([], [1], [1])): fig = Figure(figsize=(width, height), dpi=dpi) FigureCanvas.__init__(self, fig) self.setParent(parent) FigureCanvas.setSizePolicy(self, QSizePolicy.Expanding, \ QSizePolicy.Expanding) FigureCanvas.updateGeometry(self)
def compute_normalised_by_order(self, ap, n, aa) -> ApproximationErrorCode: """ Generates normalised transfer function prioritising the fixed order """ # Computing needed constants epsilon = self.compute_epsilon(ap) factor = 1 / np.float_power(epsilon, 1 / n) # Getting the Butterworth approximation for the given order # and matching it with the given maximum attenuation for pass band zeros, poles, gain = ss.buttap(n) new_zeros = zeros new_poles = [factor * pole for pole in poles] new_gain = gain # Updating the local transfer function, no errors! self.h_aux = ss.ZerosPolesGain(new_zeros, new_poles, new_gain) return ApproximationErrorCode.OK
def task3c(): sys1_num = [1, 2, 1] sys1_denom = [1] sys2_num = [1, 0] sys2_denom = [1, 0.9] sys1_gain = 1 sys1_zeros = [-1, -1] sys1_poles = [] sys1 = sig.dlti(sys1_num, sys1_denom) sys2 = sig.dlti(sys2_num, sys2_denom) w1, mag1, phase1 = sig.dbode(sys1, n=100000) w2, mag2, phase2 = sig.dbode(sys2, n=100000) plt.semilogx(w1, mag1) plt.title("magnitude response of first system") plt.savefig("task3c mag1.pdf") plt.show() plt.semilogx(w1, phase1) plt.title("phase response of first system") plt.savefig("task3c phase1.pdf") plt.show() plt.semilogx(w2, mag2) plt.title("magnitude response of second system") plt.savefig("task3c mag2.pdf") plt.show() plt.semilogx(w2, phase2) plt.title("phase response of second system") plt.savefig("task3c phase2.pdf") plt.show() sys1 = sig.ZerosPolesGain(sys1_zeros, ) n = np.arange(1000) x = 1 / 2 * np.sin(np.pi * n + np.pi / 4) out1 = sig.dlsim(sys1, x) out2 = sig.dlsim(sys2, x) plt.plot(n, out1) plt.title("output of system 1") plt.savefig("task3e output1.pdf") plt.show() plt.plot(n, out2) plt.title("output of system 2") plt.savefig("task3e output2.pdf") plt.show()
def getPidControlledResponse(t, u, dt, x1_0, x2_0): pidOutList = np.full_like(t, 0.0) systemOutList = np.full_like(t, 0.0) systemOutList[0] = x1_0 kPid = 1 numPid = [-1.0, -1.0] denPid = [-0.001, -1.0] pid = signal.ZerosPolesGain(numPid, denPid, kPid) pidSS = pid.to_ss() oldStatePid = [0.0, 0.0] # oldStatePid = pidSS.B numSys = [1.0] denSys = [1.0, 1.0, 1.0] testSystem = signal.TransferFunction(numSys, denSys) testSystemSS = testSystem.to_ss() oldStateSys = [0.0, x1_0] # oldStateSys = testSystemSS.B for tIndex in range(1, len(t)): e = [ u[tIndex - 1] - systemOutList[tIndex - 1], u[tIndex - 1] - systemOutList[tIndex - 1] ] tPid, pidOut, oldStatesPid = signal.lsim(pidSS, e, [0.0, dt], X0=oldStatePid) oldStatePid = oldStatesPid[-1] pidOutList[tIndex] = pidOut[-1] # clip the pid to 0.0 - 1.0 if pidOutList[tIndex] > 1.0: pidOutList[tIndex] = 1.0 if pidOutList[tIndex] < 0.0: pidOutList[tIndex] = 0.0 tSys, sysOut, oldStatesSys = signal.lsim( testSystemSS, [pidOutList[tIndex], pidOutList[tIndex]], [0.0, dt], X0=oldStateSys) oldStateSys = oldStatesSys[-1] systemOutList[tIndex] = sysOut[-1] return pidOutList, systemOutList
def plot_DARM_local(start, end, fres, figval=1): #ch = 'K1:CAL-CS_PROC_DARM_DISPLACEMENT_DQ' data = np.loadtxt( 'C:\\Users\\ayaka\\Dropbox (個人)\\Shoda\\NoiseSubtraction\\DARMspe.txt') ff = data[0] spectrum = data[1] tf = sig.ZerosPolesGain([10., 10., 10., 10., 10.], [1., 1., 1., 1., 1.], 1.e-14) freq, mag, phase = sig.bode(tf, ff) darm = spectrum * (10.**(mag / 20.)) fig = plt.figure(figval) plt.loglog(freq, darm, label='DARM') #plt.loglog(spectrum.frequencies,spectrum.value,label='DARM') plt.ylabel(r'Displacement [m/$\sqrt{\rm Hz}$]') plt.xlabel('Frequency [Hz]') plt.legend() plt.grid(True) return 0, freq
def plot_DARM(start, end, fres, figval=1): ch = 'K1:CAL-CS_PROC_DARM_DISPLACEMENT_DQ' try: data = TimeSeries.get(ch, start, end, host='k1nds0', port=8088) except: return 1, 'DARM data cannot be obtained. Try with more recent data.' spectrum = data.asd(1. / fres, 1. / fres / 2.) tf = sig.ZerosPolesGain([10., 10., 10., 10., 10], [1., 1., 1., 1., 1.], 1.e-14) freq, mag, phase = sig.bode(tf, spectrum.frequencies.to_value()) darm = spectrum.value * (10.**(mag / 20.)) fig = plt.figure(figval) plt.loglog(freq, darm, label='DARM') #plt.loglog(spectrum.frequencies,spectrum.value,label='DARM') plt.ylabel(r'Displacement [m/$\sqrt{\rm Hz}$]') plt.xlabel('Frequency [Hz]') plt.legend() plt.grid(True) return 0, freq
def whiten_zpk(signal, fs, flow=0.3, fhigh=30, order=6): signal = np.array(signal) if len(signal.shape) == 2: axis = np.argmax(signal.shape) else: axis = -1 zc = [-2*np.pi*flow]*(order//2) pc = [-2*np.pi*fhigh]*(order//2) kc = 1.0 sysc = sig.ZerosPolesGain(zc, pc, kc) sysd = sysc.to_discrete(dt=1/float(fs), method='bilinear') sosW = sig.zpk2sos(sysd.zeros, sysd.poles, sysd.gain) signal = sig.sosfiltfilt(sosW, signal, axis=axis) return signal
def single_stage_plots(self, filter_id): stages = self.filters[filter_id][0].stages st_plots = [] for stage in stages: tf = signal.ZerosPolesGain(stage.zeros, stage.poles, stage.gain_factor) tf = tf.to_tf() [w, y, y2] = signal.bode(system=tf, n=1000) st_plots.append( ContinuousPlotData(x_label="Frequency", x_units="rad/s", y_label="Attenuation", y_units="dB", x_data=w, y_data=(-1) * y, logscale=True, dB=True)) return st_plots
def plot_DARM(start, end, fres, figval=1): ch = 'K1:CAL-CS_PROC_DARM_DISPLACEMENT_DQ' # gps_beg = int(to_gps( start )) # gps_end = int(to_gps( end )) # gps_beg_head = int(gps_beg/100000) # gps_end_head = int(gps_end/100000) # if gps_beg_head == gps_end_head: # cache_file="/home/devel/cache/Cache_GPS/%s.cache" % gps_beg_head # else: # # merge two cache file # cache1="/home/devel/cache/Cache_GPS/%s.cache" % gps_beg_headelse # cache2="/home/devel/cache/Cache_GPS/%s.cache" % gps_end_head # cache_file="/var/www/html/past_data_viewer/data/%s_%s.cache" % (gps_beg, gps_end) # with open(cache_file, 'w') as outfile: # for i in [cache1, cache2]: # with open(i) as infile: # outfile.write(infile.read()) try: #data = TimeSeries.read(cache_file, ch, start=gps_beg, end=gps_end, nproc=4) data = TimeSeries.get(ch, start, end, host='k1nds2', port=8088) except: return 1, 'DARM data cannot be obtained. Try with more recent data. %d %d' % ( gps_beg, gps_end) spectrum = data.asd(1. / fres, 1. / fres / 2.) tf = sig.ZerosPolesGain([10., 10., 10., 10., 10], [1., 1., 1., 1., 1.], 1.e-14) freq, mag, phase = sig.bode(tf, spectrum.frequencies.to_value()) darm = spectrum.value * (10.**(mag / 20.)) fig = plt.figure(figval) plt.loglog(freq, darm, label='DARM') #plt.loglog(spectrum.frequencies,spectrum.value,label='DARM') plt.ylabel(r'Displacement [m/$\sqrt{\rm Hz}$]') plt.xlabel('Frequency [Hz]') plt.legend() plt.grid(True) return 0, freq
def loadModel(self, filePath): _, systemFullName = os.path.split( filePath) # Returns path and file name systemName, _ = os.path.splitext( systemFullName) # Returns extension and name if self.__UiElems.Sampling_LUT_Combobox.findText(systemName) == -1: try: with open(filePath, 'r') as inf: systemParameters = ast.literal_eval(inf.read()) self.__SystemModels[systemName] = signal.ZerosPolesGain( systemParameters['Zeros'], systemParameters['Poles'], systemParameters['Gain']) self.__UiElems.Sampling_LUT_Combobox.blockSignals(True) self.__UiElems.Sampling_LUT_Combobox.insertItem(0, systemName) self.__UiElems.Sampling_LUT_Combobox.blockSignals(False) except Exception as e: print("Error: Failed to load model \"%s\" with error \"%s\"" % (filePath, e)) else: print( "Error: Stopped attempted load of redundant model, existing model at: %s" % (self.__UiElems.Sampling_LUT_Combobox.findText(waveName)))
def adjust_function_gain(zeros: list, poles: list, gain): gain_in_db = 20 * np.log10(gain) transfer_function = ss.ZerosPolesGain(zeros, poles, gain) w, mag, phase = ss.bode(transfer_function, n=1000) dmag = np.diff(mag) / np.diff(w) frequencies_to_check = 10 zero_condition = 1.0e-6 for i in range(len(dmag) - frequencies_to_check): values_checked = [] for j in range(frequencies_to_check): values_checked.append(dmag[i + j]) if all([value < zero_condition for value in values_checked]): frequency_to_evaluate = math.floor(i + frequencies_to_check / 2) max_freq = w[frequency_to_evaluate] useless_1, gain_in_passband, useless_2 = ss.bode( transfer_function, [max_freq]) gain_in_passband = 10**(gain_in_passband[0] / 20) gain_needed = gain**2 / gain_in_passband return gain_needed
def from_zpk(self, zeros, poles, gain): """Define a SISO system using the zeros, poles, gain representation. Parameters ---------- zeros : (num_zeros,) array_like system zeros poles : (num_poles,) array_like system poles gain : float system gain Returns ------- controlboros.StateSpaceBuilder intermediate builder object """ zpk = signal.ZerosPolesGain(zeros, poles, gain).to_ss() self._a, self._b, self._c, self._d = zpk.A, zpk.B, zpk.C, zpk.D return self
def pend_sos(f0, Q, fs, dc_gain=1): ''' Make a digital filter for a pendulum TF in SOS form. ''' if f0 >= fs / 2: raise ValueError('f0 too high for nyquist') if Q < 0: raise ValueError('Q must be >=0') w_pole = -2 * np.pi * f0 angle = np.arccos(1 / 2 / Q) zeros = np.array([]) poles = w_pole * np.array([np.exp(1j * angle), np.exp(-1j * angle)]) gain = dc_gain * np.prod(poles) #sos conversion zd, pd, kd = zpk_bilinear(zeros, poles, gain, fs) sys_disc = sig.ZerosPolesGain(zd, pd, kd, dt=1 / fs) sos = sig.zpk2sos(sys_disc.zeros, sys_disc.poles, sys_disc.gain) return sos
def compute_normalised_by_order(self, ap, n, aa) -> ApproximationErrorCode: """ Generates normalised transfer function prioritising the fixed order """ # Computing needed constants from Legendre Approximation epsilon = LegendreApprox.compute_epsilon(ap)**2 ln = LegendreApprox.compute_odd_integrated_polynomial(n) if ( n % 2) else LegendreApprox.compute_even_integrated_polynomial(n) ln = epsilon * ln den = polyadd(poly1d([1]), ln) # Normalised transfer function new_gain = 1 new_poles = [] for pole in 1j * den.roots: if pole.real < 0: new_pole = complex( pole.real if abs(pole.real) > CONSIDERED_ZERO_LIMIT else 0, pole.imag if abs(pole.imag) > CONSIDERED_ZERO_LIMIT else 0) new_gain /= abs(new_pole) new_poles.append(new_pole) # Updating state of transfer function self.h_aux = signal.ZerosPolesGain([], new_poles, new_gain) return ApproximationErrorCode.OK