commit f26a806b5d05e90f6faba57699105192699a213b Author: Oscar Suescun Elizalde Date: Sat Nov 23 17:52:21 2024 +0100 Init diff --git a/berry_USB.py b/berry_USB.py new file mode 100644 index 0000000..4e0bd7c --- /dev/null +++ b/berry_USB.py @@ -0,0 +1 @@ +"""Aqui esta el main de la rasberri cuando funcione en modo USB""" \ No newline at end of file diff --git a/berry_server.py b/berry_server.py new file mode 100644 index 0000000..2f5bb4f --- /dev/null +++ b/berry_server.py @@ -0,0 +1,13 @@ +from clase_cliente import Cliente + +# Configuración del cliente y el servidor +SERVER_HOST = '127.0.0.1' # Asumimos localhost +SERVER_PORT = 65432 # Puerto de comunicación + +# Ejecución del cliente +if __name__ == "__main__": + berry = Cliente(SERVER_HOST, SERVER_PORT) + berry.conectar() + + while True: + berry.escuchar_y_responder() \ No newline at end of file diff --git a/clase_cliente.py b/clase_cliente.py new file mode 100644 index 0000000..447dc57 --- /dev/null +++ b/clase_cliente.py @@ -0,0 +1,72 @@ +import socket, json +from lector import * + +# Clase Cliente para la conexión y generación de ondas +class Cliente: + def __init__(self, host, port): + self.host = host + self.port = port + self.socket = None + + + def conectar(self): + """Conecta al servidor de forma persistente""" + + try: + self.socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.socket.connect((self.host, self.port)) + print("Conectado al servidor") + + except ConnectionError as e: + print(f"Error al conectar con el servidor: {e}") + + + + def escuchar_y_responder(self): + """Escucha solicitudes del servidor y responde con datos generados""" + try: + while True: + # Escucha de forma continua para recibir la solicitud de medición del servidor + print("Esperando solicitud de medición del servidor...") + data = self.socket.recv(1024) + + if data: + print("Solicitud recibida del servidor:", data.decode('utf-8')) + request_vars = json.loads(data.decode('utf-8')) + + if request_vars == 'Apagate': + break + + self.mandar_datos(request_vars) + + except Exception as e: + print(f"Error en la conexión con el servidor: {e}") + + finally: + self.socket.close() + print("Conexión cerrada con el servidor") + + + + def mandar_datos(self, request_vars): + """Genera los datos de las ondas según las variables recibidas y los envía al servidor""" + + fs = request_vars.get('Velocidad Muestreo', 1e3) # Frecuencia de muestreo en Hz, valor estandar 1e3 + size = request_vars.get('Numero Muestras', 50) # Número de muestras, valor estandar 50 + + paquete = generar_paquete_ejemplo(fs, size) + + # Envía los datos de vuelta al servidor + self.mandar_paquete(paquete) + + + + def mandar_paquete(self, data): + """Envía el JSON generado al servidor en la misma conexión""" + try: + json_data = json.dumps(data) + "\n" # Añadimos el delimitador al final del mensaje + self.socket.sendall(json_data.encode('utf-8')) + print("Datos enviados al servidor") + + except Exception as e: + print(f"Error al enviar datos al servidor: {e}") \ No newline at end of file diff --git a/clase_ploteador.py b/clase_ploteador.py new file mode 100644 index 0000000..5089342 --- /dev/null +++ b/clase_ploteador.py @@ -0,0 +1,75 @@ +import matplotlib.pyplot as plt +from matplotlib.backends.backend_qt5agg import FigureCanvasQTAgg as FigureCanvas +from funciones_analisis import * +from scipy.fft import fft, fftfreq + +class Ploteador_VI(FigureCanvas): + def __init__(self, t, V, I, Titulo = False, parent=None): + fig, self.ax = plt.subplots(figsize=(6,4)) + super().__init__(fig) + self.setParent(parent) + self.x = t + self.y1 = V + self.y2 = I + self.linea_V, self.linea_I = plot_VI(self.ax, self.x, self.y1, self.y2, Titulo=Titulo) + + def actualizar_plot(self, t, V, I): + self.linea_V.set_xdata(t) + self.linea_I.set_xdata(t) + + self.linea_V.set_ydata(V) + self.linea_I.set_ydata(I) + + self.ax.relim() + self.ax.autoscale() + + self.draw() + + + +class Ploteador_Termico(FigureCanvas): + def __init__(self, t, Temperatura1, Temperatura2, parent=None): + fig, self.ax = plt.subplots(figsize=(6,4)) + super().__init__(fig) + self.setParent(parent) + self.x = t + self.y1 = Temperatura1 + self.y2 = Temperatura2 + self.linea_1 = plot_termico(self.ax, self.x, self.y1, tags = "Cobre, ",Titulo='Termico') + self.linea_2 = plot_termico(self.ax, self.x, self.y2, tags = "Hierro", reset_plot=False) + + def actualizar_plot(self, t, Temperatura1, Temperatura2): + self.linea_1.set_xdata(t) + self.linea_2.set_xdata(t) + + self.linea_1.set_ydata(Temperatura1) + self.linea_2.set_ydata(Temperatura2) + + self.ax.relim() + self.ax.autoscale() + + self.draw() + + + +class Ploteador_fft(FigureCanvas): + def __init__(self, t, onda, fs, param, parent=None): + fig, self.ax = plt.subplots(figsize=(6,4)) + super().__init__(fig) + self.setParent(parent) + + self.linea = plot_fft(self.ax, t, onda, fs, Titulo = f"FFT de {param}") + + def actualizar_plot(self, t, onda, fs, param): + x = fftfreq(len(t), 1/fs)[:len(t)//2] + y = 1/len(x) * np.abs(fft(onda)[0:len(t)//2]) + + self.linea.set_ydata(y) + self.linea.set_xdata(x) + + self.ax.set_title(f"FFT de {param}") + + self.ax.relim() + self.ax.autoscale() + + self.draw() \ No newline at end of file diff --git a/clase_server.py b/clase_server.py new file mode 100644 index 0000000..6eaca7a --- /dev/null +++ b/clase_server.py @@ -0,0 +1,102 @@ +import socket, json + + +# Configuración del servidor +HOST = '127.0.0.1' +PORT = 65432 + +class Server: + def __init__(self): + self.server_socket = socket.socket(socket.AF_INET, socket.SOCK_STREAM) + self.server_socket.bind((HOST, PORT)) + self.server_socket.listen(1) + print("Esperando conexión del cliente...") + + self.conn, addr = self.server_socket.accept() + print(f"Cliente conectado desde {addr}") + + def apagar_cliente(self): # Funcion que manda orden de apagar cliente, util para desarrollo y debug + vars_request = "Apagate" + + flag = True + + while flag: + + try: + json_data = json.dumps(vars_request) + "\n" # Añadimos el delimitador al final + self.conn.sendall(json_data.encode('utf-8')) + print("Orden de Apagado Enviada") + + flag = False + + except Exception as e: + print(f"Error al enviar orden de apagado:", {e}) + break + +# Función para enviar solicitudes de medición al cliente de forma continua + def pedir_datos(self, fs, size=50): #necesita la frecuencia de medida si o si, size tiene un valor base que se puede cambiar + """Envia solicitudes de inicio al cliente cada f_request segundos""" + + flag = True + + while flag: + + vars_request = { + "Velocidad Muestreo": fs, + "Numero Muestras": size + } + + try: + json_data = json.dumps(vars_request) + "\n" # Añadimos el delimitador al final + self.conn.sendall(json_data.encode('utf-8')) + + datos = self.escuchar_datos() + + flag = False + + return datos + + except Exception as e: + print(f"Error al enviar solicitud de medición al cliente: {e}") + break + + +# Funcion que espera para escuchar datos + def escuchar_datos(self): + buffer_size = 4096 # Tamaño del búfer de recepción + data_buffer = "" # Almacena datos recibidos incompletos + + flag = True + + while flag: # solo acaba el bucle cuando un paquete ha sido recibido + + try: + # Recibe el siguiente fragmento de datos + packet = self.conn.recv(buffer_size).decode('utf-8') + if not packet: + break # Desconexión del cliente + + # Añade el fragmento al buffer de datos + data_buffer += packet + + # Procesa cada mensaje JSON completo en el buffer + while "\n" in data_buffer: # Verifica si hay un delimitador en el buffer + json_message, data_buffer = data_buffer.split("\n", 1) # Separa el mensaje completo + + try: + # Decodifica el mensaje JSON completo + received_data = json.loads(json_message) + flag = False + + return received_data + + except json.JSONDecodeError as e: + print(f"Error al decodificar datos JSON: {e}") + + except (ConnectionResetError, ConnectionAbortedError) as e: + print("La conexión con el cliente se cerró abruptamente:", e) + break + + except Exception as e: + print(f"Error inesperado al recibir datos del cliente: {e}") + break \ No newline at end of file diff --git a/clase_usb.py b/clase_usb.py new file mode 100644 index 0000000..692bf35 --- /dev/null +++ b/clase_usb.py @@ -0,0 +1 @@ +"""Este script se encarga de la comunicacion entre berry y ordenador por USB""" \ No newline at end of file diff --git a/comprobar_modo.sh b/comprobar_modo.sh new file mode 100644 index 0000000..3eb8d1e --- /dev/null +++ b/comprobar_modo.sh @@ -0,0 +1,9 @@ +#!/bin/bash + +if ls /dev/ttyACM* 1>/dev/null 2>&1; then + echo "USB detectado" + python3 /ruta/a/berry_usb.py +else + echo "USB no detectado, mandando al server" + python3 /ruta/a/berry_server.py +fi diff --git a/funciones_analisis.py b/funciones_analisis.py new file mode 100644 index 0000000..e81e7a7 --- /dev/null +++ b/funciones_analisis.py @@ -0,0 +1,184 @@ +import numpy as np +import pandas as pd +import os, shutil +from scipy.fft import fft, fftfreq + + +def crear_cache(): + try: + os.makedirs('temp/T1') + os.makedirs('temp/T2') + os.makedirs('temp/Tiempo') + + + except FileExistsError: + shutil.rmtree('temp') + os.makedirs('temp/T1') + os.makedirs('temp/T2') + os.makedirs('temp/Tiempo') + + + +def plot_VI(ax, t, V, I, analisis = False, Titulo = False): #parametro reset plot sirve para dar la opcion a superponer graficas + + linea_V, = ax.plot(t, V, label="Tension") # Graficar la Tension + linea_I, = ax.plot(t, I, label="Corriente") # Graficar la Corriente + ax.set_ylabel('Amplitud') + ax.set_xlabel('Tiempo [ms]') + ax.grid(True) + + if Titulo: ax.set_title(Titulo) #si hay un titulo que lo ponga + + ax.legend(loc='upper right') + + if analisis: + V_rms, I_rms, FP, tipo_FP = analizar_ondas(V,I) + data = [f"Tension RMS: {V_rms}[V]", f"Corriente RMS: {I_rms}[A]", f"FP: {FP} {tipo_FP}"] + + for i, text in enumerate(data): + ax.text(1.05, 0.8 - i*0.1, text, fontsize=12, ha='left', va='center', transform=ax.transAxes) + + return linea_V, linea_I + + + +def plot_termico(ax, t, T, reset_plot = True, tags = False, Titulo = False): + + if reset_plot: ax.clear() # que limpie la grafica + if Titulo: ax.set_title(Titulo) #que ponga un titulo si lo hay + + linea, = ax.plot(t, T, label = tags) # Graficar temperatura + ax.set_ylabel('Temperatura [ºC]') + ax.set_xlabel('Tiempo [s]') + ax.grid(True) + + if tags: ax.legend(loc='upper right') + + return linea + + + +def plot_fft(ax, t, onda, fs, threshold_picos = False, reset_plot = False, Titulo = False, tags = False): + + if reset_plot: ax.clear() # que limpie la grafica + if Titulo: ax.set_title(Titulo) #que ponga un titulo si lo hay + + x = fftfreq(len(t), 1/fs)[:len(t)//2] + y = 1/len(x) * np.abs(fft(onda)[0:len(t)//2]) + + linea, = ax.plot(x,y) + ax.set_ylabel('Amplitud') + ax.set_xlabel('Frecuencias') + + if threshold_picos: + peaks = [(freq, amp) for freq, amp in zip(x, y) if amp > threshold_picos] + + for freq, amp in peaks: + ax.annotate(f"{freq:.2f} Hz\n Amplitud: {amp:.2f}", + xy =(freq, amp), + xytext=(freq, amp +.05), + fontsize=10, + ha="left", + va = 'center') + + ax.set_xlim(left=min(x), right=max(x) + 10) + ax.set_ylim(bottom=0, top=max(y) + 0.2) + + if tags: ax.legend(loc='upper right') + + return linea + + + +def analizar_ondas(V, I): + + V_rms = round(np.sqrt(np.mean(np.array(V)**2))) + I_rms = round(np.sqrt(np.mean(np.array(I)**2))) + + V = fft(V) + I = fft(I) + + idx = np.argmax(np.abs(V)) + + fase_1 = np.angle(V[idx]) + fase_2 = np.angle(I[idx]) + + desfase = fase_2 - fase_1 + + tipo_desfase = 'Inductivo' + + if desfase > 0: + tipo_desfase = 'Capacitivo' + + factor_potencia = round(np.cos(abs(desfase)),2) + + return V_rms, I_rms, factor_potencia, tipo_desfase + + + +def guardar_todo(datos_temp, datos_electricos): + + print('Guardando Archivos') + + guardar_temperatura_npy(datos_temp['Tiempo'], datos_temp['T1'], datos_temp['T2']) + guardar_temperatura() + guardar_VI(datos_electricos['V1'], datos_electricos['I1'], datos_electricos['V2'], datos_electricos['I2']) + + shutil.rmtree('temp') #borro chache + + print('Archivos Guardados') + + + +def guardar_temperatura_npy(Tiempo, T1, T2): + + n = len(os.listdir('temp/Tiempo')) + + np.save(f"temp/Tiempo/{n}.npy", Tiempo) + np.save(f"temp/T1/{n}.npy", T1) + np.save(f"temp/T2/{n}.npy", T2) + + + +def guardar_temperatura(): # Mira los datos del directorio temp y guarda los datos de temperatura en un csv + + try: os.makedirs('Resultados/Termicos') + except:pass + + elementos = os.listdir('temp') + data = [] + + for i in elementos: + temp = [0] + + for j in os.listdir(f"temp/{i}"): + temp = np.concatenate((temp, np.load(f"temp/{i}/{j}"))) + + data.append(temp[-(len(temp)-1):]) + + + data = np.array(data) + df = pd.DataFrame(np.transpose(data), columns= elementos) + n = len(os.listdir('Resultados/Termicos')) + 1 + + df.to_csv(f"Resultados/Termicos/Datos_Termicos_{n}.csv", index=False) + + + +def guardar_VI(V1, I1, V2, I2): # guarda los utimos datos electricos en un csv + + try:os.makedirs('Resultados/Electricos') + except:pass + + data = np.array([V1, I1, V2, I2]) + + columnas = ['Tension Primario [V]', 'Corriente Primario [A]', 'Tension Secundario [V]', 'Corriente Secundario [A]'] + df = pd.DataFrame(np.transpose(data), columns = columnas) + + n = len(os.listdir('Resultados/Termicos')) + 1 + + df.to_csv(f'Resultados/Electricos/Datos_Electricos_{n}.csv') + + + + diff --git a/lector.py b/lector.py new file mode 100644 index 0000000..cb162d6 --- /dev/null +++ b/lector.py @@ -0,0 +1,26 @@ +import numpy as np +import random + +def generar_paquete_ejemplo(fs, size): + + t = np.arange(0, size/fs, 1/fs) + + # Generación de las ondas + V1 = 200 * np.sin(2 * np.pi * 50 * t ) + 100 * np.sin(2 * np.pi * 100 * t) + 50 * np.sin(2 * np.pi * 150 * t) + 10*np.random.normal(0,1,size= size) + I1 = 30* np.sin(2 * np.pi * 50 * t + np.radians(60)) + 10*np.random.normal(0,1,size= size) # Desfase de 90º + V2 = 200 * np.sin(2 * np.pi * 50 * t + np.radians(random.randint(0,90))) + 10*np.random.normal(0,1,size= size) # Desfase de 30º con V1 + I2 = 30* np.sin(2 * np.pi * 50 * t + np.radians(random.randint(0,90))) + 10*np.random.normal(0,1,size= size)# Desfase de 30º con I1 y 90º de V1 + T1 = 3*t*random.randint(0,3) + T2 = 2*t + + # Empaquetado en Diccionario + data = { + "V1": np.array(V1.tolist()), + "V2": np.array(V2.tolist()), + "I1": np.array(I1.tolist()), + "I2": np.array(I2.tolist()), + "T1": np.array(T1.tolist()), + "T2": np.array(T2.tolist()) + } + + return data \ No newline at end of file diff --git a/main_ordenador.py b/main_ordenador.py new file mode 100644 index 0000000..773f0a2 --- /dev/null +++ b/main_ordenador.py @@ -0,0 +1,334 @@ +import sys +from lector import * +from PyQt5.QtWidgets import QApplication, QMainWindow, QWidget, QHBoxLayout, QVBoxLayout, QGridLayout +from PyQt5.QtWidgets import QLabel, QLineEdit, QPushButton +from PyQt5.QtCore import QTimer, Qt +from PyQt5.QtGui import QFont +from clase_ploteador import * + +class MainWindow(QMainWindow): + def __init__(self): + super().__init__() + self.setWindowTitle("Analizador") + self.setGeometry(0, 0, 1000, 800) + self.center_window() + + central_widget = QWidget() + self.setCentralWidget(central_widget) + font = QFont('Arial',14) + + central_widget.setFont(font) + + layout = QHBoxLayout() + layout_parametros = QVBoxLayout() + layout_graficas = QGridLayout() + + self.fs = 1000 + self.buff = 100 + self.act = 500 + self.mult_V1 = 1 + self.mult_I1 = 1 + self.mult_V2 = 1 + self.mult_I2 = 1 + self.selec_fft = 'V1' + + layout_parametros = self.modulo_botones(layout_parametros) + layout_graficas = self.modulo_graficas(layout_graficas) + + layout.addLayout(layout_graficas) + layout.addLayout(layout_parametros) + + layout.setStretchFactor(layout_graficas, 6) + layout.setStretchFactor(layout_parametros, 1) + + central_widget.setLayout(layout) + + + + def center_window(self): + screen = QApplication.primaryScreen() + + frame_geom = self.frameGeometry() + + screen_center = screen.availableGeometry().center() + + frame_geom.moveCenter(screen_center) + self.move(frame_geom.topLeft()) + + + + def modulo_botones(self, layout): + self.label_fs = QLabel("Fecuencia Medida: 1 kHz") + self.label_buff= QLabel("Tamaño de Paquete Datos: 100") + self.label_act= QLabel("Frecuencia Actualizacion Graficos: 2 fps") + self.label_V1= QLabel("Multiplicador Tension 1º: 1") + self.label_I1= QLabel("Multiplicador Corriente 1º: 1") + self.label_V2= QLabel("Multiplicador Tension 2º: 1") + self.label_I2= QLabel("Multiplicador Corriente 2º: 1") + + self.input_fs = QLineEdit() + self.input_fs.setPlaceholderText('Frecuencia de medida') + + self.input_buff = QLineEdit() + self.input_buff.setPlaceholderText('Tamaño del Paquete') + + self.input_act = QLineEdit() + self.input_act.setPlaceholderText('Frecuencia de Actualizacion') + + self.input_V1 = QLineEdit() + self.input_V1.setPlaceholderText('Multiplicador Tension 1º') + + self.input_I1 = QLineEdit() + self.input_I1.setPlaceholderText('Multiplicador Corriente 1º') + + self.input_V2 = QLineEdit() + self.input_V2.setPlaceholderText('Multiplicador Tension 2º') + + self.input_I2 = QLineEdit() + self.input_I2.setPlaceholderText('Multiplicador Corriente 2º') + + self.update_button = QPushButton('Actualizar Medidas') + self.update_button.clicked.connect(self.actualizar_metodo_medida) + + self.update_button = QPushButton('Actualizar Medidas') + self.update_button.clicked.connect(self.actualizar_metodo_medida) + + layout.addWidget(self.label_fs) + layout.addWidget(self.input_fs) + layout.addWidget(self.label_buff) + layout.addWidget(self.input_buff) + layout.addWidget(self.label_act) + layout.addWidget(self.input_act) + layout.addWidget(self.label_V1) + layout.addWidget(self.input_V1) + layout.addWidget(self.label_I1) + layout.addWidget(self.input_I1) + layout.addWidget(self.label_V2) + layout.addWidget(self.input_V2) + layout.addWidget(self.label_I2) + layout.addWidget(self.input_I2) + layout.addWidget(self.update_button) + + layout.setAlignment(Qt.AlignRight) + + return layout + + + + def actualizar_metodo_medida(self): + + if self.input_fs.text(): + temp = self.input_fs.text() + + try: + self.fs = float(temp) * 1000 #Guardo el Valor + self.label_fs.setText(f"Fecuencia Medida: {temp} kHz") + + except: self.label_fs.setText(f"Fecuencia Medida: ¡No valido!") + + if self.input_buff.text(): + temp = self.input_buff.text() + + try: + self.buff = int(temp) # guardo el valor + self.label_buff.setText(f"Tamaño de Paquete Datos: {temp}") + + except: self.label_buff.setText(f"Tamaño de Paquete Datos: ¡No valido!") + + if self.input_act.text(): + temp = self.input_act.text() + self.act = 1000/float(temp) + + try: + if self.act >= self.buff/self.fs: + self.act = temp # guardo el valor + self.label_act.setText(f"Frecuencia Actualizacion Graficos: {temp} fps") + + else: self.label_act.setText(f"Frecuencia Actualizacion Graficos: ¡No valido!") + + except: self.label_act.setText(f"Frecuencia Actualizacion Graficos: ¡No valido!") + + if self.input_V1.text(): + temp = self.input_V1.text() + + try: + self.mult_V1 = float(temp) # guardo el valor + self.label_V1.setText(f"Multiplicador Tension 1º: {temp}") + + except: self.label_V1.setText("Multiplicador Tension 1º: ¡No valido!") + + if self.input_I1.text(): + temp = self.input_I1.text() + + try: + self.mult_I1 = float(temp) # guardo el valor + self.label_I1.setText(f"Multiplicador Corriente 1º: {temp}") + + except: self.label_I1.setText("Multiplicador Corriente 1º: ¡No valido!") + + if self.input_V2.text(): + temp = self.input_V2.text() + + try: + self.mult_V2 = float(temp) # guardo el valor + self.label_V2.setText(f"Multiplicador Tension 2º: {temp}") + + except: self.label_V2.setText("Multiplicador Tension 2º: ¡No valido!") + + if self.input_I2.text(): + temp = self.input_I2.text() + + try: + self.mult_I2 = float(temp) # guardo el valor + self.label_I2.setText(f"Multiplicador Corriente 2º: {temp}") + + except: self.label_I2.setText("Multiplicador Corriente 2º: ¡No valido!") + + self.input_fs.clear() + self.input_buff.clear() + self.input_act.clear() + self.input_V1.clear() + self.input_I1.clear() + self.input_V2.clear() + self.input_I2.clear() + + def modulo_seleccionador_fft(self, layout): + self.boton_fft_V1 = QPushButton("Tension 1") + self.boton_fft_I1 = QPushButton("Corriente 1") + self.boton_fft_V2 = QPushButton("Tension 2") + self.boton_fft_I2 = QPushButton("Corriente 2") + + self.boton_fft_V1.clicked.connect(lambda:self.seleccion_fft('V1')) + self.boton_fft_I1.clicked.connect(lambda:self.seleccion_fft('I1')) + self.boton_fft_V2.clicked.connect(lambda:self.seleccion_fft('V2')) + self.boton_fft_I2.clicked.connect(lambda:self.seleccion_fft('I2')) + + layout.addWidget(self.boton_fft_V1) + layout.addWidget(self.boton_fft_I1) + layout.addWidget(self.boton_fft_V2) + layout.addWidget(self.boton_fft_I2) + + return layout + + + + def seleccion_fft(self, seleccion): + self.selec_fft = seleccion + + + + def modulo_graficas(self, layout): + datos = generar_paquete_ejemplo(self.fs, self.buff) + + tiempo = np.arange(0, self.buff/self.fs, 1/self.fs) + + # Crear Layout Primero + layout_primario_main = QVBoxLayout() + layout_analisis_1 = QHBoxLayout() + + V, I, FP, tipo = analizar_ondas(datos['V1'], datos['I1']) + + self.label_V1rms = QLabel(f'V_rms = {V}V') + self.label_I1rms = QLabel(f'I_rms = {I}A') + self.label_FP1 = QLabel(f'PF = {FP} {tipo}') + + layout_analisis_1.addWidget(self.label_V1rms) + layout_analisis_1.addWidget(self.label_I1rms) + layout_analisis_1.addWidget(self.label_FP1) + + self.primario = Ploteador_VI(t=tiempo, V = datos['V1'], I = datos['I1'], Titulo = 'VI Primario') + + layout_primario_main.addWidget(self.primario) + layout_primario_main.addLayout(layout_analisis_1) + + layout_primario_main.setStretchFactor(self.primario, 8) + layout_primario_main.setStretchFactor(layout_analisis_1, 1) + + + # Crear Layout Secundario + layout_secundario_main = QVBoxLayout() + layout_analisis_2 = QHBoxLayout() + + V, I, FP, tipo = analizar_ondas(datos['V2'], datos['I2']) + + self.label_V2rms = QLabel(f'V_rms = {V}V') + self.label_I2rms = QLabel(f'I_rms = {I}A') + self.label_FP2 = QLabel(f'PF = {FP} {tipo}') + + layout_analisis_2.addWidget(self.label_V2rms) + layout_analisis_2.addWidget(self.label_I2rms) + layout_analisis_2.addWidget(self.label_FP2) + + self.secundario = Ploteador_VI(t=tiempo, V = datos['V2'], I = datos['I2'], Titulo= 'VI Secundario') + + layout_secundario_main.addWidget(self.secundario) + layout_secundario_main.addLayout(layout_analisis_2) + + layout_secundario_main.setStretchFactor(self.secundario, 8) + layout_secundario_main.setStretchFactor(layout_analisis_2, 1) + + # Crear Layout del Termico + self.termico = Ploteador_Termico(t=tiempo, Temperatura1=datos['T1'], Temperatura2=datos['T2']) + + # crear layout de la fft + layout_fft_main = QVBoxLayout() + layout_fft_selector = QHBoxLayout() + + layout_fft_selector = self.modulo_seleccionador_fft(layout_fft_selector) + + self.fourier = Ploteador_fft(t=tiempo, onda = datos[self.selec_fft], fs = self.fs, param= self.selec_fft) + + layout_fft_main.addWidget(self.fourier) + layout_fft_main.addLayout(layout_fft_selector) + + # Agregar los widgets de gráficos al layout de la cuadrícula + layout.addLayout(layout_primario_main, 0, 0) + layout.addLayout(layout_secundario_main, 0, 1) + layout.addWidget(self.termico, 1, 0) + layout.addLayout(layout_fft_main, 1, 1) + + layout.setRowStretch(0,1) + layout.setRowStretch(1,1) + + # Configurar el temporizador para actualizar las gráficas en tiempo real + self.timer = QTimer(self) + self.timer.timeout.connect(self.update_graphs) + self.timer.start(self.act) # Actualiza plots + + return layout + + + + def update_graphs(self): + # Generar nuevos datos en tiempo real (puedes reemplazar con datos reales) + datos = generar_paquete_ejemplo(self.fs, self.buff) + tiempo = np.arange(0, self.buff/self.fs, 1/self.fs) + + # Actualizar cada gráfico + self.primario.actualizar_plot(tiempo, self.mult_V1 * datos['V1'], self.mult_I1 * datos['I1']) + self.secundario.actualizar_plot(tiempo, self.mult_V2 * datos['V2'], self.mult_I2 * datos['I2']) + self.termico.actualizar_plot(tiempo, datos['T1'], datos['T2']) + self.fourier.actualizar_plot(tiempo, datos[self.selec_fft], self.fs, self.selec_fft) + + # Actualizar Los analisis + V, I, FP, tipo = analizar_ondas(datos['V1'], datos['I1']) + self.label_V1rms.setText(f"Vrms = {V} V") + self.label_I1rms.setText(f"Irms = {I} A") + self.label_FP1.setText(f"FP = {FP} {tipo}") + + V, I, FP, tipo = analizar_ondas(datos['V2'], datos['I2']) + self.label_V2rms.setText(f"Vrms = {V} V") + self.label_I2rms.setText(f"Irms = {I} A") + self.label_FP2.setText(f"FP = {FP} {tipo}") + + + + + +if __name__ == "__main__": + app = QApplication(sys.argv) + + window = MainWindow() + window.show() + + sys.exit(app.exec_()) \ No newline at end of file diff --git a/main_server.py b/main_server.py new file mode 100644 index 0000000..638fbde --- /dev/null +++ b/main_server.py @@ -0,0 +1,29 @@ +import matplotlib.pyplot as plt +import numpy as np + +from funciones_analisis import * +from clase_server import Server + + + +# Ejecución del servidor +if __name__ == "__main__": + + frecuencia_sampling = 1e3 # velocidad muestreo + tamaño_paquete = 100 # + + t = np.arange(0,tamaño_paquete/frecuencia_sampling, 1/frecuencia_sampling) + + servidor = Server() # activo el servidor + + datos = servidor.pedir_datos(fs= frecuencia_sampling, size= tamaño_paquete) + + fig, ax = plt.subplots(1,1) + + plot_fft(ax, t, datos['V1'], fs=frecuencia_sampling, threshold_picos=0.1) + + plt.tight_layout() + plt.show() + + servidor.apagar_cliente() # para debug esto hay que quitar + diff --git a/pyvenv.cfg b/pyvenv.cfg new file mode 100644 index 0000000..9f01e4c --- /dev/null +++ b/pyvenv.cfg @@ -0,0 +1,5 @@ +home = C:\Users\osuescuneli\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0 +include-system-site-packages = false +version = 3.11.9 +executable = C:\Users\osuescuneli\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\python.exe +command = C:\Users\osuescuneli\AppData\Local\Microsoft\WindowsApps\PythonSoftwareFoundation.Python.3.11_qbz5n2kfra8p0\python.exe -m venv C:\Users\osuescuneli\Desktop\Analizador_Trafos diff --git a/requirements.txt b/requirements.txt new file mode 100644 index 0000000..b7c4211 Binary files /dev/null and b/requirements.txt differ diff --git a/test.py b/test.py new file mode 100644 index 0000000..f3638b7 --- /dev/null +++ b/test.py @@ -0,0 +1,44 @@ +from PyQt5.QtWidgets import QApplication, QWidget, QHBoxLayout, QPushButton, QLabel + +class SelectorOpciones(QWidget): + def __init__(self): + super().__init__() + + # Configurar la ventana + self.setWindowTitle("Seleccionador de Opciones") + self.setGeometry(100, 100, 300, 200) + + # Layout principal + layout = QHBoxLayout() + + # Crear botones para las opciones + self.resultado = QLabel("Selecciona una opción") + self.boton1 = QPushButton("Opción 1") + self.boton2 = QPushButton("Opción 2") + self.boton3 = QPushButton("Opción 3") + self.boton4 = QPushButton("Opción 4") + + # Conectar los botones a una función + self.boton1.clicked.connect(lambda: self.mostrar_seleccion("Opción 1")) + self.boton2.clicked.connect(lambda: self.mostrar_seleccion("Opción 2")) + self.boton3.clicked.connect(lambda: self.mostrar_seleccion("Opción 3")) + self.boton4.clicked.connect(lambda: self.mostrar_seleccion("Opción 4")) + + # Agregar botones al layout + layout.addWidget(self.boton1) + layout.addWidget(self.boton2) + layout.addWidget(self.boton3) + layout.addWidget(self.boton4) + layout.addWidget(self.resultado) + + # Establecer layout + self.setLayout(layout) + + def mostrar_seleccion(self, texto): + self.resultado.setText(f"Seleccionaste: {texto}") + +if __name__ == "__main__": + app = QApplication([]) + ventana = SelectorOpciones() + ventana.show() + app.exec_()