def impinvar(b_in, a_in, fs=1, tol=0.0001): """ # Copyright (c) 2007 R.G.H. Eschauzier <*****@*****.**> # Copyright (c) 2011 Carnë Draug <*****@*****.**> # Copyright (c) 2011 Juan Pablo Carbajal <*****@*****.**> # Copyright (c) 2016 Sascha Eichstädt <*****@*****.**> # # This program is free software; you can redistribute it and/or modify it under # the terms of the GNU General Public License as published by the Free Software # Foundation; either version 3 of the License, or (at your option) any later # version. # # This program is distributed in the hope that it will be useful, but WITHOUT # ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or # FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more # details. # # You should have received a copy of the GNU General Public License along with # this program; if not, see <https://www.gnu.org/licenses/>. """ ts = 1 / fs # we should be using sampling frequencies to be compatible with Matlab [r_in, p_in, k_in] = dsp.residue(b_in, a_in) # partial fraction expansion n = len(r_in) # Number of poles/residues if len(k_in ) > 0: # Greater than zero means we cannot do impulse invariance if abs(k_in) > 0: raise ValueError("Order numerator >= order denominator") r_out = np.zeros(n, dtype=complex) # Residues of H(z) p_out = np.zeros(n, dtype=complex) # Poles of H(z) k_out = np.zeros(1) # Constant term of H(z) i = 0 while i < n: m = 0 first_pole = p_in[i] # Pole in the s-domain while (i < (n - 1) and np.abs(first_pole - p_in[i + 1]) < tol ): # Multiple poles at p(i) i += 1 # Next residue m += 1 # Next multiplicity [r, p, k] = z_res(r_in[i - m:i + 1], first_pole, ts) # Find z-domain residues k_out += k # Add direct term to output p_out[i - m:i + 1] = p # Copy z-domain pole(s) to output r_out[i - m:i + 1] = r # Copy z-domain residue(s) to output i += 1 # Next s-domain residue/pole [b_out, a_out] = dsp.invres(r_out, p_out, k_out, tol=tol) a_out = to_real(a_out) # Get rid of spurious imaginary part b_out = to_real(b_out) # Shift results right to account for calculating in z instead of z^-1 b_out = b_out[:-1] return b_out, a_out
def __init__(self,Model,ref_beta=1, nodes=[(1,0)],Nj=None,\ output=passthrough): if not Nj: Nj = Model.Nj self.Nj = Nj self.nodes = nodes self.Model = Model self.set_ref_signal(ref_beta) ds, ws = list(zip(*nodes)) ws_grid = numpy.array(ws).reshape( (len(ws), 1)) #last dimension is to broadcast over all `Nterms` equally ds = numpy.array(ds) # ---Acquire the necessary pole and residue values--- # Ps = Model.evaluate_poles(ds, Nj) Rs = Model.evaluate_residues(ds, Nj) #`rs` and `ps` can safely remain as arrays for `invres` ps = Ps.flatten() rs = (Rs * ws_grid).flatten() k0 = numpy.sum(rs / ps).tolist() # ---Rescale units to center dynamic range of `rs` and `ps` around 1e0--- # rscaling=numpy.exp(-(numpy.log(numpy.abs(rs).max())+\ numpy.log(numpy.abs(rs).min()))/2.) pscaling=numpy.exp(-(numpy.log(numpy.abs(ps).max())+\ numpy.log(numpy.abs(ps).min()))/2.) self.rscaling = rscaling self.pscaling = pscaling ps *= pscaling rs *= rscaling k0 *= rscaling / pscaling self.ps = ps self.rs = rs self.k0 = k0 # ---Inverse partial fraction expansion of Eigenfield Laurent series--- # #highest order first in `Ps` and `Qs` #VERY SLOW - about 100ms on practical inversions (~60 terms) #therefore, do it only once and store the polynomial coefficients `As` and `Bs` As, Bs = invres( rs, ps, k=[k0], tol=1e-16, rtype='avg' ) #tol=1e-16 is the smallest allowable to `unique_roots`.. #Double precision offers noticeable protection against overflow dtype = numpy.complex128 self.As = numpy.array(As, dtype=dtype) self.Bs = numpy.array(Bs, dtype=dtype) self.output = output # ---Initialize a counter so inverse function can have self-awareness of # beta continuity etc. for any series of inversions--- # self.i = 0 self.betas = []
def make_ctle(rx_bw, peak_freq, peak_mag, w, dc_offset=0): """ Generate the frequency response of a continuous time linear equalizer (CTLE), given the: - signal path bandwidth, - peaking specification, and - list of frequencies of interest. We use the 'invres()' function from scipy.signal, as it suggests itself as a natural approach, given our chosen use model of having the user provide the peaking frequency and degree of peaking. That is, we define our desired frequency response using one zero and two poles, where: - The pole locations are equal to: - the signal path natural bandwidth, and - the user specified peaking frequency. - The zero location is chosen, so as to provide the desired degree of peaking. Inputs: - rx_bw The natural (or, unequalized) signal path bandwidth (Hz). - peak_freq The location of the desired peak in the frequency response (Hz). - peak_mag The desired relative magnitude of the peak (dB). (mag(H(0)) = 1) - w The list of frequencies of interest (rads./s). - dc_offset The d.c. offset of the CTLE gain curve (dB). Outputs: - w, H The resultant complex frequency response, at the given frequencies. """ p2 = -2. * pi * rx_bw p1 = -2. * pi * peak_freq z = p1 / pow(10., peak_mag / 20.) if(p2 != p1): r1 = (z - p1) / (p2 - p1) r2 = 1 - r1 else: r1 = -1. r2 = z - p1 b, a = invres([r1, r2], [p1, p2], []) w, H = freqs(b, a, w) H *= pow(10., dc_offset / 20.) / abs(H[0]) # Enforce d.c. offset. return (w, H)
def impinvar(b_in, a_in, fs = 1, tol = 0.0001): """ ## Copyright (c) 2007 R.G.H. Eschauzier <*****@*****.**> ## Copyright (c) 2011 Carnë Draug <*****@*****.**> ## Copyright (c) 2011 Juan Pablo Carbajal <*****@*****.**> ## Copyright (c) 2016 Sascha Eichstaedt <*****@*****.**> ## ## This program is free software; you can redistribute it and/or modify it under ## the terms of the GNU General Public License as published by the Free Software ## Foundation; either version 3 of the License, or (at your option) any later ## version. ## ## This program is distributed in the hope that it will be useful, but WITHOUT ## ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or ## FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more ## details. ## ## You should have received a copy of the GNU General Public License along with ## this program; if not, see <http://www.gnu.org/licenses/>. """ ts = 1 / fs # we should be using sampling frequencies to be compatible with Matlab [r_in, p_in, k_in] = dsp.residue(b_in, a_in) # partial fraction expansion n = len(r_in) # Number of poles/residues if (len(k_in) > 0): # Greater than zero means we cannot do impulse invariance if abs(k_in)>0: raise ValueError("Order numerator >= order denominator") r_out = np.zeros(n, dtype = complex) # Residues of H(z) p_out = np.zeros(n, dtype = complex) # Poles of H(z) k_out = np.zeros(n) # Constant term of H(z) i = 0 while (i < n): m = 0 first_pole = p_in[i] # Pole in the s-domain while (i < (n-1) and np.abs(first_pole - p_in[i + 1]) < tol): # Multiple poles at p(i) i += 1 # Next residue m += 1 # Next multiplicity [r, p, k] = z_res(r_in[i - m:i+1], first_pole, ts) # Find z-domain residues k_out += k # Add direct term to output p_out[i - m:i+1] = p # Copy z-domain pole(s) to output r_out[i - m:i+1] = r # Copy z-domain residue(s) to output i += 1 # Next s-domain residue/pole [b_out, a_out] = dsp.invres(r_out, p_out, k_out, tol=tol) a_out = to_real(a_out) # Get rid of spurious imaginary part b_out = to_real(b_out) ## Shift results right to account for calculating in z instead of z^-1 b_out = b_out[:-1] return b_out, a_out
def make_ctle(rx_bw, peak_freq, peak_mag, w, dc_offset=0): """ Generate the frequency response of a continuous time linear equalizer (CTLE), given the: - signal path bandwidth, - peaking specification, and - list of frequencies of interest. We use the 'invres()' function from scipy.signal, as it suggests itself as a natural approach, given our chosen use model of having the user provide the peaking frequency and degree of peaking. That is, we define our desired frequency response using one zero and two poles, where: - The pole locations are equal to: - the signal path natural bandwidth, and - the user specified peaking frequency. - The zero location is chosen, so as to provide the desired degree of peaking. Inputs: - rx_bw The natural (or, unequalized) signal path bandwidth (Hz). - peak_freq The location of the desired peak in the frequency response (Hz). - peak_mag The desired relative magnitude of the peak (dB). (mag(H(0)) = 1) - w The list of frequencies of interest (rads./s). - dc_offset The d.c. offset of the CTLE gain curve (dB). Outputs: - w, H The resultant complex frequency response, at the given frequencies. """ p2 = -2. * pi * rx_bw p1 = -2. * pi * peak_freq z = p1 / pow(10., peak_mag / 20.) if (p2 != p1): r1 = (z - p1) / (p2 - p1) r2 = 1 - r1 else: r1 = -1. r2 = z - p1 b, a = invres([r1, r2], [p1, p2], []) w, H = freqs(b, a, w) H *= pow(10., dc_offset / 20.) / abs(H[0]) # Enforce d.c. offset. return (w, H)
def vectFitSingle(ss, yy, p0, asymptote='none'): _, _, sigma_res = getResidues(ss, yy, p0, asymptote) ones_col = np.transpose(np.matrix(np.ones(len(sigma_res)))) sigma_res_row = np.matrix(sigma_res) Hmat = np.matrix(np.diag(p0)) - ones_col * sigma_res_row yy_poles, _ = np.linalg.eig(Hmat) yy_res, asympArr, _ = getResidues(ss, yy, yy_poles, asymptote) yy_num, yy_den = sig.invres(yy_res, yy_poles, np.real(asympArr)) return sig.lti(yy_num, yy_den)
def test_invres_repeated_roots(self): r = [3 / 20, -7 / 36, -1 / 6, 2 / 45] p = [0, -2, -2, -5] k = [] a_expected = [1, 3] b_expected = [1, 9, 24, 20, 0] rtypes = ('avg', 'mean', 'min', 'minimum', 'max', 'maximum') for rtype in rtypes: a_observed, b_observed = invres(r, p, k, rtype=rtype) assert_allclose(a_observed, a_expected) assert_allclose(b_observed, b_expected)
def test_invres_repeated_roots(self): r = [3/20, -7/36, -1/6, 2/45] p = [0, -2, -2, -5] k = [] a_expected = [1, 3] b_expected = [1, 9, 24, 20, 0] rtypes = ('avg', 'mean', 'min', 'minimum', 'max', 'maximum') for rtype in rtypes: a_observed, b_observed = invres(r, p, k, rtype=rtype) assert_allclose(a_observed, a_expected) assert_allclose(b_observed, b_expected)
def test_invres_distinct_roots(self): # This test was inspired by github issue 2496. r = [3 / 10, -1 / 6, -2 / 15] p = [0, -2, -5] k = [] a_expected = [1, 3] b_expected = [1, 7, 10, 0] a_observed, b_observed = invres(r, p, k) assert_allclose(a_observed, a_expected) assert_allclose(b_observed, b_expected) rtypes = ('avg', 'mean', 'min', 'minimum', 'max', 'maximum') # With the default tolerance, the rtype does not matter # for this example. for rtype in rtypes: a_observed, b_observed = invres(r, p, k, rtype=rtype) assert_allclose(a_observed, a_expected) assert_allclose(b_observed, b_expected) # With unrealistically large tolerances, repeated roots may be inferred # and the rtype comes into play. ridiculous_tolerance = 1e10 for rtype in rtypes: a, b = invres(r, p, k, tol=ridiculous_tolerance, rtype=rtype)
def test_invres_distinct_roots(self): # This test was inspired by github issue 2496. r = [3/10, -1/6, -2/15] p = [0, -2, -5] k = [] a_expected = [1, 3] b_expected = [1, 7, 10, 0] a_observed, b_observed = invres(r, p, k) assert_allclose(a_observed, a_expected) assert_allclose(b_observed, b_expected) rtypes = ('avg', 'mean', 'min', 'minimum', 'max', 'maximum') # With the default tolerance, the rtype does not matter # for this example. for rtype in rtypes: a_observed, b_observed = invres(r, p, k, rtype=rtype) assert_allclose(a_observed, a_expected) assert_allclose(b_observed, b_expected) # With unrealistically large tolerances, repeated roots may be inferred # and the rtype comes into play. ridiculous_tolerance = 1e10 for rtype in rtypes: a, b = invres(r, p, k, tol=ridiculous_tolerance, rtype=rtype)
def vectFit(ss, yy, p0=[], numIter=10, asymptote='none', makePlot=True): """Performs vector fitting of complex data and returns a scipy.signal.lti model. Parameters ---------- ss : array of s-parameters (usually 2*np.pi*1j*ff, where ff is the non-angular Fourier frequency) yy : array of complex values to be fitted p0 : array of guesses for poles numIter : number of times to iterate the vector fitting algorithm asymptote : 'none', 'constant', or 'linear'. If 'none', the underlying function is assumed to be given entirely in terms of residues and poles. If 'constant', a complex constant d will be added. If 'linear', a complex linear term d + ss*e will be added. makePlot : generate a Bode plot (with residuals) of the data and the fit. Returns ------- yyLti : scipy.signal.lti representation of the vector-fitted data figHandle : if makePlot is true, vectFit also returns a handle to the Bode plot figure. """ thisGuess = p0 for ii in range(numIter): _, _, sigma_res = getResidues(ss, yy, thisGuess, asymptote) ones_col = np.transpose(np.matrix(np.ones(len(sigma_res)))) sigma_res_row = np.matrix(sigma_res) Hmat = np.matrix(np.diag(thisGuess)) - ones_col * sigma_res_row yy_poles, _ = np.linalg.eig(Hmat) yy_res, asympArr, _ = getResidues(ss, yy, yy_poles, asymptote) print(asympArr) yy_num, yy_den = sig.invres(yy_res, yy_poles, asympArr) yyLti = sig.lti(yy_num, yy_den) # The following loop flips poles as necessary to keep them # in the left-hand plane for poleIndex, pole in enumerate(yyLti.poles): if np.real(pole) > 0: yyLti.poles[poleIndex] = -np.conjugate(pole) thisGuess = yyLti.poles if makePlot == True: figHandle = bodePlot(ss, yy, yyLti) return yyLti, figHandle return yyLti
def leastsquare_complexexponential(self, h, t, N): ''' Model parameter estimation from impulse response using least-squares complex exponential method h: impulse response measurement t: time range vector (in sec); must be uniformly-spaced N: degree of freedom ''' no_sample = h.size if diff(t).max() > diff(t).max(): # check for uniform time steps spline_fn = interpolate.InterpolatedUnivariateSpline(t, h) t = linspace(t[0], t[-1], no_sample) h = spline_fn(t) h = h.reshape(no_sample, 1) t = t.reshape(no_sample, 1) M = no_sample - N # no of equations dT = t[1] - t[0] # least-squares estimation of eigenvalues (modes) R = matrix(toeplitz(h[N - 1::-1], h[N - 1:no_sample - 1])) A = -1 * matrix(pinv(R.transpose())) * matrix( h[N + arange(0, M, dtype=int)]) A0 = vstack((ones(A.shape[1]), A)).getA1() P = matrix(log(roots(A0)) / dT).transpose() # least-squares estimation of eigenvectors (modal coef) Q = exp(P * t.transpose()) Z = pinv(matrix(Q.transpose())) * matrix(h) # return values num, den = invres(Z.getA1(), P.getA1(), zeros(size(P)), tol=1e-4, rtype='avg') print num, den num = num.real den = den.real h_estimated = Q.transpose() * Z h_estimated = h_estimated.real.getA1() return dict(h_impulse=h, h_estimated=h_estimated, num=num, den=den)
def make_ctle(rx_bw, peak_freq, peak_mag, w, mode="Passive", dc_offset=0): """ Generate the frequency response of a continuous time linear equalizer (CTLE), given the: - signal path bandwidth, - peaking specification - list of frequencies of interest, and - operational mode/offset. We use the 'invres()' function from scipy.signal, as it suggests itself as a natural approach, given our chosen use model of having the user provide the peaking frequency and degree of peaking. That is, we define our desired frequency response using one zero and two poles, where: - The pole locations are equal to: - the signal path natural bandwidth, and - the user specified peaking frequency. - The zero location is chosen, so as to provide the desired degree of peaking. Inputs: - rx_bw The natural (or, unequalized) signal path bandwidth (Hz). - peak_freq The location of the desired peak in the frequency response (Hz). - peak_mag The desired relative magnitude of the peak (dB). (mag(H(0)) = 1) - w The list of frequencies of interest (rads./s). - mode The operational mode; must be one of: - 'Off' : CTLE is disengaged. - 'Passive': Maximum frequency response has magnitude one. - 'AGC' : Automatic gain control. (Handled by calling routine.) - 'Manual' : D.C. offset is set manually. - dc_offset The d.c. offset of the CTLE gain curve (dB). (Only valid, when 'mode' = 'Manual'.) Outputs: - w, H The resultant complex frequency response, at the given frequencies. """ if mode == "Off": return (w, ones(len(w))) p2 = -2.0 * pi * rx_bw p1 = -2.0 * pi * peak_freq z = p1 / pow(10.0, peak_mag / 20.0) if p2 != p1: r1 = (z - p1) / (p2 - p1) r2 = 1 - r1 else: r1 = -1.0 r2 = z - p1 b, a = invres([r1, r2], [p1, p2], []) w, H = freqs(b, a, w) if mode == "Passive": H /= max(abs(H)) elif mode in ("Manual", "AGC"): H *= pow(10.0, dc_offset / 20.0) / abs(H[0]) # Enforce d.c. offset. else: raise RuntimeError( "pybert_util.make_ctle(): Unrecognized value for 'mode' parameter: {}." .format(mode)) return (w, H)
def make_ctle(rx_bw, peak_freq, peak_mag, w, mode='Passive', dc_offset=0): """ Generate the frequency response of a continuous time linear equalizer (CTLE), given the: - signal path bandwidth, - peaking specification - list of frequencies of interest, and - operational mode/offset. We use the 'invres()' function from scipy.signal, as it suggests itself as a natural approach, given our chosen use model of having the user provide the peaking frequency and degree of peaking. That is, we define our desired frequency response using one zero and two poles, where: - The pole locations are equal to: - the signal path natural bandwidth, and - the user specified peaking frequency. - The zero location is chosen, so as to provide the desired degree of peaking. Inputs: - rx_bw The natural (or, unequalized) signal path bandwidth (Hz). - peak_freq The location of the desired peak in the frequency response (Hz). - peak_mag The desired relative magnitude of the peak (dB). (mag(H(0)) = 1) - w The list of frequencies of interest (rads./s). - mode The operational mode; must be one of: - 'Off' : CTLE is disengaged. - 'Passive': Maximum frequency response has magnitude one. - 'AGC' : Automatic gain control. (Handled by calling routine.) - 'Manual' : D.C. offset is set manually. - dc_offset The d.c. offset of the CTLE gain curve (dB). (Only valid, when 'mode' = 'Manual'.) Outputs: - w, H The resultant complex frequency response, at the given frequencies. """ if(mode == 'Off'): return (w, ones(len(w))) p2 = -2. * pi * rx_bw p1 = -2. * pi * peak_freq z = p1 / pow(10., peak_mag / 20.) if(p2 != p1): r1 = (z - p1) / (p2 - p1) r2 = 1 - r1 else: r1 = -1. r2 = z - p1 b, a = invres([r1, r2], [p1, p2], []) w, H = freqs(b, a, w) if(mode == 'Passive'): H /= max(abs(H)) elif(mode == 'Manual' or mode == 'AGC'): H *= pow(10., dc_offset / 20.) / abs(H[0]) # Enforce d.c. offset. else: raise RunTimeException("pybert_util.make_ctle(): Unrecognized value for 'mode' parameter: {}.".format(mode)) return (w, H)
def invert_signal(self,signals,nodes=[(1,0)],Nterms=10,\ interpolation='linear',\ select_by='continuity',\ closest_pole=0,\ scaling=10): """The inversion is not unique, consequently the selected solution will probably be wrong if signal values correspond with "beta" values that are too large (`|beta|~>min{|Poles|}`). This can be expected to break at around `|beta|>2`.""" #Default is to invert signal in contact #~10 terms seem required to converge on e.g. SiO2 spectrum, #especially on the Re(beta)<0 (low signal) side of phonons global roots,poly,root_scaling #global betas,all_roots,pmin,rs,ps,As,Bs,roots,to_minimize if self.verbose: Logger.write('Inverting `signals` based on the provided `nodes` to obtain consistent beta values...') if not hasattr(signals,'__len__'): signals=[signals] if not isinstance(signals,AWA): signals=AWA(signals) zs,ws=list(zip(*nodes)) ws_grid=numpy.array(ws).reshape((len(ws),1)) #last dimension is to broadcast over all `Nterms` equally zs=numpy.array(zs) Rs=self.Rs[:,:Nterms].interpolate_axis(zs,axis=0,kind=interpolation, bounds_error=False,extrapolate=True) Ps=self.Ps[:,:Nterms].interpolate_axis(zs,axis=0,kind=interpolation, bounds_error=False,extrapolate=True) #`rs` and `ps` can safely remain as arrays for `invres` rs=(Rs*ws_grid).flatten() ps=Ps.flatten() k0=numpy.sum(rs/ps).tolist() #Rescale units so their order of magnitude centers around 1 rscaling=numpy.exp(-(numpy.log(numpy.abs(rs).max())+\ numpy.log(numpy.abs(rs).min()))/2.) pscaling=numpy.exp(-(numpy.log(numpy.abs(ps).max())+\ numpy.log(numpy.abs(ps).min()))/2.) root_scaling=1/pscaling #rscaling=1 #pscaling=1 if self.verbose: Logger.write('\tScaling residues by a factor %1.2e to reduce floating point overflow...'%rscaling) Logger.write('\tScaling poles by a factor %1.2e to reduce floating point overflow...'%pscaling) rs*=rscaling; ps*=pscaling k0*=rscaling/pscaling signals=signals*rscaling/pscaling #highest order first in `Ps` and `Qs` #VERY SLOW - about 100ms on practical inversions (~60 terms) As,Bs=invres(rs, ps, k=[k0], tol=1e-16, rtype='avg') #tol=1e-16 is the smallest allowable to `unique_roots`.. dtype=numpy.complex128 #Double precision offers noticeable protection against overflow As=numpy.array(As,dtype=dtype) Bs=numpy.array(Bs,dtype=dtype) signals=signals.astype(dtype) #import time betas=[] for i,signal in enumerate(signals): #t1=time.time() #Root finding `roots` seems to give noisy results when `Bs` has degree >84, with dynamic range ~1e+/-30 in coefficients... #Pretty fast - 5-9 ms on practical inversions with rank ~60 companion matrices, <1 ms with ~36 terms #@TODO: Root finding chokes on `Nterms=9` (number of eigenfields) and `Nts=12` (number of nodes), # necessary for truly converged S3 on resonant phonons, probably due to # floating point overflow - leading term increases exponentially with # number of terms, leading to huge dynamic range. # Perhaps limited by the double precision of DGEEV. # So, replace with faster / more reliable root finder? # We need 1) speed, 2) ALL roots (or at least the first ~10 smallest) poly=As-signal*Bs roots=find_roots(poly,scaling=scaling) roots=roots[roots.imag>0] roots*=root_scaling #since all beta units scaled by `pscaling`, undo that here #print time.time()-t1 #How should we select the most likely beta among the multiple solutions? #1. Avoids large changes in value of beta if select_by=='difference' and i>=1: if i==1 and self.verbose: Logger.write('\tSelecting remaining roots by minimizing differences with prior...') to_minimize=numpy.abs(roots-betas[i-1]) #2. Avoids large changes in slope of beta (best for spectroscopy) #Nearly guarantees good beta spectrum, with exception of very loosely sampled SiC spectrum #Loosely samples SiO2-magnitude phonons still perfectly fine elif select_by=='continuity' and i>=2: if i==2 and self.verbose: Logger.write('\tSelecting remaining roots by ensuring continuity with prior...') earlier_diff=betas[i-1]-betas[i-2] current_diffs=roots-betas[i-1] to_minimize=numpy.abs(current_diffs-earlier_diff) #3. Select specifically which pole we want |beta| to be closest to else: if i==0 and self.verbose: Logger.write('\tSeeding inversion closest to pole %i...'%closest_pole) reordering=numpy.argsort(numpy.abs(roots)) #Order the roots towards increasing beta roots=roots[reordering] to_minimize=numpy.abs(closest_pole-numpy.arange(len(roots))) beta=roots[to_minimize==to_minimize.min()].squeeze() betas.append(beta) if not i%5 and self.verbose: Logger.write('\tProgress: %1.2f%% - Inverted %i signals of %i.'%\ (((i+1)/numpy.float(len(signals))*100),\ (i+1),len(signals))) betas=AWA(betas); betas.adopt_axes(signals) betas=betas.squeeze() if not betas.ndim: betas=betas.tolist() return betas