FUNCTION_BLOCK "FB15102_ZC_CALCULO_FCV_UF"
TITLE = FB15102_ZC_CALCULO_FCV_UF
{ S7_Optimized_Access := 'TRUE' }
AUTHOR : HCR
FAMILY : ZeusControl
VERSION : 1.0
//Bloque de funcion para la gestion del cálculo de FCV según consignas de caudal de concentrado y consigna de FCV, para máquinas de membranas
   VAR_INPUT 
      Pulso1Seg : Bool;   // Pulso de 1 segundo
      ActivarCalculosCaudal : Bool;   // Activar calculos caudal
      ActivarControlPresion : Bool;   // Activar control presion
      Marcha : Bool;   // Estado marcha
      EtapaRecircProd : Bool;   // Etapa recirculacion produccion
      CaudalTotalPermeado : Real;   // CaudalInstantáneo de permeado
      SP_FCV : Real;   // Consigna FCV
      SP_CaudalMaximoEntrada : Real;   // Consigna máxima caudal de entrada
      SP_PorcientoPermeadoTotal : Real;   // Diferencia entre consigna de permeado y permeado total
      SP_BajoCaudalPermeado : Real;   // Consigna de caudal para corregir
      SP_PresionInicial : Real;   // Consigna de presión inicial
      SP_IncrementosPresion : Real;   // Consigna de incrementos de presión
      SP_PresionMaxima : Real;   // Consigna máxima de presión
      SP_TiempoMuestreoPresion : Int;   // Consigna tiempo de mustreo incremento de presión
      SP_PorcentajeDecremento : Real;   // % de decremento caudal concentrado
      SP_CaudalMinConcentrado : Real;   // Caudal minimo de concentrado en decrementos
      SP_TiempoDecrementos : Int;   // Consigna tiempo entre decrementos
      BotonReset : Bool;   // Orden pulsador reset presión
   END_VAR

   VAR_OUTPUT 
      SP_CaudalTeoricoEntrada : Real;   // Consigna teorica caudal de entrada
      SP_CaudalPermeado : Real;   // Consigna caudal total permeado
      SP_Presion : Real;   // Consigna de presión
      ErrorDiferenciaPermeado : Bool;   // Error porcentaje caudal permeado total fuera de rango
      VisibilidadConsignasCaudal : Bool;   // Visibilidad de consignas calculadas de caudal
      VisibilidadConsignasPresion : Bool;   // Visibilidad de consignas calculadas de presion
      VisibilidadConsignaCaudalDec : Bool;   // Visibilidad de consignas caudal decremento
      PermisoReset : Bool;   // Permiso Reset Pulsador de presión
      AjusteSP_CaudalConcentrado : Bool;   // Orden de ajuste set point caudal concentrado
      MaxPresionAlcanzada : Bool;   // Maxima presion alcanzada
   END_VAR

   VAR_IN_OUT 
      SP_CaudalConcentrado : Real;   // Consigna caudal de concentrado
      SP_CaudalPermeadoTotal : Real;   // Consigna de permeado total
      ForzarIncrementos : Bool;   // Forzar incrementos de presión
   END_VAR

   VAR RETAIN
      s_SP_Presion : Real;   // Calculo interno set point presion
      s_old_SP_CaudalConcentrado : Real;   // Estado anterior set point caudal concentrado
      s_old_SP_FCV : Real;   // Estado anterior set point FCV
   END_VAR
   VAR 
      s_DiferenciaCaudalPermeado : Real;   // Diferencia caudal permeado
      s_BajoCaudalPermeado : Bool;   // Bajo caudal permeado activo
      s_MaxPresionAlcanzada : Bool;   // Maxima presion alcanzada
      s_SP_CaudalConcentrado : Real;   // Calculo interno set point caudal concentrado
      s_TON { S7_SetPoint := 'False'} : Array[0..1] of "UDT_ZC_DISP_TON";
   END_VAR

   VAR_TEMP 
      t_CaudalTeoricoEntrada : Real;   // Calculo caudal teorico entrada
   END_VAR

   VAR CONSTANT 
      LIM_MIN_CAUDAL_PERMEADO_TOTAL : Real;   // Porciento mínimo diferencia caudal total de permeado
      LIM_MAX_CAUDAL_PERMEADO_TOTAL : Real := 100.0;   // Porciento máximo diferencia caudal total de permeado
   END_VAR


BEGIN
	REGION DESCRIPCION
	//=======================================================================
	// (C)Copyright ZeusControl 2024 - 2026
	//=======================================================================
	(*
	### Información del Sistema
	| Hardware Compatible | Entorno de Ingeniería |
	|---------------------|-----------------------|
	| PLC serie 1200/1500 | TIA Portal 18         |
	
	---
	### Descripción Funcional
	El bloque `FB15102_ZC_CALCULO_FCV_UF` implementa el cálculo de la consigna de FCV (factor de conversión volumétrica) para máquinas de membranas de ultrafiltración, a partir de las consignas de caudal de concentrado y de FCV. Gestiona además el control de presión por incrementos/decrementos para mantener el caudal de permeado total dentro de los objetivos del proceso.
	
	Funcionalidades principales:
	- Validación de entradas: se detecta error (`ErrorDiferenciaPermeado`) cuando la consigna `SP_PorcientoPermeadoTotal` está fuera del rango definido por `LIM_MIN_CAUDAL_PERMEADO_TOTAL` y `LIM_MAX_CAUDAL_PERMEADO_TOTAL`. En caso de error, el cálculo del caudal teórico de permeado total se realiza con un valor de seguridad del 1%.
	- Cálculo de caudales teóricos: a partir de `SP_CaudalConcentrado` y `SP_FCV` se obtiene el caudal teórico de entrada (`SP_CaudalTeoricoEntrada`) y, por diferencia, el caudal teórico de permeado (`SP_CaudalPermeado`). Si el caudal teórico de entrada supera el `SP_CaudalMaximoEntrada`, la consigna de concentrado se reduce automáticamente, activando el flag `AjusteSP_CaudalConcentrado` para señalizar el reescalado al exterior.
	- Cálculo de caudal de permeado total: `SP_CaudalPermeadoTotal` se obtiene aplicando el porcentaje de permeado total al caudal de permeado teórico.
	- Detección de bajo caudal de permeado: se calcula la diferencia entre el caudal teórico y el real (`CaudalTotalPermeado`). El flag `s_BajoCaudalPermeado` se activa cuando la diferencia es positiva pero inferior al umbral `SP_BajoCaudalPermeado`, o cuando el teórico es superior al real.
	- Control de presión por incrementos: mediante un temporizador (`FC2928_ZC_TON_INDV` con estructura `ZC_TON`) se incrementa progresivamente la consigna `s_SP_Presion` en pasos `SP_IncrementosPresion` cuando se detecta bajo caudal de permeado, hasta alcanzar `SP_PresionMaxima`. Se permite reset a `SP_PresionInicial` mediante la entrada `BotonReset`, así como el disparo manual de un incremento con `ForzarIncrementos`.
	- Lógica de decrementos de caudal: cuando se alcanza la presión máxima (`s_MaxPresionAlcanzada`) y el caudal real sigue por debajo del teórico, un segundo temporizador (`s_TON[1]`) reduce progresivamente la consigna de concentrado aplicando un porcentaje `SP_PorcentajeDecremento`, acotado inferiormente por `SP_CaudalMinConcentrado`. Cada ajuste activa `AjusteSP_CaudalConcentrado`.
	- Modo no activo: cuando `ActivarCalculosCaudal` o `ActivarControlPresion` están desactivados, todas las salidas y variables internas se resetean a sus valores neutros, manteniendo únicamente la presión inicial si el proceso no se encuentra en recirculación de producto (`EtapaRecircProd`).
	- Salidas de visibilidad HMI: `VisibilidadConsignasCaudal`, `VisibilidadConsignasPresion` y `VisibilidadConsignaCaudalDec` se exponen para que el sistema de supervisión muestre u oculte las pantallas de consignas según la etapa activa del bloque.
	- Memoria de consignas anteriores: al final del bloque se actualizan `s_old_SP_CaudalConcentrado` y `s_old_SP_FCV` para la detección de cambios en el siguiente ciclo.
	
	> **Restricciones:** Ninguna.
	
	---
	### Dependencias Requeridas
	| Tipo | Elementos |
	|------|-----------|
	| FC   | `FC2928_ZC_TON_INDV` |
	| FB   | - |
	| DB   | - |
	| UDT  | `ZC_TON` |
	    
	---
	### Historial de Cambios
	| Versión  | Fecha      | Técnico | Cambios |
	|----------|------------|---------|---------|
	| 01.00.00 | 24.05.2023 | (HCR)   | Primera versión. |
	| 01.00.01 | 04.03.2024 | (HCR)   | Se corrige gestión de `SP_Presion`. Se añade variable estática para su gestión. |
	| 01.00.02 | 10.11.2025 | (ABH)   | Se añade salida `AjusteSP_CaudalConcentrado` para poder realizar escritura de parámetros fuera del bloque. |
	| 01.00.03 | 20.11.2025 | (CNR)   | Se añade lógica de funcionamiento por decrementos. |
	| 01.00.04 | 28.11.2025 | (ABH)   | Se elimina la parte de la diafiltración. Se añade gestión con temporizadores ZC. Se eliminan variables externas al bloque. Se estandariza el nombre de variables. |
	*)
	END_REGION DESCRIPCION
	
	REGION ERROR
	    
	    //  ====================================================
	    //  SP_PorcientoPermeadoTotal fuera de rango
	    #ErrorDiferenciaPermeado := (#SP_PorcientoPermeadoTotal < #LIM_MIN_CAUDAL_PERMEADO_TOTAL OR #SP_PorcientoPermeadoTotal > #LIM_MAX_CAUDAL_PERMEADO_TOTAL);
	    
	END_REGION
	
	
	REGION CALCULO_FCV
	    
	    //  Reinicializacion de valores
	    #AjusteSP_CaudalConcentrado := FALSE;
	    
	    //  ====================================================
	    //  Modo activo
	    IF #ActivarCalculosCaudal THEN
	        
	        #s_SP_CaudalConcentrado := #SP_CaudalConcentrado;
	        
	        //  ====================================================
	        //  Cambio de consigna caudal de concentrado
	        IF #s_SP_CaudalConcentrado <> #s_old_SP_CaudalConcentrado OR #SP_FCV <> #s_old_SP_FCV THEN
	            //  Cálculo temporal de caudal teórico de entrada
	            #t_CaudalTeoricoEntrada := #s_SP_CaudalConcentrado * #SP_FCV;
	            //  Comparación con el caudal máximo de entrada
	            IF #t_CaudalTeoricoEntrada > #SP_CaudalMaximoEntrada THEN
	                //  Recalcular caudal de concentrado
	                #s_SP_CaudalConcentrado := #SP_CaudalMaximoEntrada / #SP_FCV;
	                #AjusteSP_CaudalConcentrado := TRUE;
	            END_IF;
	            
	        END_IF;
	        
	        //  Cálculo caudal teórico de entrada
	        #SP_CaudalTeoricoEntrada := #s_SP_CaudalConcentrado * #SP_FCV;
	        //  Cálculo caudal teórico de permeado
	        #SP_CaudalPermeado := #SP_CaudalTeoricoEntrada - #s_SP_CaudalConcentrado;
	        
	        //  Cálculo caudal teórico de permeado total
	        IF NOT #ErrorDiferenciaPermeado THEN
	            #SP_CaudalPermeadoTotal := #SP_CaudalPermeado * ((#SP_PorcientoPermeadoTotal / 100) + 1);
	        ELSE
	            #SP_CaudalPermeadoTotal := #SP_CaudalPermeado * ((1 / 100) + 1);
	        END_IF;
	        
	        //  Comprobación bajo caudal de permeado total para incremento de presión
	        IF #SP_CaudalPermeadoTotal > #CaudalTotalPermeado THEN
	            #s_DiferenciaCaudalPermeado := #SP_CaudalPermeadoTotal - #CaudalTotalPermeado;
	        ELSE
	            #s_DiferenciaCaudalPermeado := 0.0;
	        END_IF;
	        
	        #s_BajoCaudalPermeado := (#s_DiferenciaCaudalPermeado < #SP_BajoCaudalPermeado AND #s_DiferenciaCaudalPermeado > 0.0 ) OR (#SP_CaudalPermeadoTotal > #CaudalTotalPermeado);
	        
	    ELSE
	        
	        //  ====================================================
	        //  Modo no activo
	        #SP_CaudalTeoricoEntrada := 0.0;
	        #SP_CaudalPermeado := 0.0;
	        #SP_CaudalPermeadoTotal := 0.0;
	        #s_DiferenciaCaudalPermeado := 0.0;
	        #s_BajoCaudalPermeado := FALSE;
	        
	        #s_MaxPresionAlcanzada := FALSE;
	        
	    END_IF;
	    
	    
	END_REGION
	
	
	REGION PRESION 
	    
	    REGION TEMPORIZADOR
	        
	        //  ====================================================
	        //  Temporizador para incrementos de presión
	        //  Configuración temporizador
	        #s_TON[0].SP := #SP_TiempoMuestreoPresion;
	        #s_TON[0].IN := NOT #s_TON[0].Q AND #ActivarControlPresion AND #Marcha AND #s_BajoCaudalPermeado AND NOT #BotonReset AND (#s_SP_Presion < #SP_PresionMaxima);
	        
	        "FC2928_ZC_TON_INDV"(Pulso1seg:=#Pulso1Seg,
	                             TON:=#s_TON[0]);
	        
	    END_REGION
	    
	    IF #ActivarControlPresion THEN
	        
	        #PermisoReset := TRUE;
	        
	        //  ====================================================
	        //  Incrementos de presión
	        IF #s_TON[0].Q OR #ForzarIncrementos AND (#s_SP_Presion < #SP_PresionMaxima) THEN
	            #ForzarIncrementos := FALSE;
	            #s_SP_Presion += #SP_IncrementosPresion;
	            //  Si el valor de presión calculado es mayor a la presión máxima, movemos la consigna máxima de presión
	            IF #s_SP_Presion > #SP_PresionMaxima THEN
	                #s_SP_Presion := #SP_PresionMaxima;
	            END_IF;
	        END_IF;
	        
	        //  Reset valor de presión a presión inicial
	        IF #BotonReset THEN
	            #s_SP_Presion := #SP_PresionInicial;
	        END_IF;
	        
	    ELSE
	
	        IF NOT #EtapaRecircProd THEN
	            #s_SP_Presion := #SP_PresionInicial;
	        END_IF;
	        
	        #ForzarIncrementos := FALSE;
	        #PermisoReset := FALSE;
	    END_IF;
	    
	    //  ====================================================
	    //  Limite presion
	    IF #s_SP_Presion < #SP_PresionInicial THEN
	        #s_SP_Presion := #SP_PresionInicial;
	    END_IF;
	    
	END_REGION
	
	
	REGION DECREMENTOS_CAUDAL
	    
	    REGION TEMPORIZADOR
	        
	        //  ====================================================
	        //  Temporizador para decrementos de caudal
	        // Configuración temporizador
	        #s_TON[1].SP := #SP_TiempoDecrementos;
	        #s_TON[1].IN := NOT #s_TON[1].Q AND #ActivarControlPresion AND #Marcha AND #s_MaxPresionAlcanzada AND (#CaudalTotalPermeado < #SP_CaudalPermeadoTotal);
	        
	        "FC2928_ZC_TON_INDV"(Pulso1seg:=#Pulso1Seg,
	                             TON:=#s_TON[1]);
	        
	    END_REGION
	    
	    IF #ActivarControlPresion THEN
	        
	        //  Presion máxima alcanzada
	        IF #s_SP_Presion >= #SP_PresionMaxima THEN
	            #s_MaxPresionAlcanzada := TRUE;
	        ELSE
	            #s_MaxPresionAlcanzada := FALSE;
	        END_IF;
	    
	        //  ====================================================
	        //  Decrementos de caudal
	        IF #s_TON[1].Q AND (#s_SP_CaudalConcentrado > #SP_CaudalMinConcentrado) THEN
	            #s_SP_CaudalConcentrado := #s_SP_CaudalConcentrado * (1 - (#SP_PorcentajeDecremento / 100.0));
	            
	            //  Si el valor de caudal calculado es menor al caudal minimo, movemos la consigna minima de caudal
	            IF #s_SP_CaudalConcentrado < #SP_CaudalMinConcentrado THEN
	                #s_SP_CaudalConcentrado := #SP_CaudalMinConcentrado;
	            END_IF;
	            #AjusteSP_CaudalConcentrado := TRUE;
	        END_IF;
	        
	    END_IF;
	    
	END_REGION
	
	
	REGION SALIDAS
	    
	    //  ====================================================
	    //  Salida de presion
	    #SP_Presion := #s_SP_Presion;
	    
	    //  ====================================================
	    //  Maxima presion alcanzada
	    #MaxPresionAlcanzada := #s_MaxPresionAlcanzada;
	    
	    //  ====================================================
	    //  Visibilidad en HMI
	    #VisibilidadConsignasCaudal := #ActivarCalculosCaudal;
	    #VisibilidadConsignasPresion := #ActivarControlPresion;
	    #VisibilidadConsignaCaudalDec := #ActivarControlPresion AND #s_MaxPresionAlcanzada;
	    
	    #SP_CaudalConcentrado := #s_SP_CaudalConcentrado;
	    
	END_REGION ;
	
	
	//  Estados anteriores
	#s_old_SP_CaudalConcentrado := #s_SP_CaudalConcentrado;
	#s_old_SP_FCV := #SP_FCV;
	
END_FUNCTION_BLOCK

