def __init__(self, b, a, Ts=1.): # multiple roots are not supported if ( np.any( sig.unique_roots( np.roots(a) )[1] > 1 ) ): raise("Roots with multiplicity > 1 not supported") self.b = b; self.a = a; # Partial Fraction Decomposition (r, p, k) = sig.residue(b,a) if ( k != 0. ): raise("System with direct term not supported ATM") # roots in half-plane with imag-part >= 0 posIP = np.imag(p) >= 0.0 r = r[posIP] p = p[posIP] # going into the discrete domain P = np.exp(p*Ts) self.PS = list() for rp in zip(r,P): self.PS.append( firstOrderSys(rp) ) # must make sure polynomial computation doesn't overflow # NOTE: if there are multiple channels then all must be normalized # by the *same* number maxResp = self.maxPolyResponse() if self.maxPolyResponse() > 1.0: raise RuntimeError("Polynomial too large (would overflow); reduce numerator by", maxResp)
def real_summation_partition(zpk, variant=0, tol=1e-16): r = random.Random(variant) zeros, poles, gain = zpk pole_groups = \ poly.real_polynomial_factorization_roots(poles, tol=tol) if len(pole_groups) < 2: return rf, ((), (), 0.) # degenerate case r.shuffle(pole_groups) i = r.choice(range(1, len(pole_groups))) q = np.concatenate(pole_groups[:i]) u = np.concatenate(pole_groups[i:]) if len(q) < len(u): q, u = u, q # improper rational for interpolation def f(z): return -(reduce(auto.numpy.multiply, z - q, 1.) / reduce(auto.numpy.multiply, z - u, 1.)) z, s = signal.unique_roots(zeros, tol=tol, rtype='avg') n = np.sum(s) - 1 k = math.floor(n / (1 + len(q) / len(u))) m = n - k p, t, v = hermite_rational_interpolant(f, z, s, m, k) p = poly.real_polynomial_roots_if_close(p, tol=tol) t = poly.real_polynomial_roots_if_close(t, tol=tol) kp, kt = np.abs(v), np.sign(v) kc = gain / poly.simplify( poly.add(kp * poly.from_roots(np.concatenate( (p, u))), kt * poly.from_roots(np.concatenate((t, q)))))[0] rfL = p, q, kc * kp rfR = t, u, kc * kt return rfL, rfR
def partial_fractions_expansion(z, p, tol=1e-16, rtype='avg'): if len(z) == 0 and len(p) == 0: return z, p, np.array([]) if len(z) >= len(p): raise ValueError('Cannot expand improper rational function') if len(p) == 1: return np.array([1]), p, np.array([1]) # Use modified Brugia method u, su = signal.unique_roots(z, tol=tol, rtype=rtype) v, sv = signal.unique_roots(p, tol=tol, rtype=rtype) N = lambda x: np.prod((x - u)**su) n = 0 r = np.zeros(len(p), dtype=complex) vm = np.ma.array(v, mask=np.zeros_like(v)) for j, (vj, sj) in enumerate(zip(v, sv)): vm.mask[j] = True Dj = lambda x: np.prod((x - vm)**sv) r[n] = N(vj) / Dj(vj) if sj > 1: h = lambda r: np.sum(su / (vj - u)**r) - np.sum(sv / (vj - vm)**r) b = np.c_[[h(i) for i in range(1, sj)]] A = np.zeros((sj - 1, sj - 1), dtype=complex) for i in range(1, sj): A[i - 1, i - 1] = i A[i:, i - 1] = b[:-i] A[i - 1:, i - 1] *= -1**(i - 1) c = scipy.linalg.solve_triangular(A, b, lower=True) r[n + 1:n + sj] = c * r[n] vm.mask[j] = False n += sj r = simple_if_possible(r, tol) p = np.concatenate([[vi] * si for vi, si in zip(v, sv)]) s = np.concatenate([range(1, si + 1) for si in sv]) return r, p, s
#vals = np.roots(np.convolve(ones(500),ones(500))) # 500 double complex roots #vals = np.roots(np.convolve(ones(5),ones(7))) # 4 double complex roots ## tests with nans #vals = list(ones(5) * 1j); vals.append(np.nan); vals.append(np.nan) #vals = [] #print(vals) Navg = 1000 rtype = 'min' print('============ dsp.unique_roots() ================================') t1 = time.clock() for i in range(Navg): roots, mult = dsp.unique_roots(vals, rtype = rtype, rdist='manhattan') t2 = time.clock() T_dsp = (t2 - t1)/Navg print (mult) print('============ signal.unique_roots() =============================') t1 = time.clock() for i in range(Navg): roots, mult = sig.unique_roots(vals, rtype = rtype) t2 = time.clock() T_sig = (t2 - t1)/Navg print (mult) print("T_dsp = ",T_dsp, " s") print("T_sig = ",T_sig, " s") print("T_dsp / T_sig = ", T_dsp / T_sig)