Beispiel #1
0
def closeLoop(tf,k_p,h_multiplier=1):
    H=control.TransferFunction([h_multiplier],[1])
    H=control.tf2io(H)
    H.name='H'
    H.set_inputs(['in'])
    H.set_outputs(['out'])

    D=control.TransferFunction([k_p],[1])
    D=control.tf2io(D)
    D.name='D'
    D.set_inputs(['in'])
    D.set_outputs(['out'])

    system=control.tf2io(tf)
    system.name='system'
    system.set_inputs(['in'])
    system.set_outputs(['out'])

    #        +
    # in ---->o---->--D-->system----> out
    #         |-                 |
    #         -------H------------     
    system_MF = control.InterconnectedSystem([H,D,system] ,name='system_MF',
        connections=[
            ['H.in','system.out'],
            ['D.in','-H.out'],
            ['system.in','D.out'],
        ],
        inplist=['D.in'],
        inputs=['in'],
        outlist=['system.out','D.out','-H.out'],
        outputs=['out','control','error'])
    return system_MF
Beispiel #2
0
def init_system():
    Qp = 400.0
    Cp = 10E-9
    Lp = 25.7E-6
    Rp = (1.0 / Qp) * math.sqrt(Lp / Cp)

    K = 0.4

    Qs = 50.0
    Ls = 14E-3
    Cs = 15.8E-12
    Rs = 1.0 / Qs * math.sqrt(Ls / Cs)

    Lm = K * math.sqrt(Lp * Ls)

    #three branches, Z1, Z2, Z3

    Branch1 = control.TransferFunction([Cp * (Lp - Lm), Cp * Rp, 1.0],
                                       [Cp, 0.0])
    Branch2 = control.TransferFunction([Cs * (Ls - Lm), Cs * Rs, 1.0],
                                       [Cs, 0.0])
    Branch3 = control.TransferFunction([Lm, 0.0], [1.0])

    BranchParallel = ((Branch3**-1) + Branch2**-1)**-1

    System = (BranchParallel + Branch1)**-1
    sys = System.returnScipySignalLTI()[0][0]

    return sys
def main():
    dt = 0.1
    T = np.arange(0, 6, dt)

    plt.figure(1)
    plt.xticks(np.arange(min(T), max(T) + 1, 1.0))
    plt.xlabel("Time (s)")
    plt.ylabel("Step response")
    tf = ct.TransferFunction(1, [1, -0.6], dt)
    sim(tf, T, "Single pole in RHP")
    tf = ct.TransferFunction(1, [1, 0.6], dt)
    sim(tf, T, "Single pole in LHP")
    if "--noninteractive" in sys.argv:
        latex.savefig("z_oscillations_1p")

    plt.figure(2)
    plt.xlabel("Time (s)")
    plt.ylabel("Step response")
    den = [np.real(x) for x in conv([1, 0.6 + 0.6j], [1, 0.6 - 0.6j])]
    tf = ct.TransferFunction(1, den, dt)
    sim(tf, T, "Complex conjugate poles in LHP")
    den = [np.real(x) for x in conv([1, -0.6 + 0.6j], [1, -0.6 - 0.6j])]
    tf = ct.TransferFunction(1, den, dt)
    sim(tf, T, "Complex conjugate poles in RHP")
    if "--noninteractive" in sys.argv:
        latex.savefig("z_oscillations_2p")
    else:
        plt.show()
Beispiel #4
0
def zero_bins_to_num(zeros):
    exponents = [None, -2, -1, 0, 1]# powers of 10 corresponding to each frequency bin
    
    if zeros[0] == 1:
        G = control.TransferFunction([1,0],1)
    elif zeros[0] == 2:
        G = control.TransferFunction([1,0,0],1)
    else:
        G = 1
    
    for z_i, exp_i in zip(zeros[1:], exponents[1:]):
        if z_i == 0:
            # skip
            continue
        freq_i = random_log_freq(exp_i)
        w_i = 2.0*np.pi*freq_i
        
        if z_i == 1:
            G_i = control.TransferFunction([1,w_i],1)
        elif z_i == 2:
            z_i = 0.8*rand()
            G_i = control.TransferFunction([1,2*z_i*w_i,w_i**2],1)
            
        G *= G_i
        
    if G == 1:
        # This is the default value if zeros is a list of 
        # all zeros: [0,0,0,...,0]
        return G
    else:
        return np.squeeze(G.num)
Beispiel #5
0
def main():
    dt = 0.0001
    T = np.arange(0, 0.25, dt)

    # Make plant
    J = 3.2284e-6  # kg-m^2
    b = 3.5077e-6  # N-m-s
    Ke = 0.0181  # V/rad/s
    Kt = 0.0181  # N-m/Amp
    K = Ke  # Ke = Kt
    R = 0.0902  # Ohms
    L = 230e-6  # H

    # Stable plant (L = 0)
    # s((Js + b)R + K^2)
    # s(JRs + bR + K^2)
    # JRs^2 + bRs + K^2s
    # JRs^2 + (bR + K^2)s
    G = ct.TransferFunction(K, [J * R, b * R + K**2, 0])
    ct.root_locus(G, grid=True)
    plt.xlabel("Real Axis (seconds$^{-1}$)")
    plt.ylabel("Imaginary Axis (seconds$^{-1}$)")
    if "--noninteractive" in sys.argv:
        latex.savefig("highfreq_stable_rlocus")

    plt.figure(2)
    plt.xlabel("Time ($s$)")
    plt.ylabel("Position ($m$)")
    sim(ct.TransferFunction(1, 1), T, "Reference")
    Gcl = make_closed_loop_plant(G, 1)
    sim(Gcl, T, "Step response")
    if "--noninteractive" in sys.argv:
        latex.savefig("highfreq_stable_step")
    else:
        plt.show()
Beispiel #6
0
def pole_bins_to_den(poles):
    # powers of 10 corresponding to each frequency bin
    exponents = [None, -2, -1, 0, 1]
    
    if poles[0] == 1:
        G = control.TransferFunction(1,[1,0])
    elif poles[0] == 2:
        G = control.TransferFunction(1,[1,0,0])
    else:
        G = 1
    
    for p_i, exp_i in zip(poles[1:], exponents[1:]):
        if p_i == 0:
            # skip
            continue
        freq_i = random_log_freq(exp_i)
        w_i = 2.0*np.pi*freq_i
        
        if p_i == 1:
            G_i = control.TransferFunction(1,[1,w_i])
        elif p_i == 2:
            z_i = 0.8*rand()
            G_i = control.TransferFunction(1,[1,2*z_i*w_i,w_i**2])
            
        G *= G_i
        
    return np.squeeze(G.den)
def main():
    dt = 0.0001
    T = np.arange(0, 0.25, dt)

    # Make plant
    J = 3.2284e-6  # kg-m^2
    b = 3.5077e-6  # N-m-s
    Ke = 0.0274  # V/rad/s
    Kt = 0.0274  # N-m/Amp
    K = Ke  # Ke = Kt
    R = 4  # Ohms
    L = 2.75e-6  # H

    # Unstable plant
    # s((Js + b)(Ls + R) + K^2)
    # s(JLs^2 + JRs + bLs + bR + K^2)
    # JLs^3 + JRs^2 + bLs^2 + bRs + K^2s
    # JLs^3 + (JR + bL)s^2 + (bR + K^2)s
    G = cnt.TransferFunction(K, [J * L, J * R + b * L, b * R + K**2, 0])
    cnt.root_locus(G, grid=True)
    plt.xlabel("Real Axis (seconds$^{-1}$)")
    plt.ylabel("Imaginary Axis (seconds$^{-1}$)")
    if "--noninteractive" in sys.argv:
        latexutils.savefig("highfreq_unstable_rlocus")

    plt.figure(2)
    plt.xlabel("Time ($s$)")
    plt.ylabel("Position ($m$)")
    sim(cnt.TransferFunction(1, 1), T, "Reference")
    Gcl = make_closed_loop_plant(G, 3)
    sim(Gcl, T, "Step response")
    if "--noninteractive" in sys.argv:
        latexutils.savefig("highfreq_unstable_step")
    else:
        plt.show()
def main():
    dt = 0.0001
    T = np.arange(0, 6, dt)

    plt.xlabel("Time ($s$)")
    plt.ylabel("Position ($m$)")

    # Make plant
    G = ct.TransferFunction(1, conv([1, 5], [1, 0]))

    sim(ct.TransferFunction(1, 1), T, "Setpoint")

    K = ct.TransferFunction(120, 1)
    Gcl = ct.feedback(G, K)
    sim(Gcl, T, "Underdamped")

    K = ct.TransferFunction(3, 1)
    Gcl = ct.feedback(G, K)
    sim(Gcl, T, "Overdamped")

    K = ct.TransferFunction(6.268, 1)
    Gcl = ct.feedback(G, K)
    sim(Gcl, T, "Critically damped")

    if "--noninteractive" in sys.argv:
        latex.savefig("pid_responses")
    else:
        plt.show()
Beispiel #9
0
    def make_statespace(self):
        jm = self.parameters["DC-Motor"]["Jm"]
        bm = self.parameters["DC-Motor"]["Bm"]
        kme = self.parameters["DC-Motor"]["Kme"]
        kmt = self.parameters["DC-Motor"]["Kmt"]
        rm = self.parameters["DC-Motor"]["Rm"]
        lm = self.parameters["DC-Motor"]["Lm"]

        kdm = self.parameters["DC-Motor"]["Kdm"]
        kpm = self.parameters["DC-Motor"]["Kpm"]
        kim = self.parameters["DC-Motor"]["Kim"]
        nm = self.parameters["DC-Motor"]["Nm"]

        dc = control.TransferFunction(
            [0, kmt], [jm * lm, bm * lm + jm * rm, bm * rm + kme * kmt])
        pidm = control.TransferFunction(
            [kpm + kdm * nm, kpm * nm + kim, kim * nm], [1, nm, 0])

        ii = control.TransferFunction([1], [1, 0, 0])

        agv = ii * control.feedback(dc * pidm, sign=-1)

        # Laplace --> Z
        agvz = control.sample_system(agv, lib.pt, method='zoh')

        # Transferfunction --> StateSpace
        ss = control.tf2ss(agvz)

        lib.set_statespace(ss)
Beispiel #10
0
def pid(kp, ki, kd):
    """
    :param kp:
    :param ki:
    :param kd:
    :return:
    """
    diff = ctrl.TransferFunction([1, 0], 1)
    intgr = ctrl.TransferFunction(1, [1, 0])
    pid_tf = kp + kd * diff + ki * intgr
    return pid_tf
Beispiel #11
0
def sys_dict():
    sdict = {}
    sdict['ss'] = ct.StateSpace([[-1]], [[1]], [[1]], [[0]])
    sdict['tf'] = ct.TransferFunction([1], [0.5, 1])
    sdict['tfx'] = ct.TransferFunction([1, 1], [1])  # non-proper TF
    sdict['frd'] = ct.frd([10 + 0j, 9 + 1j, 8 + 2j, 7 + 3j], [1, 2, 3, 4])
    sdict['lio'] = ct.LinearIOSystem(ct.ss([[-1]], [[5]], [[5]], [[0]]))
    sdict['ios'] = ct.NonlinearIOSystem(sdict['lio']._rhs,
                                        sdict['lio']._out,
                                        inputs=1,
                                        outputs=1,
                                        states=1)
    sdict['arr'] = np.array([[2.0]])
    sdict['flt'] = 3.
    return sdict
Beispiel #12
0
def pid_by_frequency(g, po, ts, err_step=None, err_ramp=None, err_para=None):
    s = ct.TransferFunction([1, 0], [1])
    ki, ess = ss_error(g/s, err_step, err_ramp, err_para)

    if abs(ess) == np.inf or abs(ess) == np.nan:
        ess = None

    if ess is None or ki is None:
        assert "Inconsistent system"

    ki = ki / np.real(ess)
    print("ki=", ki)
    log_po = np.log(100 / po)
    psi = log_po / np.sqrt(np.pi ** 2 + log_po ** 2)

    wn = 4 / psi / ts
    print("wn=", wn, "psi=", psi)

    pm = 100 * psi
    wcp = wn

    p_cut = ct.evalfr(g, wcp * 1j)
    p_cut_mag = np.abs(p_cut)
    p_cut_angle = np.angle(p_cut)

    controller_mag = 1 / p_cut_mag
    controller_angle = -np.pi + pm * np.pi / 180 - p_cut_angle

    kp = controller_mag * np.cos(controller_angle)
    kd = (controller_mag * np.sin(controller_angle) + ki / wcp) / wcp

    print(f"pm= {pm}, ki= {ki}, kp= {kp}, kd= {kd}")
    controller = kp + kd * s + ki / s

    return controller
def PDrootlocusPlot():
    G = control.TransferFunction(L, (L, K2, -9.8 + K1))

    rlist, klist = control.rlocus(G, grid=False)
    plt.title("Root Locus diagram, K1=" + str(K1) + " and K2= " + str(K2))

    plt.show()
def random_Bode_TF():
    plist = assign_poles_to_bins()
    zlist = assign_zeros_to_bins(plist)
    den = pole_bins_to_den(plist)
    num = zero_bins_to_num(zlist)
    G = control.TransferFunction(num, den)
    return G
Beispiel #15
0
def symbolic_transfer_function(
        eq: Union[sp.Expr, int, float]) -> ct.TransferFunction:
    """
    Transform a symbolic equation to a transfer function (sympy -> control)
    :param eq: your symbolic sympy based equation
    :return: a control Transfer Function class
    """
    s = sp.var('s')
    try:
        if eq.is_real:
            pass
    except:
        if not isinstance(eq, float) and not isinstance(eq, int):
            used_symbols = [str(sym) for sym in eq.free_symbols]
            if not len(used_symbols) == 1 or "s" not in used_symbols:
                raise Exception(
                    "invalid equation, please use correct transfer function equation (e.g. 1/(s**2+3))"
                )

    n, d = sp.fraction(sp.factor(eq))

    num = sp.Poly(sp.expand(n), s).all_coeffs()
    den = sp.Poly(sp.expand(d), s).all_coeffs()

    num: [float] = [float(v) for v in num]
    den: [float] = [float(v) for v in den]

    return ct.TransferFunction(num, den)
Beispiel #16
0
def feedback(tau: float, fb_gain: float) -> None:
    """Simulation of a negative feedback system, using the package 'control'.
    'time', 'in_signal', 'num' and 'den' are taken from the global workspace
    
    Parameters
    ----------
    tau : time constant of a first order lag [sec]
    fb_gain : feedback gain
    """
    
    # First, define the feedforward transfer function
    sys = control.TransferFunction(num, den)
    print(sys)          # 1 / (tau*s + 1)
    
    # Simulate the response of the feedforward system
    t_out, y_out, x_out = control.forced_response(sys, T=time, U=in_signal)
    
    # Then define a feedback-loop, with gain fb_gain
    sys_total = control.feedback(sys, fb_gain)
    print(sys_total)    # 1 / (tau*s + (1+k)) 
    
    # Simulate the response of the feedback system
    t_total, y_total, x_total = control.forced_response(sys_total,
                                                        T=time, U=in_signal)
    
    # Show the signals
    plt.plot(time, in_signal, '-', label='Input')
    plt.plot(t_out, y_out, '--', label='Feedforward')
    plt.plot(t_total, y_total, '-.', label='Feedback')
    
    # Format the plot
    plt.xlabel('Time [sec]')
    plt.title(f"First order lag (tau={tau} sec)")
    plt.text(15, 0.8, "Simulated with 'control' ", fontsize=12)
    plt.legend()
Beispiel #17
0
def pid(kp, ki, kd):
    """
    This function constructs a PID controller; returning its associated transfer function, based upon
    the provided values for its gain components.
    :param kp: The proportional gain value.
    :param ki: The integral gain value.
    :param kd: The differential gain value.
    :return: The PID's transfer function based on the gain values provided.
    """
    diff = ctrl.TransferFunction(
        [1, 0], 1)  # Defines the differential's transfer function.
    intgr = ctrl.TransferFunction(
        1, [1, 0])  # Defines the integral's transfer function.
    pid_tf = kp + (kd * diff) + (
        ki * intgr)  # Determines the PID's overall transfer function.
    return pid_tf
Beispiel #18
0
 def plot(self):
     G = control.TransferFunction((1, 1.5), (1, 11, 10, 0))
     mag, phase, omega = control.bode(G)            
     plt.title('Bode Plots', y= 2.20) 
     plt.gcf().canvas.set_window_title('Bode Plots')
     plt.grid()
     plt.show()
Beispiel #19
0
 def plot(self):
     G = control.TransferFunction((1, 1.5), (1, 11, 10, 0))
     nichols(G)
     plt.title('Nichols Plot')
     plt.gcf().canvas.set_window_title('Nichols Plot')
     plt.grid()
     plt.show()
Beispiel #20
0
def plotPolesAndZeros(tf):
    num = [tf[0], tf[1], tf[2]]
    den = [tf[3], tf[4], tf[5]]
    sistema = cl.TransferFunction(num, den)
    cl.pzmap(sistema, Plot=True)
    plt.show()
    return
    def runIdentification(self):
        n_steps = len(self.t)

        n = self.sys_id_n_poles  # order of the denominator (a_1,...,a_n)
        m = self.sys_id_n_zeros  # order of the numerator (b_0,...,b_m)
        d = self.sys_id_delays  # number of delays
        tau = 60.0  # forgetting period
        lbda = 1.0 - self.dt / tau
        self.sysid = SystemIdentification(n, m, d)
        self.sysid.lbda = lbda

        (theta_hat, a_coeffs,
         b_coeffs) = self.sysid.run(self.t, self.u, self.y)

        self.plotStateVector(a_coeffs, b_coeffs)
        self.is_system_identified = True
        self.btn_run_sys_id.setEnabled(False)
        dt = self.dt
        # num = self.sysid.getNum()
        # den = self.sysid.getDen()
        # self.Gz_dot = ctrl.TransferFunction(num, den, dt)

        # Uncomment below to add integrator
        # self.sysid.addIntegrator()
        self.num = self.sysid.getNum()

        self.den = self.sysid.getDen()

        self.Gz = ctrl.TransferFunction(self.num, self.den, dt)
        self.updateTfDisplay(a_coeffs[:, -1], b_coeffs[:, -1])
        self.plotPolesZeros()
        self.replayInputData()
def f(x):
    controler = clt.TransferFunction([x[2], x[0], x[1]],[1,0])
    sys = clt.feedback(controler*H) #fechando a malha
    #Aplica degrau
    sys2 = sys.returnScipySignalLTI()[0][0]
    t2,y2 = step(sys2,N = dots)
    return abs(1-y2[-1]) #retorna o erro
Beispiel #23
0
def setPlanta(PlantaStr):
    Planta = PlantaStr.split("/")
    numerador = [float(i) for i in Planta[0].split(',')]
    if len(Planta) >= 2:
        denominador = [float(i) for i in Planta[1].split(',')]
    else:
        denominador = [1.0]
    return control.TransferFunction(numerador, denominador)
Beispiel #24
0
def random_transfer_function():
    """Generate a random transfer function for root locus practice."""
    poles = random_poles()
    zeros = random_zeros(poles)
    zeros2 = np.floor(np.array(zeros) * 2) * 0.5
    num = np.poly(zeros2)
    den = np.poly(poles)
    G = control.TransferFunction(num, den)
    return G
Beispiel #25
0
 def plot(self):
     G = control.TransferFunction((1), (1, 1))
     real, imag, freq = control.nyquist(G)
     plt.title('Nyquist Plot') 
     plt.gcf().canvas.set_window_title('Nyquist Plot')
     plt.xlabel('Real')
     plt.ylabel('Imaginary')
     plt.grid()
     plt.show()
def make_closed_loop_plant(G, Kp):
    """Returns a TransferFunction representing a plant in negative feedback with
    a P controller that uses the given gain.

    Keyword arguments:
    G -- open-loop plant
    Kp -- proportional gain
    """
    K = cnt.TransferFunction(Kp, 1)
    return cnt.feedback(G, K)
def main():
    dt = 0.0001
    T = np.arange(0, 6, dt)

    plt.xlabel("Time ($s$)")
    plt.ylabel("Position ($m$)")

    # Make plant
    G = cnt.TransferFunction(1, conv([1, 5], [1, 0]))

    sim(cnt.TransferFunction(1, 1), T, "Reference")
    Gcl = make_closed_loop_plant(G, 120)
    sim(Gcl, T, "Underdamped")
    Gcl = make_closed_loop_plant(G, 3)
    sim(Gcl, T, "Overdamped")
    Gcl = make_closed_loop_plant(G, 6.268)
    sim(Gcl, T, "Critically damped")

    plt.savefig("pid_responses.svg")
Beispiel #28
0
def random_TF_first_order_only(max_poles=5, max_zeros=None):
    plist = assign_first_order_poles_to_bins(max_poles=max_poles)
    while not np.any(plist):
        # We will not allow a TF that has no poles
        plist = assign_poles_to_bins(max_poles=max_poles)

    zlist = assign_first_order_zeros_to_bins(plist, max_zeros=max_zeros)
    den = pole_bins_to_den(plist)
    num = zero_bins_to_num(zlist)
    G = control.TransferFunction(num,den)
    return G
def random_transfer_function(max_poles=5):
    """Generate a random transfer function for root locus practice."""
    poles = random_poles(max_poles=max_poles)
    zeros = random_zeros(poles)
    zeros2 = np.floor(np.array(zeros) *
                      2) * 0.5  # I guess I am rounding them all down here....
    poles3, zeros3 = eliminate_near_cancellations(poles, zeros2.tolist())
    num = np.poly(zeros3)
    den = np.poly(poles3)
    G = control.TransferFunction(num, den)
    return G
Beispiel #30
0
    def _create_comp(self):
        self.Gc = control.TransferFunction(self.numlist,
                                           self.denlist) * self.gain
        if hasattr(control, 'c2d'):
            c2d = control.c2d
        elif hasattr(control, 'matlab'):
            c2d = control.matlab.c2d

        self.Gd = c2d(self.Gc, dt, 'tustin')
        self.numz = squeeze(self.Gd.num)
        self.denz = squeeze(self.Gd.den)
        self.dig_comp = Digital_Compensator(self.numz, self.denz)