Simple module supplies DC grid with maximum power tracker.

within PhotoVoltaics.Examples;
model SimpleModuleMPDC "Simple module supplies DC grid with maximum power tracker"
  extends Modelica.Icons.Example;
  Modelica.Electrical.Analog.Basic.Ground groundDC
  PhotoVoltaics.Components.SimplePhotoVoltaics.SimpleModuleSymmetric module(
    moduleData=moduleData,
    T=298.15,
    useConstantIrradiance=false)
  PhotoVoltaics.Components.Converters.DCConverter converter
  PhotoVoltaics.Components.Blocks.MPTrackerSample mpTracker(VmpRef = moduleData.VmpRef, ImpRef = moduleData.ImpRef,
    samplePeriod=10)
  Modelica.Electrical.Analog.Basic.Ground ground
  Modelica.Electrical.Analog.Sensors.PowerSensor powerSensor
  parameter PhotoVoltaics.Records.SHARP_NU_S5_E3E moduleData
  PhotoVoltaics.Sources.Electrical.IdealBattery battery(
    ns=4,
    np=1,
    V1Cell=14,
    V0Cell=11,
    ECell=12*100*3600,
    allowOvercharge=true,
    allowUndercharge=true,
    ViniCell=11)
  PhotoVoltaics.Sources.Irradiance.Irradiance irradiance
equation
  connect(groundDC.p, module.n)
  connect(mpTracker.vRef, converter.vDCRef)
  connect(module.p, powerSensor.pc)
  connect(mpTracker.power, powerSensor.power)
  connect(powerSensor.pc, powerSensor.pv)
  connect(powerSensor.nv, groundDC.p)
  connect(battery.pin_n, ground.p)
  connect(irradiance.irradiance, module.variableIrradiance)
  connect(groundDC.p, converter.dc_n1)
  connect(converter.dc_p1, powerSensor.nc)
  connect(converter.dc_p2, battery.pin_p)
  connect(converter.dc_n2, ground.p)
end SimpleModuleMPDC;


Simple module supplies transient three-phase AC grid with maximum power tracker.

within PhotoVoltaics.Examples;
model SimpleModulePolyphase
  "Simple module supplies transient three-phase AC grid with maximum power tracker"

  import Modelica.Constants.pi;
  extends Modelica.Icons.Example;

  Modelica.Electrical.Analog.Basic.Ground groundDC
  Modelica.Electrical.Analog.Sensors.PowerSensor powerSensor
  Modelica.Electrical.Polyphase.Basic.Star star
  Modelica.Electrical.Analog.Basic.Ground ground
  Modelica.Electrical.Polyphase.Sources.CosineVoltage cosineVoltage(
    f=fill(50, 3),
    V=fill(400*sqrt(2/3), 3),
    phase=-Modelica.Electrical.Polyphase.Functions.symmetricOrientation(3))
  Modelica.Blocks.Sources.Ramp ramp(
    height=-100,
    duration=2,
    offset=1000,
    startTime=1)
  Modelica.Blocks.Sources.Constant powerfactor(k=-acos(0.9))
  PhotoVoltaics.Components.SimplePhotoVoltaics.SimpleModuleSymmetric module(
    moduleData=moduleData,
    useConstantIrradiance=false,
    T=298.15)
  PhotoVoltaics.Components.Blocks.MPTrackerSample mpTracker(VmpRef=moduleData.VmpRef, ImpRef=moduleData.ImpRef,
    samplePeriod=0.1)
  PhotoVoltaics.Components.Converters.PolyphaseConverter converter
  parameter PhotoVoltaics.Records.SHARP_NU_S5_E3E moduleData
  Modelica.Electrical.Polyphase.Sensors.PowerSensor powerSensorGrid
  Modelica.Electrical.Polyphase.Sensors.VoltageQuasiRMSSensor
    voltageQuasiRMSSensor(m=3)
  Modelica.Electrical.Polyphase.Sensors.CurrentQuasiRMSSensor
    currentQuasiRMSSensor(final m=3)
  Modelica.Blocks.Math.Division powerFactorActual
  Modelica.Blocks.Math.Product product
  Modelica.Blocks.Math.Gain gain(final k=3)

  Modelica.Units.SI.Power powerDC=powerSensor.power "DC power";
  Modelica.Units.SI.Power powerAC=powerSensorGrid.power "AC real power";
  Modelica.Units.SI.ApparentPower aparrentPowerAC=powerFactorActual.u2
    "AC apparent power";
  Real powerFactorAC = powerFactorActual.y "Actual power factor";

  Modelica.Blocks.Nonlinear.Limiter limiter(uMax=Modelica.Constants.inf, uMin=Modelica.Constants.small)
equation
  connect(powerSensor.pc,powerSensor. pv)
  connect(powerSensor.nv,groundDC. p)
  connect(ground.p,star. pin_n)
  connect(cosineVoltage.plug_n,star. plug_p)
  connect(module.variableIrradiance, ramp.y)
  connect(module.n, groundDC.p)
  connect(module.p, powerSensor.pc)
  connect(converter.dc_p, powerSensor.nc)
  connect(converter.dc_n, groundDC.p)
  connect(mpTracker.power, powerSensor.power)
  connect(mpTracker.vRef, converter.vDCRef)
  connect(powerfactor.y, converter.phi)
  connect(converter.ac, powerSensorGrid.pc)
  connect(powerSensorGrid.pv, powerSensorGrid.pc)
  connect(powerSensorGrid.nv, star.plug_p)
  connect(powerSensorGrid.nc, currentQuasiRMSSensor.plug_p)
  connect(currentQuasiRMSSensor.plug_n, cosineVoltage.plug_p)
  connect(voltageQuasiRMSSensor.plug_n, star.plug_p)
  connect(voltageQuasiRMSSensor.plug_p, currentQuasiRMSSensor.plug_n)
  connect(powerFactorActual.u1, powerSensorGrid.power)
  connect(gain.u, product.y)
  connect(product.u1, currentQuasiRMSSensor.I)
  connect(product.u2, voltageQuasiRMSSensor.V)
  connect(limiter.y, powerFactorActual.u2)
  connect(limiter.u, gain.y)
end SimpleModulePolyphase;


Simple module with load resistor, partially shadowed.

within PhotoVoltaics.Examples;
model SimpleModuleShadow "Simple module with load resistor, partially shadowed"
  extends Modelica.Icons.Example;
  Modelica.Electrical.Analog.Basic.Ground ground
  PhotoVoltaics.Components.SimplePhotoVoltaics.SimpleModule module(
    moduleData=moduleData,
    T=298.15,
    shadow=cat(
            1,
            fill(0.2, 1),
            fill(0, moduleData.ns - 1)),
    cell(v(start=zeros(moduleData.ns))),
    diode(i(start=fill(1E-11, moduleData.nb))))
  Modelica.Electrical.Analog.Basic.VariableResistor variableResistor
  PhotoVoltaics.Sources.Blocks.PowerRamp powerRamp(duration = 0.6, height = 8, offset = -4, ref = moduleData.VmpCellRef / moduleData.ImpRef, startTime = 0.2)
  parameter PhotoVoltaics.Records.SHARP_NU_S5_E3E moduleData
equation
  connect(powerRamp.y, variableResistor.R)
  connect(variableResistor.n, ground.p)
  connect(module.p, variableResistor.p)
  connect(ground.p, module.n)
end SimpleModuleShadow;


Simple symmetric module without freewheeling diodes.

within PhotoVoltaics.Examples;
model SimpleModuleSymmetric "Simple symmetric module without freewheeling diodes"
  extends Modelica.Icons.Example;
  Modelica.Electrical.Analog.Basic.Ground ground
  PhotoVoltaics.Components.SimplePhotoVoltaics.SimpleModuleSymmetric module(T=298.15, moduleData=moduleData)
  PhotoVoltaics.Sources.Blocks.PowerRamp powerRamp(duration = 0.6, height = 8, offset = -4, ref = moduleData.VmpCellRef / moduleData.ImpRef, startTime = 0.2)
  Modelica.Electrical.Analog.Basic.VariableResistor variableResistor
  parameter PhotoVoltaics.Records.SHARP_NU_S5_E3E moduleData
equation
  connect(variableResistor.n, ground.p)
  connect(module.p, variableResistor.p)
  connect(variableResistor.R, powerRamp.y)
  connect(ground.p, module.n)
end SimpleModuleSymmetric;


Simple symmetric plant.

within PhotoVoltaics.Examples;
model SimplePlantSymmetric "Simple symmetric plant"
  extends Modelica.Icons.Example;
  Modelica.Electrical.Analog.Basic.Ground ground
  PhotoVoltaics.Components.SimplePhotoVoltaics.SimplePlantSymmetric plant(
    moduleData=moduleData,
    T=298.15,
    nsModule=10,
    npModule=2)
  PhotoVoltaics.Sources.Blocks.PowerRamp powerRamp(duration = 0.6, height = 8, offset = -4, ref = moduleData.VmpCellRef / moduleData.ImpRef, startTime = 0.2)
  Modelica.Electrical.Analog.Basic.VariableResistor variableResistor
  parameter PhotoVoltaics.Records.SHARP_NU_S5_E3E moduleData
equation
  connect(variableResistor.n, ground.p)
  connect(plant.p, variableResistor.p)
  connect(variableResistor.R, powerRamp.y)
  connect(ground.p, plant.n)
end SimplePlantSymmetric;


Solar pyramid charging a battery.

within PhotoVoltaics.Examples;
model SolarPyramidBatteryCharge "Solar pyramid charging a battery"
  import Modelica.Constants.pi;
  extends Modelica.Icons.Example;

  PhotoVoltaics.Components.SimplePhotoVoltaics.SolarPyramidDCConverter solarPyramid(
    moduleData=moduleData,
    VRef=moduleData.VmpRef,
    VmpRef=moduleData.VmpRef,
    ImpRef=moduleData.ImpRef,
    samplePeriod=0.5,
    sunHeight=0.38397243543875)
  Modelica.Blocks.Sources.Ramp gammaRamp(
    offset=0,
    height=60*pi/180,
    startTime=10,
    duration=480)
  Modelica.Blocks.Sources.Constant azimuthConst(k=260*pi/180)
  Modelica.Electrical.Analog.Basic.Ground ground
  Modelica.Electrical.Analog.Sources.ConstantVoltage constantVoltage(V=24)
  parameter PhotoVoltaics.Records.SHARP_NU_S5_E3E moduleData

  Modelica.Units.NonSI.Angle_deg gamma_deg=
      Modelica.Units.Conversions.to_deg(solarPyramid.gamma);
equation
  connect(gammaRamp.y, solarPyramid.gamma)
  connect(azimuthConst.y, solarPyramid.azimuth)
  connect(ground.p, solarPyramid.nModule)
  connect(solarPyramid.dc_n, ground.p)
  connect(solarPyramid.dc_p, constantVoltage.p)
  connect(solarPyramid.dc_n, constantVoltage.n)
end SolarPyramidBatteryCharge;


Functions

within PhotoVoltaics;
package Functions "Functions"
  extends Modelica.Icons.Package;
end Functions;


Interfaces

within PhotoVoltaics;
package Interfaces "Interfaces"
  extends Modelica.Icons.InterfacesPackage;
end Interfaces;


Partial cell model. The partial cell model considers the basic components of a simple
cell,
simple symmetric
module
and simple symmetric
plant
model.

within PhotoVoltaics.Interfaces;
partial model PartialCell "Partial cell model"
  extends PhotoVoltaics.Interfaces.PartialComponent;
  parameter Real shadow = 0 "Shadow based on: 0 = full sun, 1 = full shadow";
  PhotoVoltaics.Components.Diodes.Diode2Module diode(final useHeatPort = useHeatPort, final T = T, final TRef = moduleData.TRef)
  PhotoVoltaics.Sources.Electrical.SignalCurrent signalCurrent(final useHeatPort = useHeatPort, final T = T, final TRef = moduleData.TRef)
  Modelica.Blocks.Math.Gain gain(final k=PhotoVoltaics.Functions.limit(1-shadow,0,1))
equation
  connect(gain.y, signalCurrent.irradiance)
  connect(irradiance, gain.u)
  connect(signalCurrent.p, n)
  connect(p, signalCurrent.n)
  connect(diode.p, signalCurrent.n)
  connect(signalCurrent.heatPort, internalHeatPort)
  connect(diode.n, signalCurrent.p)
  connect(diode.heatPort, internalHeatPort)
end PartialCell;


Partial cell or module. This partial model contains the connectors and some parameters of photovoltaic components. Interfaces voltages,
currents and power terms are defined.

within PhotoVoltaics.Interfaces;
partial model PartialComponent "Partial cell or module"
  extends Modelica.Electrical.Analog.Interfaces.TwoPin(v(start = 0));
  extends
    Modelica.Thermal.HeatTransfer.Interfaces.PartialConditionalHeatPort(      T = 298.15);
  parameter Boolean useConstantIrradiance = true "If false, signal input is used"
  parameter Modelica.Units.SI.Irradiance constantIrradiance=1000
    "Constant solar irradiance, if useConstantIrradiance = true"
  parameter Records.ModuleData moduleData "Module parameters"
  Modelica.Units.SI.Current i=p.i "Current";
  Modelica.Units.SI.Current iGenerating=-i "Negative current (generating)";
  Modelica.Units.SI.Power power=v*i "Power";
  Modelica.Units.SI.Power powerGenerating=v*iGenerating
    "Negative power consumption (generating)";
  Modelica.Blocks.Interfaces.RealInput variableIrradiance(unit = "W/m2") if not useConstantIrradiance "Solar irradiance"
  Modelica.Blocks.Sources.Constant const(final k = constantIrradiance) if useConstantIrradiance
protected
  Modelica.Blocks.Interfaces.RealInput irradiance(unit = "W/m2") "Solar irradiance (either constant or signal input)"
equation
  connect(irradiance, variableIrradiance)
  connect(const.y, irradiance)
end PartialComponent;


Diode with one exponential function. This partial model of the diode does not yet contain any current versus voltage characteristic. In this model the
temperature dependencies of the temperature voltage, the saturation current, etc. are defined.

within PhotoVoltaics.Interfaces;
partial model PartialDiode "Diode with one exponential function"
  extends Modelica.Electrical.Analog.Interfaces.OnePort(v(start = 0));
  extends Modelica.Electrical.Analog.Interfaces.ConditionalHeatPort(T = 298.15);
  constant Modelica.Units.SI.Charge Q=1.6021766208E-19
    "Elementary charge of electron";
  parameter Real m = 1 "Ideality factor of diode";
  parameter Modelica.Units.SI.Resistance R=1E8 "Parallel ohmic resistance";
  parameter Modelica.Units.SI.Temperature TRef=298.15
    "Reference temperature"
  parameter Modelica.Units.SI.Voltage VRef(min=Modelica.Constants.small) = 0.6292
    "Reference voltage > 0, i.e. open circuit voltage, at TRef"
  parameter Modelica.Units.SI.Current IRef(min=Modelica.Constants.small) = 8.540
    "Reference current > 0, i.e. short circuit current, at TRef"
  parameter Modelica.Units.SI.LinearTemperatureCoefficient alphaI=+0.00053
    "Temperature coefficient of reference current at TRef"
  parameter Modelica.Units.SI.LinearTemperatureCoefficient alphaV=-0.00340
    "Temperature coefficient of reference voltage at TRef*"
  Modelica.Units.SI.Voltage Vt "Voltage equivalent of temperature (k*T/Q)";
  Modelica.Units.SI.Voltage VRefActual
    "Reference voltage w.r.t. actual temperature";
  Modelica.Units.SI.Current IRefActual
    "Reference current w.r.t. actual temperature";
  Modelica.Units.SI.Current Ids "Saturation current";
equation
  // Temperature dependent voltage
  Vt = Modelica.Constants.k * T_heatPort / Q;
  // Re-calculate reference voltage and current with respect to reference temperature
  VRefActual = VRef * (1 + alphaV * (T_heatPort - TRef));
  IRefActual = IRef * (1 + alphaI * (T_heatPort - TRef));
  // Actual temperature dependent saturation current is determined from reference voltage and current
  Ids = IRefActual / (exp(VRefActual / m / Vt) - 1);
  LossPower = v * i;
end PartialDiode;


Single-phase AC pins. This model provides single-phase AC quasi static pins.

within PhotoVoltaics.Interfaces.QuasiStatic;
partial model ACpins "Single-phase AC pins"
  import Modelica.ComplexMath.conj;
  Modelica.Electrical.QuasiStatic.SinglePhase.Interfaces.PositivePin ac_p
    "AC positive pin"
  Modelica.Electrical.QuasiStatic.SinglePhase.Interfaces.NegativePin ac_n
    "AC negative pin"
  Modelica.Units.SI.ComplexVoltage vAC=ac_p.v - ac_n.v "AC potential";
  Modelica.Units.SI.ComplexCurrent iAC=ac_p.i "AC current";
  Modelica.Units.SI.ComplexPower apparentPowerAC=vAC .* conj(iAC)
    "AC apparent power";
end ACpins;


AC polyphase plug. This model provides a polyphase AC quasi static plug.

within PhotoVoltaics.Interfaces.QuasiStatic;
partial model ACplug "AC polyphase plug"
  import Modelica.ComplexMath.conj;
  parameter Integer m(final min = 3) = 3 "Number of phases";
  Modelica.Electrical.QuasiStatic.Polyphase.Interfaces.PositivePlug ac(final
      m=m) "AC output"
  Modelica.Units.SI.ComplexVoltage vAC[m]=ac.pin[:].v "AC potential";
  Modelica.Units.SI.ComplexCurrent iAC[m]=ac.pin[:].i "AC current";
  Modelica.Units.SI.ComplexPower apparentPowerAC[m]=vAC .* conj(iAC)
    "AC apparent power";
end ACplug;


Quasi-static interfaces

within PhotoVoltaics.Interfaces;
package QuasiStatic "Quasi-static interfaces"
  extends Modelica.Icons.Package;
end QuasiStatic;


Records

within PhotoVoltaics;
package Records "Records"

  extends Modelica.Icons.RecordsPackage;
end Records;


Sources

within PhotoVoltaics;
package Sources "Sources"
  extends Modelica.Icons.Package;
end Sources;


Block sources

within PhotoVoltaics.Sources;
package Blocks "Block sources"
  extends Modelica.Icons.Package;
end Blocks;


Generate ramp signal based logarithmic range. The Real output y of this block is determined by a
ramp output
 from which

within PhotoVoltaics.Sources.Blocks;
block PowerRamp "Generate ramp signal based logarithmic range"
  parameter Real height = 1 "Height of ramps";
  parameter Modelica.Units.SI.Time duration(min=0.0, start=2)
    "Duration of ramp (= 0.0 gives a Step)";
  parameter Real offset = 0 "Offset of output signal";
  parameter Modelica.Units.SI.Time startTime=0
    "Output = offset for time < startTime";
  parameter Real ref = 1 "Reference value, determined by ref * 10 ^ (ramp function)";
  extends Modelica.Blocks.Interfaces.SO;
equation
  y = ref * 10 ^ (offset + (if time < startTime then 0 else if time < startTime + duration then (time - startTime) * height / duration else height));
end PowerRamp;


Multiple steps and triangles.

within PhotoVoltaics.Sources.Blocks;
block TriangleAndStep "Multiple steps and triangles"
  parameter Modelica.Units.SI.Time T=1 "Total time of varying outputs";
  parameter Integer stepNumber = 5 "Number of steps";
  parameter Real stepHeight = 1 "Total step height";
  parameter Real stepOffset = 0 "Offset";
  parameter Modelica.Units.SI.Time startTime=0 "Start time";
  parameter Real triangleHeight = 1 "Height of triangle output";
  parameter Real triangleOffset = 0 "Offset of triangle output";
  Modelica.Blocks.Sources.Ramp ramp(
    final startTime=startTime,
    final height=stepNumber - 1,
    final duration=T*(stepNumber - 1)/stepNumber,
    final offset=0)
  Modelica.Blocks.Math.RealToInteger realToInteger
  Modelica.Blocks.Math.IntegerToReal integerToReal
  Modelica.Blocks.Math.Feedback feedback
  Modelica.Blocks.Sources.Constant constantOffset(final k = stepOffset)
  Modelica.Blocks.Math.Add add
  Modelica.Blocks.Math.Gain gain(final k = stepHeight / (stepNumber - 1))
  Modelica.Blocks.Sources.Trapezoid trapezoid(final amplitude = triangleHeight, final rising = T / stepNumber / 2, final width = 0, final falling = T / stepNumber / 2, final period = T / stepNumber, final nperiod = stepNumber, final offset = triangleOffset, final startTime = startTime)
  Modelica.Blocks.Interfaces.RealOutput step
  Modelica.Blocks.Interfaces.RealOutput triangle
  Modelica.Blocks.Sources.Step const(offset=0, startTime=0, height=0.5)
  Modelica.Blocks.Nonlinear.Limiter limiter(final uMax=Modelica.Constants.inf, final uMin=0)
equation
  connect(realToInteger.y, integerToReal.u)
  connect(ramp.y, feedback.u1)
  connect(integerToReal.y, gain.u)
  connect(constantOffset.y, add.u1)
  connect(gain.y, add.u2)
  connect(add.y, step)
  connect(trapezoid.y, triangle)
  connect(const.y, feedback.u2)
  connect(feedback.y, limiter.u)
  connect(limiter.y, realToInteger.u)
end TriangleAndStep;


Re-chargeable ideal battery without loss. This is a simple, linear rechargable battery model. The actual physical model consists of one
capacitor. In order to consider the number of series and parallel connected cells, an internal
scaling of voltages, currents and power terms, is performed.

within PhotoVoltaics.Sources.Electrical;
model IdealBattery "Re-chargeable ideal battery without loss"
  parameter Integer ns(min = 1) = 1 "Number of series cells";
  parameter Integer np(min = 1) = 1 "Number of parallel cells";
  parameter Modelica.Units.SI.Voltage V1Cell
    "Maximum cell voltage > V0Cell";
  parameter Modelica.Units.SI.Voltage V0Cell
    "Minimum cell voltage < V1Cell";
  final parameter Modelica.Units.SI.Voltage V1=V1Cell*ns
    "Maximum battery voltage > V0";
  final parameter Modelica.Units.SI.Voltage V0=V0Cell*ns
    "Maximum battery voltage < V1";
  parameter Boolean allowOvercharge = false
    "Allows overcharging without error";
  parameter Boolean allowUndercharge = false
    "Allows undercharging without error";
  parameter Modelica.Units.SI.Energy ECell
    "Total cell energy between V0Cell and V1Cell";
  final parameter Modelica.Units.SI.Capacitance CCell=2*ECell/(V1Cell^2 -
      V0Cell^2) "Total charge of battery";
  parameter Modelica.Units.SI.Voltage ViniCell=V1Cell
    "Initial cell voltage";
  Modelica.Units.SI.Voltage v=pin_p.v - pin_n.v "Battery voltage";
  Modelica.Units.SI.Voltage vCell=v/ns "Cell voltage";
  Modelica.Units.SI.Current i=capacitor.i "Battery current";
  Modelica.Units.SI.Current iCell=i/np "Cell current";
  Modelica.Units.SI.Power power=v*i "Battery power";
  Modelica.Units.SI.Power powerCell=power/ns/np "Cell power";
  Modelica.Units.SI.Energy energy "Energy";
  Modelica.Units.SI.Energy energyCell "Cell energy";
  Modelica.Electrical.Analog.Basic.Capacitor capacitor(final C = CCell * np / ns, v(start = ns * ViniCell, fixed = true))
  Modelica.Electrical.Analog.Interfaces.PositivePin pin_p "Positive pin"
  Modelica.Electrical.Analog.Interfaces.NegativePin pin_n "Negative pin"
initial equation
  energyCell = CCell * (ViniCell ^ 2 - V0Cell ^ 2) / 2;
equation
  der(energy) = power;
  energyCell * ns * np = energy;
  assert(vCell >= V0Cell or allowUndercharge, "Battery: cell voltage less than V0Cell");
  assert(vCell <= V1Cell or allowOvercharge, "Battery: cell voltage greater than V1Cell");
  connect(pin_p, capacitor.p)
  connect(capacitor.n, pin_n)
end IdealBattery;


Electrical sources

within PhotoVoltaics.Sources;
package Electrical "Electrical sources"
  extends Modelica.Icons.Package;
end Electrical;


Generic current source using the input signal as source current. The signal current source is a converter of real valued irradiance signal into a source current.
Depending on the actual temperature the current is adjusted through a linear temperature coeffficient.

within PhotoVoltaics.Sources.Electrical;
model SignalCurrent "Generic current source using the input signal as source current"
  extends Modelica.Electrical.Analog.Interfaces.ConditionalHeatPort(T = 298.15);
  parameter Modelica.Units.SI.Temperature TRef=298.15
    "Reference temperature";
  parameter Modelica.Units.SI.Current IRef=1
    "Reference current at reference irradiance and reference temperature";
  parameter Modelica.Units.SI.Irradiance irradianceRef=1000
    "Reference solar irradiance";
  parameter Modelica.Units.SI.LinearTemperatureCoefficient alphaRef=0
    "Temperature coefficient of reference current at TRref";
  Modelica.Electrical.Analog.Interfaces.PositivePin p
  Modelica.Electrical.Analog.Interfaces.NegativePin n
  Modelica.Units.SI.Voltage v
    "Voltage drop between the two pins (= p.v - n.v)";
  Modelica.Units.SI.Current i
    "Current flowing from pin p to pin n as input signal";
  Modelica.Blocks.Interfaces.RealInput irradiance(unit = "W/m2") "Irradiance"
equation
  i = IRef * (irradiance / irradianceRef + alphaRef * (T_heatPort - TRef));
  v = p.v - n.v;
  0 = p.i + n.i;
  i = p.i;
  LossPower = 0;
end SignalCurrent;


Unrooted variable polyphase AC current source.

within PhotoVoltaics.Sources.Electrical;
model VariableUnrootedPolyphaseCurrentSource
  "Unrooted variable polyphase AC current source"
  extends Modelica.Electrical.QuasiStatic.Polyphase.Interfaces.OnePort;
  import Modelica.Constants.pi;
  Modelica.ComplexBlocks.Interfaces.ComplexInput I[m]
equation
  i = I;
end VariableUnrootedPolyphaseCurrentSource;


within PhotoVoltaics.Sources.Electrical;
model VariableUnrootedSinglePhaseCurrentSource "Unrooted variable polyphase AC current source"
  extends Modelica.Electrical.QuasiStatic.SinglePhase.Interfaces.OnePort;
  import Modelica.Constants.pi;
  Modelica.ComplexBlocks.Interfaces.ComplexInput I
equation
  i = I;
end VariableUnrootedSinglePhaseCurrentSource;


Simple solar irradiance without considering weather conditions.

within PhotoVoltaics.Sources.Irradiance;
model Irradiance "Simple solar irradiance without considering weather conditions"
  import Modelica.Constants.pi;
  import PhotoVoltaics.Functions.rad;
  import PhotoVoltaics.Functions.degree;
  import PhotoVoltaics.Functions.dayOfTheYear;
  parameter Integer startDay(final min = 1, final max = 31) = 10 "Day";
  parameter Integer startMonth(final min = 1, final max = 12) = 9 "Month";
  parameter Integer startYear = 2016 "Year";
  parameter Integer TimeZone = 1 "Time zone";
  parameter Modelica.Units.SI.Angle longitude=0.2856929452589518
    "Longitude";
  parameter Modelica.Units.SI.Angle latitude=0.8418964085999744
    "Latitude";
  parameter Modelica.Units.SI.Irradiance irradianceRef=1000
    "Reference solar irradiance";
  parameter Modelica.Units.SI.Angle gamma=10*pi/180
    "Angle of PV module with w.r.t. horizontal plane";
  parameter Modelica.Units.SI.Angle azimuth=0
    "Azimuth of the PV module orientation";
  Integer startDayOfYear(start = dayOfTheYear(startDay, startMonth, startYear), fixed = true) "Start day of year in simulation";
  Integer dayOfYear(final start = dayOfTheYear(startDay, startMonth, startYear), fixed = true) "Actual day of year";
  Integer daysOfYear(final start = dayOfTheYear(31, 12, startYear), fixed = true) "Total number of days of year";
  Integer year(final start = startYear, fixed = true) "Actual year";
  Modelica.Units.SI.Angle Jprime(final start=dayOfTheYear(
              startDay,
              startMonth,
              startYear)/dayOfTheYear(
              31,
              12,
              startYear)*2*pi, fixed=true)
    "Equivalent Angle of the day of the year w.r.t. total number of days";
  Real delta_J;
  Real timeequation_J;
  Modelica.Units.NonSI.Time_day localTimeDays "Local time in days";
  Integer localDays "Locale day";
  Modelica.Units.SI.Time localTime "Local time";
  Modelica.Units.NonSI.Time_hour localTimeHours
    "Local time in unit hours";
  Modelica.Units.NonSI.Time_hour LocalMeanTimeHours
    "Local mean time in unit hours";
  Modelica.Units.NonSI.Time_hour trueMeanTimeHours
    "True mean time in unit hours";
  Modelica.Units.SI.Angle hoursAngle "Hours angle";
  Modelica.Units.SI.Angle sunHeight "Sun height";
  Modelica.Units.SI.Angle sunAzimuth1 "Sun azimuth before 12 p.m.";
  Modelica.Units.SI.Angle sunAzimuth2 "Sun azimuth after 12 p.m.";
  Modelica.Units.SI.Angle sunAzimuth "Sun azimuth";
  Modelica.Units.SI.Angle angleOfIncidence
    "Angle of incidence between a vector in sun direction and a normal vector";
  Modelica.Units.SI.Irradiance directIrradianceHorizontal
    "Direct irradiance on the horizontal in W/m^2";
  Modelica.Units.SI.Irradiance directIrradianceInclined
    "Direct irradiance on the inclined plane in w/m^2";
  Modelica.Blocks.Interfaces.RealOutput irradiance "Irradiance of inclined area"
algorithm
  // Calculate ratio of day w.r.t. total number of days of a year as equivalent angle
  when sample(24 * 3600, 24 * 3600) then
    dayOfYear := mod(pre(dayOfYear), pre(daysOfYear)) + 1;
  end when;
  when startDayOfYear + localDays == daysOfYear + 1 then
    startDayOfYear := 1;
    year := pre(year) + 1;
    daysOfYear := dayOfTheYear(31, 12, year);
  end when;
  // One full year is reached
  // Reset start day of year
  // Increment year
  // Determined actual number of total days of year
equation
  Jprime = dayOfYear / daysOfYear * 2 * pi;
  delta_J = rad(0.3948 - 23.2559 * cos(Jprime + rad(9.1)) - 0.3915 * cos(2 * Jprime + rad(5.4)) - 0.1764 * cos(3 * Jprime + rad(26)));
  timeequation_J = 0.0066 + 7.3525 * cos(Jprime + rad(85.9)) + 9.9359 * cos(2 * Jprime + rad(108.9)) + 0.3387 * cos(3 * Jprime + rad(105.2));
  // Zeit LZ = time
  localTime = time;
  // Convert time into unit hours
  localTimeHours = localTime / 3600;
  // Convert time into unit days
  localTimeDays = localTimeHours / 24;
  // Convert time from real days into integer days (floor)
  localDays = integer(floor(localTimeDays));
  // Calculate locale mean time
  LocalMeanTimeHours = localTimeHours - TimeZone + 4 / 60 * longitude * 180 / Modelica.Constants.pi;
  // cos(latitude)*tan(...)
  trueMeanTimeHours = LocalMeanTimeHours + timeequation_J / 60;
  hoursAngle = rad((12 - trueMeanTimeHours) * 15);
  sunHeight = degree(asin(cos(hoursAngle) * cos(latitude) * cos(delta_J) + sin(latitude) * sin(delta_J))) * (Modelica.Constants.pi / 180);
  sunAzimuth1 = Modelica.Constants.pi - acos((sin(sunHeight) * sin(latitude) - sin(delta_J)) / (cos(sunHeight) * cos(latitude)));
  sunAzimuth2 = Modelica.Constants.pi + acos((sin(sunHeight) * sin(latitude) - sin(delta_J)) / (cos(sunHeight) * cos(latitude)));
  sunAzimuth = if mod(localTimeHours, 24) <= 12 then sunAzimuth1 else sunAzimuth2;
  angleOfIncidence = acos((-cos(sunHeight) * sin(gamma) * cos(sunAzimuth - azimuth)) + sin(sunHeight) * cos(gamma));
  directIrradianceHorizontal = if sunHeight < 0 then 0 else irradianceRef * sin(sunHeight);
  directIrradianceInclined = if angleOfIncidence > pi / 2 then 0 else if abs(sin(sunHeight)) < 1E-5 then 0 else directIrradianceHorizontal * (cos(angleOfIncidence) / sin(sunHeight));
  irradiance = directIrradianceInclined;
end Irradiance;


Simple solar irradiance with fixed sun position.

within PhotoVoltaics.Sources.Irradiance;
model IrradianceFixedSun "Simple solar irradiance with fixed sun position"
  import Modelica.Constants.pi;
  parameter Modelica.Units.SI.Irradiance irradianceRef=1000
    "Reference solar irradiance";
  parameter Modelica.Units.SI.Angle sunHeight "Sun height";
  parameter Modelica.Units.SI.Angle sunAzimuth "Sun azimuth";
  Modelica.Units.SI.Angle angleOfIncidence
    "Angle of incidence between a vector in sun direction and a normal vector";
  Modelica.Units.SI.Irradiance directIrradianceHorizontal
    "Direct irradiance on the horizontal";
  Modelica.Units.SI.Irradiance directIrradianceInclined
    "Direct irradiance on the inclined plane";
  Modelica.Blocks.Interfaces.RealOutput irradiance
  Modelica.Blocks.Interfaces.RealInput gamma
  Modelica.Blocks.Interfaces.RealInput azimuth
equation
  angleOfIncidence = acos((-cos(sunHeight) * sin(gamma) * cos(sunAzimuth - azimuth)) + sin(sunHeight) * cos(gamma));
  directIrradianceHorizontal = if sunHeight < 0 then 0 else irradianceRef * sin(sunHeight);
  directIrradianceInclined = if angleOfIncidence > pi / 2 then 0 else if abs(sin(sunHeight)) < 1E-5 then 0 else directIrradianceHorizontal * (cos(angleOfIncidence) / sin(sunHeight));
  irradiance = directIrradianceInclined;
end IrradianceFixedSun;


within PhotoVoltaics.Sources.Irradiance;
model IrradianceVariableLocation "Simple solar irradiance without considering weather conditions"
  import Modelica.Constants.pi;
  import PhotoVoltaics.Functions.rad;
  import PhotoVoltaics.Functions.degree;
  import PhotoVoltaics.Functions.dayOfTheYear;
  parameter Integer startDay(final min = 1, final max = 31) = 10 "Day";
  parameter Integer startMonth(final min = 1, final max = 12) = 9 "Month";
  parameter Integer startYear = 2016 "Year";
  parameter Integer TimeZone = 1 "Time zone";
  parameter Modelica.Units.SI.Angle longitude=0.2856929452589518
    "Longitude";
  parameter Modelica.Units.SI.Angle latitude=0.8418964085999744
    "Latitude";
  parameter Modelica.Units.SI.Irradiance irradianceRef=1000
    "Reference solar irradiance";
  Integer startDayOfYear(start = dayOfTheYear(startDay, startMonth, startYear)) "Start day of year in simulation";
  Integer dayOfYear(final start = dayOfTheYear(startDay, startMonth, startYear)) "Actual day of year";
  Integer daysOfYear(final start = dayOfTheYear(31, 12, startYear)) "Total number of days of year";
  Integer year(final start = startYear) "Actual year";
  Modelica.Units.SI.Angle Jprime(final start=dayOfTheYear(
              startDay,
              startMonth,
              startYear)/dayOfTheYear(
              31,
              12,
              startYear)*2*pi)
    "Equivalent Angle of the day of the year w.r.t. total number of days";
  Real delta_J;
  Real timeequation_J;
  Modelica.Units.NonSI.Time_day localTimeDays "Local time in days";
  Integer localDays "Locale day";
  Modelica.Units.SI.Time localTime "Local time";
  Modelica.Units.NonSI.Time_hour localTimeHours
    "Local time in unit hours";
  Modelica.Units.NonSI.Time_hour LocalMeanTimeHours
    "Local mean time in unit hours";
  Modelica.Units.NonSI.Time_hour trueMeanTimeHours
    "True mean time in unit hours";
  Modelica.Units.SI.Angle hoursAngle "Hours angle";
  Modelica.Units.SI.Angle sunHeight "Sun height";
  Modelica.Units.SI.Angle sunAzimuth1 "Sun azimuth before 12 p.m.";
  Modelica.Units.SI.Angle sunAzimuth2 "Sun azimuth after 12 p.m.";
  Modelica.Units.SI.Angle sunAzimuth "Sun azimuth";
  Modelica.Units.SI.Angle angleOfIncidence
    "Angle of incidence between a vector in sun direction and a normal vector";
  Modelica.Units.SI.Irradiance directIrradianceHorizontal
    "Direct irradiance on the horizontal in W/m^2";
  Modelica.Units.SI.Irradiance directIrradianceInclined
    "Direct irradiance on the inclined plane in w/m^2";
  Modelica.Blocks.Interfaces.RealOutput irradiance "Irradiance of inclined area"
  Modelica.Blocks.Interfaces.RealInput gamma "Inclination angle of area"
  Modelica.Blocks.Interfaces.RealInput azimuth "Azimuth of area"
algorithm
  // Calculate ratio of day w.r.t. total number of days of a year as equivalent angle
  when sample(24 * 3600, 24 * 3600) then
    dayOfYear := mod(pre(dayOfYear), pre(daysOfYear)) + 1;
  end when;
  when startDayOfYear + localDays == daysOfYear + 1 then
    startDayOfYear := 1;
    year := pre(year) + 1;
    daysOfYear := dayOfTheYear(31, 12, year);
  end when;
  // One full year is reached
  // Reset start day of year
  // Increment year
  // Determined actual number of total days of year
equation
  Jprime = dayOfYear / daysOfYear * 2 * pi;
  delta_J = rad(0.3948 - 23.2559 * cos(Jprime + rad(9.1)) - 0.3915 * cos(2 * Jprime + rad(5.4)) - 0.1764 * cos(3 * Jprime + rad(26)));
  timeequation_J = 0.0066 + 7.3525 * cos(Jprime + rad(85.9)) + 9.9359 * cos(2 * Jprime + rad(108.9)) + 0.3387 * cos(3 * Jprime + rad(105.2));
  // Zeit LZ = time
  localTime = time;
  // Convert time into unit hours
  localTimeHours = localTime / 3600;
  // Convert time into unit days
  localTimeDays = localTimeHours / 24;
  // Convert time from real days into integer days (floor)
  localDays = integer(floor(localTimeDays));
  // Calculate locale mean time
  LocalMeanTimeHours = localTimeHours - TimeZone + 4 / 60 * longitude * 180 / Modelica.Constants.pi;
  // cos(latitude)*tan(...)
  trueMeanTimeHours = LocalMeanTimeHours + timeequation_J / 60;
  hoursAngle = rad((12 - trueMeanTimeHours) * 15);
  sunHeight = degree(asin(cos(hoursAngle) * cos(latitude) * cos(delta_J) + sin(latitude) * sin(delta_J))) * (Modelica.Constants.pi / 180);
  sunAzimuth1 = Modelica.Constants.pi - acos((sin(sunHeight) * sin(latitude) - sin(delta_J)) / (cos(sunHeight) * cos(latitude)));
  sunAzimuth2 = Modelica.Constants.pi + acos((sin(sunHeight) * sin(latitude) - sin(delta_J)) / (cos(sunHeight) * cos(latitude)));
  sunAzimuth = if mod(localTimeHours, 24) <= 12 then sunAzimuth1 else sunAzimuth2;
  angleOfIncidence = acos((-cos(sunHeight) * sin(gamma) * cos(sunAzimuth - azimuth)) + sin(sunHeight) * cos(gamma));
  directIrradianceHorizontal = if sunHeight < 0 then 0 else irradianceRef * sin(sunHeight);
  directIrradianceInclined = if angleOfIncidence > pi / 2 then 0 else if abs(sin(sunHeight)) < 1E-5 then 0 else directIrradianceHorizontal * (cos(angleOfIncidence) / sin(sunHeight));
  irradiance = directIrradianceInclined;
end IrradianceVariableLocation;


Irradiance

within PhotoVoltaics.Sources;
package Irradiance "Irradiance"
  extends Modelica.Icons.Package;
end Irradiance;