Seguimiento solar con Siemens 1200 TIA Portal

Recientemente, y debido al proceso de documentación que estoy realizando para el curso de TIA Portal sobre la serie 1200 de Siemens (en el cual veremos ejemplos también en SCL), me he topado con este ejemplo de Seguimiento solar con Siemens 1200 realizado en TIA Portal.

Es un ejemplo publicado en inglés de la empresa Bytex Automation, en Italia. Me he puesto en contacto con ellos para pedirles la oportunidad de traducir el ejemplo a castellano y compartirlo contigo.

Su contacto Massimo me ha dado permiso, por lo que aquí te lo traigo para que lo conozcas si no lo habías visto o bien si la lengua de Shakespeare se te resiste un poco.

La traducción es lo más literal posible para ser fiel a la entrada original.

Seguimiento solar con Siemens 1200 y TIA Portal

Este artículo explica como construir un sistema de seguimiento solar con usando un PLC Simatic S7-1200. La función astronómica estças desarrollada en lenguaje SCL. El objetivo principal es desarrollar una función capaz de retornar la elevación del Sol (ángulo de altitud solar), y su ángulo con el norte (ángulo azimutal).

La función retornará también el tiempo que falta para el amanecer y el ocaso, la duración total de horas de sol, el momento en el que se hace de día y cuándo se hace de noche. Puedes usar esta  característica para encender una lámpara en tu jardín cuando el sol se pone o dirigir uno o varios paneles, manejados por ejes motorizados,  siguiendo el sol para conseguir el máximo de energía.

Seguimiento solar con Siemens 1200 Seguimiento solar con Siemens 1200 Seguimiento solar con Siemens 1200

Ejemplos de paneles solares usando uno o dos ejes motorizados

La función necesita algunos parámetros de entrada, como la latitud, longitud y elevación local, la zona horaria, ajuste de luz de día, y finalmente la hora actual dada desde el reloj del PLC.

Función astronómica – Parámetros de entrada

  • LocalLatitude Número decimal representando la latitud local. Asigna números positivos para el hemisferio norte y negativos para el hemisferio sur. Por ejemplo 45.838073
  • LocalLongitude Número decimal que representa la longitud local. Asigna números positivos para meridianos del Este y negativos para el Oeste de Greenwich. Por ejemplo -13.406095)
  • Elevation Número decimal que representa la elevación local sobre el mar medido en metros.
  • TimeZone (Número decimal que representa la zona horaria respecto a Greenwich.
  • DayLightAdjustement Fija DayLightAdjustement = 1  en verano y  DayLightAdjustement = 0 para invierno
  • ActualDateAndTime Fecha y hora actual

Seguimiento solar con Siemens 1200

Función astronómica – Parámetros de salida

  • AltitudeAngle Número decimal que representa el ángulo entre la posición del sol y el horizonte del observador local.
  • AzimuthAngle Número decimal que representa el ángulo entre una dirección de referencia (Norte) y una línea desde el observador hasta la posición del sol proyectada en el mismo plano como la dirección de referencia.
  • SunRiseTime Amanecer en tipo de datos DTL
  • SunSetTime Puesta del Sol en tipo de datos DTL
  • SunDurationTime Duración total de sol en tipo de datos Time
  • IsDay  Booleana que indica el el evento del amanecer
  • IsNight Booleana que indica el evento del anochecer

Cómo funciona: Ajuste de luz solar

Si tu país tiene un sistema de ahorro de luz solar (como por ejemplo España), tienes que ajustar el parámetro DayLightAdjustement=1 en verano, y DayLightAdjustement=0 en invierno. Si no lo tiene, el parámetro tiene que estar siempre a 0.

¿Cómo hacerlo?

Usando la función RD_LOC_T puedes leer la fecha y hora actual del PLC Simatic S7-1200 y leyendo el valor RET_VAL de la función, puedes leer el estado del tiempo de luz solar actual (W#16#0001)

Seguimiento solar con Siemens 1200

 Cómo funciona: Sincronizar el relos del PLC con la hora de internet

¿Cómo hacerlo?

Si tienes una conexión de internet para el PLC es bastante simple. Ve a la configuración del dispositivo en el panel izquierdo del TIA Portal; pica y haz click en el interface PROFINET y selecciona Activar sincronización horaria via servidor NTP y añade una dirección de servidor de hora de internet. Por ejemplo 192.204.114.232.

Seguimiento solar con Siemens 1200

Cómo funciona: Función astronómica de un sistema de seguimiento solar con Siemens 1200

Lenguaje SCL – Esta es la lista de declaración de variables


  // Input parameters
  //-------------------------------
  // LocalLatitude:       Real
  // LocalLongitude:      Real
  // Elevation:           Real
  // TimeZone:            Int
  // DayLightAdjustement: Int
  // ActualDateAndTime:   DTL
  
  // Output parameters
  //-------------------------------
  // AltitudeAngle:       Real
  // AzimuthAngle:        Real
  // SunRiseTime:         DTL
  // SunSetTime:          DTL
  // SunDurationTime:     Time
  // IsDay:               Bool
  // IsNight:             Bool
  // PreSet:              Bool
  
  // Static declarations
  //-------------------------------  
  // #RadiansToDegrees          Real  
  // #DegreesToRadians          Real
  // #Meridian                  Real
  // #HoursAfterMidnight        Real
  // #MinutesAfterMidnight      Real
  // #UT                        Real
  // #CorrectedYear             UInt
  // #CorrectedMonth            USInt
  // #t                         Real
  // #g                         Real
  // #gn                        Real
  // #C                         Real
  // #L                         Real
  // #Alpha                     Real
  // #GHA                       Real
  // #GHAn                      Real
  // #Obliquity                 Real
  // #Declination               Real
  // #EotAdjustment             Real
  // #ClockTimeToLSOTAdjustment Real
  // #SolarHourAngle            Real
  // #ApparentSolarTime         Real
  // #SolarMinutesAfterMidnight Real
  // #whichDay                  Int
  // #HourAngle                 Real
  // #PreAzimuthAngle           Real
  // #x                         Bool
  // #SunRiseSetLSoTMinutes     Real
  // #SunRiseTime_R             Real
  // #SunSetTime_R              Real
  // #SunDurationTime_R         Real
  // #RHour                     Real
  // #RMin                      Real
  // #RSec                      Real
  // #IHOUR                     Int
  // #IMIN                      Int
  // #ISEC                      Int
							

Lenguaje SCL –  Código ejemplo de seguimiento solar


	//******************************************************
	// THIS CODE MUST BE COMPILED AS FUNCTION_BLOCK							
	//******************************************************

    // Define Radians and Degrees conversion
    // -------------------------------------
    #RadiansToDegrees := 57.295779513082323;
    #DegreesToRadians := 0.017453292519943295;
    
    
    #Meridian := -15.0 * INT_TO_REAL(#TimeZone);

    // Calculate Hours after midnight
    // ------------------------------
    #HoursAfterMidnight := INT_TO_REAL(#ActualDateAndTime.HOUR) +
                            INT_TO_REAL(#ActualDateAndTime.MINUTE) / 60.0 +
                            INT_TO_REAL(#ActualDateAndTime.SECOND) / 3600.0;

    // Calculate Minutes after midnight
    // --------------------------------
    #MinutesAfterMidnight := INT_TO_REAL(#ActualDateAndTime.HOUR) * 60.0 +
                            INT_TO_REAL(#ActualDateAndTime.MINUTE) +
                            INT_TO_REAL(#ActualDateAndTime.SECOND) / 60.0;

    // calculate Universal Time
    // ------------------------  
    #UT := #HoursAfterMidnight - INT_TO_REAL(#TimeZone) - INT_TO_REAL(#DayLightAdjustment);
     
    IF #ActualDateAndTime.MONTH > 2 THEN
        #CorrectedYear := #ActualDateAndTime.YEAR;
        #CorrectedMonth := #ActualDateAndTime.MONTH - 3;
    ELSE
        #CorrectedYear := #ActualDateAndTime.YEAR -1;
        #CorrectedMonth := #ActualDateAndTime.MONTH + 9;
    END_IF;

    #t := ((#UT / 24.0) + USINT_TO_REAL(#ActualDateAndTime.DAY) +
          DINT_TO_REAL(FLOOR(30.6 * USINT_TO_REAL(#CorrectedMonth) + 0.5)) + 
          DINT_TO_REAL(FLOOR(365.25 * (UINT_TO_REAL(#CorrectedYear) - 1976.0))) - 8707.5) / 36525.0;
    
    #g := 357.528 + 35999.05 * #t;

    #gn := "NormalizeTo360"(#g);

    #C := (1.915 * SIN(#gn * #DegreesToRadians)) + 
            (0.02 * SIN((2.0 * #gn) * #DegreesToRadians));

    #L := 280.46 + (36000.77 * #t) + #C;

    #Alpha := #L - 2.466 * SIN((2.0 * #L) * #DegreesToRadians) + 
                0.053 * SIN((4.0 * #L) * #DegreesToRadians);

    #GHAn := #UT * 15.0 - 180.0 - #C + #L - #Alpha;
    #GHA := "NormalizeTo360"(#GHAn);

    #Obliquity := 23.4393 - 0.013 * #t;

    #Declination := ATAN(TAN(#Obliquity * #DegreesToRadians) * SIN(#Alpha * #DegreesToRadians));
    #Declination := #Declination * #RadiansToDegrees;

    #EotAdjustment := (#L - #C - #Alpha) / 15.0;   // EOT adjustment in hours

    #ClockTimeToLSOTAdjustment := ((#LocalLongitude - #Meridian) / 15.0) - 
                                    #EotAdjustment + #DayLightAdjustment;

    #SolarHourAngle := 0.0;
    #SolarHourAngle := #GHA - #LocalLongitude;
    #TempReal := "NormalizeTo180"(#SolarHourAngle);
    #SolarHourAngle := #TempReal;
    
    #ApparentSolarTime := 0.0;
    #TempReal := 12.0 + #SolarHourAngle / 15.0;
    #ApparentSolarTime := "NormalizeTo24"(#TempReal);

    #SolarMinutesAfterMidnight := #MinutesAfterMidnight - (#ClockTimeToLSOTAdjustment * 60.0);

    #whichDay := 0;

    #HourAngle := (#SolarMinutesAfterMidnight - 720.0) / 4.0 * -1.0;

    #AltitudeAngle := #RadiansToDegrees * 
                            (ASIN((SIN(#LocalLatitude * #DegreesToRadians) * 
                            SIN(#Declination * #DegreesToRadians)) - 
                            (COS(#LocalLatitude * #DegreesToRadians) * 
                            COS(#Declination * #DegreesToRadians) * 
                            COS((#SolarHourAngle + 180.0) * #DegreesToRadians))));

    #PreAzimuthAngle := #RadiansToDegrees * ACOS((COS(#Declination * #DegreesToRadians) * 
                    ((COS(#LocalLatitude * #DegreesToRadians) * 
                     TAN(#Declination * #DegreesToRadians)) + 
                     (SIN(#LocalLatitude * #DegreesToRadians) * 
                     COS((#SolarHourAngle + 180.0) * #DegreesToRadians)))) / 
                     COS(#AltitudeAngle * #DegreesToRadians));

    #x := False;
    IF (#HourAngle > 0.0) THEN
      IF (#HourAngle < 180.0) THEN
        #x := True;
      END_IF;
    END_IF;

    IF #x THEN
      #AzimuthAngle := (360.0 - #PreAzimuthAngle);
    ELSE
      #AzimuthAngle := #PreAzimuthAngle;
    END_IF;

    #SunRiseSetLSoTMinutes := #RadiansToDegrees * ACOS(-1.0 * 
            (SIN(#LocalLatitude * #DegreesToRadians) * 
            SIN(#Declination * #DegreesToRadians) - 
            SIN((-0.8333 - 0.0347 * SQRT((#Elevation))) * #DegreesToRadians)) / 
            COS(#LocalLatitude * #DegreesToRadians) / 
            COS(#Declination * #DegreesToRadians)) * 4.0;


    #SunRiseTime_R := ((720.0 - #SunRiseSetLSoTMinutes + (#ClockTimeToLSOTAdjustment * 60.0)));
    #TempReal := #SunRiseTime_R;
    #RSec := DINT_TO_REAL(FLOOR((#TempReal - DINT_TO_REAL(FLOOR(#TempReal))) * 60.0));
    #RSec := #RSec + DINT_TO_REAL(FLOOR(#TempReal)) * 60.0;
    #RHour := DINT_TO_REAL(FLOOR(#RSec / 3600.0));
    #RMin := DINT_TO_REAL(FLOOR((#RSec / 3600.0 - #RHour) * 60.0));
    #RSec := #RSec - #RHour * 3600.0 - #RMin * 60.0;
    IF #RSec >= 30.0 AND #RMin < 59 THEN
        #RMin := #RMin + 1.0;
    END_IF;
    #IHOUR := REAL_TO_INT(#RHour);
    #IMIN := REAL_TO_INT(#RMin);
    #ISEC := REAL_TO_INT(#RSec);
    #SunRiseTime := #ActualDateAndTime;
    #SunRiseTime.HOUR := INT_TO_USINT(#IHOUR);
    #SunRiseTime.MINUTE := INT_TO_USINT(#IMIN);
    #SunRiseTime.SECOND := INT_TO_USINT(#ISEC);
    
    
    #SunSetTime_R := ((720.0 + #SunRiseSetLSoTMinutes + (#ClockTimeToLSOTAdjustment * 60.0)));
    #TempReal := #SunSetTime_R;
    #RSec := DINT_TO_REAL(FLOOR((#TempReal - DINT_TO_REAL(FLOOR(#TempReal))) * 60.0));
    #RSec := #RSec + DINT_TO_REAL(FLOOR(#TempReal)) * 60.0;
    #RHour := DINT_TO_REAL(FLOOR(#RSec / 3600.0));
    #RMin := DINT_TO_REAL(FLOOR((#RSec / 3600.0 - #RHour) * 60.0));
    #RSec := #RSec - #RHour * 3600.0 - #RMin * 60.0;
    IF #RSec >= 30.0 AND #RMin < 59 THEN
        #RMin := #RMin + 1.0;
    END_IF;
    #IHOUR := REAL_TO_INT(#RHour);
    #IMIN := REAL_TO_INT(#RMin);
    #ISEC := REAL_TO_INT(#RSec);
    #SunSetTime := #ActualDateAndTime;
    #SunSetTime.HOUR := INT_TO_USINT(#IHOUR);
    #SunSetTime.MINUTE := INT_TO_USINT(#IMIN);
    #SunSetTime.SECOND := INT_TO_USINT(#ISEC);

    #SunDurationTime_R := (#SunSetTime_R - #SunRiseTime_R) / 60.0;

    IF #ActualDateAndTime >= #SunRiseTime AND #ActualDateAndTime <= #SunSetTime THEN
      #IsDay := true;
      #IsNight := false;
      ELSE
      #IsDay := false;
      #IsNight := true;
    END_IF;

    IF #ActualDateAndTime >= (#SunSetTime - 1) THEN
      #PreSet := true;
      ELSE
      #PreSet := false;
    END_IF;
							

Lenguaje SCL – Código de la función NormalizeTo24


  //***********************************************
  // Assign to the FUNCTION the name=NormalizeTo24
  //***********************************************

  // Input parameters
  //-------------------------
  // aTime:       Real
  
  // Return variable
  //-------------------------
  // Ret_Val      Real  

  #NormalizeTo24 := (#aTime - DINT_TO_REAL(FLOOR(#aTime / 24.0)) * 24.0);
							

Lenguaje SCL – Código de la función NormalizeTo180


  //************************************************
  // Assign to the FUNCTION the name=NormalizeTo180
  //************************************************

  // Input parameters
  //-------------------------
  // Angle:       Real

  // Temporary variables
  //-------------------------
  // TempAngle:   Real

  // Return variable
  //-------------------------
  // Ret_Val      Real  


  #TempAngle := "NormalizeTo360"(#Angle);
  IF "NormalizeTo360"(#Angle) > 180.0 THEN
    #TempAngle := "NormalizeTo360"(#Angle) - 360.0;
  END_IF;
  #NormalizeTo180 := #TempAngle;
							

Lenguaje SCL – Código de la función NormalizeTo360


  //************************************************
  // Assign to the FUNCTION the name=NormalizeTo360
  //************************************************

  // Input parameters
  //-------------------------
  // Angle:       Real

  // Return variable
  //-------------------------
  // Ret_Val      Real  

  #NormalizeTo360 := (#Angle - DINT_TO_REAL(FLOOR(#Angle / 360.0)) * 360.0);
							

Últimas recomendaciones sobre esta función para el Seguimiento solar con Siemens 1200 y TIA Portal.

Recuerda llamar al bloque principal dentro de un OB de iterrupción fijando el tiempo de interrupción a 1000 misisegundos o 10000 milisegundos.

Esta entrada de Seguimiento solar con Siemens 1200 es original de:

Bytex Automation

Bytex Automation  es una compañía italiana con muchos años de experiencia internacional en automatización industrial (especialmente en el sector de acero), webs en tiempo real para análisis y manejo de procesos industriales como manufactura y logistica. Su fortaleza radica en la capacidad de desarrollar sistemas que comunican PLC y bases de datos EPR para producir plataformas web integradas y amigables.

 

Acerca de Iñigo Gútiez

Ingeniero industrial por la Escuela de Ingenieros Superiores de Bilbao. Trabajo como ingeniero de proyectos y automatización en Guardian Industries

Te puede interesar

Entrevista a Juan Carlos Martín (REEA)

En esta ocasión traigo al blog algo muy especial. Más bien a alguien especial. La …

10 Comentarios

  1. Hola Íñigo tienes el proyecto completo para poder descargarlo, no lo encuentro en la página donde dices que lo has sacado.

    saludos y gracias

  2. Íñigo, no me queda claro la explicación de comparar el ret_val de la instrucción de extracción de hora local, con w#16#0001

    saludos

    • La usa para saber si tiene horario de verano o de invierno. La compara con un “1” en hexadecimal. Si está a uno, es que tiene esa hora de diferencia, y si está a cero, que no. De ahí, que le sume una hora o no tras la comparación.

      Saludos

      • No lo entendía porque en las instrucciones de siemens indicaba otra cosa para ret val 0 si no había error.

        saludos

  3. Hola Iñigo,

    Muy bueno este artículo. Este código o programa se necesita especialmente el ST-1200 o cualquier otro autómata podría dar el mismo resultado, porque no sé si el SCL se podría hacer servir en otros, parece que es como el Visual Basic?, vaya por cierto dispones de autómatas o colaboras con más Voltaje. Quiero hacerme una instalación solar y necesitaría también al menos un autómata. Podrías conseguirme uno que no fuera nuevo y que hiciera el trabajo