Código fuente para rutinas_CSV

""" 
Archivo que contiene todas las rutinas necesarias para la funcionalidad de identificacion de modelo y tunning con csv
"""

from scipy.ndimage import gaussian_filter

import matplotlib.ticker as mticker
import controlmdf as ctrl
import numpy as np


[documentos]def procesar_csv(self, csv_data): """ Funcion para procesar la data del archivo csv, se crea una nueva data en un diccionario, se normalizan las escalas con el span y se transforma el tiempo a segundos. Para la transformacion de tiempo a segundos los formatos aceptados son hh:mm:ss mm:ss ss En cualquiera de los casos se llevara a segundos y se restara el tiempo inicial para que empiece en cero :param csv_data: Data del csv :type csv_data: numpyArray """ # Identificacion de columnas for i, header in enumerate(csv_data[0]): if 'time' in header.lower(): indexTime = i if 'vp' in header.lower(): indexVp = i if 'efc' in header.lower(): indexEFC = i csv_data = np.delete(csv_data, 0, 0) dict_data = dict() try: dict_data['time'] = np.array(csv_data[:, indexTime]) dict_data['vp'] = np.array(list(map(float, csv_data[:, indexVp]))) dict_data['efc'] = np.array(list(map(float, csv_data[:, indexEFC]))) except UnboundLocalError: raise UnboundLocalError Tiempo = [] # Transformacion de tiempo a segundos for time_entry in dict_data['time']: my_time = str(time_entry) t1 = sum(i * j for i, j in zip(list(map(float, my_time.split(':')))[::-1], [1, 60, 3600])) Tiempo.append(t1) dict_data['time'] = np.array(Tiempo) - Tiempo[0] MinVP = float(self.main.EditLVP.text()) MaxVP = float(self.main.EditUVP.text()) MinEFC = float(self.main.EditLEFC.text()) MaxEFC = float(self.main.EditUEFC.text()) # Normalizacion FactorVP = 100 / MaxVP - MinVP FactorEFC = 100 / MaxEFC - MinEFC dict_data['vp'] = (dict_data['vp']-MinVP)*FactorVP dict_data['efc'] = (dict_data['efc']-MinEFC)*FactorEFC dict_data['time'] = dict_data['time'] dict_data['vp'] = gaussian_filter(dict_data['vp'], 5) dict_data['efc'] = gaussian_filter(dict_data['efc'], 2) return dict_data, [indexTime, indexVp, indexEFC, MinVP, MaxVP, MinEFC, MaxEFC]
[documentos]def calcular_modelo(self, dict_data, indexTime, indexVp, indexEFC, MinVP, MaxVP, MinEFC, MaxEFC): """ Fucion para calcular los parametros del modelo de primer orden :param dict_data: Diccionario con la data procesada del csv :type dict_data: dict :param indexTime: Indice que identifica al tiempo :type indexTime: int :param indexVp: Indice que identifica a Vp :type indexVp: int :param indexEFC: Indice que identifica al EFC :type indexEFC: int :param MinVP: Limite inferior de Vp :type MinVP: float :param MaxVP: Limite superior de Vp :type MaxVP: float :param MinEFC: Limite inferior de EFC :type MinEFC: float :param MaxEFC: Limite superior de EFC :type MaxEFC: float """ y = dict_data['vp'] t = dict_data['time'] vpmin = np.min(dict_data['vp'][0]) vpmax = np.max(dict_data['vp'][-1]) efcmin = np.min(dict_data['efc'][0]) efcmax = np.max(dict_data['efc'][-1]) i_max = np.argmax(np.abs(np.gradient(y))) efc_max = np.argmax(np.abs(np.gradient(dict_data['efc']))) for index, i in enumerate(y): if i >= 0.63 * (vpmax-vpmin) + vpmin: indexv = index break Kc = (vpmax - vpmin)/(efcmax - efcmin) slop_efc = (dict_data['efc'][efc_max] - dict_data['efc'][efc_max - 1]) / (t[efc_max] - t[efc_max - 1]) t0 = ((efcmin - dict_data['efc'][efc_max]) / (slop_efc) + t[efc_max]) slop = (y[i_max] - y[i_max - 1]) / (t[i_max] - t[i_max - 1]) t1 = ((vpmin - y[i_max]) / (slop) + t[i_max]) t2 = t[indexv] y1 = vpmin y2 = slop * (t2 - t[i_max]) + y[i_max] tau = t2 - t1 anclaT = t[i_max] anclaY = y[i_max] return Kc, tau, y1, y2, t0, t1, t2, anclaT, anclaY
[documentos]def entonar_y_graficar(self, dict_data, Kc, tau, y1, y2, t0, t1, t2): """ Funcion para calcular el controlador PID a partir de los datos del modelo de primer orden, ademas, se grafica la data del csv junto con algunos parametros de la identificacion del modelo :param dict_data: Diccionario con la data procesada del csv :type dict_data: dict :param Kc: Ganancia del proceso :type Kc: float :param tau: Constante de tiempo del proceso :type tau: float :param y1: Punto y1 de la recta de identifiacion, en este punto se encuentra el mayor cambio respecto al tiempo :type y1: float :param y2: Punto y2 de la recta de identificacion :type y2: float :param t0: Tiempo del inicio del escalon :type t0: float :param t1: Tiempo del inicio de la respuesta del proceso ante el escalon :type t1: float :param t2: Tiempo en el que el proceso alcanza el 63% de su valor final respecto al cambio :type t2: float """ kp, ki, kd = auto_tuning_method_csv(self, Kc, tau, t1-t0, self.main.csvMetodo.currentText()) self.main.csvGraphicsView.canvas.axes1.clear() self.main.csvGraphicsView.canvas.axes1.plot(dict_data['time'], dict_data['efc'], label='EFC') t0_efc = self.main.csvGraphicsView.canvas.axes1.axvline(x=t0, color='k', linestyle=':', zorder=-20, label='t0, t1, t2') t1_efc = self.main.csvGraphicsView.canvas.axes1.axvline(x=t1, color='k', linestyle=':', zorder=-20) t2_efc = self.main.csvGraphicsView.canvas.axes1.axvline(x=t2, color='k', linestyle=':', zorder=-20) self.main.csvGraphicsView.canvas.axes1.grid(True, which="both", color="lightgray") self.main.csvGraphicsView.canvas.axes1.legend() self.main.csvGraphicsView.canvas.axes1.yaxis.set_major_formatter( mticker.FormatStrFormatter("%.1f %%") ) self.main.csvGraphicsView.canvas.axes2.clear() self.main.csvGraphicsView.canvas.axes2.plot(dict_data['time'], dict_data['vp'], label='Vp') recta, = self.main.csvGraphicsView.canvas.axes2.plot([t1, t2], [y1, y2], label='recta') t0_vp = self.main.csvGraphicsView.canvas.axes2.axvline(x=t0, color='k', linestyle=':', zorder=-20, label='t0, t1, t2') t1_vp = self.main.csvGraphicsView.canvas.axes2.axvline(x=t1, color='k', linestyle=':', zorder=-20) t2_vp = self.main.csvGraphicsView.canvas.axes2.axvline(x=t2, color='k', linestyle=':', zorder=-20) self.main.csvGraphicsView.canvas.axes2.grid(True, which="both", color="lightgray") self.main.csvGraphicsView.canvas.axes2.legend() self.main.csvGraphicsView.canvas.axes2.yaxis.set_major_formatter( mticker.FormatStrFormatter("%.1f %%") ) self.main.csvGraphicsView.canvas.draw() self.main.csvGraphicsView.toolbar.update() actualizar_Datos(self, Kc, t0, t1, t2, kp, ki, kd) self.main.pidTiempoSlider.blockSignals(True) self.main.pidTiempoSlider.setValue(np.round(1000*(t1-t0)/(t2-t0), 3)) self.main.pidTiempoLabelValue.setText(str(np.round(t1, 3))) self.main.pidTiempoSlider.blockSignals(False) return [t0_efc, t1_efc, t2_efc, recta, t0_vp, t1_vp, t2_vp], [Kc, t0, t1, t2, y2, y1]
[documentos]def calculos_manual(self, GraphObjets, Kc, t0, t1, t2, slop, y1): """ Funcion para recalcular el controlador PID a partir de los datos del modelo de primer orden con el nueto tiempo t1, ademas, se grafica la data del csv junto con algunos parametros de la identificacion del modelo y la nueva recta :param GraphObjets: Lista de objetos de graficacion :type GraphObjets: list :param Kc: Ganancia del proceso :type Kc: float :param t0: Tiempo del inicio del escalon :type t0: float :param t1: Tiempo del inicio de la respuesta del proceso ante el escalon :type t1: float :param t2: Tiempo en el que el proceso alcanza el 63% de su valor final respecto al cambio :type t2: float :param slop: Pendiente de la recta de identificacion :type slop: float :param y1: Punto y1 de la recta de identifiacion, en este punto se encuentra el mayor cambio respecto al tiempo :type y1: float """ kp, ki, kd = auto_tuning_method_csv(self, Kc, t2-t1, t1-t0, self.main.csvMetodo.currentText()) GraphObjets[1].set_data(t1, [0, 1]) GraphObjets[5].set_data(t1, [0, 1]) new_y2 = slop * (t2 - t1) + y1 GraphObjets[3].set_data([t1, t2], [y1, new_y2]) self.main.csvGraphicsView.canvas.draw() actualizar_Datos(self, Kc, t0, t1, t2, kp, ki, kd)
[documentos]def actualizar_Datos(self, Kc, t0, t1, t2, kp, ki, kd): """ Funcion para mostrar los resultados obtenidos del modelo en un TextEdit :param Kc: Ganancia del proceso :type Kc: float :param t0: Tiempo del inicio del escalon :type t0: float :param t1: Tiempo del inicio de la respuesta del proceso ante el escalon :type t1: float :param t2: Tiempo en el que el proceso alcanza el 63% de su valor final respecto al cambio :type t2: float :param kp: Ganancia proporcional :type kp: float :param ki: Ganancia integral :type ki: float :param kd: Ganancia derivativa :type kd: float """ Datos = "Modelo:\n" Datos += str(ctrl.TransferFunction([Kc], [t2-t1, 1])) + "\n" Datos += f"Delay: {t1-t0:.3f}\n" Datos += "----------------------------------------------\n" Datos += f"Kp: {kp:.4f}\n" Datos += f"Ki: {ki:.4f}\n" Datos += f"Kd: {kd:.4f}\n" self.main.csvdatosTextEdit2.setPlainText(Datos) self.main.pidLabelController.setText( f" Kc = {Kc:.3f} -- Tau = {t2-t1:.3f} -- Alpha = {t1-t0:.3f}")
[documentos]def auto_tuning_method_csv(self, k_proceso, tau, alpha, metodo): """ Funcion para obtener las ganancias del controlador PID a partir de los parametros del modelo de primer orden obtenidos de una respuesta escalon, las formulas son las dadas por Ziegler-Nichols y Cohen-Coon para una respuesta escalon en lazo abierto :param k_proceso: Ganancia del proceso :type k_proceso: float :param tau: Constante de tiempo del proceso :type tau: float :param alpha: Tiempo muerto o delay del proceso :type alpha: float :param metodo: Metodo a utilizar :type metodo: str """ if alpha <= 0.05: print('Alfa es demasiado pequeño') raise TypeError('Alfa es demasiado pequeño') if 'ZN' in metodo: if 'P--' in metodo: kp = (1/k_proceso) * (tau/alpha) ti = np.infty td = 0 if 'PI-' in metodo: kp = (0.9/k_proceso) * (tau/alpha) ti = alpha * 3.33 td = 0 if 'PID' in metodo: kp = (1.2/k_proceso) * (tau/alpha) ti = alpha * 2 td = alpha * 0.5 kp = kp ki = kp / ti kd = kp * td if 'CC' in metodo: if 'P--' in metodo: kp = (1/k_proceso) * (tau/alpha) * (1 + (1/3) * (alpha/tau)) ti = np.infty td = 0 if 'PI-' in metodo: kp = (1/k_proceso) * (tau/alpha) * (0.9 + (1/12) * (alpha/tau)) ti = alpha * ((30 + 3 * (alpha/tau)) / (9 + 20 * (alpha/tau))) td = 0 if 'PD-' in metodo: kp = ((1/k_proceso) * (tau/alpha) * ((5/4) + (1/6) * (alpha/tau))) ti = np.infty td = alpha * ((6 - 2 * (alpha/tau)) / (22 + 3 * (alpha/tau))) if 'PID' in metodo: kp = ((1/k_proceso) * (tau/alpha) * ((4/3) + (1/4) * (alpha/tau))) ti = alpha * ((32 + 6 * (alpha/tau)) / (13 + 8 * (alpha/tau))) td = alpha * (4 / (11 + 2 * (alpha/tau))) kp = kp / 2 ki = kp / ti kd = kp * td return kp, ki, kd