Ejemplo n.º 1
0
def rutina_step_plot(self, system, T, kp, ki, kd):
    """
    Función para obtener la respuesta escalón del sistema en lazo cerrado en combinación con un controlador PID y su respectiva graficacion.
    
    :param system: Representacion del sistema
    :type system: LTI
    :param T: Vector de tiempo
    :type T: numpyArray
    :param kp: Ganancia proporcional
    :type kp: float
    :param ki: Ganancia integral
    :type ki: float
    :param kd: Ganancia derivativa
    :type kd: float
    :return: Respuesta escalón separada en vector de tiempo y vector de salida
    :rtype: tuple(numpyArray, numpyArray)
    """

    U = np.ones_like(T)

    # Discriminación entre continue y discreto, con delay o sin delay, delay realizado con pade
    if ctrl.isdtime(system, strict=True):
        t, y, _ = ctrl.forced_response(system, T, U)
    elif (self.main.tfdelaycheckBox2.isChecked()
          and self.main.PIDstackedWidget.currentIndex() == 0):
        pade = ctrl.TransferFunction(
            *ctrl.pade(json.loads(self.main.tfdelayEdit2.text()), 10))
        N = self.main.pidNSlider.value()
        pid = ctrl.TransferFunction([N * kd + kp, N * kp + ki, N * ki],
                                    [1, N, 0])
        system = ctrl.feedback(pid * system * pade)
        t, y, _ = ctrl.forced_response(system, T, U)
    elif (self.main.ssdelaycheckBox2.isChecked()
          and self.main.PIDstackedWidget.currentIndex() == 1):
        pade = ctrl.TransferFunction(
            *ctrl.pade(json.loads(self.main.ssdelayEdit2.text()), 10))
        N = self.main.pidNSlider.value()
        pid = ctrl.TransferFunction([N * kd + kp, N * kp + ki, N * ki],
                                    [1, N, 0])
        system = ctrl.feedback(pid * system * pade)
        t, y, _ = ctrl.forced_response(system, T, U)
    else:
        N = self.main.pidNSlider.value()
        pid = ctrl.TransferFunction([N * kd + kp, N * kp + ki, N * ki],
                                    [1, N, 0])
        system = ctrl.feedback(pid * system)
        t, y, _ = ctrl.forced_response(system, T, U)

    if ctrl.isdtime(system, strict=True):
        y = y[0]
        y = np.clip(y, -1e12, 1e12)
        self.main.stepGraphicsView2.curva.setData(t, y[:-1], stepMode=True)
    else:
        y = np.clip(y, -1e12, 1e12)
        self.main.stepGraphicsView2.curva.setData(t, y, stepMode=False)

    return t, y
Ejemplo n.º 2
0
def rutina_impulse_plot(self, system, T):
    """
    Función para obtener la respuesta impulso del sistema y su respectiva graficacion.
    
    
    :param system: Representacion del sistema
    :type system: LTI
    :param T: Vector de tiempo
    :type T: numpyArray
    :return: Respuesta impulso separada en vector de tiempo y vector de salida
    :rtype: tuple(numpyArray, numpyArray)
    """

    U = np.zeros_like(T)

    # Tomado de la libreria de control
    if ctrl.isdtime(system, strict=True):
        U[0] = 1 / self.dt
        new_X0 = 0
    else:
        temp_sys = ctrl.tf2ss(system)
        n_states = temp_sys.A.shape[0]
        X0 = ctrl.timeresp._check_convert_array(0, [(n_states, ),
                                                    (n_states, 1)],
                                                'Parameter ``X0``: \n',
                                                squeeze=True)
        B = np.asarray(temp_sys.B).squeeze()
        new_X0 = B + X0

    t, y, _ = ctrl.forced_response(system, T, U, X0=new_X0)

    # Desplazamiento en el tiempo en caso de delay
    if system.delay:
        y_delay = np.zeros(int(system.delay / 0.01)).tolist()
        y_delay.extend(y[:-int(system.delay / 0.01)].tolist())
        y = y_delay

    self.main.impulseGraphicsView1.canvas.axes.clear()

    if ctrl.isdtime(system, strict=True):
        y = y[0]
        y = np.clip(y, -1e300, 1e300)
        self.main.impulseGraphicsView1.canvas.axes.step(t, y, where="mid")
    else:
        y = np.clip(y, -1e300, 1e300)
        self.main.impulseGraphicsView1.canvas.axes.plot(t, y)

    self.main.impulseGraphicsView1.canvas.axes.grid(color="lightgray")
    self.main.impulseGraphicsView1.canvas.axes.set_title("Respuesta impulso")
    self.main.impulseGraphicsView1.canvas.axes.xaxis.set_major_formatter(
        mticker.FormatStrFormatter("%.2f s"))
    self.main.impulseGraphicsView1.canvas.axes.set_xlabel("Tiempo")
    self.main.impulseGraphicsView1.canvas.axes.set_ylabel("Respuesta")
    self.main.impulseGraphicsView1.canvas.draw()
    self.main.impulseGraphicsView1.toolbar.update()

    return t, y
Ejemplo n.º 3
0
def system_creator_ss(self, A, B, C, D):
    """
    Función para la creación del sistema a partir de la matriz de estado, matriz de entrada, matriz de salida y la matriz de transmisión directa la ecuación de espacio de estados.
    
    :param A: Matriz de estados
    :type A: list
    :param B: Matriz de entrada
    :type B: list
    :param C: Matriz de salida
    :type C: list
    :param D: Matriz de transmisión directa
    :type D: list
    :return: El sistema, el vector de tiempo, el sistema con delay y el sistema en el espacio de estados, si el sistema no tiene delay, ambos son iguales
    :rtype: tuple(LTI, numpyArray, LTI, LTI)
    """

    if not self.main.ssdiscretocheckBox1.isChecked(
    ) and self.main.ssdelaycheckBox1.isChecked():
        delay = json.loads(self.main.ssdelayEdit1.text())
    else:
        delay = 0

    system = ctrl.StateSpace(A, B, C, D, delay=delay)

    # Para obtener un tiempo aproximado
    t, y = ctrl.impulse_response(system)

    # En caso de que el sistema sea discreto
    if self.main.ssdiscretocheckBox1.isChecked():
        system = ctrl.sample_system(system, self.dt,
                                    self.main.sscomboBox1.currentText())

        system_ss = system
        system = ctrl.ss2tf(system)

        if self.main.ssdelaycheckBox1.isChecked():
            delay = [0] * (
                int(json.loads(self.main.ssdelayEdit1.text()) / self.dt) + 1)
            delay[0] = 1
            system_delay = system * ctrl.TransferFunction([1], delay, self.dt)
        else:
            system_delay = None
    else:
        system_ss = system
        system = ctrl.ss2tf(system)
        system_delay = None

    try:
        if ctrl.isdtime(system, strict=True):
            T = np.arange(0, 2 * np.max(t), self.dt)
        else:
            T = np.arange(0, 2 * np.max(t), 0.01)
    except ValueError:
        T = np.arange(0, 100, 0.01)

    return system, T, system_delay, system_ss
Ejemplo n.º 4
0
def rutina_root_locus_plot(self, system):
    """
    Función para obtener el lugar de la raíces del sistema y su respectiva graficacion, la graficacion se realizo de forma interna en la libreria de control, para esto se modificó la función root_locus para poder enviar el axis y la figura.
    
    :param system: Representacion del sistema
    :type system: LTI
    """

    self.main.rlocusGraphicsView1.canvas.axes.cla()

    # Distinción entre discreto y continuo, con delay y sin delay.
    if not ctrl.isdtime(system, strict=True):
        if self.main.tfdelaycheckBox1.isChecked(
        ) and self.main.AnalisisstackedWidget.currentIndex() == 0:
            pade_delay = ctrl.TransferFunction(
                *ctrl.pade(json.loads(self.main.tfdelayEdit1.text()), 4))
            t, y = ctrl.root_locus(
                pade_delay * system,
                figure=self.main.rlocusGraphicsView1,
                ax=self.main.rlocusGraphicsView1.canvas.axes)

        if self.main.ssdelaycheckBox1.isChecked(
        ) and self.main.AnalisisstackedWidget.currentIndex() == 1:
            pade_delay = ctrl.TransferFunction(
                *ctrl.pade(json.loads(self.main.ssdelayEdit1.text()), 4))
            t, y = ctrl.root_locus(
                pade_delay * system,
                figure=self.main.rlocusGraphicsView1,
                ax=self.main.rlocusGraphicsView1.canvas.axes)

        if not self.main.tfdelaycheckBox1.isChecked(
        ) and self.main.AnalisisstackedWidget.currentIndex() == 0:
            t, y = ctrl.root_locus(
                system,
                figure=self.main.rlocusGraphicsView1,
                ax=self.main.rlocusGraphicsView1.canvas.axes)

        if not self.main.ssdelaycheckBox1.isChecked(
        ) and self.main.AnalisisstackedWidget.currentIndex() == 1:
            t, y = ctrl.root_locus(
                system,
                figure=self.main.rlocusGraphicsView1,
                ax=self.main.rlocusGraphicsView1.canvas.axes)
    else:
        t, y = ctrl.root_locus(system,
                               figure=self.main.rlocusGraphicsView1,
                               ax=self.main.rlocusGraphicsView1.canvas.axes)

    self.main.rlocusGraphicsView1.canvas.axes.set_title("Lugar de las raíces")
    self.main.rlocusGraphicsView1.canvas.draw()
    self.main.rlocusGraphicsView1.toolbar.update()

    return
Ejemplo n.º 5
0
def system_creator_tf(self, numerador, denominador):
    """
    Función para la creación del sistema a partir de los coeficientes del numerador y del denominador de la función de transferencia.
    
    :param numerador: Coeficientes del numerador
    :type numerador: list
    :param denominador: Coeficientes del denominador
    :type denominador: list
    :return: El sistema, el vector de tiempo y el sistema con delay, si el sistema no tiene delay, ambos son iguales
    :rtype: tuple(LTI, numpyArray, LTI)
    """

    if not self.main.tfdiscretocheckBox1.isChecked(
    ) and self.main.tfdelaycheckBox1.isChecked():
        delay = json.loads(self.main.tfdelayEdit1.text())
    else:
        delay = 0

    system = ctrl.TransferFunction(numerador, denominador, delay=delay)

    # Para obtener un tiempo aproximado
    t, y = ctrl.impulse_response(system)

    # En caso de que el sistema sea discreto
    if self.main.tfdiscretocheckBox1.isChecked():
        system = ctrl.sample_system(system, self.dt,
                                    self.main.tfcomboBox1.currentText())

        if self.main.tfdelaycheckBox1.isChecked():
            delay = [0] * (
                int(json.loads(self.main.tfdelayEdit1.text()) / self.dt) + 1)
            delay[0] = 1
            system_delay = system * ctrl.TransferFunction([1], delay, self.dt)
        else:
            system_delay = None
    else:
        system_delay = system

    try:
        if ctrl.isdtime(system, strict=True):
            T = np.arange(0, 2 * np.max(t), self.dt)
        else:
            T = np.arange(0, 2 * np.max(t), 0.01)
    except ValueError:
        T = np.arange(0, 100, 0.01)

    return system, T, system_delay
Ejemplo n.º 6
0
def rutina_nichols_plot(self, system):
    """
    Función para obtener el diagrama de nichols del sistema y su respectiva graficacion, la graficacion se realizo de forma interna en la libreria de control, para esto se modificó la función nichols_plot para poder enviar el axis y la figura, adicionalmente se realizaron algunas modificaciones para una mejor presentación de la gráfica.
    
    :param system: Representacion del sistema
    :type system: LTI
    """

    self.main.nicholsGraphicsView1.canvas.axes.cla()

    if ctrl.isdtime(system, strict=True):
        if (self.main.tfdelaycheckBox1.isChecked()
                and self.main.AnalisisstackedWidget.currentIndex() == 0) or (
                    self.main.ssdelaycheckBox1.isChecked()
                    and self.main.AnalisisstackedWidget.currentIndex() == 1):

            ctrl.nichols_plot(system,
                              figure=self.main.nicholsGraphicsView1,
                              ax=self.main.nicholsGraphicsView1.canvas.axes,
                              delay=True)
        else:
            ctrl.nichols_plot(system,
                              figure=self.main.nicholsGraphicsView1,
                              ax=self.main.nicholsGraphicsView1.canvas.axes)
    else:
        if (self.main.tfdelaycheckBox1.isChecked()
                and self.main.AnalisisstackedWidget.currentIndex() == 0) or (
                    self.main.ssdelaycheckBox1.isChecked()
                    and self.main.AnalisisstackedWidget.currentIndex() == 1):

            ctrl.nichols_plot(system,
                              figure=self.main.nicholsGraphicsView1,
                              ax=self.main.nicholsGraphicsView1.canvas.axes,
                              delay=True)
        else:
            ctrl.nichols_plot(system,
                              figure=self.main.nicholsGraphicsView1,
                              ax=self.main.nicholsGraphicsView1.canvas.axes)

    self.main.nicholsGraphicsView1.canvas.draw()
    self.main.nicholsGraphicsView1.toolbar.update()

    return
Ejemplo n.º 7
0
def rutina_step_plot(self, system, T):
    """
    Función para obtener la respuesta escalón del sistema y su respectiva graficacion.
    
    
    :param system: Representacion del sistema
    :type system: LTI
    :param T: Vector de tiempo
    :type T: numpyArray
    :return: Respuesta escalón separada en vector de tiempo y vector de salida
    :rtype: tuple(numpyArray, numpyArray)
    """

    U = np.ones_like(T)

    # Desplazamiento en el tiempo en caso de delay
    if system.delay:
        U[:int(system.delay / 0.01) + 1] = 0

    t, y, _ = ctrl.forced_response(system, T, U)

    self.main.stepGraphicsView1.canvas.axes.clear()

    if ctrl.isdtime(system, strict=True):
        y = y[0]
        y = np.clip(y, -1e300, 1e300)
        self.main.stepGraphicsView1.canvas.axes.step(t, y, where="mid")
    else:
        y = np.clip(y, -1e300, 1e300)
        self.main.stepGraphicsView1.canvas.axes.plot(t, y)

    self.main.stepGraphicsView1.canvas.axes.grid(color="lightgray")
    self.main.stepGraphicsView1.canvas.axes.set_title("Respuesta escalón")
    self.main.stepGraphicsView1.canvas.axes.xaxis.set_major_formatter(
        mticker.FormatStrFormatter("%.2f s"))
    self.main.stepGraphicsView1.canvas.axes.set_xlabel("Tiempo")
    self.main.stepGraphicsView1.canvas.axes.set_ylabel("Respuesta")
    self.main.stepGraphicsView1.canvas.draw()
    self.main.stepGraphicsView1.toolbar.update()

    return t, y
Ejemplo n.º 8
0
def margenes_ganancias(self, system, mag, phase, omega):
    """
    Función para obtener el margen de ganancia y el margen de fase.
    
    :param system: Representación del sistema
    :type system: LTI
    :param mag: Magnitud de la respuesta en frecuencia
    :type mag: numpyArray
    :param phase: Fase de la respuesta en frecuencia
    :type phase: numpyArray
    :param omega: Frecuencias utilizadas para la respuesta en frecuencia
    :type omega: numpyArray
    :return: Margenes de ganancia y fase separados en margen de ganancia, margen de fase, frecuencia del margen de ganancia y frecuencia del margen de fase
    :rtype: tuple(float, float, float, float)
    """

    gainDb = 20 * np.log10(mag)
    degPhase = phase * 180.0 / np.pi

    # Transformado la fase a : -360 < phase < 360, para +/- 360  phase -> 0
    comp_phase = np.copy(degPhase)
    degPhase = degPhase - (degPhase / 360).astype(int) * 360

    # Para evitar la detección de cruces al llevar las fases al rango -360 < phase < 360
    crossHack1 = np.diff(1 * (degPhase > -183) != 0)
    crossHack2 = np.diff(1 * (degPhase > -177) != 0)
    crossHack = ~crossHack1 * ~crossHack2

    # Detección de cruce
    indPhase = np.diff(1 * (gainDb > 0) != 0)
    indGain = np.diff(1 * (degPhase > -180) != 0)
    indGain = indGain * crossHack

    # Cálculo de la respuesta en frecuencia para omega = 0 rad/s y pi en caso de ser discreto
    if ctrl.isdtime(system, strict=True):
        zero_freq_response = ctrl.evalfr(system, 1)

        nyquist_freq_response = ctrl.evalfr(system, np.exp(np.pi * 1j))
        nyquistMag = np.abs(nyquist_freq_response)
        nyquistPhase = np.angle(nyquist_freq_response)

        if nyquistPhase * 180.0 / np.pi >= 180:
            nyquistPhase = nyquistPhase - 2 * np.pi

        omega = np.insert(omega, len(omega), np.pi / self.dt)
        gainDb = np.insert(gainDb, len(gainDb), 20 * np.log10(nyquistMag))
        degPhase = np.insert(degPhase, len(degPhase),
                             nyquistPhase * 180.0 / np.pi)

        # Verificando "cruce" por -180 grados para la frecuencia de Nyquist
        if np.isclose(nyquistPhase * 180.0 / np.pi, -180):
            indGain = np.insert(indGain, len(indGain), True)
        else:
            indGain = np.insert(indGain, len(indGain), False)

        # Verificando "cruce" por 0 dB para la frecuencia de Nyquist
        if np.isclose(20 * np.log10(nyquistMag), 0):
            indPhase = np.insert(indPhase, len(indPhase), True)
        else:
            indPhase = np.insert(indPhase, len(indPhase), False)
    else:
        zero_freq_response = ctrl.evalfr(system, 0j)

    omega = np.insert(omega, 0, 0)
    zeroPhase = np.angle(zero_freq_response)
    zeroMag = np.abs(zero_freq_response)
    if zeroPhase * 180.0 / np.pi >= 180:
        zeroPhase = zeroPhase - 2 * np.pi
    gainDb = np.insert(gainDb, 0, 20 * np.log10(zeroMag))
    degPhase = np.insert(degPhase, 0, zeroPhase * 180.0 / np.pi)

    # Verificando "cruce" por -180 grados para omega = 0 rad/s
    if np.isclose(zeroPhase * 180.0 / np.pi, -180):
        indGain = np.insert(indGain, 0, True)
    else:
        indGain = np.insert(indGain, 0, False)

    # Verificando "cruce" por 0 dB para omega = 0 rad/s
    if np.isclose(20 * np.log10(zeroMag), 0):
        indPhase = np.insert(indPhase, 0, True)
    else:
        indPhase = np.insert(indPhase, 0, False)

    # Margen de ganancia
    if len(omega[:-1][indGain]) > 0:
        newGainIndex = np.argmin(np.abs(gainDb[:-1][indGain]))
        omegaGain = omega[:-1][indGain][newGainIndex]
        GainMargin = -gainDb[:-1][indGain][newGainIndex]
    else:
        omegaGain = np.nan
        GainMargin = np.infty

    # Margen de Fase
    if len(omega[:-1][indPhase]) > 0:
        newPhaIndex = min(
            range(len(degPhase[:-1][indPhase])),
            key=lambda i: abs(np.abs(degPhase[:-1][indPhase][i]) - 180))
        omegaPhase = omega[:-1][indPhase][newPhaIndex]
        PhaseMargin = 180 + degPhase[:-1][indPhase][newPhaIndex]
    else:
        omegaPhase = np.nan
        PhaseMargin = np.infty

    return GainMargin, PhaseMargin, omegaGain, omegaPhase
Ejemplo n.º 9
0
def rutina_nyquist_plot(self, system):
    """
    Función para obtener la respuesta en frecuencia del sistema y su respectiva graficacion en diagrama de Nyquist.
    
    :param system: Representacion del sistema
    :type system: LTI
    :return: Respuesta en frecuencia separada en vector de valores reales, vector de valores imaginarios y vector de frecuencias
    :rtype: tuple(numpyArray, numpyArray, numpyArray)
    """

    if ctrl.isdtime(system, strict=True):
        real, imag, freq = ctrl.nyquist_plot(system)
    else:
        real, imag, freq = ctrl.nyquist_plot(system)

    self.main.NyquistGraphicsView1.canvas.axes.cla()
    self.main.NyquistGraphicsView1.canvas.axes.plot([-1], [0], "r+")

    # Flechas para la dirección
    self.main.NyquistGraphicsView1.canvas.axes.arrow(
        real[0],
        imag[0],
        (real[1] - real[0]) / 2,
        (imag[1] - imag[0]) / 2,
        width=np.max(np.abs(real)) / 70,
    )

    self.main.NyquistGraphicsView1.canvas.axes.arrow(
        real[-1],
        imag[-1],
        (real[-1] - real[-2]) / 2,
        (imag[-1] - imag[-2]) / 2,
        width=np.max(np.abs(real)) / 70,
    )

    mindex = int(len(real) / 2)

    self.main.NyquistGraphicsView1.canvas.axes.arrow(
        real[mindex],
        imag[mindex],
        (real[mindex + 1] - real[mindex]) / 2,
        (imag[mindex + 1] - imag[mindex]) / 2,
        width=np.max(np.abs(real)) / 70,
    )

    self.main.NyquistGraphicsView1.canvas.axes.arrow(
        real[-mindex],
        -imag[-mindex],
        (real[-mindex] - real[-mindex + 1]) / 2,
        (imag[-mindex + 1] - imag[-mindex]) / 2,
        width=np.max(np.abs(real)) / 70,
    )

    # Graficacion del diagrama de Nyquist
    self.main.NyquistGraphicsView1.canvas.axes.plot(real, imag, "tab:blue")
    self.main.NyquistGraphicsView1.canvas.axes.plot(real, -imag, "tab:blue")
    self.main.NyquistGraphicsView1.canvas.axes.grid(color="lightgray")
    self.main.NyquistGraphicsView1.canvas.axes.set_title("Diagrama de Nyquist")
    self.main.NyquistGraphicsView1.canvas.draw()
    self.main.NyquistGraphicsView1.toolbar.update()

    return real, imag, freq
Ejemplo n.º 10
0
def rutina_bode_plot(self, system):
    """
    Función para obtener la respuesta en frecuencia del sistema y su respectiva graficacion en diagrama de bode.
    
    :param system: Representacion del sistema
    :type system: LTI
    :return: Respuesta en frecuencia separada en vector de magnitudes, vector de fases y vector de frecuencias
    :rtype: tuple(numpyArray, numpyArray, numpyArray)
    """

    if ctrl.isdtime(system, strict=True):
        mag, phase, omega = ctrl.bode(system)
    else:
        mag, phase, omega = ctrl.bode(system)

    # Gráfica de amplitud en dB
    bodeDb = 20 * np.log10(mag)
    self.main.BodeGraphicsView1.canvas.axes1.clear()
    self.main.BodeGraphicsView1.canvas.axes1.semilogx(omega, bodeDb,
                                                      "tab:blue")
    self.main.BodeGraphicsView1.canvas.axes1.grid(True,
                                                  which="both",
                                                  color="lightgray")
    self.main.BodeGraphicsView1.canvas.axes1.set_title("Magnitud")
    self.main.BodeGraphicsView1.canvas.axes1.yaxis.set_major_formatter(
        mticker.FormatStrFormatter("%.1f dB"))

    # Transformación de grados mayores a 180
    if np.any((phase * 180.0 / np.pi) >= 180):
        phase = phase - 2 * np.pi

    # Gráfica de fase en grados
    self.main.BodeGraphicsView1.canvas.axes2.clear()
    self.main.BodeGraphicsView1.canvas.axes2.semilogx(omega,
                                                      phase * 180.0 / np.pi,
                                                      "tab:blue")
    self.main.BodeGraphicsView1.canvas.axes2.grid(True,
                                                  which="both",
                                                  color="lightgray")
    self.main.BodeGraphicsView1.canvas.axes2.set_title("Fase")
    self.main.BodeGraphicsView1.canvas.axes2.yaxis.set_major_formatter(
        mticker.FormatStrFormatter("%.1f °"))
    self.main.BodeGraphicsView1.canvas.axes2.set_xlabel("rad/s")

    # Cálculo y graficacion del margen de ganancia y de fase
    gm, pm, wg, wp = margenes_ganancias(self, system, mag, phase, omega)

    self.main.BodeGraphicsView1.canvas.axes1.axhline(y=0,
                                                     color='k',
                                                     linestyle=':',
                                                     zorder=-20)
    self.main.BodeGraphicsView1.canvas.axes2.axhline(y=-180,
                                                     color='k',
                                                     linestyle=':',
                                                     zorder=-20)

    if not gm == np.infty:
        self.main.BodeGraphicsView1.canvas.axes1.axvline(x=wg,
                                                         color='k',
                                                         linestyle=':',
                                                         zorder=-20)
        self.main.BodeGraphicsView1.canvas.axes2.semilogx([wg, wg], [-180, 0],
                                                          color='k',
                                                          linestyle=':',
                                                          zorder=-20)
        self.main.BodeGraphicsView1.canvas.axes1.semilogx([wg, wg], [-gm, 0],
                                                          color='k',
                                                          linewidth=3)
    if not pm == np.infty:
        self.main.BodeGraphicsView1.canvas.axes2.axvline(x=wp,
                                                         color='k',
                                                         linestyle=':',
                                                         zorder=-20)
        self.main.BodeGraphicsView1.canvas.axes1.semilogx([wp, wp],
                                                          [np.min(bodeDb), 0],
                                                          color='k',
                                                          linestyle=':',
                                                          zorder=-20)
        self.main.BodeGraphicsView1.canvas.axes2.semilogx([wp, wp],
                                                          [-180, pm - 180],
                                                          color='k',
                                                          linewidth=3)

    self.main.BodeGraphicsView1.canvas.draw()
    self.main.BodeGraphicsView1.toolbar.update()

    return mag, phase, omega
Ejemplo n.º 11
0
def system_creator_ss(self, A, B, C, D):
    """
    Función para la creación del sistema a partir de la matriz de estado, matriz de entrada, matriz de salida y la matriz de transmisión directa.
    
    :param A: Matriz de estados
    :type A: list
    :param B: Matriz de entrada
    :type B: list
    :param C: Matriz de salida
    :type C: list
    :param D: Matriz de transmisión directa
    :type D: list
    :return: El sistema, el vector de tiempo, el sistema con delay, el sistema en el espacio de estados y las ganancias kp, ki y kd. Si el sistema no tiene delay, ambos son iguales
    :rtype: tuple(LTI, numpyArray, LTI, LTI, float, float, float)
    """

    if not self.main.ssdiscretocheckBox2.isChecked(
    ) and self.main.ssdelaycheckBox2.isChecked():
        delay = json.loads(self.main.ssdelayEdit2.text())
    else:
        delay = 0

    system = ctrl.StateSpace(A, B, C, D, delay=delay)

    if self.main.kpCheckBox2.isChecked():
        kp = self.main.kpHSlider2.value() / self.ssSliderValue
    else:
        kp = 0
    if self.main.kiCheckBox2.isChecked():
        ki = self.main.kiHSlider2.value() / self.ssSliderValue
    else:
        ki = 0
    if self.main.kdCheckBox2.isChecked():
        kd = self.main.kdHSlider2.value() / self.ssSliderValue
    else:
        kd = 0

    t = self.main.pidTiempoSlider.value()

    # En caso de que el sistema sea discreto
    if self.main.ssdiscretocheckBox2.isChecked():
        pid = ctrl.TransferFunction([
            2 * kd + 2 * self.dt * kp + ki * self.dt**2,
            -2 * self.dt * kp - 4 * kd + ki * self.dt**2, 2 * kd
        ], [2 * self.dt, -2 * self.dt, 0], self.dt)

        system = ctrl.sample_system(system, self.dt,
                                    self.main.sscomboBox2.currentText())

        system_ss = system
        system = ctrl.ss2tf(system)

        if self.main.ssdelaycheckBox2.isChecked():
            delayV = [0] * (
                int(json.loads(self.main.ssdelayEdit2.text()) / self.dt) + 1)
            delayV[0] = 1
            system_delay = system * ctrl.TransferFunction([1], delayV, self.dt)
            system_delay = ctrl.feedback(pid * system_delay)
        else:
            system_delay = None

        system = ctrl.feedback(pid * system)
    else:
        system_ss = system
        system = ctrl.ss2tf(system)
        system_delay = None

    try:
        if ctrl.isdtime(system, strict=True):
            T = np.arange(0, t + self.dt, self.dt)
        else:
            T = np.arange(0, t + 0.05, 0.05)

    except ValueError:
        T = np.arange(0, 100, 0.05)

    return system, T, system_delay, system_ss, kp, ki, kd
Ejemplo n.º 12
0
def system_creator_ss_tuning(self, A, B, C, D):
    """
    Función para la creación del sistema a partir de la matriz de estado, matriz de entrada, matriz de salida y la matriz de transmisión directa, adicionalmente se realiza el auto tuning utilizando el método escogido por el usuario.
    
    :param A: Matriz de estados
    :type A: list
    :param B: Matriz de entrada
    :type B: list
    :param C: Matriz de salida
    :type C: list
    :param D: Matriz de transmisión directa
    :type D: list
    :return: El sistema, el vector de tiempo, el sistema con delay, el sistema en el espacio de estados y las ganancias kp, ki y kd. Si el sistema no tiene delay, ambos son iguales
    :rtype: tuple(LTI, numpyArray, LTI, LTI, float, float, float)
    """

    if not self.main.ssdiscretocheckBox2.isChecked(
    ) and self.main.ssdelaycheckBox2.isChecked():
        delay = json.loads(self.main.ssdelayEdit2.text())
    else:
        delay = 0

    system = ctrl.StateSpace(A, B, C, D, delay=delay)

    t = self.main.pidTiempoSlider.value()
    T = np.arange(0, t, 0.05)
    U = np.ones_like(T)

    t_temp, y, _ = ctrl.forced_response(system, T, U)
    dc_gain = ctrl.dcgain(system)

    # Parametros del modelo
    K_proceso, tau, alpha = model_method(self, t_temp, y, dc_gain)

    # Auto tunning
    try:
        kp, ki, kd = auto_tuning_method(
            self, K_proceso, tau, alpha,
            self.main.ssAutoTuningcomboBox2.currentText())
    except TypeError:
        raise TypeError('Alfa es muy pequeño')

    # En caso de que el sistema sea discreto
    if self.main.ssdiscretocheckBox2.isChecked():
        pid = ctrl.TransferFunction([
            2 * kd + 2 * self.dt * kp + ki * self.dt**2,
            -2 * self.dt * kp - 4 * kd + ki * self.dt**2, 2 * kd
        ], [2 * self.dt, -2 * self.dt, 0], self.dt)

        system = ctrl.sample_system(system, self.dt,
                                    self.main.sscomboBox2.currentText())

        if self.main.ssdelaycheckBox2.isChecked():
            delayV = [0] * (
                int(json.loads(self.main.ssdelayEdit2.text()) / self.dt) + 1)
            delayV[0] = 1
            system_delay = system * ctrl.TransferFunction([1], delayV, self.dt)
            system_delay = ctrl.feedback(pid * system_delay)
        else:
            system_delay = None

        system_ss = system
        system = ctrl.feedback(pid * system)
    else:
        system_ss = system
        system_delay = system

    try:
        if ctrl.isdtime(system, strict=True):
            T = np.arange(0, t + self.dt, self.dt)
        else:
            T = np.arange(0, t + 0.05, 0.05)

    except ValueError:
        T = np.arange(0, 100, 0.05)

    return system, T, system_delay, system_ss, kp, ki, kd
Ejemplo n.º 13
0
def system_creator_tf(self, numerador, denominador):
    """
    Función para la creación del sistema a partir de los coeficientes del numerador y del denominador de la función de transferencia.
    
    :param numerador: Coeficientes del numerador
    :type numerador: list
    :param denominador: Coeficientes del denominador
    :type denominador: list
    :return: El sistema, el vector de tiempo, el sistema con delay y las ganancias kp, ki y kd. Si el sistema no tiene delay, ambos son iguales
    :rtype: tuple(LTI, numpyArray, LTI, float, float, float)
    """

    if not self.main.tfdiscretocheckBox2.isChecked(
    ) and self.main.tfdelaycheckBox2.isChecked():
        delay = json.loads(self.main.tfdelayEdit2.text())
    else:
        delay = 0

    system = ctrl.TransferFunction(numerador, denominador, delay=delay)

    if self.main.kpCheckBox2.isChecked():
        kp = self.main.kpHSlider2.value() / self.tfSliderValue
    else:
        kp = 0
    if self.main.kiCheckBox2.isChecked():
        ki = self.main.kiHSlider2.value() / self.tfSliderValue
    else:
        ki = 0
    if self.main.kdCheckBox2.isChecked():
        kd = self.main.kdHSlider2.value() / self.tfSliderValue
    else:
        kd = 0

    t = self.main.pidTiempoSlider.value()

    # En caso de que el sistema sea discreto
    if self.main.tfdiscretocheckBox2.isChecked():
        pid = ctrl.TransferFunction([
            2 * kd + 2 * self.dt * kp + ki * self.dt**2,
            -2 * self.dt * kp - 4 * kd + ki * self.dt**2, 2 * kd
        ], [2 * self.dt, -2 * self.dt, 0], self.dt)

        system = ctrl.sample_system(system, self.dt,
                                    self.main.tfcomboBox2.currentText())

        if self.main.tfdelaycheckBox2.isChecked():
            delayV = [0] * (
                int(json.loads(self.main.tfdelayEdit2.text()) / self.dt) + 1)
            delayV[0] = 1
            system_delay = system * ctrl.TransferFunction([1], delayV, self.dt)
            system_delay = ctrl.feedback(pid * system_delay)
        else:
            system_delay = None

        system = ctrl.feedback(pid * system)
    else:
        system_delay = system

    try:
        if ctrl.isdtime(system, strict=True):
            T = np.arange(0, t + self.dt, self.dt)
        else:
            T = np.arange(0, t + 0.05, 0.05)

    except ValueError:
        T = np.arange(0, 100, 0.05)

    return system, T, system_delay, kp, ki, kd