00001
00010 #include <stdlib.h>
00011 #include <stdio.h>
00012 #include <errno.h>
00013 #include <math.h>
00014
00015 #include "inverter.h"
00016
00017
00018 CLASS *inverter::oclass = NULL;
00019 inverter *inverter::defaults = NULL;
00020
00021 static PASSCONFIG passconfig = PC_BOTTOMUP|PC_POSTTOPDOWN;
00022 static PASSCONFIG clockpass = PC_BOTTOMUP;
00023
00024
00025 inverter::inverter(MODULE *module)
00026 {
00027 if (oclass==NULL)
00028 {
00029 oclass = gl_register_class(module,"inverter",sizeof(inverter),PC_PRETOPDOWN|PC_BOTTOMUP|PC_POSTTOPDOWN|PC_AUTOLOCK);
00030 if (oclass==NULL)
00031 throw "unable to register class inverter";
00032 else
00033 oclass->trl = TRL_PROOF;
00034
00035 if (gl_publish_variable(oclass,
00036
00037 PT_enumeration,"inverter_type",PADDR(inverter_type_v), PT_DESCRIPTION, "LEGACY MODEL: Sets efficiencies and other parameters; if using four_quadrant_control_mode, set this to FOUR_QUADRANT",
00038 PT_KEYWORD,"TWO_PULSE",(enumeration)TWO_PULSE,
00039 PT_KEYWORD,"SIX_PULSE",(enumeration)SIX_PULSE,
00040 PT_KEYWORD,"TWELVE_PULSE",(enumeration)TWELVE_PULSE,
00041 PT_KEYWORD,"PWM",(enumeration)PWM,
00042 PT_KEYWORD,"FOUR_QUADRANT",(enumeration)FOUR_QUADRANT,
00043
00044 PT_enumeration,"four_quadrant_control_mode",PADDR(four_quadrant_control_mode), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Activates various control modes",
00045 PT_KEYWORD,"NONE",(enumeration)FQM_NONE,
00046 PT_KEYWORD,"CONSTANT_PQ",(enumeration)FQM_CONSTANT_PQ,
00047 PT_KEYWORD,"CONSTANT_PF",(enumeration)FQM_CONSTANT_PF,
00048
00049 PT_KEYWORD,"VOLT_VAR",(enumeration)FQM_VOLT_VAR,
00050 PT_KEYWORD,"VOLT_WATT",(enumeration)FQM_VOLT_WATT,
00051 PT_KEYWORD,"VOLT_VAR_FREQ_PWR",FQM_VOLT_VAR_FREQ_PWR,
00052 PT_KEYWORD,"LOAD_FOLLOWING",(enumeration)FQM_LOAD_FOLLOWING,
00053 PT_KEYWORD,"GROUP_LOAD_FOLLOWING",(enumeration)FQM_GROUP_LF,
00054 PT_KEYWORD,"VOLTAGE_SOURCE",(enumeration)FQM_VSI,
00055
00056 PT_enumeration,"pf_reg",PADDR(pf_reg), PT_DESCRIPTION, "Activate (or not) power factor regulation in four_quadrant_control_mode",
00057 PT_KEYWORD,"INCLUDED",(enumeration)INCLUDED,
00058 PT_KEYWORD,"INCLUDED_ALT",(enumeration)INCLUDED_ALT,
00059 PT_KEYWORD,"EXCLUDED",(enumeration)EXCLUDED,
00060
00061 PT_enumeration,"generator_status",PADDR(gen_status_v), PT_DESCRIPTION, "describes whether the generator is online or offline",
00062 PT_KEYWORD,"OFFLINE",(enumeration)OFFLINE,
00063 PT_KEYWORD,"ONLINE",(enumeration)ONLINE,
00064
00065 PT_enumeration,"generator_mode",PADDR(gen_mode_v), PT_DESCRIPTION, "LEGACY MODEL: Selects generator control mode when using legacy model; in non-legacy models, this should be SUPPLY_DRIVEN.",
00066 PT_KEYWORD,"UNKNOWN",UNKNOWN,
00067 PT_KEYWORD,"CONSTANT_V",(enumeration)CONSTANT_V,
00068 PT_KEYWORD,"CONSTANT_PQ",(enumeration)CONSTANT_PQ,
00069 PT_KEYWORD,"CONSTANT_PF",(enumeration)CONSTANT_PF,
00070 PT_KEYWORD,"SUPPLY_DRIVEN",(enumeration)SUPPLY_DRIVEN,
00071
00072 PT_double, "inverter_convergence_criterion",PADDR(inverter_convergence_criterion), PT_DESCRIPTION, "The maximum change in error threshold for exitting deltamode.",
00073 PT_complex, "V_In[V]",PADDR(V_In), PT_DESCRIPTION, "DC voltage",
00074 PT_complex, "I_In[A]",PADDR(I_In), PT_DESCRIPTION, "DC current",
00075 PT_complex, "VA_In[VA]", PADDR(VA_In), PT_DESCRIPTION, "DC power",
00076 PT_complex, "VA_Out[VA]", PADDR(VA_Out), PT_DESCRIPTION, "AC power",
00077 PT_double, "Vdc[V]", PADDR(Vdc), PT_DESCRIPTION, "LEGACY MODEL: DC voltage",
00078 PT_complex, "phaseA_V_Out[V]", PADDR(phaseA_V_Out), PT_DESCRIPTION, "AC voltage on A phase in three-phase system; 240-V connection on a triplex system",
00079 PT_complex, "phaseB_V_Out[V]", PADDR(phaseB_V_Out), PT_DESCRIPTION, "AC voltage on B phase in three-phase system",
00080 PT_complex, "phaseC_V_Out[V]", PADDR(phaseC_V_Out), PT_DESCRIPTION, "AC voltage on C phase in three-phase system",
00081 PT_complex, "phaseA_I_Out[V]", PADDR(phaseA_I_Out), PT_DESCRIPTION, "AC current on A phase in three-phase system; 240-V connection on a triplex system",
00082 PT_complex, "phaseB_I_Out[V]", PADDR(phaseB_I_Out), PT_DESCRIPTION, "AC current on B phase in three-phase system",
00083 PT_complex, "phaseC_I_Out[V]", PADDR(phaseC_I_Out), PT_DESCRIPTION, "AC current on C phase in three-phase system",
00084 PT_complex, "power_A[VA]", PADDR(power_val[0]), PT_DESCRIPTION, "AC power on A phase in three-phase system; 240-V connection on a triplex system",
00085 PT_complex, "power_B[VA]", PADDR(power_val[1]), PT_DESCRIPTION, "AC power on B phase in three-phase system",
00086 PT_complex, "power_C[VA]", PADDR(power_val[2]), PT_DESCRIPTION, "AC power on C phase in three-phase system",
00087 PT_complex, "curr_VA_out_A[VA]", PADDR(curr_VA_out[0]), PT_DESCRIPTION, "AC power on A phase in three-phase system; 240-V connection on a triplex system",
00088 PT_complex, "curr_VA_out_B[VA]", PADDR(curr_VA_out[1]), PT_DESCRIPTION, "AC power on B phase in three-phase system",
00089 PT_complex, "curr_VA_out_C[VA]", PADDR(curr_VA_out[2]), PT_DESCRIPTION, "AC power on C phase in three-phase system",
00090 PT_complex, "prev_VA_out_A[VA]", PADDR(prev_VA_out[0]), PT_DESCRIPTION, "AC power on A phase in three-phase system; 240-V connection on a triplex system",
00091 PT_complex, "prev_VA_out_B[VA]", PADDR(prev_VA_out[1]), PT_DESCRIPTION, "AC power on B phase in three-phase system",
00092 PT_complex, "prev_VA_out_C[VA]", PADDR(prev_VA_out[2]), PT_DESCRIPTION, "AC power on C phase in three-phase system",
00093
00094
00095 PT_double, "e_source_A", PADDR(e_source[0]), PT_ACCESS, PA_HIDDEN, PT_DESCRIPTION, "DELTAMODE: Internal voltage of grid-forming source, phase A",
00096 PT_double, "e_source_B", PADDR(e_source[1]), PT_ACCESS, PA_HIDDEN, PT_DESCRIPTION, "DELTAMODE: Internal voltage of grid-forming source, phase B",
00097 PT_double, "e_source_C", PADDR(e_source[2]), PT_ACCESS, PA_HIDDEN, PT_DESCRIPTION, "DELTAMODE: Internal voltage of grid-forming source, phase C",
00098 PT_double, "V_angle_A", PADDR(V_angle[0]), PT_ACCESS, PA_HIDDEN, PT_DESCRIPTION, "DELTAMODE: Internal angle of grid-forming source, phase A",
00099 PT_double, "V_angle_B", PADDR(V_angle[1]), PT_ACCESS, PA_HIDDEN, PT_DESCRIPTION, "DELTAMODE: Internal angle of grid-forming source, phase B",
00100 PT_double, "V_angle_C", PADDR(V_angle[2]), PT_ACCESS, PA_HIDDEN, PT_DESCRIPTION, "DELTAMODE: Internal angle of grid-forming source, phase C",
00101
00102
00103 PT_double, "pCircuit_V_Avg", PADDR(pCircuit_V_Avg), PT_ACCESS, PA_HIDDEN, PT_DESCRIPTION, "DELTAMODE: three-phase average value of terminal voltage",
00104
00105
00106 PT_double, "P_Out[VA]", PADDR(P_Out), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Scheduled real power out in CONSTANT_PQ control mode",
00107 PT_double, "Q_Out[VAr]", PADDR(Q_Out), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Schedule reactive power out in CONSTANT_PQ control mode",
00108 PT_double, "power_in[W]", PADDR(p_in), PT_DESCRIPTION, "LEGACY MODEL: No longer used",
00109 PT_double, "rated_power[VA]", PADDR(p_rated), PT_DESCRIPTION, "FOUR QUADRANT MODEL: The rated power of the inverter",
00110 PT_double, "rated_battery_power[W]", PADDR(bp_rated), PT_DESCRIPTION, "FOUR QUADRANT MODEL: The rated power of battery when battery is attached",
00111 PT_double, "inverter_efficiency", PADDR(inv_eta), PT_DESCRIPTION, "FOUR QUADRANT MODEL: The efficiency of the inverter",
00112 PT_double, "battery_soc[pu]", PADDR(b_soc), PT_DESCRIPTION, "FOUR QUADRANT MODEL: The state of charge of an attached battery",
00113 PT_double, "soc_reserve[pu]", PADDR(soc_reserve), PT_DESCRIPTION, "FOUR QUADRANT MODEL: The reserve state of charge of an attached battery for islanding cases",
00114 PT_double, "power_factor[unit]", PADDR(power_factor), PT_DESCRIPTION, "FOUR QUADRANT MODEL: The power factor used for CONSTANT_PF control mode",
00115 PT_bool,"islanded_state", PADDR(islanded), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Boolean used to let control modes to act under island conditions",
00116 PT_double, "nominal_frequency[Hz]", PADDR(f_nominal),
00117
00118
00119 PT_double, "Pref", PADDR(Pref), PT_DESCRIPTION, "DELTAMODE: The real power reference.",
00120 PT_double, "Qref", PADDR(Qref), PT_DESCRIPTION, "DELTAMODE: The reactive power reference.",
00121 PT_double, "kpd", PADDR(kpd), PT_DESCRIPTION, "DELTAMODE: The d-axis integration gain for the current modulation PI controller.",
00122 PT_double, "kpq", PADDR(kpq), PT_DESCRIPTION, "DELTAMODE: The q-axis integration gain for the current modulation PI controller.",
00123 PT_double, "kid", PADDR(kid), PT_DESCRIPTION, "DELTAMODE: The d-axis proportional gain for the current modulation PI controller.",
00124 PT_double, "kiq", PADDR(kiq), PT_DESCRIPTION, "DELTAMODE: The q-axis proportional gain for the current modulation PI controller.",
00125 PT_double, "kdd", PADDR(kdd), PT_DESCRIPTION, "DELTAMODE: The d-axis differentiator gain for the current modulation PID controller",
00126 PT_double, "kdq", PADDR(kdq), PT_DESCRIPTION, "DELTAMODE: The q-axis differentiator gain for the current modulation PID controller",
00127
00128
00129 PT_double, "epA", PADDR(curr_state.ed[0]), PT_DESCRIPTION, "DELTAMODE: The real current error for phase A or triplex phase.",
00130 PT_double, "epB", PADDR(curr_state.ed[1]), PT_DESCRIPTION, "DELTAMODE: The real current error for phase B.",
00131 PT_double, "epC", PADDR(curr_state.ed[2]), PT_DESCRIPTION, "DELTAMODE: The real current error for phase C.",
00132 PT_double, "eqA", PADDR(curr_state.eq[0]), PT_DESCRIPTION, "DELTAMODE: The reactive current error for phase A or triplex phase.",
00133 PT_double, "eqB", PADDR(curr_state.eq[1]), PT_DESCRIPTION, "DELTAMODE: The reactive current error for phase B.",
00134 PT_double, "eqC", PADDR(curr_state.eq[2]), PT_DESCRIPTION, "DELTAMODE: The reactive current error for phase C.",
00135 PT_double, "delta_epA", PADDR(curr_state.ded[0]), PT_DESCRIPTION, "DELTAMODE: The change in real current error for phase A or triplex phase.",
00136 PT_double, "delta_epB", PADDR(curr_state.ded[1]), PT_DESCRIPTION, "DELTAMODE: The change in real current error for phase B.",
00137 PT_double, "delta_epC", PADDR(curr_state.ded[2]), PT_DESCRIPTION, "DELTAMODE: The change in real current error for phase C.",
00138 PT_double, "delta_eqA", PADDR(curr_state.deq[0]), PT_DESCRIPTION, "DELTAMODE: The change in reactive current error for phase A or triplex phase.",
00139 PT_double, "delta_eqB", PADDR(curr_state.deq[1]), PT_DESCRIPTION, "DELTAMODE: The change in reactive current error for phase B.",
00140 PT_double, "delta_eqC", PADDR(curr_state.deq[2]), PT_DESCRIPTION, "DELTAMODE: The change in reactive current error for phase C.",
00141 PT_double, "mdA", PADDR(curr_state.md[0]), PT_DESCRIPTION, "DELTAMODE: The d-axis current modulation for phase A or triplex phase.",
00142 PT_double, "mdB", PADDR(curr_state.md[1]), PT_DESCRIPTION, "DELTAMODE: The d-axis current modulation for phase B.",
00143 PT_double, "mdC", PADDR(curr_state.md[2]), PT_DESCRIPTION, "DELTAMODE: The d-axis current modulation for phase C.",
00144 PT_double, "mqA", PADDR(curr_state.mq[0]), PT_DESCRIPTION, "DELTAMODE: The q-axis current modulation for phase A or triplex phase.",
00145 PT_double, "mqB", PADDR(curr_state.mq[1]), PT_DESCRIPTION, "DELTAMODE: The q-axis current modulation for phase B.",
00146 PT_double, "mqC", PADDR(curr_state.mq[2]), PT_DESCRIPTION, "DELTAMODE: The q-axis current modulation for phase C.",
00147 PT_double, "delta_mdA", PADDR(curr_state.dmd[0]), PT_DESCRIPTION, "DELTAMODE: The change in d-axis current modulation for phase A or triplex phase.",
00148 PT_double, "delta_mdB", PADDR(curr_state.dmd[1]), PT_DESCRIPTION, "DELTAMODE: The change in d-axis current modulation for phase B.",
00149 PT_double, "delta_mdC", PADDR(curr_state.dmd[2]), PT_DESCRIPTION, "DELTAMODE: The change in d-axis current modulation for phase C.",
00150 PT_double, "delta_mqA", PADDR(curr_state.dmq[0]), PT_DESCRIPTION, "DELTAMODE: The change in q-axis current modulation for phase A or triplex phase.",
00151 PT_double, "delta_mqB", PADDR(curr_state.dmq[1]), PT_DESCRIPTION, "DELTAMODE: The change in q-axis current modulation for phase B.",
00152 PT_double, "delta_mqC", PADDR(curr_state.dmq[2]), PT_DESCRIPTION, "DELTAMODE: The change in q-axis current modulation for phase C.",
00153 PT_complex, "IdqA", PADDR(curr_state.Idq[0]), PT_DESCRIPTION, "DELTAMODE: The dq-axis current for phase A or triplex phase.",
00154 PT_complex, "IdqB", PADDR(curr_state.Idq[1]), PT_DESCRIPTION, "DELTAMODE: The dq-axis current for phase B.",
00155 PT_complex, "IdqC", PADDR(curr_state.Idq[2]), PT_DESCRIPTION, "DELTAMODE: The dq-axis current for phase C.",
00156
00157 PT_double, "Tfreq_delay",PADDR(Tfreq_delay), PT_DESCRIPTION, "DELTAMODE: The time constant for delayed frequency seen by the inverter",
00158 PT_bool, "inverter_droop_fp", PADDR(inverter_droop_fp), PT_DESCRIPTION, "DELTAMODE: Boolean used to indicate whether inverter f/p droop is included or not",
00159 PT_double, "R_fp",PADDR(R_fp), PT_DESCRIPTION, "DELTAMODE: The droop parameter of the f/p droop",
00160 PT_double, "kppmax",PADDR(kppmax), PT_DESCRIPTION, "DELTAMODE: The proportional gain of Pmax controller",
00161 PT_double, "kipmax",PADDR(kipmax), PT_DESCRIPTION, "DELTAMODE: The integral gain of Pmax controller",
00162 PT_double, "Pmax",PADDR(Pmax), PT_DESCRIPTION, "DELTAMODE: power limit of grid forming inverter",
00163 PT_double, "Pmin",PADDR(Pmin), PT_DESCRIPTION, "DELTAMODE: power limit of grid forming inverter",
00164
00165 PT_double, "Tvol_delay",PADDR(Tvol_delay), PT_DESCRIPTION, "DELTAMODE: The time constant for delayed voltage seen by the inverter",
00166 PT_bool, "inverter_droop_vq", PADDR(inverter_droop_vq), PT_DESCRIPTION, "DELTAMODE: Boolean used to indicate whether inverter q/v droop is included or not",
00167 PT_double, "R_vq",PADDR(R_vq), PT_DESCRIPTION, "DELTAMODE: The droop parameter of the v/q droop",
00168
00169 PT_double, "Tp_delay",PADDR(Tp_delay), PT_DESCRIPTION, "DELTAMODE: The time constant for delayed real power seen by the VSI droop controller",
00170 PT_double, "Tq_delay",PADDR(Tq_delay), PT_DESCRIPTION, "DELTAMODE: The time constant for delayed reactive power seen by the VSI droop controller",
00171
00172
00173 PT_complex,"VSI_Rfilter[pu]",PADDR(Rfilter),PT_DESCRIPTION,"VSI filter resistance (p.u.)",
00174 PT_complex,"VSI_Xfilter[pu]",PADDR(Xfilter),PT_DESCRIPTION,"VSI filter inductance (p.u.)",
00175 PT_enumeration,"VSI_mode",PADDR(VSI_mode), PT_DESCRIPTION, "VSI MODEL: Selects VSI mode for either isochronous or droop one",
00176 PT_KEYWORD,"VSI_ISOCHRONOUS",(enumeration)VSI_ISOCHRONOUS,
00177 PT_KEYWORD,"VSI_DROOP",(enumeration)VSI_DROOP,
00178 PT_double, "VSI_freq",PADDR(VSI_freq), PT_DESCRIPTION, "VSI frequency",
00179 PT_double, "ki_Vterminal", PADDR(ki_Vterminal), PT_DESCRIPTION, "DELTAMODE: The integrator gain for the VSI terminal voltage modulation",
00180 PT_double, "kp_Vterminal", PADDR(kp_Vterminal), PT_DESCRIPTION, "DELTAMODE: The proportional gain for the VSI terminal voltage modulation",
00181 PT_double, "V_set_droop", PADDR(V_mag_ref[0]), PT_DESCRIPTION, "DELTAMODE: The voltage setpoint of droop control",
00182
00183
00184 PT_bool, "enable_ramp_rates_real", PADDR(checkRampRate_real), PT_DESCRIPTION, "DELTAMODE: Boolean used to indicate whether inverter ramp rate is enforced or not",
00185 PT_double, "max_ramp_up_real[W/s]", PADDR(rampUpRate_real), PT_DESCRIPTION, "DELTAMODE: The real power ramp up rate limit",
00186 PT_double, "max_ramp_down_real[W/s]", PADDR(rampDownRate_real), PT_DESCRIPTION, "DELTAMODE: The real power ramp down rate limit",
00187 PT_bool, "enable_ramp_rates_reactive", PADDR(checkRampRate_reactive), PT_DESCRIPTION, "DELTAMODE: Boolean used to indicate whether inverter ramp rate is enforced or not",
00188 PT_double, "max_ramp_up_reactive[VAr/s]", PADDR(rampUpRate_reactive), PT_DESCRIPTION, "DELTAMODE: The reactive power ramp up rate limit",
00189 PT_double, "max_ramp_down_reactive[VAr/s]", PADDR(rampDownRate_reactive), PT_DESCRIPTION, "DELTAMODE: The reactive power ramp down rate limit",
00190
00191
00192 PT_enumeration, "dynamic_model_mode", PADDR(inverter_dyn_mode), PT_DESCRIPTION, "DELTAMODE: Underlying model to use for deltamode control",
00193 PT_KEYWORD, "PID", (enumeration)PID_CONTROLLER,
00194 PT_KEYWORD, "PI", (enumeration)PI_CONTROLLER,
00195
00196
00197 PT_bool, "enable_1547_checks", PADDR(enable_1547_compliance), PT_DESCRIPTION, "DELTAMODE: Enable IEEE 1547-2003 disconnect checking",
00198 PT_double, "reconnect_time[s]", PADDR(reconnect_time), PT_DESCRIPTION, "DELTAMODE: Time delay after IEEE 1547-2003 violation clears before resuming generation",
00199 PT_bool, "inverter_1547_status", PADDR(inverter_1547_status), PT_DESCRIPTION, "DELTAMODE: Indicator if the inverter is curtailed due to a 1547 violation or not",
00200
00201
00202 PT_enumeration, "IEEE_1547_version", PADDR(ieee_1547_version), PT_DESCRIPTION, "DELTAMODE: Version of IEEE 1547 to use to populate defaults",
00203 PT_KEYWORD, "NONE", (enumeration)IEEE_NONE,
00204 PT_KEYWORD, "IEEE1547", (enumeration)IEEE1547,
00205 PT_KEYWORD, "IEEE1547A", (enumeration)IEEE1547A,
00206
00207
00208 PT_double, "over_freq_high_cutout[Hz]", PADDR(over_freq_high_band_setpoint),PT_DESCRIPTION,"DELTAMODE: OF2 set point for IEEE 1547a",
00209 PT_double, "over_freq_high_disconenct_time[s]", PADDR(over_freq_high_band_delay),PT_DESCRIPTION,"DELTAMODE: OF2 clearing time for IEEE1547a",
00210 PT_double, "over_freq_low_cutout[Hz]", PADDR(over_freq_low_band_setpoint),PT_DESCRIPTION,"DELTAMODE: OF1 set point for IEEE 1547a",
00211 PT_double, "over_freq_low_disconenct_time[s]", PADDR(over_freq_low_band_delay),PT_DESCRIPTION,"DELTAMODE: OF1 clearing time for IEEE 1547a",
00212 PT_double, "under_freq_high_cutout[Hz]", PADDR(under_freq_high_band_setpoint),PT_DESCRIPTION,"DELTAMODE: UF2 set point for IEEE 1547a",
00213 PT_double, "under_freq_high_disconenct_time[s]", PADDR(under_freq_high_band_delay),PT_DESCRIPTION,"DELTAMODE: UF2 clearing time for IEEE1547a",
00214 PT_double, "under_freq_low_cutout[Hz]", PADDR(under_freq_low_band_setpoint),PT_DESCRIPTION,"DELTAMODE: UF1 set point for IEEE 1547a",
00215 PT_double, "under_freq_low_disconenct_time[s]", PADDR(under_freq_low_band_delay),PT_DESCRIPTION,"DELTAMODE: UF1 clearing time for IEEE 1547a",
00216
00217
00218 PT_double,"under_voltage_low_cutout[pu]",PADDR(under_voltage_lowest_voltage_setpoint),PT_DESCRIPTION,"Lowest voltage threshold for undervoltage",
00219 PT_double,"under_voltage_middle_cutout[pu]",PADDR(under_voltage_middle_voltage_setpoint),PT_DESCRIPTION,"Middle-lowest voltage threshold for undervoltage",
00220 PT_double,"under_voltage_high_cutout[pu]",PADDR(under_voltage_high_voltage_setpoint),PT_DESCRIPTION,"High value of low voltage threshold for undervoltage",
00221 PT_double,"over_voltage_low_cutout[pu]",PADDR(over_voltage_low_setpoint),PT_DESCRIPTION,"Lowest voltage value for overvoltage",
00222 PT_double,"over_voltage_high_cutout[pu]",PADDR(over_voltage_high_setpoint),PT_DESCRIPTION,"High voltage value for overvoltage",
00223 PT_double,"under_voltage_low_disconnect_time[s]",PADDR(under_voltage_lowest_delay),PT_DESCRIPTION,"Lowest voltage clearing time for undervoltage",
00224 PT_double,"under_voltage_middle_disconnect_time[s]",PADDR(under_voltage_middle_delay),PT_DESCRIPTION,"Middle-lowest voltage clearing time for undervoltage",
00225 PT_double,"under_voltage_high_disconnect_time[s]",PADDR(under_voltage_high_delay),PT_DESCRIPTION,"Highest voltage clearing time for undervoltage",
00226 PT_double,"over_voltage_low_disconnect_time[s]",PADDR(over_voltage_low_delay),PT_DESCRIPTION,"Lowest voltage clearing time for overvoltage",
00227 PT_double,"over_voltage_high_disconnect_time[s]",PADDR(over_voltage_high_delay),PT_DESCRIPTION,"Highest voltage clearing time for overvoltage",
00228
00229
00230 PT_enumeration, "IEEE_1547_trip_method", PADDR(ieee_1547_trip_method), PT_DESCRIPTION, "DELTAMODE: Reason for IEEE 1547 disconnect - which threshold was hit",
00231 PT_KEYWORD, "NONE",(enumeration)IEEE_1547_NONE, PT_DESCRIPTION, "No trip reason",
00232 PT_KEYWORD, "OVER_FREQUENCY_HIGH",(enumeration)IEEE_1547_HIGH_OF, PT_DESCRIPTION, "High over-frequency level trip - OF2",
00233 PT_KEYWORD, "OVER_FREQUENCY_LOW",(enumeration)IEEE_1547_LOW_OF, PT_DESCRIPTION, "Low over-frequency level trip - OF1",
00234 PT_KEYWORD, "UNDER_FREQUENCY_HIGH",(enumeration)IEEE_1547_HIGH_UF, PT_DESCRIPTION, "High under-frequency level trip - UF2",
00235 PT_KEYWORD, "UNDER_FREQUENCY_LOW",(enumeration)IEEE_1547_LOW_UF, PT_DESCRIPTION, "Low under-frequency level trip - UF1",
00236 PT_KEYWORD, "UNDER_VOLTAGE_LOW",(enumeration)IEEE_1547_LOWEST_UV, PT_DESCRIPTION, "Lowest under-voltage level trip",
00237 PT_KEYWORD, "UNDER_VOLTAGE_MID",(enumeration)IEEE_1547_MIDDLE_UV, PT_DESCRIPTION, "Middle under-voltage level trip",
00238 PT_KEYWORD, "UNDER_VOLTAGE_HIGH",(enumeration)IEEE_1547_HIGH_UV, PT_DESCRIPTION, "High under-voltage level trip",
00239 PT_KEYWORD, "OVER_VOLTAGE_LOW",(enumeration)IEEE_1547_LOW_OV, PT_DESCRIPTION, "Low over-voltage level trip",
00240 PT_KEYWORD, "OVER_VOLTAGE_HIGH",(enumeration)IEEE_1547_HIGH_OV, PT_DESCRIPTION, "High over-voltage level trip",
00241
00242 PT_set, "phases", PADDR(phases), PT_DESCRIPTION, "The phases the inverter is attached to",
00243 PT_KEYWORD, "A",(set)PHASE_A,
00244 PT_KEYWORD, "B",(set)PHASE_B,
00245 PT_KEYWORD, "C",(set)PHASE_C,
00246 PT_KEYWORD, "N",(set)PHASE_N,
00247 PT_KEYWORD, "S",(set)PHASE_S,
00248
00249 PT_bool, "use_multipoint_efficiency", PADDR(use_multipoint_efficiency), PT_DESCRIPTION, "FOUR QUADRANT MODEL: boolean to used the multipoint efficiency curve for the inverter when solar is attached",
00250 PT_enumeration, "inverter_manufacturer", PADDR(inverter_manufacturer), PT_DESCRIPTION, "MULTIPOINT EFFICIENCY MODEL: the manufacturer of the inverter to setup up pre-existing efficiency curves",
00251 PT_KEYWORD, "NONE", (enumeration)NONE,
00252 PT_KEYWORD, "FRONIUS", (enumeration)FRONIUS,
00253 PT_KEYWORD, "SMA", (enumeration)SMA,
00254 PT_KEYWORD, "XANTREX", (enumeration)XANTREX,
00255 PT_double, "maximum_dc_power", PADDR(p_dco), PT_DESCRIPTION, "MULTIPOINT EFFICIENCY MODEL: the maximum dc power point for the efficiency curve",
00256 PT_double, "maximum_dc_voltage", PADDR(v_dco), PT_DESCRIPTION, "MULTIPOINT EFFICIENCY MODEL: the maximum dc voltage point for the efficiency curve",
00257 PT_double, "minimum_dc_power", PADDR(p_so), PT_DESCRIPTION, "MULTIPOINT EFFICIENCY MODEL: the minimum dc power point for the efficiency curve",
00258 PT_double, "c_0", PADDR(c_o), PT_DESCRIPTION, "MULTIPOINT EFFICIENCY MODEL: the first coefficient in the efficiency curve",
00259 PT_double, "c_1", PADDR(c_1), PT_DESCRIPTION, "MULTIPOINT EFFICIENCY MODEL: the second coefficient in the efficiency curve",
00260 PT_double, "c_2", PADDR(c_2), PT_DESCRIPTION, "MULTIPOINT EFFICIENCY MODEL: the third coefficient in the efficiency curve",
00261 PT_double, "c_3", PADDR(c_3), PT_DESCRIPTION, "MULTIPOINT EFFICIENCY MODEL: the fourth coefficient in the efficiency curve",
00262
00263 PT_object,"sense_object", PADDR(sense_object), PT_DESCRIPTION, "FOUR QUADRANT MODEL: name of the object the inverter is trying to mitigate the load on (node/link) in LOAD_FOLLOWING",
00264 PT_double,"max_charge_rate[W]", PADDR(max_charge_rate), PT_DESCRIPTION, "FOUR QUADRANT MODEL: maximum rate the battery can be charged in LOAD_FOLLOWING",
00265 PT_double,"max_discharge_rate[W]", PADDR(max_discharge_rate), PT_DESCRIPTION, "FOUR QUADRANT MODEL: maximum rate the battery can be discharged in LOAD_FOLLOWING",
00266 PT_double,"charge_on_threshold[W]", PADDR(charge_on_threshold), PT_DESCRIPTION, "FOUR QUADRANT MODEL: power level at which the inverter should try charging the battery in LOAD_FOLLOWING",
00267 PT_double,"charge_off_threshold[W]", PADDR(charge_off_threshold), PT_DESCRIPTION, "FOUR QUADRANT MODEL: power level at which the inverter should cease charging the battery in LOAD_FOLLOWING",
00268 PT_double,"discharge_on_threshold[W]", PADDR(discharge_on_threshold), PT_DESCRIPTION, "FOUR QUADRANT MODEL: power level at which the inverter should try discharging the battery in LOAD_FOLLOWING",
00269 PT_double,"discharge_off_threshold[W]", PADDR(discharge_off_threshold), PT_DESCRIPTION, "FOUR QUADRANT MODEL: power level at which the inverter should cease discharging the battery in LOAD_FOLLOWING",
00270 PT_double,"excess_input_power[W]", PADDR(excess_input_power), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Excess power at the input of the inverter that is otherwise just lost, or could be shunted to a battery",
00271 PT_double,"charge_lockout_time[s]",PADDR(charge_lockout_time), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Lockout time when a charging operation occurs before another LOAD_FOLLOWING dispatch operation can occur",
00272 PT_double,"discharge_lockout_time[s]",PADDR(discharge_lockout_time), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Lockout time when a discharging operation occurs before another LOAD_FOLLOWING dispatch operation can occur",
00273
00274
00275
00276 PT_double,"pf_reg_activate", PADDR(pf_reg_activate), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Lowest acceptable power-factor level below which power-factor regulation will activate.",
00277 PT_double,"pf_reg_deactivate", PADDR(pf_reg_deactivate), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Lowest acceptable power-factor above which no power-factor regulation is needed.",
00278
00279
00280 PT_double,"pf_target", PADDR(pf_target_var), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Desired power-factor to maintain (signed) positive is inductive",
00281 PT_double,"pf_reg_high", PADDR(pf_reg_high), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Upper limit for power-factor - if exceeds, go full reverse reactive",
00282 PT_double,"pf_reg_low", PADDR(pf_reg_low), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Lower limit for power-factor - if exceeds, stop regulating - pf_target_var is below this",
00283
00284
00285 PT_double,"pf_reg_activate_lockout_time[s]", PADDR(pf_reg_activate_lockout_time), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Mandatory pause between the deactivation of power-factor regulation and it reactivation",
00286
00287 PT_bool, "disable_volt_var_if_no_input_power", PADDR(disable_volt_var_if_no_input_power),
00288 PT_double, "delay_time[s]", PADDR(delay_time),
00289 PT_double, "max_var_slew_rate[VAr/s]", PADDR(max_var_slew_rate),
00290 PT_double, "max_pwr_slew_rate[W/s]", PADDR(max_pwr_slew_rate),
00291 PT_char1024, "volt_var_sched", PADDR(volt_var_sched),
00292 PT_char1024, "freq_pwr_sched", PADDR(freq_pwr_sched),
00293
00294 PT_double,"charge_threshold[W]", PADDR(charge_threshold), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Level at which all inverters in the group will begin charging attached batteries. Regulated minimum load level.",
00295 PT_double,"discharge_threshold[W]", PADDR(discharge_threshold), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Level at which all inverters in the group will begin discharging attached batteries. Regulated maximum load level.",
00296 PT_double,"group_max_charge_rate[W]", PADDR(group_max_charge_rate), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Sum of the charge rates of the batteries involved in the group load-following.",
00297 PT_double,"group_max_discharge_rate[W]", PADDR(group_max_discharge_rate), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Sum of the discharge rates of the batteries involved in the group load-following.",
00298 PT_double,"group_rated_power[W]", PADDR(group_rated_power), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Sum of the inverter power ratings of the inverters involved in the group power-factor regulation.",
00299
00300 PT_double,"V_base[V]", PADDR(V_base), PT_DESCRIPTION, "FOUR QUADRANT MODEL: The base voltage on the grid side of the inverter. Used in VOLT_VAR control mode.",
00301 PT_double,"V1[pu]", PADDR(V1), PT_DESCRIPTION, "FOUR QUADRANT MODEL: voltage point 1 in volt/var curve. Used in VOLT_VAR control mode.",
00302 PT_double,"Q1[pu]", PADDR(Q1), PT_DESCRIPTION, "FOUR QUADRANT MODEL: VAR point 1 in volt/var curve. Used in VOLT_VAR control mode.",
00303 PT_double,"V2[pu]", PADDR(V2), PT_DESCRIPTION, "FOUR QUADRANT MODEL: voltage point 2 in volt/var curve. Used in VOLT_VAR control mode.",
00304 PT_double,"Q2[pu]", PADDR(Q2), PT_DESCRIPTION, "FOUR QUADRANT MODEL: VAR point 2 in volt/var curve. Used in VOLT_VAR control mode.",
00305 PT_double,"V3[pu]", PADDR(V3), PT_DESCRIPTION, "FOUR QUADRANT MODEL: voltage point 3 in volt/var curve. Used in VOLT_VAR control mode.",
00306 PT_double,"Q3[pu]", PADDR(Q3), PT_DESCRIPTION, "FOUR QUADRANT MODEL: VAR point 3 in volt/var curve. Used in VOLT_VAR control mode.",
00307 PT_double,"V4[pu]", PADDR(V4), PT_DESCRIPTION, "FOUR QUADRANT MODEL: voltage point 4 in volt/var curve. Used in VOLT_VAR control mode.",
00308 PT_double,"Q4[pu]", PADDR(Q4), PT_DESCRIPTION, "FOUR QUADRANT MODEL: VAR point 4 in volt/var curve. Used in VOLT_VAR control mode.",
00309 PT_double,"volt_var_control_lockout[s]", PADDR(vv_lockout), PT_DESCRIPTION, "FOUR QUADRANT QUADRANT MODEL: the lockout time between volt/var actions.",
00310
00311
00312 PT_int32,"number_of_phases_out",PADDR(number_of_phases_out),PT_ACCESS,PA_HIDDEN,PT_DESCRIPTION,"Exposed variable - hidden for solar",
00313 PT_double,"efficiency_value",PADDR(efficiency),PT_ACCESS,PA_HIDDEN,PT_DESCRIPTION,"Exposed variable - hidden for solar",
00314
00315
00316 PT_double,"VW_V1[pu]", PADDR(VW_V1), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Voltage at which power limiting begins (e.g. 1.0583). Used in VOLT_WATT control mode.",
00317 PT_double,"VW_V2[pu]", PADDR(VW_V2), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Voltage at which power limiting ends. (e.g. 1.1000). Used in VOLT_WATT control mode.",
00318 PT_double,"VW_P1[pu]", PADDR(VW_P1), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Power limit at VW_P1 (e.g. 1). Used in VOLT_WATT control mode.",
00319 PT_double,"VW_P2[pu]", PADDR(VW_P2), PT_DESCRIPTION, "FOUR QUADRANT MODEL: Power limit at VW_P2 (e.g. 0). Used in VOLT_WATT control mode.",
00320 NULL)<1) GL_THROW("unable to publish properties in %s",__FILE__);
00321
00322 defaults = this;
00323
00324 memset(this,0,sizeof(inverter));
00325
00326 if (gl_publish_function(oclass, "preupdate_gen_object", (FUNCTIONADDR)preupdate_inverter)==NULL)
00327 GL_THROW("Unable to publish inverter deltamode function");
00328 if (gl_publish_function(oclass, "interupdate_gen_object", (FUNCTIONADDR)interupdate_inverter)==NULL)
00329 GL_THROW("Unable to publish inverter deltamode function");
00330 if (gl_publish_function(oclass, "postupdate_gen_object", (FUNCTIONADDR)postupdate_inverter)==NULL)
00331 GL_THROW("Unable to publish inverter deltamode function");
00332 if (gl_publish_function(oclass, "current_injection_update", (FUNCTIONADDR)inverter_NR_current_injection_update)==NULL)
00333 GL_THROW("Unable to publish inverter current injection update function");
00334 }
00335 }
00336
00337 int inverter::create(void)
00338 {
00339
00340 P_Out = 0;
00341 Q_Out = 0;
00342 V_In_Set_A = complex(480,0);
00343 V_In_Set_B = complex(-240, 415.69);
00344 V_In_Set_C = complex(-240,-415.69);
00345 V_Set_A = 240;
00346 V_Set_B = 240;
00347 V_Set_C = 240;
00348 margin = 10;
00349 I_out_prev = 0;
00350 I_step_max = 100;
00351 C_Storage_In = 0;
00352 power_factor = 1;
00353
00354
00355 freq_ref = 60;
00356 Tfreq_delay = 0.0;
00357 inverter_droop_fp = false;
00358 R_fp = 3.77;
00359 R_vq = 0.05;
00360
00361
00362 disable_volt_var_if_no_input_power = false;
00363 delay_time = -1;
00364 max_var_slew_rate = 0;
00365 volt_var_sched[0] = '\0';
00366 freq_pwr_sched[0] = '\0';
00367
00368
00369
00370 Max_P = 10;
00371 Max_Q = 10;
00372 Rated_kVA = 15;
00373 Rated_kV = 10;
00374
00375 Vdc = 480;
00376
00377 phaseAOut = true;
00378 phaseBOut = true;
00379 phaseCOut = true;
00380
00381 last_current[0] = last_current[1] = last_current[2] = last_current[3] = 0.0;
00382 last_power[0] = last_power[1] = last_power[2] = last_power[3] = 0.0;
00383
00384 islanded = FALSE;
00385 use_multipoint_efficiency = FALSE;
00386 p_dco = -1;
00387 p_so = -1;
00388 v_dco = -1;
00389 c_o = -1;
00390 c_1 = -1;
00391 c_2 = -1;
00392 c_3 = -1;
00393 p_max = -1;
00394 pMeterStatus = NULL;
00395 efficiency = 0;
00396 inv_eta = 0.0;
00397
00398 sense_object = NULL;
00399 max_charge_rate = 0;
00400 max_discharge_rate = 0;
00401 charge_on_threshold = 0;
00402 charge_off_threshold = 0;
00403 discharge_on_threshold = 0;
00404 discharge_off_threshold = 0;
00405 powerCalc = NULL;
00406 sense_is_link = false;
00407 sense_power = NULL;
00408
00409 pf_reg = EXCLUDED;
00410 pf_reg_activate = -2;
00411 pf_reg_deactivate = -1;
00412 pf_reg_dispatch_change_allowed = true;
00413 pf_reg_dispatch_VAR = 0.0;
00414 pf_reg_status = IDLING;
00415 pf_reg_next_update_time = 0;
00416 pf_reg_activate_lockout_time = -1;
00417
00418 pf_target_var = -2;
00419 pf_reg_high = -2;
00420 pf_reg_low = -2;
00421
00422 charge_threshold = -1;
00423 discharge_threshold = -1;
00424 group_max_charge_rate = -1;
00425 group_max_discharge_rate = -1;
00426 group_rated_power = -1;
00427
00428 excess_input_power = 0.0;
00429 lf_dispatch_power = 0.0;
00430 load_follow_status = IDLE;
00431 four_quadrant_control_mode = FQM_CONSTANT_PF;
00432
00433 next_update_time = 0;
00434 lf_dispatch_change_allowed = true;
00435 charge_lockout_time = 0.0;
00436 discharge_lockout_time = 0.0;
00437 b_soc = -1;
00438 f_nominal = 60;
00439
00441
00443 deltamode_inclusive = false;
00444 first_run = true;
00445 inverter_convergence_criterion = 1e-3;
00446
00447
00448 kpd = 0.0;
00449 kpq = 0.0;
00450 kid = 0.0;
00451 kiq = 0.0;
00452 kdd = 0.0;
00453 kdq = 0.0;
00454 first_sync_delta_enabled = false;
00455 first_iter_counter = 0;
00456
00457
00458 inverter_dyn_mode = PI_CONTROLLER;
00459
00460
00461 enable_1547_compliance = false;
00462 reconnect_time = 300.0;
00463 inverter_1547_status = true;
00464 out_of_violation_time_total = 0.0;
00465 ieee_1547_double = -1.0;
00466 pFrequency = NULL;
00467 value_Frequency = 60.0;
00468 prev_time = 0;
00469 prev_time_dbl = 0.0;
00470
00471
00472 ieee_1547_version = IEEE1547A;
00473
00474
00475 ieee_1547_trip_method = IEEE_1547_NONE;
00476
00477
00478 over_freq_high_band_setpoint = 62.0;
00479 over_freq_high_band_delay = 0.16;
00480 over_freq_high_band_viol_time = 0.0;
00481 over_freq_low_band_setpoint = 60.5;
00482 over_freq_low_band_delay = 2.0;
00483 over_freq_low_band_viol_time = 0.0;
00484 under_freq_high_band_setpoint = 59.5;
00485 under_freq_high_band_delay = 2.0;
00486 under_freq_high_band_viol_time = 0.0;
00487 under_freq_low_band_setpoint = 57;
00488 under_freq_low_band_delay = 0.16;
00489 under_freq_low_band_viol_time = 0.0;
00490
00491
00492 under_voltage_lowest_voltage_setpoint = 0.45;
00493 under_voltage_middle_voltage_setpoint = 0.60;
00494 under_voltage_high_voltage_setpoint = 0.88;
00495 over_voltage_low_setpoint = 1.10;
00496 over_voltage_high_setpoint = 1.20;
00497 under_voltage_lowest_delay = 0.16;
00498 under_voltage_middle_delay = 1.0;
00499 under_voltage_high_delay = 2.0;
00500 over_voltage_low_delay = 1.0;
00501 over_voltage_high_delay = 0.16;
00502 under_voltage_lowest_viol_time = 0.0;
00503 under_voltage_middle_viol_time = 0.0;
00504 under_voltage_high_viol_time = 0.0;
00505 over_voltage_low_viol_time = 0.0;
00506 over_voltage_high_viol_time = 0.0;
00507
00508 node_nominal_voltage = 120.0;
00509
00510
00511 V_base = 0;
00512 V1 = -2;
00513 Q1 = -2;
00514 V2 = -2;
00515 Q2 = -2;
00516 V3 = -2;
00517 Q3 = -2;
00518 V4 = -2;
00519 Q4 = -2;
00520 vv_lockout = -1;
00521
00522
00523 mapped_freq_variable = NULL;
00524 VSI_freq = 60;
00525
00526
00527
00528 Rfilter = 0.02;
00529 Xfilter = 0.1;
00530
00531
00532 VSI_mode = VSI_ISOCHRONOUS;
00533
00534
00535 VSI_esource_init = false;
00536
00537
00538 ki_Vterminal = 5.86;
00539 kp_Vterminal = 0;
00540
00541
00542 Pmin = 0;
00543 Pmax = 1;
00544 kppmax = 3;
00545 kipmax = 30;
00546
00547
00548 checkRampRate_real = false;
00549 rampUpRate_real = 1.0e9;
00550 rampDownRate_real = 1.0e9;
00551 checkRampRate_reactive = false;
00552 rampUpRate_reactive = 1.0e9;
00553 rampDownRate_reactive = 1.0e9;
00554 prev_VA_out[0] = prev_VA_out[1] = prev_VA_out[2] = complex(0.0,0.0);
00555 curr_VA_out[0] = curr_VA_out[1] = curr_VA_out[2] = complex(0.0,0.0);
00556 event_deltat = 10000000.0;
00557 parent_is_a_meter = false;
00558 parent_is_triplex = false;
00559
00560 pCircuit_V[0] = pCircuit_V[1] = pCircuit_V[2] = NULL;
00561 pLine_I[0] = pLine_I[1] = pLine_I[2] = NULL;
00562 pLine_unrotI[0] = pLine_unrotI[1] = pLine_unrotI[2] = NULL;
00563 pPower[0] = pPower[1] = pPower[2] = NULL;
00564 pIGenerated[0] = pIGenerated[1] = pIGenerated[2] = NULL;
00565 pLine12 = NULL;
00566 pPower12 = NULL;
00567 pMeterStatus = NULL;
00568 pbus_full_Y_mat = NULL;
00569 pGenerated = NULL;
00570
00571
00572 value_Circuit_V[0] = value_Circuit_V[1] = value_Circuit_V[2] = complex(0.0,0.0);
00573 value_Line_I[0] = value_Line_I[1] = value_Line_I[2] = complex(0.0,0.0);
00574 value_Line_unrotI[0] = value_Line_unrotI[1] = value_Line_unrotI[2] = complex(0.0,0.0);
00575 value_Power[0] = value_Power[1] = value_Power[2] = complex(0.0,0.0);
00576 value_IGenerated[0] = value_IGenerated[1] = value_IGenerated[2] = complex(0.0,0.0);
00577 value_Line12 = complex(0.0,0.0);
00578 value_Power12 = complex(0.0,0.0);
00579 value_MeterStatus = 1;
00580
00581
00582 VW_V1 = -2;
00583 VW_V2 = -2;
00584 VW_P1 = -2;
00585 VW_P2 = -2;
00586
00587
00588 return 1;
00589 }
00590
00591
00592 int inverter::init(OBJECT *parent)
00593 {
00594 OBJECT *obj = OBJECTHDR(this);
00595 PROPERTY *pval;
00596 bool *dyn_gen_posting;
00597 unsigned iindex, jindex;
00598 complex filter_impedance;
00599 double *nominal_voltage;
00600 double *ptemp_double;
00601 double temp_double_high, temp_double_low, tdiff, ang_diff;
00602 FINDLIST *batteries;
00603 OBJECT *objBattery = NULL;
00604 int index = 0;
00605 STATUS return_value_init;
00606 double temp_volt_mag;
00607 gld_property *temp_property_pointer;
00608 gld_property *Frequency_mapped;
00609 gld_wlock *test_rlock;
00610 bool temp_bool_value;
00611 int temp_idx_x, temp_idx_y;
00612 complex temp_complex_value;
00613 complex_array temp_complex_array;
00614 set parent_phases;
00615 OBJECT *tmp_obj = NULL;
00616
00617 if(parent != NULL){
00618 if((parent->flags & OF_INIT) != OF_INIT){
00619 char objname[256];
00620 gl_verbose("inverter::init(): deferring initialization on %s", gl_name(parent, objname, 255));
00621 return 2;
00622 }
00623 }
00624
00625 std::string tempV, tempQ, tempf, tempP;
00626 std::string VoltVArSchedInput, freq_pwrSchedInput;
00627
00628
00629 if ((obj->flags & OF_DELTAMODE) == OF_DELTAMODE)
00630 {
00631 deltamode_inclusive = true;
00632 }
00633
00634
00635
00636 if (parent!=NULL)
00637 {
00638
00639 if (gl_object_isa(parent,"meter","powerflow") || gl_object_isa(parent,"node","powerflow") || gl_object_isa(parent,"load","powerflow") ||
00640 gl_object_isa(parent,"triplex_meter","powerflow") || gl_object_isa(parent,"triplex_node","powerflow") || gl_object_isa(parent,"triplex_load","powerflow"))
00641 {
00642
00643
00644 if ((deltamode_inclusive == true) && (four_quadrant_control_mode == FQM_VSI))
00645 {
00646
00647 if (parent->parent != NULL)
00648 {
00649
00650 tmp_obj = parent->parent;
00651
00652
00653 if ((gl_object_isa(tmp_obj,"meter","powerflow") == false) && (gl_object_isa(tmp_obj,"node","powerflow")==false) && (gl_object_isa(tmp_obj,"load","powerflow")==false) &&
00654 (gl_object_isa(tmp_obj,"triplex_meter","powerflow") == false) && (gl_object_isa(tmp_obj,"triplex_node","powerflow")==false) && (gl_object_isa(tmp_obj,"triplex_load","powerflow")==false))
00655 {
00656
00657 tmp_obj = parent;
00658 }
00659 else
00660 {
00661
00662
00663 temp_property_pointer = new gld_property(parent,"Norton_dynamic");
00664
00665
00666 if ((temp_property_pointer->is_valid() != true) || (temp_property_pointer->is_bool() != true))
00667 {
00668 GL_THROW("inverter:%s failed to map Norton-equivalence deltamode variable from %s",obj->name?obj->name:"unnamed",parent->name?parent->name:"unnamed");
00669
00670
00671
00672
00673 }
00674
00675
00676 temp_bool_value = true;
00677 temp_property_pointer->setp<bool>(temp_bool_value,*test_rlock);
00678
00679
00680 delete temp_property_pointer;
00681 }
00682 }
00683 else
00684 {
00685
00686 tmp_obj = parent;
00687 }
00688 }
00689 else
00690 {
00691
00692 tmp_obj = parent;
00693 }
00694
00695
00696
00697 if ((gl_object_isa(tmp_obj,"triplex_meter","powerflow") == true) || (gl_object_isa(tmp_obj,"triplex_node","powerflow")==true) || (gl_object_isa(tmp_obj,"triplex_load","powerflow")==true))
00698 {
00699
00700 parent_is_a_meter = true;
00701 parent_is_triplex = true;
00702
00703
00704 pCircuit_V[0] = map_complex_value(tmp_obj,"voltage_12");
00705 pCircuit_V[1] = map_complex_value(tmp_obj,"voltage_1N");
00706 pCircuit_V[2] = map_complex_value(tmp_obj,"voltage_2N");
00707
00708
00709 pLine_I[0] = NULL;
00710 pLine_I[1] = NULL;
00711 pLine_I[2] = NULL;
00712
00713
00714 pLine12 = map_complex_value(tmp_obj,"current_12");
00715
00716 pPower12 = map_complex_value(tmp_obj,"power_12");
00717
00718
00719 pPower[0] = NULL;
00720 pPower[1] = NULL;
00721 pPower[2] = NULL;
00722
00723 pLine_unrotI[0] = map_complex_value(tmp_obj,"prerotated_current_12");
00724 pLine_unrotI[1] = NULL;
00725 pLine_unrotI[2] = NULL;
00726
00727
00728 pIGenerated[0] = map_complex_value(tmp_obj,"deltamode_generator_current_12");
00729 pIGenerated[1] = NULL;
00730 pIGenerated[2] = NULL;
00731 }
00732 else if ((gl_object_isa(tmp_obj,"meter","powerflow") == true) || (gl_object_isa(tmp_obj,"node","powerflow")==true) || (gl_object_isa(tmp_obj,"load","powerflow")==true))
00733 {
00734
00735 parent_is_a_meter = true;
00736 parent_is_triplex = false;
00737
00738
00739 pCircuit_V[0] = map_complex_value(tmp_obj,"voltage_A");
00740 pCircuit_V[1] = map_complex_value(tmp_obj,"voltage_B");
00741 pCircuit_V[2] = map_complex_value(tmp_obj,"voltage_C");
00742
00743 pLine_I[0] = map_complex_value(tmp_obj,"current_A");
00744 pLine_I[1] = map_complex_value(tmp_obj,"current_B");
00745 pLine_I[2] = map_complex_value(tmp_obj,"current_C");
00746
00747 pPower[0] = map_complex_value(tmp_obj,"power_A");
00748 pPower[1] = map_complex_value(tmp_obj,"power_B");
00749 pPower[2] = map_complex_value(tmp_obj,"power_C");
00750
00751 pLine_unrotI[0] = map_complex_value(tmp_obj,"prerotated_current_A");
00752 pLine_unrotI[1] = map_complex_value(tmp_obj,"prerotated_current_B");
00753 pLine_unrotI[2] = map_complex_value(tmp_obj,"prerotated_current_C");
00754
00755
00756 pIGenerated[0] = map_complex_value(tmp_obj,"deltamode_generator_current_A");
00757 pIGenerated[1] = map_complex_value(tmp_obj,"deltamode_generator_current_B");
00758 pIGenerated[2] = map_complex_value(tmp_obj,"deltamode_generator_current_C");
00759 }
00760
00761
00762
00763
00764
00765 if ((deltamode_inclusive == true) && (four_quadrant_control_mode == FQM_VSI))
00766 {
00767
00768 temp_property_pointer = new gld_property(tmp_obj,"Norton_dynamic");
00769
00770
00771 if ((temp_property_pointer->is_valid() != true) || (temp_property_pointer->is_bool() != true))
00772 {
00773 GL_THROW("inverter:%s failed to map Norton-equivalence deltamode variable from %s",obj->name?obj->name:"unnamed",tmp_obj->name?tmp_obj->name:"unnamed");
00774
00775 }
00776
00777
00778 temp_bool_value = true;
00779 temp_property_pointer->setp<bool>(temp_bool_value,*test_rlock);
00780
00781
00782 delete temp_property_pointer;
00783
00784
00785
00786
00787 Frequency_mapped = NULL;
00788
00789
00790 Frequency_mapped = new gld_property("powerflow::master_frequency_update");
00791
00792
00793 if ((Frequency_mapped->is_valid() != true) || (Frequency_mapped->is_bool() != true))
00794 {
00795 GL_THROW("inverter:%s - Failed to map frequency checking variable from powerflow for deltamode",obj->name?obj->name:"unnamed");
00796
00797
00798
00799
00800
00801 }
00802
00803
00804 Frequency_mapped->getp<bool>(temp_bool_value,*test_rlock);
00805
00806
00807 if (temp_bool_value == false)
00808 {
00809
00810 mapped_freq_variable = new gld_property("powerflow::current_frequency");
00811
00812
00813 if ((mapped_freq_variable->is_valid() != true) || (mapped_freq_variable->is_double() != true))
00814 {
00815 GL_THROW("diesel_dg:%s - Failed to map frequency checking variable from powerflow for deltamode",obj->name?obj->name:"unnamed");
00816
00817 }
00818
00819
00820 temp_bool_value = true;
00821 Frequency_mapped->setp<bool>(temp_bool_value,*test_rlock);
00822 }
00823
00824
00825
00826 delete Frequency_mapped;
00827
00828
00829
00830 temp_property_pointer = new gld_property(parent,"nominal_voltage");
00831
00832
00833 if ((temp_property_pointer->is_valid() != true) || (temp_property_pointer->is_double() != true))
00834 {
00835 gl_error("Inverter:%d %s failed to map the nominal_voltage property",obj->id, (obj->name ? obj->name : "Unnamed"));
00836
00837
00838
00839
00840
00841 return FAILED;
00842 }
00843
00844
00845
00846 node_nominal_voltage = temp_property_pointer->get_double();
00847
00848
00849 delete temp_property_pointer;
00850
00851 Zbase = (node_nominal_voltage * node_nominal_voltage)/p_rated;
00852 filter_impedance = complex(1.0,0.0)/(complex(Rfilter,Xfilter) * Zbase);
00853
00854 for (iindex=0; iindex<3; iindex++)
00855 {
00856 for (jindex=0; jindex<3; jindex++)
00857 {
00858 if (iindex==jindex)
00859 {
00860 generator_admittance[iindex][jindex] = filter_impedance;
00861 }
00862 else
00863 {
00864 generator_admittance[iindex][jindex] = complex(0.0,0.0);
00865 }
00866 }
00867 }
00868
00869
00870 pbus_full_Y_mat = new gld_property(tmp_obj,"deltamode_full_Y_matrix");
00871
00872
00873 if ((pbus_full_Y_mat->is_valid() != true) || (pbus_full_Y_mat->is_complex_array() != true))
00874 {
00875 GL_THROW("inverter:%s failed to map Norton-equivalence deltamode variable from %s",obj->name?obj->name:"unnamed",tmp_obj->name?tmp_obj->name:"unnamed");
00876
00877
00878
00879
00880 }
00881
00882
00883 pbus_full_Y_mat->getp<complex_array>(temp_complex_array,*test_rlock);
00884
00885
00886 if (temp_complex_array.is_valid(0,0) != true)
00887 {
00888
00889 temp_complex_array.grow_to(3,3);
00890
00891
00892 for (temp_idx_x=0; temp_idx_x<3; temp_idx_x++)
00893 {
00894 for (temp_idx_y=0; temp_idx_y<3; temp_idx_y++)
00895 {
00896 temp_complex_array.set_at(temp_idx_x,temp_idx_y,complex(0.0,0.0));
00897 }
00898 }
00899 }
00900 else
00901 {
00902 if ((temp_complex_array.get_rows() != 3) && (temp_complex_array.get_cols() != 3))
00903 {
00904 GL_THROW("inverter:%s exposed Norton-equivalent matrix is the wrong size!",obj->name?obj->name:"unnamed");
00905
00906
00907
00908
00909 }
00910
00911 }
00912
00913
00914 for (temp_idx_x=0; temp_idx_x<3; temp_idx_x++)
00915 {
00916 for (temp_idx_y=0; temp_idx_y<3; temp_idx_y++)
00917 {
00918
00919 temp_complex_value = temp_complex_array.get_at(temp_idx_x,temp_idx_y);
00920
00921
00922 temp_complex_value += generator_admittance[temp_idx_x][temp_idx_y];
00923
00924
00925 temp_complex_array.set_at(temp_idx_x,temp_idx_y,temp_complex_value);
00926 }
00927 }
00928
00929
00930 pbus_full_Y_mat->setp<complex_array>(temp_complex_array,*test_rlock);
00931
00932
00933 temp_property_pointer = new gld_property(tmp_obj,"bustype");
00934
00935
00936 if ((temp_property_pointer->is_valid() != true) || (temp_property_pointer->is_enumeration() != true))
00937 {
00938 GL_THROW("inverter:%s failed to map bustype variable from %s",obj->name?obj->name:"unnamed",tmp_obj->name?tmp_obj->name:"unnamed");
00939
00940
00941
00942
00943 }
00944
00945
00946 VSI_bustype = temp_property_pointer->get_enumeration();
00947
00948
00949 delete temp_property_pointer;
00950
00951
00952 pGenerated = map_complex_value(tmp_obj,"deltamode_PGenTotal");
00953
00954
00955
00956 batteries = gl_find_objects(FL_NEW, FT_CLASS, SAME, "battery", FT_END);
00957 if(batteries == NULL || batteries->hit_count == 0){
00958 gl_warning("No battery objects were found, but the VSI object exists. Now assume the VSI is attached with infinite input power.");
00959
00960
00961
00962 }
00963 else {
00964 while(objBattery = gl_find_next(batteries,objBattery)){
00965 if(index >= batteries->hit_count){
00966 gl_warning("VSI: %s does not find a battery attached to it. Now assume VSI: %s is attached with infinite input power.", (obj->name ? obj->name : "Unnamed"), (obj->name ? obj->name : "Unnamed"));
00967 break;
00968 }
00969 if (strcmp(objBattery->parent->name, obj->name) == 0) {
00970 break;
00971 }
00972 ++index;
00973 }
00974 }
00975 }
00976
00977
00978 pMeterStatus = new gld_property(parent,"service_status");
00979
00980
00981 if ((pMeterStatus->is_valid() != true) || (pMeterStatus->is_enumeration() != true))
00982 {
00983 GL_THROW("Inverter failed to map powerflow status variable");
00984
00985
00986
00987
00988
00989 }
00990
00991
00992 temp_property_pointer = new gld_property(parent,"phases");
00993
00994
00995 if ((temp_property_pointer->is_valid() != true) || (temp_property_pointer->is_set() != true))
00996 {
00997 GL_THROW("Unable to map phases property - ensure the parent is a meter or triplex_meter");
00998
00999
01000
01001
01002
01003 }
01004
01005
01006 parent_phases = temp_property_pointer->get_set();
01007
01008
01009 delete temp_property_pointer;
01010
01011
01012 pFrequency = new gld_property(tmp_obj,"measured_frequency");
01013
01014
01015 if ((pFrequency->is_valid() != true) || (pFrequency->is_double() != true))
01016 {
01017 GL_THROW("Inverter:%d %s failed to map the measured_frequency property",obj->id, (obj->name ? obj->name : "Unnamed"));
01018
01019
01020
01021
01022 }
01023
01024
01025 value_Circuit_V[0] = pCircuit_V[0]->get_complex();
01026 value_Circuit_V[1] = pCircuit_V[1]->get_complex();
01027 value_Circuit_V[2] = pCircuit_V[2]->get_complex();
01028 }
01029 else
01030 {
01031 GL_THROW("Inverter must have a valid powerflow object as its parent, or no parent at all");
01032
01033
01034
01035
01036
01037 }
01038 }
01039 else
01040 {
01041
01042 parent_is_a_meter = false;
01043 parent_is_triplex = false;
01044
01045 gl_warning("Inverter:%d has no parent meter object defined; using static voltages", obj->id);
01046
01047
01048
01049
01050
01051 parent_phases = 0x07;
01052
01053
01054
01055 temp_volt_mag = Rated_kV * 1000.0 / sqrt(3.0);
01056 value_Circuit_V[0].SetPolar(temp_volt_mag,0);
01057 value_Circuit_V[1].SetPolar(temp_volt_mag,-2.0/3.0*PI);
01058 value_Circuit_V[2].SetPolar(temp_volt_mag,2.0/3.0*PI);
01059
01060
01061 value_MeterStatus = 1;
01062
01063
01064 value_Frequency = 60.0;
01065 }
01066
01067
01068 if (phases == 0x00)
01069 {
01070 phases = parent_phases;
01071 }
01072
01073
01074 if ((((phases & 0x10) == 0x10) && ((parent_phases & 0x10) != 0x10)) || (((parent_phases & 0x10) == 0x10) && ((phases & 0x10) != 0x10)))
01075 {
01076 GL_THROW("Inverter:%d %s - Inverter has a triplex-related phase mismatch!",obj->id,(obj->name ? obj->name : "Unnamed"));
01077
01078
01079
01080
01081 }
01082 else if ((parent_phases & phases) != phases)
01083 {
01084 GL_THROW("Inverter:%d %s - Inverter phases are incompatible with the parent object phases!",obj->id,(obj->name ? obj->name : "Unnamed"));
01085
01086
01087
01088 }
01089
01090
01091 if ( (phases & 0x10) == 0x10)
01092 number_of_phases_out = 1;
01093 else if ( (phases & 0x07) == 0x07 )
01094 number_of_phases_out = 3;
01095 else if ( ((phases & 0x03) == 0x03) || ((phases & 0x05) == 0x05) || ((phases & 0x06) == 0x06) )
01096 number_of_phases_out = 2;
01097 else if ( ((phases & 0x01) == 0x01) || ((phases & 0x02) == 0x02) || ((phases & 0x04) == 0x04) )
01098 number_of_phases_out = 1;
01099 else
01100 {
01101
01102 GL_THROW("Invalid phase configuration specified!");
01103
01104
01105
01106
01107 }
01108
01109 if ((gen_mode_v == UNKNOWN) && (inverter_type_v != FOUR_QUADRANT))
01110 {
01111 gl_warning("Inverter control mode is not specified! Using default: CONSTANT_PF");
01112 gen_mode_v = (enumeration)CONSTANT_PF;
01113 }
01114 if (gen_status_v == UNKNOWN)
01115 {
01116 gl_warning("Inverter status is unknown! Using default: ONLINE");
01117 gen_status_v = (enumeration)ONLINE;
01118 }
01119 if (inverter_type_v == UNKNOWN)
01120 {
01121 gl_warning("Inverter type is unknown! Using default: PWM");
01122 inverter_type_v = (enumeration)PWM;
01123 }
01124
01125
01126 efficiency=inv_eta;
01127
01128
01129 switch(inverter_type_v)
01130 {
01131 case TWO_PULSE:
01132 if (inv_eta==0)
01133 {
01134 efficiency = 0.8;
01135 gl_warning("Efficiency unspecified - defaulted to %f for this inverter type",efficiency);
01136
01137
01138
01139
01140
01141 }
01142 break;
01143 case SIX_PULSE:
01144 if (inv_eta==0)
01145 {
01146 efficiency = 0.8;
01147 gl_warning("Efficiency unspecified - defaulted to %f for this inverter type",efficiency);
01148
01149 }
01150 break;
01151 case TWELVE_PULSE:
01152 if (inv_eta==0)
01153 {
01154 efficiency = 0.8;
01155 gl_warning("Efficiency unspecified - defaulted to %f for this inverter type",efficiency);
01156
01157 }
01158 break;
01159 case PWM:
01160 if (inv_eta==0)
01161 {
01162 efficiency = 0.9;
01163 gl_warning("Efficiency unspecified - defaulted to %f for this inverter type",efficiency);
01164
01165 }
01166 break;
01167 case FOUR_QUADRANT:
01168
01169
01170 if (inv_eta==0){
01171 efficiency = 0.9;
01172 gl_warning("Efficiency unspecified - defaulted to %f for this inverter type",efficiency);
01173 }
01174 if(inv_eta == 0){
01175 inv_eta = 0.9;}
01176 else if(inv_eta < 0){
01177 inv_eta = 0.9;
01178 gl_warning("Inverter efficiency must be positive--using default value");
01179 }
01180
01181 if(p_rated == 0){
01182 p_rated = 25000;
01183
01184 gl_warning("Inverter must have a nonzero power rating--using default value");
01185 }
01186
01187
01188 if(number_of_phases_out == 1){
01189 bp_rated = p_rated/inv_eta;}
01190 else if(number_of_phases_out == 2){
01191 bp_rated = 2*p_rated/inv_eta;}
01192 else if(number_of_phases_out == 3){
01193 bp_rated = 3*p_rated/inv_eta;
01194 }
01195
01196 if(use_multipoint_efficiency == FALSE){
01197 if(p_max == -1){
01198 p_max = bp_rated*inv_eta;
01199 }
01200 }
01201
01202 if(four_quadrant_control_mode == FQM_VOLT_VAR_FREQ_PWR)
01203 {
01204 if (delay_time < 0) {
01205 delay_time = 0.0;
01206 gl_warning("Delay time for Volt/VAr mode unspecified or negative. Setting to default of %f", delay_time);
01207 }
01208 if (max_var_slew_rate <= 0) {
01209 max_var_slew_rate = -1.0;
01210 gl_warning("Maximum VAr slew rate for Volt-VAr mode unspecified, negative or zero. Disabling");
01211 }
01212 if (max_pwr_slew_rate <= 0) {
01213 max_pwr_slew_rate = -1.0;
01214 gl_warning("Maximum output power slew rate for freq-power mode unspecified, negative or zero. Disabling");
01215 }
01216
01217
01218 VoltVArSchedInput = volt_var_sched;
01219 gl_warning(VoltVArSchedInput.c_str());
01220 if(VoltVArSchedInput.length() == 0) {
01221 VoltVArSched.push_back(std::make_pair (119.5,0));
01222
01223 VoltVArSched.push_back(std::make_pair (120.5,0));
01224 gl_warning("Volt/VAr schedule unspecified. Setting inverter for constant power factor of 1.0");
01225 }
01226 else
01227 {
01228
01229 int cntr = 0;
01230
01231 tempV = "";
01232 tempQ = "";
01233 for(int i = 0; i < VoltVArSchedInput.length(); i++) {
01234 if(VoltVArSchedInput[i] != ',') {
01235 if(cntr % 2 == 0)
01236 tempV += VoltVArSchedInput[i];
01237 else
01238 tempQ += VoltVArSchedInput[i];
01239 }
01240 else
01241 {
01242 if(cntr % 2 == 1){
01243 VoltVArSched.push_back(std::make_pair (atof(tempV.c_str()),atof(tempQ.c_str())));
01244 tempQ = "";
01245 tempV = "";
01246 }
01247 cntr++;
01248 }
01249 }
01250 if(cntr % 2 == 1)
01251 VoltVArSched.push_back(std::make_pair (atof(tempV.c_str()),atof(tempQ.c_str())));
01252 }
01253
01254
01255
01256 freq_pwrSchedInput = freq_pwr_sched;
01257 gl_warning(freq_pwrSchedInput.c_str());
01258 if(freq_pwrSchedInput.length() == 0) {
01259 freq_pwrSched.push_back(std::make_pair (f_nominal*0.9,0));
01260
01261 freq_pwrSched.push_back(std::make_pair (f_nominal*1.1,0));
01262 gl_warning("Frequency-Power schedule unspecified. Setting power for frequency regulation to zero.");
01263 }
01264 else
01265 {
01266
01267 int cntr = 0;
01268 tempf = "";
01269 tempP = "";
01270 for(int i = 0; i < freq_pwrSchedInput.length(); i++) {
01271 if(freq_pwrSchedInput[i] != ',') {
01272 if(cntr % 2 == 0)
01273 tempf += freq_pwrSchedInput[i];
01274 else
01275 tempP += freq_pwrSchedInput[i];
01276 }
01277 else
01278 {
01279 if(cntr % 2 == 1) {
01280 freq_pwrSched.push_back(std::make_pair (atof(tempf.c_str()),atof(tempP.c_str())));
01281 tempf = "";
01282 tempP = "";
01283 }
01284 cntr++;
01285 }
01286 }
01287 if(cntr % 2 == 1)
01288 freq_pwrSched.push_back(std::make_pair (atof(tempf.c_str()),atof(tempP.c_str())));
01289 }
01290
01291 }
01292
01293
01294 if(four_quadrant_control_mode == FQM_LOAD_FOLLOWING || pf_reg == INCLUDED || four_quadrant_control_mode == FQM_GROUP_LF )
01295 {
01296
01297 if (sense_object == NULL)
01298 {
01299 if (parent!=NULL)
01300 {
01301
01302 sense_object = parent;
01303 gl_warning("inverter:%s - sense_object not specified for LOAD_FOLLOWING and/or power-factor regulation - attempting to use parent object",obj->name);
01304
01305
01306
01307
01308
01309 }
01310 else
01311 {
01312 gl_error("inverter:%s - LOAD_FOLLOWING and power-factor regulation will not work without a specified sense_object!",obj->name);
01313
01314
01315
01316
01317 return 0;
01318 }
01319 }
01320
01321
01322 if (gl_object_isa(sense_object,"node","powerflow"))
01323 {
01324
01325 if (gl_object_isa(sense_object,"meter","powerflow") || gl_object_isa(sense_object,"triplex_meter","powerflow"))
01326 {
01327
01328 sense_is_link = false;
01329
01330
01331 sense_power = new gld_property(sense_object,"measured_power");
01332
01333
01334 if ((sense_power->is_valid() != true) || (sense_power->is_complex() != true))
01335 {
01336 gl_error("inverter:%s - an error occurred while mapping the sense_object power measurement!",obj->name);
01337
01338
01339
01340
01341 return 0;
01342 }
01343
01344
01345 if (sense_object != parent)
01346 {
01347 gl_warning("inverter:%s is LOAD_FOLLOWING and/or power-factor regulating based on a meter or triplex_meter, ensure the inverter is connected inline with that object!",obj->name);
01348
01349
01350
01351
01352 }
01353 }
01354 else
01355 {
01356 gl_error("inverter:%s - sense_object is a node, but not a meter or triplex_meter!",obj->name);
01357
01358
01359
01360
01361 return 0;
01362 }
01363 }
01364 else if (gl_object_isa(sense_object,"link","powerflow"))
01365 {
01366
01367 if (gl_object_isa(sense_object,"transformer","powerflow"))
01368 {
01369
01370 sense_is_link = true;
01371
01372
01373 powerCalc = (FUNCTIONADDR)(gl_get_function(sense_object,"power_calculation"));
01374
01375
01376 if (powerCalc==NULL)
01377 {
01378 gl_error("inverter:%s - inverter failed to map power calculation function of transformer!",obj->name);
01379
01380
01381
01382
01383
01384 return 0;
01385 }
01386
01387
01388 sense_power = new gld_property(sense_object,"power_out");
01389
01390
01391 if ((sense_power->is_valid() != true) || (sense_power->is_complex() != true))
01392 {
01393 gl_error("inverter:%s - an error occurred while mapping the sense_object power measurement!",obj->name);
01394
01395 return 0;
01396 }
01397 }
01398 else
01399 {
01400 gl_error("inverter:%s - sense_object is a link, but not a transformer!",obj->name);
01401
01402
01403
01404
01405 return 0;
01406 }
01407
01408 }
01409 else
01410 {
01411 gl_error("inverter:%s - sense_object is not a proper powerflow object!",obj->name);
01412
01413
01414
01415
01416
01417 return 0;
01418 }
01419
01420
01421 if (pf_reg != EXCLUDED)
01422 {
01423 if (pf_reg_activate_lockout_time < 0)
01424 {
01425 pf_reg_activate_lockout_time = 60;
01426 gl_warning("inverter:%s - pf_reg_activate_lockout_time is unassigned, using default value of 60s.",obj->name);
01427
01428
01429
01430
01431
01432 }
01433 else if (pf_reg_activate_lockout_time < 60)
01434 {
01435 pf_reg_activate_lockout_time = 1;
01436 gl_warning("inverter:%s - a short pf_reg_activate_lockout_time may lead to inverter controller oscillations. Recommended time: > 60s",obj->name);
01437
01438
01439
01440
01441
01442 }
01443
01444 else if (charge_lockout_time == 0.0)
01445 {
01446 gl_warning("inverter:%s - pf_reg_activate_lockout_time is zero, oscillations may occur",obj->name);
01447
01448
01449
01450
01451
01452 }
01453 }
01454 if (four_quadrant_control_mode == FQM_LOAD_FOLLOWING)
01455 {
01456 if (charge_lockout_time<0)
01457 {
01458 gl_error("inverter:%s - charge_lockout_time is negative!",obj->name);
01459
01460
01461
01462
01463 return 0;
01464 }
01465 else if (charge_lockout_time == 0.0)
01466 {
01467 gl_warning("inverter:%s - charge_lockout_time is zero, oscillations may occur",obj->name);
01468
01469
01470
01471
01472
01473 }
01474
01475
01476 if (discharge_lockout_time<0)
01477 {
01478 gl_error("inverter:%s - discharge_lockout_time is negative!",obj->name);
01479
01480
01481
01482
01483 return 0;
01484 }
01485 else if (discharge_lockout_time == 0.0)
01486 {
01487 gl_warning("inverter:%s - discharge_lockout_time is zero, oscillations may occur",obj->name);
01488
01489
01490
01491
01492
01493 }
01494 }
01495
01496 }
01497
01498
01499
01500
01501
01502
01503
01504
01505
01506
01507
01508
01509
01510
01511
01512
01513
01514
01515
01516
01517
01518
01519
01520
01521
01522
01523
01524
01525
01526
01527
01528 break;
01529 default:
01530
01531 GL_THROW("Invalid inverter type specified!");
01532
01533
01534
01535
01536 break;
01537 }
01538
01539
01540 if ((efficiency<=0) || (efficiency>1))
01541 {
01542 GL_THROW("The efficiency specified for inverter:%s is invalid",obj->name);
01543
01544
01545
01546
01547 }
01548
01549
01550 if(use_multipoint_efficiency == TRUE){
01551 switch(inverter_manufacturer){
01552 case NONE:
01553 if(p_dco < 0){
01554 gl_error("no maximum dc power was given for the inverter.");
01555 return 0;
01556 }
01557 if(v_dco < 0){
01558 gl_error("no maximum dc voltage was given for the inverter.");
01559 return 0;
01560 }
01561 if(p_so < 0){
01562 gl_error("no minimum dc power was given for the inverter.");
01563 return 0;
01564 }
01565 if(p_rated <= 0){
01566 gl_error("no rated per phase power was given for the inverter.");
01567 return 0;
01568 } else {
01569 switch (number_of_phases_out)
01570 {
01571
01572 case 1:
01573 p_max = p_rated;
01574 break;
01575
01576 case 2:
01577 p_max = 2*p_rated;
01578 break;
01579
01580 case 3:
01581 p_max = 3*p_rated;
01582 break;
01583 default:
01584
01585 GL_THROW("Invalid phase configuration specified!");
01586
01587
01588
01589
01590 break;
01591 }
01592 }
01593 if(c_o == -1){
01594 c_o = 0;
01595 }
01596 if(c_1 == -1){
01597 c_1 = 0;
01598 }
01599 if(c_2 == -1){
01600 c_2 = 0;
01601 }
01602 if(c_3 == -1){
01603 c_3 = 0;
01604 }
01605 break;
01606 case FRONIUS:
01607 if(p_dco < 0){
01608 p_dco = 2879;
01609 }
01610 if(v_dco < 0){
01611 v_dco = 277;
01612 }
01613 if(p_so < 0){
01614 p_so = 27.9;
01615 }
01616 if(c_o == -1){
01617 c_o = -1.009e-5;
01618 }
01619 if(c_1 == -1){
01620 c_1 = -1.367e-5;
01621 }
01622 if(c_2 == -1){
01623 c_2 = -3.587e-5;
01624 }
01625 if(c_3 == -1){
01626 c_3 = -3.421e-3;
01627 }
01628 if(p_max < 0){
01629 p_max = 2700;
01630 switch (number_of_phases_out)
01631 {
01632
01633 case 1:
01634 p_rated = p_max;
01635 break;
01636
01637 case 2:
01638 p_rated = p_max/2;
01639 break;
01640
01641 case 3:
01642 p_rated = p_max/3;
01643 break;
01644 default:
01645
01646 GL_THROW("Invalid phase configuration specified!");
01647
01648
01649
01650
01651 break;
01652 }
01653 }
01654 break;
01655 case SMA:
01656 if(p_dco < 0){
01657 p_dco = 2694;
01658 }
01659 if(v_dco < 0){
01660 v_dco = 302;
01661 }
01662 if(p_so < 0){
01663 p_so = 20.7;
01664 }
01665 if(c_o == -1){
01666 c_o = -1.545e-5;
01667 }
01668 if(c_1 == -1){
01669 c_1 = 6.525e-5;
01670 }
01671 if(c_2 == -1){
01672 c_2 = 2.836e-3;
01673 }
01674 if(c_3 == -1){
01675 c_3 = -3.058e-4;
01676 }
01677 if(p_max < 0){
01678 p_max = 2500;
01679 switch (number_of_phases_out)
01680 {
01681
01682 case 1:
01683 p_rated = p_max;
01684 break;
01685
01686 case 2:
01687 p_rated = p_max/2;
01688 break;
01689
01690 case 3:
01691 p_rated = p_max/3;
01692 break;
01693 default:
01694
01695 GL_THROW("Invalid phase configuration specified!");
01696
01697
01698
01699
01700 break;
01701 }
01702 }
01703 break;
01704 case XANTREX:
01705 if(p_dco < 0){
01706 p_dco = 4022;
01707 }
01708 if(v_dco < 0){
01709 v_dco = 266;
01710 }
01711 if(p_so < 0){
01712 p_so = 24.1;
01713 }
01714 if(c_o == -1){
01715 c_o = -8.425e-6;
01716 }
01717 if(c_1 == -1){
01718 c_1 = 8.590e-6;
01719 }
01720 if(c_2 == -1){
01721 c_2 = 7.76e-4;
01722 }
01723 if(c_3 == -1){
01724 c_3 = -5.278e-4;
01725 }
01726 if(p_max < 0){
01727 p_max = 3800;
01728 switch (number_of_phases_out)
01729 {
01730
01731 case 1:
01732 p_rated = p_max;
01733 break;
01734
01735 case 2:
01736 p_rated = p_max/2;
01737 break;
01738
01739 case 3:
01740 p_rated = p_max/3;
01741 break;
01742 default:
01743
01744 GL_THROW("Invalid phase configuration specified!");
01745
01746
01747
01748
01749 break;
01750 }
01751 }
01752 break;
01753 }
01754 if(p_max > p_dco){
01755 gl_error("The maximum dc power into the inverter cannot be less than the maximum ac power out.");
01756 return 0;
01757 }
01758 if(p_so > p_dco){
01759 gl_error("The maximum dc power into the inverter cannot be less than the minimum dc power.");
01760 return 0;
01761 }
01762 }
01763
01764
01765 if (four_quadrant_control_mode == FQM_VOLT_VAR) {
01766 if (V1 == -2) {
01767 V1 = 0.97;
01768 }
01769 if (V2 == -2) {
01770 V2 = 0.99;
01771 }
01772 if (V3 == -2) {
01773 V3 = 1.01;
01774 }
01775 if (V4 == -2) {
01776 V4 = 1.03;
01777 }
01778 if (Q1 == -2) {
01779 Q1 = 0.50;
01780 }
01781 if (Q2 == -2) {
01782 Q2 = 0.0;
01783 }
01784 if (Q3 == -2) {
01785 Q3 = 0.0;
01786 }
01787 if (Q4 == -2) {
01788 Q4 = -0.50;
01789 }
01790 if (V1 > V2 || V2 > V3 || V3 > V4) {
01791 gl_error("inverter::init(): The curve was not constructed properly. V1 <= V2 <= V3 <= V4 must be true.");
01792 return 0;
01793 }
01794 if (Q1 < Q2 || Q2 < Q3 || Q3 < Q4) {
01795 gl_error("inverter::init(): The curve was not constructed properly. Q1 >= Q2 >= Q3 >= Q4 must be true.");
01796 return 0;
01797 }
01798 if (V_base == 0) {
01799 gl_error("inverter::init(): The base voltage must be greater than 0.");
01800 return 0;
01801 }
01802 if (V2 != V1) {
01803 m12 = (Q2 - Q1) / (V2 - V1);
01804 } else {
01805 m12 = 0;
01806 }
01807 if (V3 != V2) {
01808 m23 = (Q3 - Q2) / (V3 - V2);
01809 } else {
01810 m23 = 0;
01811 }
01812 if (V4 != V3) {
01813 m34 = (Q4 - Q3) / (V4 - V3);
01814 } else {
01815 m34 = 0;
01816 }
01817 b12 = Q1 - (m12 * V1);
01818 b23 = Q2 - (m23 * V2);
01819 b34 = Q3 - (m34 * V3);
01820
01821 if (vv_lockout < 0.0) {
01822 gl_warning("volt var control lockout is 0. Warning this may cause oscillating behavior.");
01823 vv_lockout = 0;
01824 }
01825 allowed_vv_action = 0;
01826 last_vv_check = 0;
01827 }
01828 else if (four_quadrant_control_mode == FQM_VOLT_WATT) {
01829 if (VW_V1 == -2) VW_V1 = 1.05833;
01830 if (VW_V2 == -2) VW_V2 = 1.10;
01831 if (VW_P1 == -2) VW_P1 = 1.00;
01832 if (VW_P2 == -2) VW_P2 = 0.0;
01833 if (VW_V1 >= VW_V2) {
01834 gl_error("inverter::init(): VOLT_WATT mode requires VW_V2 > VW_V1.");
01835 return 0;
01836 }
01837 if (VW_P1 <= VW_P2) {
01838 gl_error("inverter::init(): VOLT_WATT mode requires VW_P1 > VW_P2.");
01839 return 0;
01840 }
01841 if (V_base == 0) {
01842 gl_error("inverter::init(): The base voltage must be greater than 0 for VOLT_WATT.");
01843 return 0;
01844 }
01845 VW_m = (VW_P2 - VW_P1) / (VW_V2 - VW_V1);
01846
01847 if (vv_lockout < 0.0) {
01848 gl_warning("VOLT_WATT uses the VOLT_VAR lockout, which is 0. Warning this may cause oscillating behavior.");
01849 vv_lockout = 0;
01850 }
01851 allowed_vv_action = 0;
01852 last_vv_check = 0;
01853 pa_vw_limited = pb_vw_limited = pc_vw_limited = p_rated;
01854 }
01855
01857
01859
01860 if (deltamode_inclusive)
01861 {
01862
01863 if (enable_subsecond_models!=true)
01864 {
01865 gl_warning("inverter:%s indicates it wants to run deltamode, but the module-level flag is not set!",obj->name?obj->name:"unnamed");
01866
01867
01868
01869
01870 }
01871 else
01872 {
01873 gen_object_count++;
01874 first_sync_delta_enabled = true;
01875 }
01876
01877
01878 if (enable_1547_compliance == true)
01879 {
01880 return_value_init = initalize_IEEE_1547_checks(parent);
01881
01882
01883 if (return_value_init == FAILED)
01884 {
01885 GL_THROW("inverter:%d-%s - initalizing the IEEE 1547 checks failed",obj->id,(obj->name ? obj->name : "Unnamed"));
01886
01887
01888
01889
01890 }
01891 }
01892
01893 }
01894 else
01895 {
01896 if (enable_subsecond_models == true)
01897 {
01898 gl_warning("inverter:%d %s - Deltamode is enabled for the module, but not this inverter!",obj->id, (obj->name ? obj->name : "Unnamed"));
01899
01900
01901
01902
01903
01904 }
01905 else if (enable_1547_compliance == true)
01906 {
01907
01908 return_value_init = initalize_IEEE_1547_checks(parent);
01909
01910
01911 if (return_value_init == FAILED)
01912 {
01913 GL_THROW("inverter:%d-%s - initalizing the IEEE 1547 checks failed",obj->id,(obj->name ? obj->name : "Unnamed"));
01914
01915
01916
01917
01918 }
01919
01920
01921 gl_warning("inverter:%d-%s - IEEE 1547 checks are enabled, but the model is not deltamode-enabled",obj->id,(obj->name ? obj->name : "Unnamed"));
01922
01923
01924
01925
01926 }
01927 }
01928
01929
01930 prev_time = gl_globalclock;
01931 prev_time_dbl = (double)(prev_time);
01932
01933
01934 start_time = gl_globalclock;
01935
01936
01937 VA_Out = complex(P_Out,Q_Out);
01938 VA_Out_past = VA_Out;
01939
01940 P_Out_t0 = P_Out;
01941 Q_Out_t0 = Q_Out;
01942 power_factor_t0 = power_factor;
01943 I_Out[0] = complex(0);
01944 I_Out[1] = complex(0);
01945 I_Out[2] = complex(0);
01946
01947 return 1;
01948
01949 }
01950
01951 TIMESTAMP inverter::presync(TIMESTAMP t0, TIMESTAMP t1)
01952 {
01953 TIMESTAMP t2 = TS_NEVER;
01954 OBJECT *obj = OBJECTHDR(this);
01955
01956
01957 if (parent_is_a_meter == true)
01958 {
01959
01960 reset_complex_powerflow_accumulators();
01961
01962
01963 pull_complex_powerflow_values();
01964 }
01965
01966 if(inverter_type_v != FOUR_QUADRANT){
01967 phaseA_I_Out = phaseB_I_Out = phaseC_I_Out = 0.0;
01968 } else {
01969 if (pf_reg == INCLUDED)
01970 {
01971 if (t1 != t0)
01972 {
01973
01974 if (t1>=pf_reg_next_update_time)
01975 {
01976
01977 pf_reg_dispatch_change_allowed = true;
01978 }
01979 if (pf_reg_activate == -2)
01980 {
01981 pf_reg_activate = 0.80;
01982 gl_warning("inverter:%s - pf_reg_activate undefined, setting to default value of 0.80.",obj->name);
01983 }
01984 if (pf_reg_deactivate == -1)
01985 {
01986 pf_reg_deactivate = 0.95;
01987 gl_warning("inverter:%s - pf_reg_deactivate undefined, setting to default value of 0.95.",obj->name);
01988 }
01989 if (pf_reg_deactivate >= 0.99)
01990 {
01991 gl_warning("inverter:%s - Very high values pf_reg_deactivate (~ 0.99) may lead to inverter control oscillation.",obj->name);
01992 }
01993 if (pf_reg_activate > pf_reg_deactivate)
01994 {
01995 GL_THROW("inverter:%s - pf_reg_activate is greater than pf_reg_deactivate.",obj->name);
01996 }
01997 if (pf_reg_activate < 0 || pf_reg_deactivate < 0)
01998 {
01999 GL_THROW("inverter:%s - pf_reg_activate and/or pf_reg_deactivate are negative.",obj->name);
02000 }
02001 if (pf_reg_activate == pf_reg_deactivate)
02002 {
02003 gl_warning("inverter:%s - pf_reg_activate and pf_reg_deactivate are equal - pf regluation may not behave properly and/or oscillate.",obj->name);;
02004 }
02005 }
02006 }
02007 else if (pf_reg == INCLUDED_ALT)
02008 {
02009 if (t1 != t0)
02010 {
02011
02012 if (t1>=pf_reg_next_update_time)
02013 {
02014
02015 pf_reg_dispatch_change_allowed = true;
02016 }
02017
02018
02019 if (pf_target_var == -2.0)
02020 {
02021 pf_target_var = 0.95;
02022 gl_warning("inverter:%s - pf_target_var is undefined, setting to a default value of 0.95",obj->name ? obj->name : "Unnamed");
02023
02024
02025
02026
02027 }
02028
02029 if (pf_reg_high == -2.0)
02030 {
02031 pf_reg_high = -0.95;
02032 gl_warning("inverter:%s - pf_reg_high is undefined, setting to a default value of -0.95",obj->name ? obj->name : "Unnamed");
02033
02034
02035
02036
02037 }
02038
02039 if (pf_reg_low == -2.0)
02040 {
02041 pf_reg_low = 0.97;
02042 gl_warning("inverter:%s - pf_reg_low is undefined, setting to a default value of 0.97",obj->name ? obj->name : "Unnamed");
02043
02044
02045
02046
02047 }
02048
02049
02050 if (pf_target_var < 0.0)
02051 {
02052
02053 if ((pf_reg_low < 0) && (pf_reg_low > pf_target_var))
02054 {
02055 GL_THROW("inverter:%s - pf_reg_low is below the pf_target_var value!",obj->name ? obj->name : "Unnamed");
02056
02057
02058
02059 }
02060 }
02061 else
02062 {
02063
02064 if ((pf_reg_low > 0) && (pf_reg_low < pf_target_var))
02065 {
02066 GL_THROW("inverter:%s - pf_reg_low is below the pf_target_var value!",obj->name ? obj->name : "Unnamed");
02067
02068 }
02069
02070 }
02071
02072
02073
02074 if (((pf_reg_high > 0) && (pf_reg_low > 0) && (pf_reg_high <= pf_reg_low)) || ((pf_reg_low < 0) && (pf_reg_high < 0) && (pf_reg_high >= pf_reg_low)))
02075 {
02076 GL_THROW("inverter:%s - pf_reg_low is higher than pf_reg_high",obj->name ? obj->name : "Unnamed");
02077
02078
02079
02080
02081 }
02082 }
02083 }
02084
02085 if(four_quadrant_control_mode == FQM_LOAD_FOLLOWING)
02086 {
02087 if (t1 != t0)
02088 {
02089
02090 if (t1>=next_update_time)
02091 {
02092
02093 lf_dispatch_change_allowed = true;
02094 }
02095
02096
02097 if (max_charge_rate <0)
02098 {
02099 GL_THROW("inverter:%s - max_charge_rate is negative!",obj->name);
02100
02101
02102
02103
02104 }
02105 else if (max_charge_rate == 0)
02106 {
02107 gl_warning("inverter:%s - max_charge_rate is zero",obj->name);
02108
02109
02110
02111
02112
02113 }
02114
02115 if (max_discharge_rate <0)
02116 {
02117 GL_THROW("inverter:%s - max_discharge_rate is negative!",obj->name);
02118
02119
02120
02121
02122 }
02123 else if (max_discharge_rate == 0)
02124 {
02125 gl_warning("inverter:%s - max_discharge_rate is zero",obj->name);
02126
02127
02128
02129
02130
02131 }
02132
02133
02134 if (charge_on_threshold > charge_off_threshold)
02135 {
02136 GL_THROW("inverter:%s - charge_on_threshold is greater than charge_off_threshold!",obj->name);
02137
02138
02139
02140
02141 }
02142 else if (charge_on_threshold == charge_off_threshold)
02143 {
02144 gl_warning("inverter:%s - charge_on_threshold and charge_off_threshold are equal - may not behave properly!",obj->name);
02145
02146
02147
02148
02149 }
02150
02151
02152 if (discharge_on_threshold < discharge_off_threshold)
02153 {
02154 GL_THROW("inverter:%s - discharge_on_threshold is less than discharge_off_threshold!",obj->name);
02155
02156
02157
02158
02159 }
02160 else if (discharge_on_threshold == discharge_off_threshold)
02161 {
02162 gl_warning("inverter:%s - discharge_on_threshold and discharge_off_threshold are equal - may not behave properly!",obj->name);
02163
02164
02165
02166
02167 }
02168
02169
02170 if (discharge_off_threshold <= charge_off_threshold)
02171 {
02172 gl_warning("inverter:%s - discharge_off_threshold should be larger than the charge_off_threshold",obj->name);
02173
02174
02175
02176
02177 }
02178 }
02179 }
02180 else if ((four_quadrant_control_mode == FQM_VOLT_VAR) || (four_quadrant_control_mode == FQM_VOLT_WATT))
02181 {
02182 if ((phases & 0x10) == 0x10)
02183 {
02184 value_Power12 = -last_power[3];
02185 }
02186 else
02187 {
02188 value_Power[0] = -last_power[0];
02189 value_Power[1] = -last_power[1];
02190 value_Power[2] = -last_power[2];
02191 }
02192
02193
02194 if (parent_is_a_meter == true)
02195 {
02196 push_complex_powerflow_values();
02197 }
02198
02199 }
02200 else if(four_quadrant_control_mode == FQM_GROUP_LF)
02201 {
02202 if (t1 != t0)
02203 {
02204
02205 if (t1>=next_update_time)
02206 {
02207
02208 lf_dispatch_change_allowed = true;
02209 }
02210
02211
02212 if (group_max_charge_rate < 0)
02213 {
02214 GL_THROW("inverter:%s - group_max_charge_rate cannot be negative.",obj->name);
02215 }
02216 else if (max_charge_rate == 0)
02217 {
02218 gl_warning("inverter:%s - group_max_charge_rate is zero.",obj->name);
02219 }
02220
02221 if (group_max_discharge_rate < 0)
02222 {
02223 GL_THROW("inverter:%s - group_max_discharge_rate cannot be negative.",obj->name);
02224 }
02225 else if (group_max_discharge_rate == 0)
02226 {
02227 gl_warning("inverter:%s - group_max_discharge_rate is zero",obj->name);
02228 }
02229
02230 if (group_rated_power <= 0)
02231 {
02232 GL_THROW("inverter:%s - group_rated_power must be positive.",obj->name);
02233 }
02234
02235
02236
02237 if (charge_threshold == -1)
02238 {
02239 GL_THROW("inverter:%s - charge_threshold must be defined for GROUP_LOAD_FOLLOW mode.",obj->name);
02240 }
02241
02242 if (discharge_threshold == -1)
02243 {
02244 GL_THROW("inverter:%s - discharge_threshold must be defined for GROUP_LOAD_FOLLOW mode.",obj->name);
02245 }
02246
02247 if (charge_threshold == discharge_threshold)
02248 {
02249 gl_warning("inverter:%s - charge_threshold and discharge_threshold are equal - not recommended, oscillations may occur.",obj->name);
02250 }
02251
02252
02253
02254 if (discharge_threshold < charge_threshold)
02255 {
02256 gl_error("inverter:%s - discharge_threshold must be larger than the charge_threshold",obj->name);
02257 }
02258 }
02259 }
02260
02261 if((deltamode_inclusive == true) && (enable_subsecond_models==true) && (inverter_dyn_mode == PI_CONTROLLER)) {
02262
02263 if ((t1 == start_time) || (t1 != t0)) {
02264 last_I_In = I_In.Re();
02265 for(int i = 0; i < 3; i++) {
02266 last_I_Out[i] = I_Out[i];
02267 }
02268 }
02269 }
02270 }
02271
02272 return t2;
02273 }
02274
02275 TIMESTAMP inverter::sync(TIMESTAMP t0, TIMESTAMP t1)
02276 {
02277 OBJECT *obj = OBJECTHDR(this);
02278 TIMESTAMP tret_value;
02279 double curr_ts_dbl, diff_dbl;
02280 double ieee_1547_return_value;
02281 TIMESTAMP new_ret_value;
02282 FUNCTIONADDR test_fxn;
02283 bool *gen_dynamic_flag;
02284 STATUS fxn_return_status;
02285
02286 complex rotate_value;
02287 complex calculated_iO[3];
02288
02289 complex temp_current_val[3];
02290 complex temp_power_val[3];
02291
02292 complex temp_complex_value;
02293 gld_wlock *test_rlock;
02294
02295
02296 tret_value = TS_NEVER;
02297
02298
02299 if (parent_is_a_meter == true)
02300 {
02301
02302 reset_complex_powerflow_accumulators();
02303
02304
02305 pull_complex_powerflow_values();
02306 }
02307
02308 if(gen_status_v == OFFLINE){
02309 power_val[0] = complex(0.0,0.0);
02310 power_val[1] = complex(0.0,0.0);
02311 power_val[2] = complex(0.0,0.0);
02312 P_Out = 0;
02313 Q_Out = 0;
02314 VA_Out = complex(0);
02315 if ((phases & 0x10) == 0x10) {
02316 last_power[3] = -power_val[0];
02317 value_Power12 = last_power[3];
02318 } else {
02319 p_in = 0;
02320 if ((phases & 0x01) == 0x01) {
02321 last_power[0] = -power_val[0];
02322 value_Power[0] = last_power[0];
02323 }
02324 if ((phases & 0x02) == 0x02) {
02325 last_power[1] = -power_val[1];
02326 value_Power[1] = last_power[1];
02327 }
02328 if ((phases & 0x04) == 0x04) {
02329 last_power[2] = -power_val[2];
02330 value_Power[2] = last_power[2];
02331 }
02332 }
02333
02334
02335 if (parent_is_a_meter == true)
02336 {
02337 push_complex_powerflow_values();
02338 }
02339
02340 return tret_value;
02341 }
02342
02343 if (first_sync_delta_enabled == true)
02344 {
02345
02346 if ((deltamode_inclusive == true) && (enable_subsecond_models == true))
02347 {
02348
02349 if (first_iter_counter == 0)
02350 {
02351 if (((gen_object_current == -1) || (delta_objects==NULL)) && (enable_subsecond_models == true))
02352 {
02353
02354 allocate_deltamode_arrays();
02355 }
02356
02357
02358 if (gen_object_current>=gen_object_count)
02359 {
02360 GL_THROW("Too many objects tried to populate deltamode objects array in the generators module!");
02361
02362
02363
02364
02365
02366 }
02367
02368
02369 delta_objects[gen_object_current] = obj;
02370
02371
02372 delta_functions[gen_object_current] = (FUNCTIONADDR)(gl_get_function(obj,"interupdate_gen_object"));
02373
02374
02375 if (delta_functions[gen_object_current] == NULL)
02376 {
02377 GL_THROW("Failure to map deltamode function for device:%s",obj->name);
02378
02379
02380
02381
02382
02383 }
02384
02385
02386 post_delta_functions[gen_object_current] = (FUNCTIONADDR)(gl_get_function(obj,"postupdate_gen_object"));
02387
02388
02389 if (post_delta_functions[gen_object_current] == NULL)
02390 {
02391 GL_THROW("Failure to map post-deltamode function for device:%s",obj->name);
02392
02393
02394
02395
02396
02397 }
02398
02399
02400 delta_preupdate_functions[gen_object_current] = (FUNCTIONADDR)(gl_get_function(obj,"preupdate_gen_object"));
02401
02402
02403 if (delta_preupdate_functions[gen_object_current] == NULL)
02404 {
02405 GL_THROW("Failure to map pre-deltamode function for device:%s",obj->name);
02406
02407
02408
02409
02410
02411 }
02412
02413
02414 gen_object_current++;
02415
02416
02417
02418 if (four_quadrant_control_mode == FQM_CONSTANT_PQ)
02419 {
02420
02421 test_fxn = (FUNCTIONADDR)(gl_get_function(obj->parent,"pwr_current_injection_update_map"));
02422
02423
02424 if (test_fxn == NULL)
02425 {
02426 GL_THROW("PQ_CONSTANT inverter:%s - failed to map additional current injection mapping for node:%s",(obj->name?obj->name:"unnamed"),(obj->parent->name?obj->parent->name:"unnamed"));
02427
02428
02429
02430
02431 }
02432
02433
02434 fxn_return_status = ((STATUS (*)(OBJECT *, OBJECT *))(*test_fxn))(obj->parent,obj);
02435
02436
02437 if (fxn_return_status != SUCCESS)
02438 {
02439 GL_THROW("PQ_CONSTANT inverter:%s - failed to map additional current injection mapping for node:%s",(obj->name?obj->name:"unnamed"),(obj->parent->name?obj->parent->name:"unnamed"));
02440
02441 }
02442 }
02443
02444
02445 if (four_quadrant_control_mode == FQM_VSI)
02446 {
02447
02448 if (obj->parent != NULL)
02449 {
02450 if (gl_object_isa(obj->parent,"meter","powerflow") || gl_object_isa(obj->parent,"load","powerflow") || gl_object_isa(obj->parent,"node","powerflow") || gl_object_isa(obj->parent,"elec_frequency","powerflow"))
02451 {
02452
02453 temp_complex_value = complex(P_Out, Q_Out);
02454
02455
02456 pGenerated->setp<complex>(temp_complex_value,*test_rlock);
02457
02458
02459 test_fxn = (FUNCTIONADDR)(gl_get_function(obj->parent,"pwr_current_injection_update_map"));
02460
02461
02462 if (test_fxn == NULL)
02463 {
02464 GL_THROW("Voltage source inverter:%s - failed to map additional current injection mapping for node:%s",(obj->name?obj->name:"unnamed"),(obj->parent->name?obj->parent->name:"unnamed"));
02465
02466
02467
02468
02469 }
02470
02471
02472 fxn_return_status = ((STATUS (*)(OBJECT *, OBJECT *))(*test_fxn))(obj->parent,obj);
02473
02474
02475 if (fxn_return_status != SUCCESS)
02476 {
02477 GL_THROW("Voltage source inverter:%s - failed to map additional current injection mapping for node:%s",(obj->name?obj->name:"unnamed"),(obj->parent->name?obj->parent->name:"unnamed"));
02478
02479 }
02480 }
02481 else
02482 {
02483 GL_THROW("Voltage source inverter:%s - invalid parent object:%s",(obj->name?obj->name:"unnamed"),(obj->parent->name?obj->parent->name:"unnamed"));
02484
02485
02486
02487
02488 }
02489 }
02490 }
02491 }
02492
02493
02494 first_iter_counter++;
02495
02496
02497 if (first_iter_counter < 3)
02498 {
02499
02500 tret_value = t1;
02501 }
02502 else
02503 {
02504
02505 first_sync_delta_enabled = false;
02506 }
02507 }
02508 else
02509 {
02510 first_sync_delta_enabled = false;
02511 }
02512 }
02513
02514
02515
02516 if (enable_1547_compliance == true)
02517 {
02518
02519 curr_ts_dbl = (double)gl_globalclock;
02520
02521
02522 if (prev_time_dbl < curr_ts_dbl)
02523 {
02524
02525 diff_dbl = curr_ts_dbl - prev_time_dbl;
02526
02527
02528 prev_time_dbl = curr_ts_dbl;
02529
02530
02531 ieee_1547_return_value = perform_1547_checks(diff_dbl);
02532
02533
02534 if (ieee_1547_return_value > 0.0)
02535 {
02536
02537 if (deltamode_inclusive == true)
02538 {
02539 new_ret_value = t1 + (TIMESTAMP)(floor(ieee_1547_return_value));
02540
02541
02542
02543 schedule_deltamode_start(new_ret_value);
02544 }
02545 else
02546 {
02547 new_ret_value = t1 + (TIMESTAMP)(ceil(ieee_1547_return_value));
02548 }
02549
02550
02551 if ((tret_value != TS_NEVER) && (new_ret_value < tret_value))
02552 {
02553 tret_value = new_ret_value;
02554 }
02555
02556 }
02557 }
02558
02559 }
02560
02561
02562 if ((value_MeterStatus==1) && (inverter_1547_status == true))
02563 {
02564 phaseA_V_Out = value_Circuit_V[0];
02565 phaseB_V_Out = value_Circuit_V[1];
02566 phaseC_V_Out = value_Circuit_V[2];
02567
02568 if(inverter_type_v != FOUR_QUADRANT)
02569 {
02570 switch(gen_mode_v)
02571 {
02572 case CONSTANT_PF:
02573 VA_In = V_In * ~ I_In;
02574
02575
02576 if(use_multipoint_efficiency == FALSE){
02577 VA_Out = VA_In * efficiency;
02578 } else {
02579 if(VA_In <= p_so){
02580 VA_Out = 0;
02581 } else {
02582 if(V_In > v_dco){
02583 gl_warning("The dc voltage is greater than the specified maximum for the inverter. Efficiency model may be inaccurate.");
02584 }
02585 C1 = p_dco*(1+c_1*(V_In.Re()-v_dco));
02586 C2 = p_so*(1+c_2*(V_In.Re()-v_dco));
02587 C3 = c_o*(1+c_3*(V_In.Re()-v_dco));
02588 VA_Out.SetReal((((p_max/(C1-C2))-C3*(C1-C2))*(VA_In.Re()-C2)+C3*(VA_In.Re()-C2)*(VA_In.Re()-C2)));
02589 }
02590 }
02591
02592 if ((phases & 0x10) == 0x10)
02593 {
02594 power_val[0] = complex(VA_Out.Mag()*fabs(power_factor),power_factor/fabs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)));
02595 if (phaseA_V_Out.Mag() != 0.0)
02596 phaseA_I_Out = ~(power_val[0] / phaseA_V_Out);
02597 else
02598 phaseA_I_Out = complex(0.0,0.0);
02599
02600 value_Line12 = -phaseA_I_Out;
02601
02602
02603 last_current[3] = -phaseA_I_Out;
02604
02605
02606
02607
02608 }
02609 else if (number_of_phases_out == 3)
02610 {
02611 power_val[0] = power_val[1] = power_val[2] = complex(VA_Out.Mag()*fabs(power_factor),power_factor/fabs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)))/3;
02612 if (phaseA_V_Out.Mag() != 0.0)
02613 phaseA_I_Out = ~(power_val[0] / phaseA_V_Out);
02614 else
02615 phaseA_I_Out = complex(0.0,0.0);
02616 if (phaseB_V_Out.Mag() != 0.0)
02617 phaseB_I_Out = ~(power_val[1] / phaseB_V_Out);
02618 else
02619 phaseB_I_Out = complex(0.0,0.0);
02620 if (phaseC_V_Out.Mag() != 0.0)
02621 phaseC_I_Out = ~(power_val[2] / phaseC_V_Out);
02622 else
02623 phaseC_I_Out = complex(0.0,0.0);
02624
02625 value_Line_I[0] = -phaseA_I_Out;
02626 value_Line_I[1] = -phaseB_I_Out;
02627 value_Line_I[2] = -phaseC_I_Out;
02628
02629
02630 last_current[0] = -phaseA_I_Out;
02631 last_current[1] = -phaseB_I_Out;
02632 last_current[2] = -phaseC_I_Out;
02633 }
02634 else if(number_of_phases_out == 2)
02635 {
02636 OBJECT *obj = OBJECTHDR(this);
02637
02638 if ( ((phases & 0x01) == 0x01) && phaseA_V_Out.Mag() != 0)
02639 {
02640 power_val[0] = complex(VA_Out.Mag()*fabs(power_factor),power_factor/fabs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)))/2;;
02641 phaseA_I_Out = ~(power_val[0] / phaseA_V_Out);
02642 }
02643 else
02644 phaseA_I_Out = complex(0,0);
02645
02646 if ( ((phases & 0x02) == 0x02) && phaseB_V_Out.Mag() != 0)
02647 {
02648 power_val[1] = complex(VA_Out.Mag()*fabs(power_factor),power_factor/fabs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)))/2;;
02649 phaseB_I_Out = ~(power_val[1] / phaseB_V_Out);
02650 }
02651 else
02652 phaseB_I_Out = complex(0,0);
02653
02654 if ( ((phases & 0x04) == 0x04) && phaseC_V_Out.Mag() != 0)
02655 {
02656 power_val[2] = complex(VA_Out.Mag()*fabs(power_factor),power_factor/fabs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)))/2;;
02657 phaseC_I_Out = ~(power_val[2] / phaseC_V_Out);
02658 }
02659 else
02660 phaseC_I_Out = complex(0,0);
02661
02662 value_Line_I[0] = -phaseA_I_Out;
02663 value_Line_I[1] = -phaseB_I_Out;
02664 value_Line_I[2] = -phaseC_I_Out;
02665
02666
02667 last_current[0] = -phaseA_I_Out;
02668 last_current[1] = -phaseB_I_Out;
02669 last_current[2] = -phaseC_I_Out;
02670
02671 }
02672 else
02673 {
02674 if( ((phases & 0x01) == 0x01) && phaseA_V_Out.Mag() != 0)
02675 {
02676 power_val[0] = complex(VA_Out.Mag()*fabs(power_factor),power_factor/fabs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)));
02677 phaseA_I_Out = ~(power_val[0] / phaseA_V_Out);
02678
02679
02680 }
02681 else if( ((phases & 0x02) == 0x02) && phaseB_V_Out.Mag() != 0)
02682 {
02683 power_val[1] = complex(VA_Out.Mag()*fabs(power_factor),power_factor/fabs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)));
02684 phaseB_I_Out = ~(power_val[1] / phaseB_V_Out);
02685
02686
02687 }
02688 else if( ((phases & 0x04) == 0x04) && phaseC_V_Out.Mag() != 0)
02689 {
02690 power_val[2] = complex(VA_Out.Mag()*fabs(power_factor),power_factor/fabs(power_factor)*VA_Out.Mag()*sin(acos(power_factor)));
02691 phaseC_I_Out = ~(power_val[2] / phaseC_V_Out);
02692
02693
02694 }
02695 else
02696 {
02697 gl_warning("None of the phases specified have voltages!");
02698 phaseA_I_Out = phaseB_I_Out = phaseC_I_Out = complex(0.0,0.0);
02699 }
02700 value_Line_I[0] = -phaseA_I_Out;
02701 value_Line_I[1] = -phaseB_I_Out;
02702 value_Line_I[2] = -phaseC_I_Out;
02703
02704
02705 last_current[0] = -phaseA_I_Out;
02706 last_current[1] = -phaseB_I_Out;
02707 last_current[2] = -phaseC_I_Out;
02708
02709 }
02710 break;
02711 case CONSTANT_PQ:
02712 GL_THROW("Constant PQ mode not supported at this time");
02713
02714
02715
02716 gl_verbose("inverter sync: constant pq");
02717
02718 if(parent_is_a_meter == true)
02719 {
02720 VA_Out = complex(P_Out,Q_Out);
02721 }
02722 else
02723 {
02724
02725 phaseA_I_Out = value_Line_I[0];
02726 phaseB_I_Out = value_Line_I[1];
02727 phaseC_I_Out = value_Line_I[2];
02728
02729
02730
02731
02732 VA_Out = phaseA_V_Out * (~ phaseA_I_Out) + phaseB_V_Out * (~ phaseB_I_Out) + phaseC_V_Out * (~ phaseC_I_Out);
02733 }
02734
02735 if ( (phases & 0x07) == 0x07)
02736 {
02737 power_val[0] = power_val[1] = power_val[2] = VA_Out /3;
02738 phaseA_I_Out = (power_val[0] / phaseA_V_Out);
02739 phaseB_I_Out = (power_val[1] / phaseB_V_Out);
02740 phaseC_I_Out = (power_val[2] / phaseC_V_Out);
02741
02742 phaseA_I_Out = ~ phaseA_I_Out;
02743 phaseB_I_Out = ~ phaseB_I_Out;
02744 phaseC_I_Out = ~ phaseC_I_Out;
02745
02746 }
02747 else if ( (number_of_phases_out == 1) && ((phases & 0x01) == 0x01) )
02748 {
02749 power_val[0] = VA_Out;
02750 phaseA_I_Out = (power_val[0] / phaseA_V_Out);
02751 phaseA_I_Out = ~ phaseA_I_Out;
02752 }
02753 else if ( (number_of_phases_out == 1) && ((phases & 0x02) == 0x02) )
02754 {
02755 power_val[1] = VA_Out;
02756 phaseB_I_Out = (power_val[1] / phaseB_V_Out);
02757 phaseB_I_Out = ~ phaseB_I_Out;
02758 }
02759 else if ( (number_of_phases_out == 1) && ((phases & 0x04) == 0x04) )
02760 {
02761 power_val[2] = VA_Out;
02762 phaseC_I_Out = (power_val[2] / phaseC_V_Out);
02763 phaseC_I_Out = ~ phaseC_I_Out;
02764 }
02765 else
02766 {
02767 throw ("unsupported number of phases");
02768 }
02769
02770 VA_In = VA_Out / efficiency;
02771
02772 V_In.Re() = Vdc;
02773
02774 I_In = VA_In / V_In;
02775 I_In = ~I_In;
02776
02777 gl_verbose("Inverter sync: V_In asked for by inverter is: (%f , %f)", V_In.Re(), V_In.Im());
02778 gl_verbose("Inverter sync: I_In asked for by inverter is: (%f , %f)", I_In.Re(), I_In.Im());
02779
02780
02781 value_Line_I[0] = phaseA_I_Out;
02782 value_Line_I[1] = phaseB_I_Out;
02783 value_Line_I[2] = phaseC_I_Out;
02784
02785
02786 last_current[0] = phaseA_I_Out;
02787 last_current[1] = phaseB_I_Out;
02788 last_current[2] = phaseC_I_Out;
02789
02790 break;
02791 case CONSTANT_V:
02792 {
02793 GL_THROW("Constant V mode not supported at this time");
02794
02795
02796
02797 gl_verbose("inverter sync: constant v");
02798 bool changed = false;
02799
02800 if(phaseAOut)
02801 {
02802 if (phaseA_V_Out.Re() < (V_Set_A - margin))
02803 {
02804 phaseA_I_Out = phaseA_I_Out_prev + I_step_max/2;
02805 changed = true;
02806 }
02807 else if (phaseA_V_Out.Re() > (V_Set_A + margin))
02808 {
02809 phaseA_I_Out = phaseA_I_Out_prev - I_step_max/2;
02810 changed = true;
02811 }
02812 else
02813 {
02814 changed = false;
02815 }
02816 }
02817 if (phaseBOut)
02818 {
02819 if (phaseB_V_Out.Re() < (V_Set_B - margin))
02820 {
02821 phaseB_I_Out = phaseB_I_Out_prev + I_step_max/2;
02822 changed = true;
02823 }
02824 else if (phaseB_V_Out.Re() > (V_Set_B + margin))
02825 {
02826 phaseB_I_Out = phaseB_I_Out_prev - I_step_max/2;
02827 changed = true;
02828 }
02829 else
02830 {
02831 changed = false;
02832 }
02833 }
02834 if (phaseCOut)
02835 {
02836 if (phaseC_V_Out.Re() < (V_Set_C - margin))
02837 {
02838 phaseC_I_Out = phaseC_I_Out_prev + I_step_max/2;
02839 changed = true;
02840 }
02841 else if (phaseC_V_Out.Re() > (V_Set_C + margin))
02842 {
02843 phaseC_I_Out = phaseC_I_Out_prev - I_step_max/2;
02844 changed = true;
02845 }
02846 else
02847 {
02848 changed = false;
02849 }
02850 }
02851
02852 power_val[0] = (~phaseA_I_Out) * phaseA_V_Out;
02853 power_val[1] = (~phaseB_I_Out) * phaseB_V_Out;
02854 power_val[2] = (~phaseC_I_Out) * phaseC_V_Out;
02855
02856
02857 if (((power_val[0] + power_val[1] + power_val[2]) > Rated_kVA) ||
02858 ((power_val[0].Re() + power_val[1].Re() + power_val[2].Re()) > Max_P) ||
02859 ((power_val[0].Im() + power_val[1].Im() + power_val[2].Im()) > Max_Q))
02860 {
02861 VA_Out = Rated_kVA / number_of_phases_out;
02862
02863 changed = false;
02864 if(phaseAOut)
02865 {
02866 phaseA_I_Out = VA_Out / phaseA_V_Out;
02867 phaseA_I_Out = (~phaseA_I_Out);
02868 }
02869 if(phaseBOut)
02870 {
02871 phaseB_I_Out = VA_Out / phaseB_V_Out;
02872 phaseB_I_Out = (~phaseB_I_Out);
02873 }
02874 if(phaseCOut)
02875 {
02876 phaseC_I_Out = VA_Out / phaseC_V_Out;
02877 phaseC_I_Out = (~phaseC_I_Out);
02878 }
02879 }
02880
02881
02882 if(power_val[0] < 0)
02883 {
02884 power_val[0] = 0;
02885 phaseA_I_Out = 0;
02886 throw("phaseA power is negative!");
02887 }
02888 if(power_val[1] < 0)
02889 {
02890 power_val[1] = 0;
02891 phaseB_I_Out = 0;
02892 throw("phaseB power is negative!");
02893 }
02894 if(power_val[2] < 0)
02895 {
02896 power_val[2] = 0;
02897 phaseC_I_Out = 0;
02898 throw("phaseC power is negative!");
02899 }
02900
02901 VA_In = VA_Out / efficiency;
02902
02903 V_In.Re() = Vdc;
02904
02905 I_In = ~(VA_In / V_In);
02906
02907 gl_verbose("Inverter sync: I_In asked for by inverter is: (%f , %f)", I_In.Re(), I_In.Im());
02908
02909
02910
02911 if(changed)
02912 {
02913 value_Line_I[0] = phaseA_I_Out;
02914 value_Line_I[1] = phaseB_I_Out;
02915 value_Line_I[2] = phaseC_I_Out;
02916
02917
02918 last_current[0] = phaseA_I_Out;
02919 last_current[1] = phaseB_I_Out;
02920 last_current[2] = phaseC_I_Out;
02921
02922 TIMESTAMP t2 = t1 + 10 * 60 * TS_SECOND;
02923
02924 if (tret_value != TS_NEVER)
02925 {
02926 if (t2 < tret_value)
02927 {
02928 tret_value = t2;
02929 }
02930 }
02931 else
02932 {
02933 tret_value = t2;
02934 }
02935 }
02936 else
02937 {
02938 value_Line_I[0] = phaseA_I_Out;
02939 value_Line_I[1] = phaseB_I_Out;
02940 value_Line_I[2] = phaseC_I_Out;
02941
02942
02943 last_current[0] = phaseA_I_Out;
02944 last_current[1] = phaseB_I_Out;
02945 last_current[2] = phaseC_I_Out;
02946 }
02947 break;
02948 }
02949 case SUPPLY_DRIVEN:
02950 GL_THROW("SUPPLY_DRIVEN mode for inverters not supported at this time");
02951 break;
02952 default:
02953 value_Line_I[0] = phaseA_I_Out;
02954 value_Line_I[1] = phaseB_I_Out;
02955 value_Line_I[2] = phaseC_I_Out;
02956
02957
02958 last_current[0] = phaseA_I_Out;
02959 last_current[1] = phaseB_I_Out;
02960 last_current[2] = phaseC_I_Out;
02961
02962 break;
02963 }
02964 }
02965 else
02966 {
02967
02968 double VA_Efficiency, temp_PF, temp_QVal, P_in, net_eff;
02969 complex temp_VA;
02970 complex battery_power_out = complex(0,0);
02971 if ((four_quadrant_control_mode != FQM_VOLT_VAR) && (four_quadrant_control_mode != FQM_VOLT_WATT))
02972 {
02973
02974 VA_In = V_In * ~ I_In;
02975
02976
02977 if((phases & 0x10) == 0x10){
02978 battery_power_out = power_val[0];
02979 } else {
02980 if((phases & 0x01) == 0x01){
02981 battery_power_out += power_val[0];
02982 }
02983 if((phases & 0x02) == 0x02){
02984 battery_power_out += power_val[1];
02985 }
02986 if((phases & 0x04) == 0x04){
02987 battery_power_out += power_val[2];
02988 }
02989 }
02990
02991 if(use_multipoint_efficiency == false)
02992 {
02993
02994 VA_Efficiency = VA_In.Re() * efficiency;
02995
02996 P_in = fabs(VA_In.Re());
02997 net_eff = efficiency;
02998
02999 }
03000 else
03001 {
03002
03003 if(VA_In.Mag() <= p_so)
03004 {
03005 VA_Efficiency = 0.0;
03006
03007 P_in = 0;
03008 net_eff = 0;
03009
03010 }
03011 else
03012 {
03013
03014 if(V_In.Mag() > v_dco)
03015 {
03016 gl_warning("The dc voltage is greater than the specified maximum for the inverter. Efficiency model may be inaccurate.");
03017
03018
03019
03020
03021 }
03022
03023
03024 C1 = p_dco*(1+c_1*(V_In.Re()-v_dco));
03025 C2 = p_so*(1+c_2*(V_In.Re()-v_dco));
03026 C3 = c_o*(1+c_3*(V_In.Re()-v_dco));
03027
03028
03029 VA_Efficiency = (((p_max/(C1-C2))-C3*(C1-C2))*(VA_In.Re()-C2)+C3*(VA_In.Re()-C2)*(VA_In.Re()-C2));
03030
03031 P_in = fabs(VA_In.Re());
03032 net_eff = fabs(VA_Efficiency / P_in);
03033
03034 }
03035 }
03036 VA_Efficiency += battery_power_out.Mag();
03037 } else {
03038 if (four_quadrant_control_mode == FQM_VOLT_VAR) {
03039 if (V1 == -2) V1 = 0.97;
03040 if (V2 == -2) V2 = 0.99;
03041 if (V3 == -2) V3 = 1.01;
03042 if (V4 == -2) V4 = 1.03;
03043 if (Q1 == -2) Q1 = 0.50;
03044 if (Q2 == -2) Q2 = 0.0;
03045 if (Q3 == -2) Q3 = 0.0;
03046 if (Q4 == -2) Q4 = -0.50;
03047 if (V1 > V2 || V2 > V3 || V3 > V4) {
03048 gl_error("inverter::sync(): The curve was not constructed properly. V1 <= V2 <= V3 <= V4 must be true.");
03049 return TS_INVALID;
03050 }
03051 if (Q1 < Q2 || Q2 < Q3 || Q3 < Q4) {
03052 gl_error("inverter::sync(): The curve was not constructed properly. V1 <= V2 <= V3 <= V4 must be true.");
03053 return TS_INVALID;
03054 }
03055 if (V_base == 0) {
03056 gl_error("inverter::sync(): The curve was not constructed properly. V1 <= V2 <= V3 <= V4 must be true.");
03057 return TS_INVALID;
03058 }
03059 if (V2 != V1) {
03060 m12 = (Q2 - Q1) / (V2 - V1);
03061 } else {
03062 m12 = 0;
03063 }
03064 if (V3 != V2) {
03065 m23 = (Q3 - Q2) / (V3 - V2);
03066 } else {
03067 m23 = 0;
03068 }
03069 if (V4 != V3) {
03070 m34 = (Q4 - Q3) / (V4 - V3);
03071 } else {
03072 m34 = 0;
03073 }
03074 b12 = Q1 - (m12 * V1);
03075 b23 = Q2 - (m23 * V2);
03076 b34 = Q3 - (m34 * V3);
03077 } else if (four_quadrant_control_mode == FQM_VOLT_WATT) {
03078
03079 if (VW_V1 == -2) VW_V1 = 1.05833;
03080 if (VW_V2 == -2) VW_V2 = 1.10;
03081 if (VW_P1 == -2) VW_P1 = 1.00;
03082 if (VW_P2 == -2) VW_P2 = 0.0;
03083 if (VW_V1 >= VW_V2) {
03084 gl_error("inverter::sync(): VOLT_WATT mode requires VW_V2 > VW_V1.");
03085 return TS_INVALID;
03086 }
03087 if (VW_P1 <= VW_P2) {
03088 gl_error("inverter::sync(): VOLT_WATT mode requires VW_P1 > VW_P2.");
03089 return TS_INVALID;
03090 }
03091 if (V_base == 0) {
03092 gl_error("inverter::sync(): The base voltage must be greater than 0 for VOLT_WATT.");
03093 return TS_INVALID;
03094 }
03095 VW_m = (VW_P2 - VW_P1) / (VW_V2 - VW_V1);
03096 }
03097
03098
03099 VA_In = V_In * ~ I_In;
03100
03101 if(use_multipoint_efficiency == false)
03102 {
03103
03104 VA_Efficiency = VA_In.Re() * efficiency;
03105 }
03106 else
03107 {
03108
03109 if(VA_In.Mag() <= p_so)
03110 {
03111 VA_Efficiency = 0.0;
03112 }
03113 else
03114 {
03115
03116 if(V_In.Mag() > v_dco)
03117 {
03118 gl_warning("The dc voltage is greater than the specified maximum for the inverter. Efficiency model may be inaccurate.");
03119
03120
03121
03122
03123 }
03124
03125
03126 C1 = p_dco*(1+c_1*(V_In.Re()-v_dco));
03127 C2 = p_so*(1+c_2*(V_In.Re()-v_dco));
03128 C3 = c_o*(1+c_3*(V_In.Re()-v_dco));
03129
03130
03131 VA_Efficiency = (((p_max/(C1-C2))-C3*(C1-C2))*(VA_In.Re()-C2)+C3*(VA_In.Re()-C2)*(VA_In.Re()-C2));
03132 }
03133 }
03134 if ((phases & 0x10) == 0x10){
03135 power_val[0].SetReal(VA_Efficiency);
03136 } else {
03137 if ((phases & 0x01) == 0x01) {
03138 power_val[0].SetReal(VA_Efficiency/number_of_phases_out);
03139 }
03140 if ((phases & 0x02) == 0x02) {
03141 power_val[1].SetReal(VA_Efficiency/number_of_phases_out);
03142 }
03143 if ((phases & 0x04) == 0x04) {
03144 power_val[2].SetReal(VA_Efficiency/number_of_phases_out);
03145 }
03146 }
03147 }
03148
03149
03150 if(four_quadrant_control_mode == FQM_CONSTANT_PF)
03151 {
03152 if(power_factor != 0.0)
03153 {
03154 if (VA_In<0.0)
03155 {
03156
03157 VA_Out.SetReal(VA_Efficiency*-1.0);
03158 }
03159 else if (VA_In>0.0)
03160 {
03161
03162 VA_Out.SetReal(VA_Efficiency);
03163 }
03164 else
03165 {
03166 VA_Out.SetReal(0.0);
03167 }
03168
03169
03170
03171 if (power_factor < 0)
03172 {
03173 VA_Out.SetImag((VA_Efficiency/sqrt(power_factor*power_factor))*sqrt(1.0-(power_factor*power_factor)));
03174 }
03175 else
03176 {
03177 VA_Out.SetImag((VA_Efficiency/sqrt(power_factor*power_factor))*-1.0*sqrt(1.0-(power_factor*power_factor)));
03178 }
03179 }
03180 else
03181 {
03182 VA_Out = complex(0.0,VA_Efficiency);
03183 }
03184 }
03185
03186
03187 else if (four_quadrant_control_mode == FQM_CONSTANT_PQ)
03188 {
03189
03190 Pref = P_Out;
03191 Qref = Q_Out;
03192
03193
03194 temp_VA = complex(P_Out,Q_Out);
03195
03196 if (b_soc != -1) {
03197
03198 if ((b_soc >= 1.0) && (temp_VA.Re() < 0))
03199 {
03200 gl_warning("inverter:%s - battery full - no charging allowed",obj->name);
03201 temp_VA.SetReal(0.0);
03202 }
03203 else if ((b_soc <= soc_reserve) && (temp_VA.Re() > 0))
03204 {
03205 gl_warning("inverter:%s - battery at or below the SOC reserve - no discharging allowed",obj->name);
03206 temp_VA.SetReal(0.0);
03207 }
03208
03209
03210 if (fabs(temp_VA.Mag()) > p_max){
03211 if (p_max > fabs(temp_VA.Re()))
03212 {
03213
03214 temp_QVal = sqrt((p_max*p_max) - (temp_VA.Re()*temp_VA.Re()));
03215
03216
03217 if (temp_VA.Im() < 0.0)
03218 {
03219 VA_Out = complex(temp_VA.Re(),-temp_QVal);
03220 }
03221 else
03222 {
03223 VA_Out = complex(temp_VA.Re(),temp_QVal);
03224 }
03225 }
03226 else
03227 {
03228
03229 if (temp_VA.Re() < 0.0)
03230 {
03231 VA_Out = complex(-p_max,0.0);
03232 }
03233 else
03234 {
03235 VA_Out = complex(p_max,0.0);
03236 }
03237 }
03238 }
03239 else
03240 {
03241 VA_Out = temp_VA;
03242 }
03243
03244
03245 if (VA_Out.Re() > 0.0)
03246 {
03247 p_in = VA_Out.Re()/inv_eta;
03248 }
03249 else if (VA_Out.Re() == 0.0)
03250 {
03251 p_in = 0.0;
03252 }
03253 else
03254 {
03255 p_in = VA_Out.Re()*inv_eta;
03256 }
03257 } else {
03258
03259 if (fabs(temp_VA.Mag()) > p_max){
03260 if (p_max > fabs(temp_VA.Re()))
03261 {
03262
03263 temp_QVal = sqrt((p_max*p_max) - (temp_VA.Re()*temp_VA.Re()));
03264
03265
03266 if (temp_VA.Im() < 0.0)
03267 {
03268 temp_VA.SetImag(-temp_QVal);
03269 }
03270 else
03271 {
03272 temp_VA.SetImag(temp_QVal);
03273 }
03274 }
03275 else
03276 {
03277
03278 if (temp_VA.Re() < 0.0)
03279 {
03280 temp_VA = complex(-p_max,0.0);
03281 }
03282 else
03283 {
03284 temp_VA = complex(p_max,0.0);
03285 }
03286 }
03287 }
03288
03289 if (fabs(temp_VA.Mag()) > VA_Efficiency){
03290 if (VA_Efficiency > fabs(temp_VA.Re()))
03291 {
03292
03293 temp_QVal = sqrt((VA_Efficiency*VA_Efficiency) - (temp_VA.Re()*temp_VA.Re()));
03294
03295
03296 if (temp_VA.Im() < 0.0)
03297 {
03298 VA_Out = complex(temp_VA.Re(),-temp_QVal);
03299 }
03300 else
03301 {
03302 VA_Out = complex(temp_VA.Re(),temp_QVal);
03303 }
03304 }
03305 else
03306 {
03307
03308 if (temp_VA.Re() < 0.0)
03309 {
03310 VA_Out = complex(-VA_Efficiency,0.0);
03311 }
03312 else
03313 {
03314 VA_Out = complex(VA_Efficiency,0.0);
03315 }
03316 }
03317 } else {
03318 VA_Out = temp_VA;
03319 }
03320 }
03321
03322
03323
03324
03325 }
03326 else if (four_quadrant_control_mode == FQM_VSI)
03327 {
03328
03329 if (VSI_mode == VSI_ISOCHRONOUS || VSI_mode == VSI_DROOP) {
03330
03331 if ((phases & 0x10) == 0x10)
03332 {
03333
03334
03335 temp_current_val[0] = value_IGenerated[0] - generator_admittance[0][0]*value_Circuit_V[0];
03336
03337
03338 VA_Out = value_Circuit_V[0]*~temp_current_val[0];
03339
03340 }
03341 else
03342 {
03343
03344
03345 temp_current_val[0] = (value_IGenerated[0] - generator_admittance[0][0]*value_Circuit_V[0] - generator_admittance[0][1]*value_Circuit_V[1] - generator_admittance[0][2]*value_Circuit_V[2]);
03346 temp_current_val[1] = (value_IGenerated[1] - generator_admittance[1][0]*value_Circuit_V[0] - generator_admittance[1][1]*value_Circuit_V[1] - generator_admittance[1][2]*value_Circuit_V[2]);
03347 temp_current_val[2] = (value_IGenerated[2] - generator_admittance[2][0]*value_Circuit_V[0] - generator_admittance[2][1]*value_Circuit_V[1] - generator_admittance[2][2]*value_Circuit_V[2]);
03348
03349
03350 power_val[0] = value_Circuit_V[0]*~temp_current_val[0];
03351 power_val[1] = value_Circuit_V[1]*~temp_current_val[1];
03352 power_val[2] = value_Circuit_V[2]*~temp_current_val[2];
03353
03354 VA_Out = power_val[0] + power_val[1] + power_val[2];
03355 }
03356 }
03357
03358
03359 temp_VA = VA_Out;
03360
03361
03362
03363 if (first_run == true) {
03364 p_in = 0;
03365 }
03366 else {
03367
03368 if ((b_soc >= 1.0) && (temp_VA.Re() < 0) && (b_soc != -1))
03369 {
03370 gl_warning("inverter:%s - battery full - no charging allowed",obj->name);
03371 temp_VA.SetReal(0.0);
03372 }
03373 else if ((b_soc <= soc_reserve) && (temp_VA.Re() > 0) && (b_soc != -1))
03374 {
03375 gl_warning("inverter:%s - battery at or below the SOC reserve - no discharging allowed",obj->name);
03376 temp_VA.SetReal(0.0);
03377 }
03378
03379
03380 if (fabs(temp_VA.Mag()) > p_max){
03381 if (p_max > fabs(temp_VA.Re()))
03382 {
03383
03384 temp_QVal = sqrt((p_max*p_max) - (temp_VA.Re()*temp_VA.Re()));
03385
03386
03387 if (temp_VA.Im() < 0.0)
03388 {
03389 VA_Out = complex(temp_VA.Re(),-temp_QVal);
03390 }
03391 else
03392 {
03393 VA_Out = complex(temp_VA.Re(),temp_QVal);
03394 }
03395 }
03396 else
03397 {
03398
03399 if (temp_VA.Re() < 0.0)
03400 {
03401 VA_Out = complex(-p_max,0.0);
03402 }
03403 else
03404 {
03405 VA_Out = complex(p_max,0.0);
03406 }
03407 }
03408 }
03409 else
03410 {
03411 VA_Out = temp_VA;
03412 }
03413
03414
03415
03416 if (VA_Out.Re() > 0.0)
03417 {
03418 p_in = VA_Out.Re()/inv_eta;
03419 }
03420 else if (VA_Out.Re() == 0.0)
03421 {
03422 p_in = 0.0;
03423 }
03424 else
03425 {
03426 p_in = VA_Out.Re()*inv_eta;
03427 }
03428 }
03429
03430
03431 Pref = VA_Out.Re();
03432 Qref = VA_Out.Im();
03433 }
03434 else if (four_quadrant_control_mode == FQM_LOAD_FOLLOWING)
03435 {
03436 VA_Out = -lf_dispatch_power;
03437 }
03438 else if (four_quadrant_control_mode == FQM_GROUP_LF)
03439 {
03440 VA_Out = -lf_dispatch_power;
03441 }
03442 else if (four_quadrant_control_mode == FQM_VOLT_VAR_FREQ_PWR) {
03443
03444
03445
03446
03447
03448
03449
03450
03451 if((VA_In.Re() == 0.0) && (disable_volt_var_if_no_input_power == true))
03452 VA_Out = complex(0,0);
03453 else
03454 {
03455
03456
03457
03458 double Qo = VoltVArSched.back().second;
03459 double prevV = 0;
03460 double prevQ = VoltVArSched.front().second;
03461 for (size_t i = 0; i < VoltVArSched.size(); i++)
03462 {
03463 if(phaseA_V_Out.Mag() <= VoltVArSched[i].first) {
03464 double m = (VoltVArSched[i].second - prevQ)/(VoltVArSched[i].first - prevV);
03465 double b = VoltVArSched[i].second - (m * VoltVArSched[i].first);
03466 Qo = m * phaseA_V_Out.Mag() + b;
03467 break;
03468 }
03469 prevV = VoltVArSched[i].first;
03470 prevQ = VoltVArSched[i].second;
03471 }
03472
03473 double Po = (P_in * net_eff) - fabs(Qo) * (1 - net_eff)/net_eff;
03474
03475 if(VA_In.Re() < 0.0)
03476 VA_Out = complex(Po,-Qo);
03477 else
03478 VA_Out = complex(-Po,-Qo);
03479 }
03480
03481
03482
03483 }
03484
03485
03486 if ((pf_reg == INCLUDED) || (pf_reg == INCLUDED_ALT))
03487 {
03488 VA_Out.Im() = -pf_reg_dispatch_VAR;
03489 }
03490
03491
03492
03493
03494
03495
03496
03497 if ((four_quadrant_control_mode != FQM_VOLT_VAR) && (four_quadrant_control_mode != FQM_VOLT_WATT))
03498 {
03499
03500 if(VA_Out.Mag() > p_max)
03501 {
03502
03503 excess_input_power = (VA_Out.Mag() - p_max);
03504
03505
03506 if (four_quadrant_control_mode == FQM_CONSTANT_PF)
03507 {
03508 temp_PF = power_factor;
03509 }
03510 else
03511 {
03512 temp_PF = VA_Out.Re()/VA_Out.Mag();
03513 }
03514
03515
03516 temp_VA = complex(fabs(p_max*temp_PF),fabs(p_max*sqrt(1.0-(temp_PF*temp_PF))));
03517
03518
03519 if ((VA_Out.Re()<0) && (VA_Out.Im()<0))
03520 {
03521 VA_Out = -temp_VA;
03522 }
03523 else if ((VA_Out.Re()<0) && (VA_Out.Im()>=0))
03524 {
03525 VA_Out = complex(-temp_VA.Re(),temp_VA.Im());
03526 }
03527 else if ((VA_Out.Re()>=0) && (VA_Out.Im()<0))
03528 {
03529 VA_Out = complex(temp_VA.Re(),-temp_VA.Im());
03530 }
03531 else
03532 {
03533 VA_Out = temp_VA;
03534 }
03535 }
03536 else
03537 {
03538 excess_input_power = 0.0;
03539 }
03540
03541
03542 if (four_quadrant_control_mode == FQM_LOAD_FOLLOWING || four_quadrant_control_mode == FQM_GROUP_LF || battery_power_out.Mag() != 0.0)
03543 {
03544 if ((b_soc == 1.0) && (VA_Out.Re() < 0) && (b_soc != -1))
03545 {
03546 gl_warning("inverter:%s - battery full - no charging allowed",obj->name);
03547
03548
03549
03550
03551 VA_Out.SetReal(0.0);
03552 }
03553 else if ((b_soc <= soc_reserve) && (VA_Out.Re() > 0) && (b_soc != -1))
03554 {
03555 gl_warning("inverter:%s - battery at or below the SOC reserve - no discharging allowed",obj->name);
03556
03557
03558
03559
03560 VA_Out.SetReal(0.0);
03561 }
03562
03563
03564
03565 if (VA_Out.Re() > 0.0)
03566 {
03567 p_in = VA_Out.Re()/inv_eta;
03568 }
03569 else if (VA_Out.Re() == 0.0)
03570 {
03571 p_in = 0.0;
03572 }
03573 else
03574 {
03575 p_in = VA_Out.Re()*inv_eta;
03576 }
03577 }
03578
03579
03580 if(four_quadrant_control_mode != FQM_CONSTANT_PQ && four_quadrant_control_mode != FQM_VSI){
03581 P_Out = VA_Out.Re();
03582 Q_Out = VA_Out.Im();
03583 }
03584
03585
03586 if (four_quadrant_control_mode == FQM_VSI && VSI_mode == VSI_DROOP) {
03587
03588
03589 if ((prev_time < t1) && (first_run == false))
03590 {
03591
03592 if ((phases & 0x10) == 0x10)
03593 {
03594 if (VSI_bustype != 2) {
03595
03596
03597 complex temp_VA = complex(P_Out,Q_Out);
03598
03599
03600 value_IGenerated[0] = ~(temp_VA/value_Circuit_V[0]) + generator_admittance[0][0]*value_Circuit_V[0];
03601
03602
03603 e_source[0] = value_IGenerated[0] * (complex(Rfilter,Xfilter) * Zbase);
03604 V_angle[0] = (e_source[0]).Arg();
03605 V_mag[0] = e_source[0].Mag();
03606 }
03607 }
03608 else {
03609
03610 if (VSI_bustype != 2) {
03611
03612
03613 complex temp_VA = complex(P_Out,Q_Out);
03614
03615
03616
03617 temp_current_val[0] = (value_IGenerated[0] - generator_admittance[0][0]*value_Circuit_V[0] - generator_admittance[0][1]*value_Circuit_V[1] - generator_admittance[0][2]*value_Circuit_V[2]);
03618 temp_current_val[1] = (value_IGenerated[1] - generator_admittance[1][0]*value_Circuit_V[0] - generator_admittance[1][1]*value_Circuit_V[1] - generator_admittance[1][2]*value_Circuit_V[2]);
03619 temp_current_val[2] = (value_IGenerated[2] - generator_admittance[2][0]*value_Circuit_V[0] - generator_admittance[2][1]*value_Circuit_V[1] - generator_admittance[2][2]*value_Circuit_V[2]);
03620
03621
03622 power_val[0] = value_Circuit_V[0]*~temp_current_val[0];
03623 power_val[1] = value_Circuit_V[1]*~temp_current_val[1];
03624 power_val[2] = value_Circuit_V[2]*~temp_current_val[2];
03625
03626 VA_Out = power_val[0] + power_val[1] + power_val[2];
03627
03628
03629 temp_power_val[0] = power_val[0] + (temp_VA - VA_Out) / 3.0;
03630 temp_power_val[1] = power_val[1] + (temp_VA - VA_Out) / 3.0;
03631 temp_power_val[2] = power_val[2] + (temp_VA - VA_Out) / 3.0;
03632
03633
03634 temp_current_val[0] = ~(temp_power_val[0]/value_Circuit_V[0]) + generator_admittance[0][0]*value_Circuit_V[0] + generator_admittance[0][1]*value_Circuit_V[1] + generator_admittance[0][2]*value_Circuit_V[2];
03635 temp_current_val[1] = ~(temp_power_val[1]/value_Circuit_V[1]) + generator_admittance[1][0]*value_Circuit_V[0] + generator_admittance[1][1]*value_Circuit_V[1] + generator_admittance[1][2]*value_Circuit_V[2];
03636 temp_current_val[2] = ~(temp_power_val[2]/value_Circuit_V[2]) + generator_admittance[2][0]*value_Circuit_V[0] + generator_admittance[2][1]*value_Circuit_V[1] + generator_admittance[2][2]*value_Circuit_V[2];
03637
03638
03639 value_IGenerated[0] = temp_current_val[0];
03640 value_IGenerated[1] = temp_current_val[1];
03641 value_IGenerated[2] = temp_current_val[2];
03642
03643
03644 for (int i = 0; i < 3; i++) {
03645
03646 e_source[i] = value_IGenerated[i] * (complex(Rfilter,Xfilter) * Zbase);
03647 V_angle[i] = (e_source[i]).Arg();
03648 V_mag[i] = e_source[i].Mag();
03649 }
03650 }
03651 }
03652
03653
03654 prev_time = t1;
03655 prev_time_dbl = (double)(t1);
03656
03657
03658 tret_value = t1;
03659 }
03660 }
03661
03662 else if (four_quadrant_control_mode != FQM_VSI)
03663 {
03664
03665 if ((phases & 0x10) == 0x10)
03666 {
03667
03668 last_power[3] = -VA_Out;
03669 curr_VA_out[0] = VA_Out;
03670
03671
03672 if (value_Circuit_V[0].Mag() > 0.0)
03673 {
03674 I_Out[0] = ~(VA_Out / value_Circuit_V[0]);
03675 }
03676 else
03677 {
03678 I_Out[0] = complex(0.0,0.0);
03679 }
03680
03681 if (four_quadrant_control_mode != FQM_VSI) {
03682 if (deltamode_inclusive == true)
03683 {
03684 last_current[3] = -I_Out[0];
03685 value_Line_unrotI[0] = last_current[3];
03686 }
03687 else
03688 {
03689 value_Power12 =last_power[3];
03690 }
03691 }
03692
03693
03694 }
03695 else
03696 {
03697
03698 temp_VA = -VA_Out/number_of_phases_out;
03699
03700 if ( (phases & 0x01) == 0x01 )
03701 {
03702 curr_VA_out[0] = -temp_VA;
03703 last_power[0] = temp_VA;
03704
03705 if (value_Circuit_V[0].Mag() > 0.0)
03706 {
03707 I_Out[0] = ~(-temp_VA / value_Circuit_V[0]);
03708 }
03709 else
03710 {
03711 I_Out[0] = complex(0.0,0.0);
03712 }
03713
03714 if (four_quadrant_control_mode != FQM_VSI) {
03715 if (deltamode_inclusive == true)
03716 {
03717 last_current[0] = -I_Out[0];
03718 value_Line_unrotI[0] = last_current[0];
03719 }
03720 else
03721 {
03722 value_Power[0] = temp_VA;
03723 }
03724 }
03725 }
03726
03727 if ( (phases & 0x02) == 0x02 )
03728 {
03729 curr_VA_out[1] = -temp_VA;
03730 last_power[1] = temp_VA;
03731
03732 if (value_Circuit_V[1].Mag() > 0.0)
03733 {
03734 I_Out[1] = ~(-temp_VA / value_Circuit_V[1]);
03735 }
03736 else
03737 {
03738 I_Out[1] = complex(0.0,0.0);
03739 }
03740
03741 if (four_quadrant_control_mode != FQM_VSI) {
03742 if (deltamode_inclusive == true)
03743 {
03744 last_current[1] = -I_Out[1];
03745 value_Line_unrotI[1] = last_current[1];
03746 }
03747 else
03748 {
03749 value_Power[1] = temp_VA;
03750 }
03751
03752 }
03753 }
03754
03755 if ( (phases & 0x04) == 0x04 )
03756 {
03757 curr_VA_out[2] = -temp_VA;
03758 last_power[2] = temp_VA;
03759
03760 if (value_Circuit_V[2].Mag() > 0.0)
03761 {
03762 I_Out[2] = ~(-temp_VA / value_Circuit_V[2]);
03763 }
03764 else
03765 {
03766 I_Out[2] = complex(0.0,0.0);
03767 }
03768
03769 if (four_quadrant_control_mode != FQM_VSI) {
03770 if (deltamode_inclusive == true)
03771 {
03772 last_current[2] = -I_Out[2];
03773 value_Line_unrotI[2] = last_current[2];
03774 }
03775 else
03776 {
03777 value_Power[2] = temp_VA;
03778 }
03779 }
03780 }
03781 }
03782 }
03783 } else {
03784 if (four_quadrant_control_mode == FQM_VOLT_VAR)
03785 {
03786 if (power_val[0].Mag() > p_rated) {
03787 if (power_val[0].Re() > p_rated) {
03788 power_val[0].SetReal(p_rated);
03789 power_val[0].SetImag(0);
03790 } else if (power_val[0].Re() < -p_rated) {
03791 power_val[0].SetReal(-p_rated);
03792 power_val[0].SetImag(0);
03793 } else if (power_val[0].Re() < p_rated && power_val[0].Re() > -p_rated) {
03794 double q_max = 0;
03795 q_max = sqrt((p_rated * p_rated) - (power_val[0].Re() * power_val[0].Re()));
03796 if (power_val[0].Im() > q_max) {
03797 power_val[0].SetImag(q_max);
03798 } else {
03799 power_val[0].SetImag(-q_max);
03800 }
03801 }
03802 }
03803 if (power_val[1].Mag() > p_rated ) {
03804 if (power_val[1].Re() > p_rated) {
03805 power_val[1].SetReal(p_rated);
03806 power_val[1].SetImag(0);
03807 } else if (power_val[1].Re() < -p_rated) {
03808 power_val[1].SetReal(-p_rated);
03809 power_val[1].SetImag(0);
03810 } else if (power_val[1].Re() < p_rated && power_val[1].Re() > -p_rated) {
03811 double q_max = 0;
03812 q_max = sqrt((p_rated * p_rated) - (power_val[1].Re() * power_val[1].Re()));
03813 if (power_val[1].Im() > q_max) {
03814 power_val[1].SetImag(q_max);
03815 } else {
03816 power_val[1].SetImag(-q_max);
03817 }
03818 }
03819 }
03820 if (power_val[2].Mag() > p_rated ) {
03821 if (power_val[2].Re() > p_rated) {
03822 power_val[2].SetReal(p_rated);
03823 power_val[2].SetImag(0);
03824 } else if (power_val[2].Re() < -p_rated) {
03825 power_val[2].SetReal(-p_rated);
03826 power_val[2].SetImag(0);
03827 } else if (power_val[2].Re() < p_rated && power_val[2].Re() > -p_rated) {
03828 double q_max = 0;
03829 q_max = sqrt((p_rated * p_rated) - (power_val[2].Re() * power_val[2].Re()));
03830 if (power_val[2].Im() > q_max) {
03831 power_val[2].SetImag(q_max);
03832 } else {
03833 power_val[2].SetImag(-q_max);
03834 }
03835 }
03836 }
03837 }
03838 else if (four_quadrant_control_mode == FQM_VOLT_WATT)
03839 {
03840 if (power_val[0].Re() > pa_vw_limited) {
03841 power_val[0].SetReal (pa_vw_limited);
03842 }
03843 if (power_val[1].Re() > pb_vw_limited) {
03844 power_val[1].SetReal (pb_vw_limited);
03845 }
03846 if (power_val[2].Re() > pc_vw_limited) {
03847 power_val[2].SetReal (pc_vw_limited);
03848 }
03849 }
03850
03851 if ((phases & 0x10) == 0x10) {
03852 p_in = power_val[0].Re() / inv_eta;
03853 last_power[3] = -power_val[0];
03854 value_Power12 = last_power[3];
03855
03856 if (value_Circuit_V[0].Mag() > 0.0)
03857 {
03858 I_Out[0] = ~(power_val[0] / value_Circuit_V[0]);
03859 }
03860 else
03861 {
03862 I_Out[0] = complex(0.0,0.0);
03863 }
03864 } else {
03865 p_in = 0;
03866 if ((phases & 0x01) == 0x01) {
03867 p_in += power_val[0].Re()/inv_eta;
03868 last_power[0] = -power_val[0];
03869 value_Power[0] = last_power[0];
03870 if (value_Circuit_V[0].Mag() > 0.0)
03871 {
03872 I_Out[0] = ~(power_val[0] / value_Circuit_V[0]);
03873 }
03874 else
03875 {
03876 I_Out[0] = complex(0.0,0.0);
03877 }
03878 }
03879 if ((phases & 0x02) == 0x02) {
03880 p_in += power_val[1].Re()/inv_eta;
03881 last_power[1] = -power_val[1];
03882 value_Power[1] = last_power[1];
03883 if (value_Circuit_V[1].Mag() > 0.0)
03884 {
03885 I_Out[1] = ~(power_val[1] / value_Circuit_V[1]);
03886 }
03887 else
03888 {
03889 I_Out[1] = complex(0.0,0.0);
03890 }
03891 }
03892 if ((phases & 0x04) == 0x04) {
03893 p_in += power_val[2].Re()/inv_eta;
03894 last_power[2] = -power_val[2];
03895 value_Power[2] = last_power[2];
03896 if (value_Circuit_V[2].Mag() > 0.0)
03897 {
03898 I_Out[2] = ~(power_val[2] / value_Circuit_V[2]);
03899 }
03900 else
03901 {
03902 I_Out[2] = complex(0.0,0.0);
03903 }
03904 }
03905 }
03906 }
03907
03908
03909 if (P_in < p_in) {
03910 gl_warning("DC maximum power output is less than the real power output from the inverter. A higher DC power rating is recommended. Currently the VSI power output is not limited by the DC power output.");
03911
03912
03913
03914
03915
03916 }
03917
03918 }
03919 }
03920 else
03921 {
03922
03923 if ((value_MeterStatus==1) && (inverter_1547_status==true))
03924 {
03925 if (inverter_type_v != FOUR_QUADRANT)
03926 {
03927
03928 if ((phases & 0x10) == 0x10)
03929 {
03930 value_Line12 = last_current[3];
03931 }
03932 else
03933 {
03934 value_Line_I[0] = last_current[0];
03935 value_Line_I[1] = last_current[1];
03936 value_Line_I[2] = last_current[2];
03937 }
03938 }
03939 else
03940 {
03941
03942 if ((phases & 0x10) == 0x10)
03943 {
03944 value_Power12 = last_power[3];
03945 }
03946 else
03947 {
03948 value_Power[0] = last_power[0];
03949 value_Power[1] = last_power[1];
03950 value_Power[2] = last_power[2];
03951 }
03952 }
03953 }
03954 else
03955 {
03956
03957 last_current[0] = 0.0;
03958 last_current[1] = 0.0;
03959 last_current[2] = 0.0;
03960 last_current[3] = 0.0;
03961
03962
03963 last_power[0] = 0.0;
03964 last_power[1] = 0.0;
03965 last_power[2] = 0.0;
03966 last_power[3] = 0.0;
03967 }
03968 }
03969
03970
03971 if (parent_is_a_meter == true)
03972 {
03973 push_complex_powerflow_values();
03974 }
03975
03976
03977 if (tret_value != TS_NEVER)
03978 {
03979 return -tret_value;
03980 }
03981 else
03982 {
03983 return TS_NEVER;
03984 }
03985 }
03986
03987
03988 TIMESTAMP inverter::postsync(TIMESTAMP t0, TIMESTAMP t1)
03989 {
03990 OBJECT *obj = OBJECTHDR(this);
03991 TIMESTAMP t2 = TS_NEVER;
03992 LOAD_FOLLOW_STATUS new_lf_status;
03993 PF_REG_STATUS new_pf_reg_status;
03994 double new_lf_dispatch_power, curr_power_val, diff_power_val;
03995 double new_pf_reg_distpatch_VAR, curr_real_power_val, curr_reactive_power_val, curr_pf, available_VA, new_Q_out, Q_out, Q_required, Q_available, Q_load;
03996 double scaling_factor, Q_target;
03997 complex temp_current_val[3];
03998 TIMESTAMP dt;
03999 double inputPower;
04000 complex temp_complex_value;
04001
04002
04003 if (parent_is_a_meter == true)
04004 {
04005 reset_complex_powerflow_accumulators();
04006
04007
04008 pull_complex_powerflow_values();
04009 }
04010
04011
04012 if ((inverter_type_v == FOUR_QUADRANT) && (four_quadrant_control_mode == FQM_LOAD_FOLLOWING) && (lf_dispatch_change_allowed==true))
04013 {
04014
04015 if (sense_is_link)
04016 {
04017
04018 ((void (*)(OBJECT *))(*powerCalc))(sense_object);
04019 }
04020
04021
04022 temp_complex_value = sense_power->get_complex();
04023 curr_power_val = temp_complex_value.Re();
04024
04025
04026 if (curr_power_val<=charge_on_threshold)
04027 {
04028
04029 if ((b_soc < 1.0) && (b_soc != -1))
04030 {
04031
04032 if (lf_dispatch_power < max_charge_rate)
04033 {
04034
04035 if (load_follow_status == DISCHARGE)
04036 {
04037
04038 new_lf_status = IDLE;
04039 new_lf_dispatch_power = 0.0;
04040 }
04041 else
04042 {
04043
04044 new_lf_status = CHARGE;
04045
04046
04047 diff_power_val = charge_on_threshold - curr_power_val;
04048
04049
04050 new_lf_dispatch_power = lf_dispatch_power + diff_power_val;
04051
04052
04053 if (new_lf_dispatch_power > max_charge_rate)
04054 {
04055 new_lf_dispatch_power = max_charge_rate;
04056 }
04057 }
04058 }
04059 else
04060 {
04061 new_lf_status = CHARGE;
04062 new_lf_dispatch_power = max_charge_rate;
04063 }
04064
04065 }
04066 else
04067 {
04068 gl_verbose("inverter:%s - charge desired, but battery full!",obj->name);
04069
04070
04071
04072
04073
04074 new_lf_status = IDLE;
04075 new_lf_dispatch_power = 0.0;
04076 }
04077 }
04078 else if (curr_power_val<=charge_off_threshold)
04079 {
04080 if (load_follow_status != CHARGE)
04081 {
04082 new_lf_status = IDLE;
04083 new_lf_dispatch_power = 0.0;
04084 }
04085 else
04086 {
04087
04088 if ((b_soc < 1.0) && (b_soc != -1))
04089 {
04090 new_lf_status = CHARGE;
04091
04092
04093 new_lf_dispatch_power = lf_dispatch_power;
04094 }
04095 else
04096 {
04097 gl_verbose("inverter:%s - charge desired, but battery full!",obj->name);
04098
04099
04100 new_lf_status = IDLE;
04101 new_lf_dispatch_power = 0.0;
04102 }
04103 }
04104 }
04105 else if (curr_power_val<=discharge_off_threshold)
04106 {
04107 new_lf_status = IDLE;
04108 new_lf_dispatch_power = 0.0;
04109 }
04110 else if (curr_power_val<=discharge_on_threshold)
04111 {
04112
04113 if (load_follow_status == DISCHARGE)
04114 {
04115
04116 if ((b_soc > soc_reserve) && (b_soc != -1))
04117 {
04118 new_lf_status = DISCHARGE;
04119
04120 new_lf_dispatch_power = lf_dispatch_power;
04121 }
04122 else
04123 {
04124 gl_verbose("inverter:%s - discharge desired, but not enough battery capacity!",obj->name);
04125
04126
04127
04128
04129
04130 new_lf_status = IDLE;
04131 new_lf_dispatch_power = 0.0;
04132 }
04133 }
04134 else
04135 {
04136 new_lf_status = IDLE;
04137 new_lf_dispatch_power = 0.0;
04138 }
04139 }
04140 else
04141 {
04142 new_lf_status = DISCHARGE;
04143
04144
04145 if ((b_soc > soc_reserve) && (b_soc != -1))
04146 {
04147
04148 if (load_follow_status == CHARGE)
04149 {
04150 new_lf_status = IDLE;
04151 new_lf_dispatch_power = 0.0;
04152 }
04153 else
04154 {
04155 new_lf_status = DISCHARGE;
04156
04157
04158 if (lf_dispatch_power > -max_discharge_rate)
04159 {
04160
04161 diff_power_val = discharge_on_threshold - curr_power_val;
04162
04163
04164 new_lf_dispatch_power = lf_dispatch_power + diff_power_val;
04165
04166
04167 if (new_lf_dispatch_power < -max_discharge_rate)
04168 {
04169 new_lf_dispatch_power = -max_discharge_rate;
04170 }
04171 }
04172 else
04173 {
04174 new_lf_dispatch_power = -max_discharge_rate;
04175 }
04176 }
04177 }
04178 else
04179 {
04180 gl_verbose("inverter:%s - discharge desired, but not enough battery capacity!",obj->name);
04181
04182
04183 new_lf_status = IDLE;
04184 new_lf_dispatch_power = 0.0;
04185 }
04186 }
04187
04188
04189 if (new_lf_status != load_follow_status)
04190 {
04191
04192 load_follow_status = new_lf_status;
04193
04194
04195 lf_dispatch_power = new_lf_dispatch_power;
04196
04197
04198 t2 = t1;
04199
04200
04201 if (new_lf_status == CHARGE)
04202 {
04203
04204 lf_dispatch_change_allowed = false;
04205
04206
04207 next_update_time = t1 + ((TIMESTAMP)(charge_lockout_time));
04208 }
04209 else if (new_lf_status == DISCHARGE)
04210 {
04211
04212 lf_dispatch_change_allowed = false;
04213
04214
04215 next_update_time = t1 + ((TIMESTAMP)(discharge_lockout_time));
04216 }
04217
04218 }
04219
04220
04221 if (new_lf_dispatch_power != lf_dispatch_power)
04222 {
04223
04224 if (fabs(new_lf_dispatch_power - lf_dispatch_power)>=0.001)
04225 {
04226
04227 lf_dispatch_power = new_lf_dispatch_power;
04228
04229
04230 t2 = t1;
04231
04232
04233 if (new_lf_status == CHARGE)
04234 {
04235
04236 lf_dispatch_change_allowed = false;
04237
04238
04239 next_update_time = t1 + ((TIMESTAMP)(charge_lockout_time));
04240 }
04241 else if (new_lf_status == DISCHARGE)
04242 {
04243
04244 lf_dispatch_change_allowed = false;
04245
04246
04247 next_update_time = t1 + ((TIMESTAMP)(discharge_lockout_time));
04248 }
04249
04250 }
04251
04252 }
04253
04254 }
04255
04256
04257
04258 if (inverter_type_v == FOUR_QUADRANT && four_quadrant_control_mode == FQM_GROUP_LF && lf_dispatch_change_allowed==true)
04259 {
04260
04261 if (sense_is_link)
04262 {
04263
04264 ((void (*)(OBJECT *))(*powerCalc))(sense_object);
04265 }
04266
04267
04268 temp_complex_value = sense_power->get_complex();
04269 curr_power_val = temp_complex_value.Re();
04270
04271
04272 if (curr_power_val<=charge_threshold)
04273 {
04274
04275 if ((b_soc < 1.0) && (b_soc != -1))
04276 {
04277
04278 if (lf_dispatch_power < max_charge_rate)
04279 {
04280
04281 if (load_follow_status == DISCHARGE)
04282 {
04283
04284 new_lf_status = IDLE;
04285 new_lf_dispatch_power = 0.0;
04286 }
04287 else
04288 {
04289
04290 new_lf_status = CHARGE;
04291
04292
04293 scaling_factor = (charge_threshold - curr_power_val)/(group_max_charge_rate);
04294 new_lf_dispatch_power = (scaling_factor * max_charge_rate) + lf_dispatch_power;
04295
04296
04297 if (new_lf_dispatch_power > max_charge_rate)
04298 {
04299 new_lf_dispatch_power = max_charge_rate;
04300 }
04301 }
04302 }
04303 else
04304 {
04305 new_lf_status = CHARGE;
04306 new_lf_dispatch_power = max_charge_rate;
04307 }
04308
04309 }
04310 else
04311 {
04312 gl_verbose("inverter:%s - charge desired, but battery full!",obj->name);
04313
04314
04315
04316
04317
04318 new_lf_status = IDLE;
04319 new_lf_dispatch_power = 0.0;
04320 }
04321 }
04322 else if (curr_power_val > charge_threshold && curr_power_val < discharge_threshold)
04323 {
04324 new_lf_status = IDLE;
04325 new_lf_dispatch_power = 0.00;
04326 }
04327 else if (curr_power_val >= discharge_threshold)
04328 {
04329 new_lf_status = DISCHARGE;
04330
04331
04332 if ((b_soc > soc_reserve) && (b_soc != -1))
04333 {
04334
04335 if (load_follow_status == CHARGE)
04336 {
04337 new_lf_status = IDLE;
04338 new_lf_dispatch_power = 0.0;
04339 }
04340 else
04341 {
04342 new_lf_status = DISCHARGE;
04343
04344
04345 if (lf_dispatch_power > -max_discharge_rate)
04346 {
04347
04348
04349 scaling_factor = (curr_power_val - discharge_threshold)/(group_max_discharge_rate);
04350 new_lf_dispatch_power = lf_dispatch_power + (scaling_factor * -max_charge_rate);
04351
04352
04353 if (new_lf_dispatch_power < -max_discharge_rate)
04354 {
04355 new_lf_dispatch_power = -max_discharge_rate;
04356 }
04357 }
04358 else
04359 {
04360 new_lf_dispatch_power = -max_discharge_rate;
04361 }
04362 }
04363 }
04364 else
04365 {
04366 gl_verbose("inverter:%s - discharge desired, but not enough battery capacity!",obj->name);
04367
04368
04369 new_lf_status = IDLE;
04370 new_lf_dispatch_power = 0.0;
04371 }
04372 }
04373
04374
04375 if (new_lf_status != load_follow_status)
04376 {
04377
04378 load_follow_status = new_lf_status;
04379
04380
04381 lf_dispatch_power = new_lf_dispatch_power;
04382
04383
04384 t2 = t1;
04385
04386
04387 if (new_lf_status == CHARGE)
04388 {
04389
04390 lf_dispatch_change_allowed = false;
04391
04392
04393 next_update_time = t1 + ((TIMESTAMP)(charge_lockout_time));
04394 }
04395 else if (new_lf_status == DISCHARGE)
04396 {
04397
04398 lf_dispatch_change_allowed = false;
04399
04400
04401 next_update_time = t1 + ((TIMESTAMP)(discharge_lockout_time));
04402 }
04403
04404 }
04405
04406
04407 if (new_lf_dispatch_power != lf_dispatch_power)
04408 {
04409
04410 if (fabs(new_lf_dispatch_power - lf_dispatch_power)>=0.001)
04411 {
04412
04413 lf_dispatch_power = new_lf_dispatch_power;
04414
04415
04416 t2 = t1;
04417
04418
04419 if (new_lf_status == CHARGE)
04420 {
04421
04422 lf_dispatch_change_allowed = false;
04423
04424
04425 next_update_time = t1 + ((TIMESTAMP)(charge_lockout_time));
04426 }
04427 else if (new_lf_status == DISCHARGE)
04428 {
04429
04430 lf_dispatch_change_allowed = false;
04431
04432
04433 next_update_time = t1 + ((TIMESTAMP)(discharge_lockout_time));
04434 }
04435
04436 }
04437
04438 }
04439
04440 }
04441 else if ((inverter_type_v == FOUR_QUADRANT) && ((four_quadrant_control_mode == FQM_VOLT_VAR) || (four_quadrant_control_mode == FQM_VOLT_WATT)))
04442 {
04443 if (four_quadrant_control_mode == FQM_VOLT_VAR)
04444 {
04445 if (t1 >= allowed_vv_action && (t1 > last_vv_check))
04446 {
04447 vv_operation = false;
04448 last_vv_check = t1;
04449 if ((phases & 0x10) == 0x10) {
04450 if((value_Circuit_V[0].Mag() / V_base) <= V1) {
04451 power_val[0].SetImag(Q1 * p_rated);
04452 } else if ((value_Circuit_V[0].Mag() / V_base) <= V2 && V1 < (value_Circuit_V[0].Mag() / V_base)) {
04453 power_val[0].SetImag(lin_eq_volt((value_Circuit_V[0].Mag() / V_base), m12, b12) * p_rated);
04454 } else if ((value_Circuit_V[0].Mag() / V_base) <= V3 && V2 < (value_Circuit_V[0].Mag() / V_base)) {
04455 power_val[0].SetImag(lin_eq_volt((value_Circuit_V[0].Mag() / V_base), m23, b23) * p_rated);
04456 } else if ((value_Circuit_V[0].Mag() / V_base) <= V4 && V3 < (value_Circuit_V[0].Mag() / V_base)) {
04457 power_val[0].SetImag(lin_eq_volt((value_Circuit_V[0].Mag() / V_base), m34, b34) * p_rated);
04458 } else if (V4 < (value_Circuit_V[0].Mag() / V_base)) {
04459 power_val[0].SetImag(Q4 * p_rated);
04460 }
04461 if (last_power->Im() != power_val[0].Im()) {
04462 vv_operation = true;
04463 }
04464 VA_Out = power_val[0];
04465 } else {
04466 if ((phases & 0x01) == 0x01) {
04467 if((value_Circuit_V[0].Mag() / V_base) <= V1) {
04468 power_val[0].SetImag(Q1 * p_rated);
04469 } else if ((value_Circuit_V[0].Mag() / V_base) <= V2 && V1 < (value_Circuit_V[0].Mag() / V_base)) {
04470 power_val[0].SetImag(lin_eq_volt((value_Circuit_V[0].Mag() / V_base), m12, b12) * p_rated);
04471 } else if ((value_Circuit_V[0].Mag() / V_base) <= V3 && V2 < (value_Circuit_V[0].Mag() / V_base)) {
04472 power_val[0].SetImag(lin_eq_volt((value_Circuit_V[0].Mag() / V_base), m23, b23) * p_rated);
04473 } else if ((value_Circuit_V[0].Mag() / V_base) <= V4 && V3 < (value_Circuit_V[0].Mag() / V_base)) {
04474 power_val[0].SetImag(lin_eq_volt((value_Circuit_V[0].Mag() / V_base), m34, b34) * p_rated);
04475 } else if (V4 < (value_Circuit_V[0].Mag() / V_base)) {
04476 power_val[0].SetImag(Q4 * p_rated);
04477 }
04478 if (last_power[0].Im() != power_val[0].Im()) {
04479 vv_operation = true;
04480 }
04481 }
04482 if ((phases & 0x02) == 0x02) {
04483 if((value_Circuit_V[1].Mag() / V_base) <= V1) {
04484 power_val[1].SetImag(Q1 * p_rated);
04485 } else if ((value_Circuit_V[1].Mag() / V_base) <= V2 && V1 < (value_Circuit_V[1].Mag() / V_base)) {
04486 power_val[1].SetImag(lin_eq_volt((value_Circuit_V[1].Mag() / V_base), m12, b12) * p_rated);
04487 } else if ((value_Circuit_V[1].Mag() / V_base) <= V3 && V2 < (value_Circuit_V[1].Mag() / V_base)) {
04488 power_val[1].SetImag(lin_eq_volt((value_Circuit_V[1].Mag() / V_base), m23, b23) * p_rated);
04489 } else if ((value_Circuit_V[1].Mag() / V_base) <= V4 && V3 < (value_Circuit_V[1].Mag() / V_base)) {
04490 power_val[1].SetImag(lin_eq_volt((value_Circuit_V[1].Mag() / V_base), m34, b34) * p_rated);
04491 } else if (V4 < (value_Circuit_V[1].Mag() / V_base)) {
04492 power_val[1].SetImag(Q4 * p_rated);
04493 }
04494 if (last_power[1].Im() != power_val[1].Im()) {
04495 vv_operation = true;
04496 }
04497 }
04498 if ((phases & 0x04) == 0x04) {
04499 if((value_Circuit_V[2].Mag() / V_base) <= V1) {
04500 power_val[2].SetImag(Q1 * p_rated);
04501 } else if ((value_Circuit_V[2].Mag() / V_base) <= V2 && V1 < (value_Circuit_V[2].Mag() / V_base)) {
04502 power_val[2].SetImag(lin_eq_volt((value_Circuit_V[2].Mag() / V_base), m12, b12) * p_rated);
04503 } else if ((value_Circuit_V[2].Mag() / V_base) <= V3 && V2 < (value_Circuit_V[2].Mag() / V_base)) {
04504 power_val[2].SetImag(lin_eq_volt((value_Circuit_V[2].Mag() / V_base), m23, b23) * p_rated);
04505 } else if ((value_Circuit_V[2].Mag() / V_base) <= V4 && V3 < (value_Circuit_V[2].Mag() / V_base)) {
04506 power_val[2].SetImag(lin_eq_volt((value_Circuit_V[2].Mag() / V_base), m34, b34) * p_rated);
04507 } else if (V4 < (value_Circuit_V[2].Mag() / V_base)) {
04508 power_val[2].SetImag(Q4 * p_rated);
04509 }
04510 if (last_power[2].Im() != power_val[2].Im()) {
04511 vv_operation = true;
04512 }
04513 }
04514 VA_Out = power_val[0] + power_val[1] + power_val[2];
04515 }
04516 if (vv_operation) {
04517 t2 = t1;
04518 allowed_vv_action = (TIMESTAMP)floor((double)t1 + vv_lockout + 0.5);
04519 }
04520 }
04521 }
04522 else if (four_quadrant_control_mode == FQM_VOLT_WATT)
04523 {
04524 if (t1 >= allowed_vv_action && (t1 > last_vv_check))
04525 {
04526 vv_operation = false;
04527 last_vv_check = t1;
04528 double vpu;
04529 pa_vw_limited = pb_vw_limited = pc_vw_limited = p_rated;
04530 if ((phases & 0x10) == 0x10) {
04531 vpu = value_Circuit_V[0].Mag() / V_base;
04532 if (vpu > VW_V1) {
04533 pa_vw_limited = p_rated * (1.0 + VW_m * (vpu - VW_V1));
04534 if (pa_vw_limited < 0.0) pa_vw_limited = 0.0;
04535 if (power_val[0].Re() > pa_vw_limited) power_val[0].SetReal (pa_vw_limited);
04536 }
04537 if (last_power->Re() != power_val[0].Re()) {
04538 vv_operation = true;
04539 }
04540 VA_Out = power_val[0];
04541 } else {
04542 if ((phases & 0x01) == 0x01) {
04543 vpu = value_Circuit_V[0].Mag() / V_base;
04544 if (vpu > VW_V1) {
04545 pa_vw_limited = p_rated * (1.0 + VW_m * (vpu - VW_V1));
04546 if (pa_vw_limited < 0.0) pa_vw_limited = 0.0;
04547 if (power_val[0].Re() > pa_vw_limited) power_val[0].SetReal (pa_vw_limited);
04548 }
04549 if (last_power[0].Re() != power_val[0].Re()) {
04550 vv_operation = true;
04551 }
04552 }
04553 if ((phases & 0x02) == 0x02) {
04554 vpu = value_Circuit_V[1].Mag() / V_base;
04555 if (vpu > VW_V1) {
04556 pb_vw_limited = p_rated * (1.0 + VW_m * (vpu - VW_V1));
04557 if (pb_vw_limited < 0.0) pb_vw_limited = 0.0;
04558 if (power_val[1].Re() > pb_vw_limited) power_val[1].SetReal (pb_vw_limited);
04559 }
04560 if (last_power[1].Re() != power_val[1].Re()) {
04561 vv_operation = true;
04562 }
04563 }
04564 if ((phases & 0x04) == 0x04) {
04565 vpu = value_Circuit_V[2].Mag() / V_base;
04566 if (vpu > VW_V1) {
04567 pc_vw_limited = p_rated * (1.0 + VW_m * (vpu - VW_V1));
04568 if (pc_vw_limited < 0.0) pc_vw_limited = 0.0;
04569 if (power_val[2].Re() > pc_vw_limited) power_val[2].SetReal (pc_vw_limited);
04570 }
04571 if (last_power[2].Re() != power_val[2].Re()) {
04572 vv_operation = true;
04573 }
04574 }
04575 VA_Out = power_val[0] + power_val[1] + power_val[2];
04576 }
04577 if (vv_operation) {
04578 t2 = t1;
04579 allowed_vv_action = (TIMESTAMP)floor((double)t1 + vv_lockout + 0.5);
04580 }
04581 }
04582 }
04583 }
04584
04585
04586
04587 if ((inverter_type_v == FOUR_QUADRANT) && (pf_reg != EXCLUDED) && (pf_reg_dispatch_change_allowed==true))
04588 {
04589
04590
04591 if (sense_is_link)
04592 {
04593
04594 ((void (*)(OBJECT *))(*powerCalc))(sense_object);
04595 }
04596
04597
04598 temp_complex_value = sense_power->get_complex();
04599 curr_real_power_val = temp_complex_value.Re();
04600 curr_reactive_power_val = temp_complex_value.Im();
04601 curr_pf = fabs(curr_real_power_val)/sqrt((curr_reactive_power_val*curr_reactive_power_val)+(curr_real_power_val * curr_real_power_val));
04602
04603 if (pf_reg == INCLUDED)
04604 {
04605
04606 if ( (curr_pf <= pf_reg_activate) ||
04607 ((curr_pf >= pf_reg_activate) && (curr_pf <= pf_reg_deactivate) && (pf_reg_status == REGULATING)) ||
04608 ((curr_reactive_power_val < 0) && (curr_pf < 0.98)) )
04609 {
04610
04611
04612 if ((inverter_type_v == FOUR_QUADRANT) && (VA_Out.Mag() <= p_max))
04613 {
04614 new_pf_reg_status = REGULATING;
04615
04616
04617
04618 if (curr_reactive_power_val < 0)
04619 {
04620 if (four_quadrant_control_mode == FQM_GROUP_LF)
04621 {
04622 if ((pf_reg_dispatch_VAR * group_rated_power/p_max) > fabs(curr_reactive_power_val))
04623 {
04624 Q_target = - (curr_reactive_power_val - pf_reg_dispatch_VAR);
04625 }
04626 else
04627 {
04628 Q_target = - (curr_reactive_power_val - (pf_reg_dispatch_VAR * group_rated_power/p_max));
04629 }
04630
04631 }
04632 else
04633 {
04634 Q_target = - (curr_reactive_power_val - pf_reg_dispatch_VAR);
04635 }
04636
04637 }
04638 else
04639 {
04640 Q_target = - (curr_reactive_power_val - curr_real_power_val * tan(acos(pf_reg_deactivate)));
04641 }
04642
04643
04644 if (four_quadrant_control_mode == FQM_GROUP_LF)
04645 {
04646 scaling_factor = (Q_target - curr_reactive_power_val)/group_rated_power;
04647 Q_out = (scaling_factor * p_max) + pf_reg_dispatch_VAR;
04648 }
04649 else
04650 {
04651 Q_out = Q_target;
04652 }
04653
04654
04655 Q_available = sqrt((p_max*p_max) - (VA_Out.Re()*VA_Out.Re()));
04656
04657
04658 if (fabs(Q_out) <= fabs(Q_available))
04659 {
04660 new_pf_reg_distpatch_VAR = Q_out;
04661 }
04662 else
04663 {
04664 if (Q_out < 0)
04665 {
04666 new_pf_reg_distpatch_VAR = -Q_available;
04667 }
04668 else
04669 {
04670 new_pf_reg_distpatch_VAR = Q_available;
04671 }
04672 }
04673 }
04674 else
04675 {
04676 new_pf_reg_status = REGULATING;
04677 new_pf_reg_distpatch_VAR = -VA_Out.Im();
04678 }
04679 }
04680 else if (curr_pf >= pf_reg_deactivate)
04681
04682
04683
04684 {
04685 new_pf_reg_status = IDLING;
04686 new_pf_reg_distpatch_VAR = pf_reg_dispatch_VAR;
04687 }
04688 else
04689 {
04690 new_pf_reg_status = IDLING;
04691 new_pf_reg_distpatch_VAR = pf_reg_dispatch_VAR;
04692 }
04693 }
04694 else if (pf_reg == INCLUDED_ALT)
04695 {
04696
04697 Q_target = pf_reg_dispatch_VAR;
04698
04699
04700 if (VA_Out.Mag() <= p_max)
04701 {
04702
04703 if (curr_reactive_power_val < 0.0)
04704 {
04705 curr_pf = -1.0 * curr_pf;
04706 }
04707
04708
04709 if (curr_real_power_val < 0.0)
04710 {
04711 curr_real_power_val = -1.0 * curr_real_power_val;
04712 }
04713
04714
04715 if (pf_target_var < 0)
04716 {
04717
04718 if (pf_reg_low < 0.0)
04719 {
04720 if (pf_reg_high < 0.0)
04721 {
04722
04723 if (((curr_pf < 0.0) && (curr_pf <= pf_reg_high)) || (curr_pf > 0.0))
04724 {
04725
04726 new_pf_reg_status = REGULATING;
04727
04728
04729 Q_target = -(curr_reactive_power_val - (curr_real_power_val * tan(acos(pf_reg_high)))) + pf_reg_dispatch_VAR;
04730 }
04731 else if (curr_pf <= pf_reg_low)
04732 {
04733
04734 new_pf_reg_status = IDLING;
04735
04736
04737 Q_target = pf_reg_dispatch_VAR;
04738 }
04739 else
04740 {
04741
04742 new_pf_reg_status = REGULATING;
04743
04744
04745 Q_target = -(curr_reactive_power_val - (curr_real_power_val * tan(acos(pf_target_var)))) + pf_reg_dispatch_VAR;
04746 }
04747 }
04748 else
04749 {
04750 if ((curr_pf > 0.0) && (curr_pf <= pf_reg_high))
04751 {
04752
04753 new_pf_reg_status = REGULATING;
04754
04755
04756 Q_target = -(curr_reactive_power_val - (curr_real_power_val * tan(acos(pf_target_var)))) + pf_reg_dispatch_VAR;
04757 }
04758 else if (((curr_pf < 0.0) && (curr_pf <= pf_reg_low)) || ((curr_pf > 0.0) && (curr_pf >= pf_reg_high)))
04759 {
04760
04761 new_pf_reg_status = IDLING;
04762
04763
04764 Q_target = pf_reg_dispatch_VAR;
04765 }
04766 else
04767 {
04768
04769 new_pf_reg_status = REGULATING;
04770
04771
04772 Q_target = -(curr_reactive_power_val - (curr_real_power_val * tan(acos(pf_target_var)))) + pf_reg_dispatch_VAR;
04773 }
04774 }
04775 }
04776 else
04777 {
04778 if ((curr_pf > 0.0) && (curr_pf <= pf_reg_high))
04779 {
04780
04781 new_pf_reg_status = REGULATING;
04782
04783
04784 Q_target = -(curr_reactive_power_val - (curr_real_power_val * tan(acos(pf_target_var)))) + pf_reg_dispatch_VAR;
04785 }
04786 else if ((curr_pf > 0.0) && (curr_pf <= pf_reg_low))
04787 {
04788
04789 new_pf_reg_status = IDLING;
04790
04791
04792 Q_target = pf_reg_dispatch_VAR;
04793 }
04794 else
04795 {
04796
04797 new_pf_reg_status = REGULATING;
04798
04799
04800
04801 Q_target = -(curr_reactive_power_val - (curr_real_power_val * tan(acos(pf_target_var)))) + pf_reg_dispatch_VAR;
04802 }
04803 }
04804 }
04805 else
04806 {
04807 if (pf_reg_low < 0.0)
04808 {
04809 if ((curr_pf < 0.0) && (curr_pf >= pf_reg_high))
04810 {
04811
04812 new_pf_reg_status = REGULATING;
04813
04814
04815 Q_target = -(curr_reactive_power_val - (curr_real_power_val * tan(acos(pf_target_var)))) + pf_reg_dispatch_VAR;
04816 }
04817 else if ((curr_pf < 0.0) && (curr_pf >= pf_reg_low))
04818 {
04819
04820 new_pf_reg_status = IDLING;
04821
04822
04823 Q_target = pf_reg_dispatch_VAR;
04824 }
04825 else
04826 {
04827
04828 new_pf_reg_status = REGULATING;
04829
04830
04831
04832 Q_target = -(curr_reactive_power_val - (curr_real_power_val * tan(acos(pf_target_var)))) + pf_reg_dispatch_VAR;
04833 }
04834 }
04835 else
04836 {
04837 if (pf_reg_high < 0.0)
04838 {
04839 if ((curr_pf < 0.0) && (curr_pf >= pf_reg_high))
04840 {
04841
04842 new_pf_reg_status = REGULATING;
04843
04844
04845 Q_target = -(curr_reactive_power_val - (curr_real_power_val * tan(acos(pf_target_var)))) + pf_reg_dispatch_VAR;
04846 }
04847 else if (((curr_pf < 0.0) && (curr_pf <= pf_reg_high)) || ((curr_pf > 0.0) && (curr_pf >= pf_reg_low)))
04848 {
04849
04850 new_pf_reg_status = IDLING;
04851
04852
04853 Q_target = pf_reg_dispatch_VAR;
04854 }
04855 else
04856 {
04857
04858 new_pf_reg_status = REGULATING;
04859
04860
04861 Q_target = -(curr_reactive_power_val - (curr_real_power_val * tan(acos(pf_target_var)))) + pf_reg_dispatch_VAR;
04862 }
04863 }
04864 else
04865 {
04866 if ((curr_pf < 0.0) || ((curr_pf > 0.0) && (curr_pf >= pf_reg_high)))
04867 {
04868
04869 new_pf_reg_status = REGULATING;
04870
04871
04872 Q_target = -(curr_reactive_power_val - (curr_real_power_val * tan(acos(pf_target_var)))) + pf_reg_dispatch_VAR;
04873 }
04874 else if (curr_pf >= pf_reg_low)
04875 {
04876
04877 new_pf_reg_status = IDLING;
04878
04879
04880 Q_target = pf_reg_dispatch_VAR;
04881 }
04882 else
04883 {
04884
04885 new_pf_reg_status = REGULATING;
04886
04887
04888 Q_target = -(curr_reactive_power_val - (curr_real_power_val * tan(acos(pf_target_var)))) + pf_reg_dispatch_VAR;
04889 }
04890 }
04891 }
04892 }
04893 }
04894 else
04895 {
04896 new_pf_reg_status = IDLING;
04897 new_pf_reg_distpatch_VAR = 0.0;
04898 }
04899 }
04900
04901
04902
04903 if (new_pf_reg_status != pf_reg_status)
04904 {
04905
04906 pf_reg_status = new_pf_reg_status;
04907
04908
04909 pf_reg_dispatch_VAR = new_pf_reg_distpatch_VAR;
04910
04911
04912 t2 = t1;
04913
04914
04915 if (new_pf_reg_status == REGULATING)
04916 {
04917
04918 pf_reg_dispatch_change_allowed = false;
04919
04920
04921 pf_reg_next_update_time = t1 + ((TIMESTAMP)(pf_reg_activate_lockout_time));
04922 }
04923 }
04924
04925
04926 if (new_pf_reg_distpatch_VAR != pf_reg_dispatch_VAR)
04927 {
04928
04929 if (fabs(new_pf_reg_distpatch_VAR - pf_reg_dispatch_VAR)>=0.001)
04930 {
04931
04932 pf_reg_dispatch_VAR = new_pf_reg_distpatch_VAR;
04933
04934
04935 t2 = t1;
04936
04937
04938 if (new_pf_reg_status == REGULATING)
04939 {
04940
04941 pf_reg_dispatch_change_allowed = false;
04942
04943
04944 pf_reg_next_update_time = t1 + ((TIMESTAMP)(pf_reg_activate_lockout_time));
04945 }
04946
04947 }
04948 }
04949 }
04950
04951 if (inverter_type_v != FOUR_QUADRANT)
04952 {
04953 if ((phases & 0x10) == 0x10)
04954 {
04955 value_Line12 = -last_current[3];
04956 }
04957 else
04958 {
04959
04960 value_Line_I[0] = -last_current[0];
04961 value_Line_I[1] = -last_current[1];
04962 value_Line_I[2] = -last_current[2];
04963 }
04964 }
04965 else
04966 {
04967 if ((four_quadrant_control_mode != FQM_VOLT_VAR) && (four_quadrant_control_mode != FQM_VSI) && (four_quadrant_control_mode != FQM_VOLT_WATT)) {
04968 if ((phases & 0x10) == 0x10)
04969 {
04970 if (deltamode_inclusive == true)
04971 {
04972 value_Line_unrotI[0] = -last_current[3];
04973 }
04974 else
04975 {
04976 value_Power12 = -last_power[3];
04977 }
04978 }
04979 else
04980 {
04981 if (deltamode_inclusive == true)
04982 {
04983 value_Line_unrotI[0] = -last_current[0];
04984 value_Line_unrotI[1] = -last_current[1];
04985 value_Line_unrotI[2] = -last_current[2];
04986 }
04987 else
04988 {
04989 value_Power[0] = -last_power[0];
04990 value_Power[1] = -last_power[1];
04991 value_Power[2] = -last_power[2];
04992 }
04993 }
04994 }
04995
04996 else if (four_quadrant_control_mode == FQM_VSI) {
04997
04998
04999 if ((phases & 0x10) == 0x10)
05000 {
05001
05002
05003 temp_current_val[0] = value_IGenerated[0] - generator_admittance[0][0]*value_Circuit_V[0];
05004
05005
05006 VA_Out = value_Circuit_V[0]*~temp_current_val[0];
05007
05008 }
05009 else
05010 {
05011
05012
05013 temp_current_val[0] = (value_IGenerated[0] - generator_admittance[0][0]*value_Circuit_V[0] - generator_admittance[0][1]*value_Circuit_V[1] - generator_admittance[0][2]*value_Circuit_V[2]);
05014 temp_current_val[1] = (value_IGenerated[1] - generator_admittance[1][0]*value_Circuit_V[0] - generator_admittance[1][1]*value_Circuit_V[1] - generator_admittance[1][2]*value_Circuit_V[2]);
05015 temp_current_val[2] = (value_IGenerated[2] - generator_admittance[2][0]*value_Circuit_V[0] - generator_admittance[2][1]*value_Circuit_V[1] - generator_admittance[2][2]*value_Circuit_V[2]);
05016
05017
05018 power_val[0] = value_Circuit_V[0]*~temp_current_val[0];
05019 power_val[1] = value_Circuit_V[1]*~temp_current_val[1];
05020 power_val[2] = value_Circuit_V[2]*~temp_current_val[2];
05021
05022 VA_Out = power_val[0] + power_val[1] + power_val[2];
05023 }
05024
05025 if (first_run == true)
05026 {
05027
05028 if (value_IGenerated[0] != complex(0.0,0.0)) {
05029 if ((VSI_bustype == 2) && (VSI_mode == VSI_DROOP)) {
05030 P_Out = VA_Out.Re();
05031 Q_Out = VA_Out.Im();
05032 first_run = false;
05033 }
05034 else {
05035 first_run = false;
05036 }
05037
05038 if (VSI_esource_init == false) {
05039 VSI_esource_init = true;
05040 }
05041 }
05042 }
05043 else {
05044
05045 if (fabs(VA_Out_past.Mag() - VA_Out.Mag()) > 1000) {
05046 schedule_deltamode_start(t0);
05047 }
05048 }
05049
05050 VA_Out_past = VA_Out;
05051 }
05052
05053 }
05054
05055
05056 if (parent_is_a_meter == true)
05057 {
05058 push_complex_powerflow_values();
05059 }
05060
05061 return t2;
05062 }
05063
05065
05067
05068 STATUS inverter::pre_deltaupdate(TIMESTAMP t0, unsigned int64 delta_time)
05069 {
05070 STATUS stat_val;
05071 FUNCTIONADDR funadd = NULL;
05072 OBJECT *hdr = OBJECTHDR(this);
05073
05074
05075 if (inverter_dyn_mode == PI_CONTROLLER)
05076 {
05077
05078 stat_val = init_PI_dynamics(&curr_state);
05079 }
05080 else if (inverter_dyn_mode == PID_CONTROLLER)
05081 {
05082
05083 stat_val = init_PID_dynamics();
05084 }
05085 else
05086 {
05087 stat_val = SUCCESS;
05088 }
05089
05090 if (stat_val != SUCCESS)
05091 {
05092 gl_error("Inverter failed pre_deltaupdate call");
05093
05094
05095
05096
05097
05098 return FAILED;
05099 }
05100
05101 if (four_quadrant_control_mode == FQM_VSI)
05102 {
05103
05104
05105 funadd = (FUNCTIONADDR)(gl_get_function(hdr->parent,"pwr_object_swing_swapper"));
05106
05107
05108 if (funadd==NULL)
05109 {
05110 gl_error("inverter:%s -- Failed to find node swing swapper function",(hdr->name ? hdr->name : "Unnamed"));
05111
05112
05113
05114
05115
05116
05117 return FAILED;
05118 }
05119
05120
05121 stat_val = ((STATUS (*)(OBJECT *, bool))(*funadd))(hdr->parent,false);
05122
05123 if (stat_val == 0)
05124 {
05125 gl_error("Failed to swap SWING status of node:%s on inverter:%s",(hdr->parent->name ? hdr->parent->name : "Unnamed"),(hdr->name ? hdr->name : "Unnamed"));
05126
05127
05128
05129
05130
05131 return FAILED;
05132 }
05133 }
05134
05135
05136 return SUCCESS;
05137 }
05138
05139
05140 SIMULATIONMODE inverter::inter_deltaupdate(unsigned int64 delta_time, unsigned long dt, unsigned int iteration_count_val)
05141 {
05142 double deltat, deltath;
05143 unsigned char pass_mod;
05144 int indexval;
05145 complex derror[3];
05146 complex pid_out[3];
05147 double temp_val_d, temp_val_q;
05148 complex work_power_vals;
05149 double power_diff_val;
05150 double prev_error_ed;
05151 double prev_error_eq;
05152 bool deltaConverged = false;
05153 bool ramp_change;
05154 int i;
05155 complex temp_current_val[3];
05156 double inputPower;
05157 gld_wlock *test_rlock;
05158
05159 SIMULATIONMODE simmode_return_value = SM_EVENT;
05160
05161
05162 if (parent_is_a_meter == true)
05163 {
05164 reset_complex_powerflow_accumulators();
05165
05166 pull_complex_powerflow_values();
05167 }
05168
05169
05170 deltat = (double)dt/(double)DT_SECOND;
05171 deltath = deltat/2.0;
05172
05173
05174 pass_mod = iteration_count_val - ((iteration_count_val >> 1) << 1);
05175
05176 if (prev_time_dbl != gl_globaldeltaclock)
05177 {
05178
05179 prev_time_dbl = gl_globaldeltaclock;
05180 }
05181
05182
05183 if ((enable_1547_compliance == true) && (iteration_count_val == 0))
05184 {
05185
05186 ieee_1547_double = perform_1547_checks(deltat);
05187 }
05188
05189
05190 if (inverter_1547_status == true)
05191 {
05192
05193 if (inverter_dyn_mode == PI_CONTROLLER)
05194 {
05195 if (inverter_type_v == FOUR_QUADRANT && four_quadrant_control_mode == FQM_VSI) {
05196
05197
05198 if ((delta_time==0) && (iteration_count_val==0))
05199 {
05200 if (Tp_delay == 0 || Tp_delay < deltat) {
05201 Tp_delay = deltat;
05202 }
05203
05204 if (Tq_delay == 0 || Tq_delay < deltat) {
05205 Tq_delay = deltat;
05206 }
05207 }
05208
05209
05210 if (pass_mod==0)
05211 {
05212
05213 if((phases & 0x10) == 0x10) {
05214
05215
05216 temp_current_val[0] = value_IGenerated[0] - generator_admittance[0][0]*value_Circuit_V[0];
05217
05218
05219 VA_Out = value_Circuit_V[0] * ~temp_current_val[0];
05220
05221
05222 if (checkRampRate_real == true)
05223 {
05224
05225 power_diff_val = (VA_Out.Re() - prev_VA_out[0].Re()) / deltat;
05226
05227
05228 if (VA_Out.Re() > prev_VA_out[0].Re())
05229 {
05230
05231 if (power_diff_val > rampUpRate_real)
05232 {
05233 VA_Out.SetReal(prev_VA_out[0].Re() + (rampUpRate_real * deltat));
05234 }
05235
05236 }
05237 else
05238 {
05239
05240 if (power_diff_val < -rampDownRate_real)
05241 {
05242 VA_Out.SetReal(prev_VA_out[0].Re() - (rampDownRate_real * deltat));
05243 }
05244
05245 }
05246
05247
05248 curr_VA_out[0] = VA_Out;
05249 }
05250
05251
05252 curr_state.dp_mea_delayed = 1.0/Tp_delay*(VA_Out.Re() - curr_state.p_mea_delayed);
05253 curr_state.dq_mea_delayed = 1.0/Tq_delay*(VA_Out.Im() - curr_state.q_mea_delayed);
05254
05255
05256 pred_state.p_mea_delayed = curr_state.p_mea_delayed + (deltat * curr_state.dp_mea_delayed);
05257 pred_state.q_mea_delayed = curr_state.q_mea_delayed + (deltat * curr_state.dq_mea_delayed);
05258
05259
05260 if (VSI_mode == VSI_ISOCHRONOUS) {
05261
05262
05263 pred_state.dV_StateVal[0] = (V_mag_ref[0] - value_Circuit_V[0].Mag()) * ki_Vterminal;
05264 pred_state.V_StateVal[0] = curr_state.V_StateVal[0] + pred_state.dV_StateVal[0] * deltat;
05265 pred_state.e_source_mag[0] = pred_state.V_StateVal[0] + pred_state.dV_StateVal[0] * kp_Vterminal / ki_Vterminal;
05266 e_source[0] = complex(pred_state.e_source_mag[0] * cos(V_angle[0]), pred_state.e_source_mag[0] * sin(V_angle[0]));
05267
05268
05269 value_IGenerated[0] = e_source[0]/(complex(Rfilter,Xfilter) * Zbase);
05270 }
05271
05272
05273 else if (VSI_mode == VSI_DROOP) {
05274
05275
05276 double delta_f = (curr_state.p_mea_delayed - Pref) / p_rated * (R_fp/(2.0 * PI));
05277
05278
05279 pred_state.dfmax_ini_StateVal = (Pmax - curr_state.p_mea_delayed / p_rated) * kipmax / (2.0 * PI);
05280 pred_state.fmax_ini_StateVal = curr_state.fmax_ini_StateVal + pred_state.dfmax_ini_StateVal * deltat;
05281
05282
05283 if (pred_state.fmax_ini_StateVal > 0.0){
05284
05285 pred_state.fmax_ini_StateVal = 0.0;
05286
05287 }
05288
05289
05290 pred_state.fmax_StateVal = pred_state.fmax_ini_StateVal + pred_state.dfmax_ini_StateVal * kppmax / (2.0 * PI) / kipmax;
05291
05292 if (pred_state.fmax_StateVal > 0.0){
05293
05294 pred_state.fmax_StateVal = 0.0;
05295
05296 }
05297
05298
05299
05300
05301 pred_state.dfmin_ini_StateVal = (Pmin - curr_state.p_mea_delayed / p_rated) * kipmax / (2.0 * PI);
05302 pred_state.fmin_ini_StateVal = curr_state.fmin_ini_StateVal + pred_state.dfmin_ini_StateVal * deltat;
05303
05304
05305 if (pred_state.fmin_ini_StateVal < 0.0){
05306
05307 pred_state.fmin_ini_StateVal = 0.0;
05308
05309 }
05310
05311
05312 pred_state.fmin_StateVal = pred_state.fmin_ini_StateVal + pred_state.dfmin_ini_StateVal * kppmax / (2.0 * PI) / kipmax;
05313
05314 if (pred_state.fmin_StateVal < 0.0){
05315
05316 pred_state.fmin_StateVal = 0.0;
05317
05318 }
05319
05320 VSI_freq = freq_ref - delta_f + pred_state.fmax_StateVal + pred_state.fmin_StateVal;
05321
05322
05323 V_angle[0] = V_angle[0] - (delta_f - pred_state.fmax_StateVal - pred_state.fmin_StateVal) * 2.0 * PI * deltat;
05324
05325
05326 V_mag[0] = V_mag_ref[0] - (pred_state.q_mea_delayed - Qref) / p_rated * R_vq * node_nominal_voltage;
05327
05328
05329 pred_state.dV_StateVal[0] = (V_mag[0] - value_Circuit_V[0].Mag()) * ki_Vterminal;
05330 pred_state.V_StateVal[0] = curr_state.V_StateVal[0] + pred_state.dV_StateVal[0] * deltat;
05331 pred_state.e_source_mag[0] = pred_state.V_StateVal[0] + pred_state.dV_StateVal[0] * kp_Vterminal / ki_Vterminal;
05332 e_source[0] = complex(pred_state.e_source_mag[0] * cos(V_angle[0]), pred_state.e_source_mag[0] * sin(V_angle[0]));
05333
05334
05335 value_IGenerated[0] = e_source[0]/(complex(Rfilter,Xfilter) * Zbase);
05336 }
05337 }
05338
05339
05340 if((phases & 0x07) == 0x07) {
05341
05342
05343 temp_current_val[0] = (value_IGenerated[0] - generator_admittance[0][0]*value_Circuit_V[0] - generator_admittance[0][1]*value_Circuit_V[1] - generator_admittance[0][2]*value_Circuit_V[2]);
05344 temp_current_val[1] = (value_IGenerated[1] - generator_admittance[1][0]*value_Circuit_V[0] - generator_admittance[1][1]*value_Circuit_V[1] - generator_admittance[1][2]*value_Circuit_V[2]);
05345 temp_current_val[2] = (value_IGenerated[2] - generator_admittance[2][0]*value_Circuit_V[0] - generator_admittance[2][1]*value_Circuit_V[1] - generator_admittance[2][2]*value_Circuit_V[2]);
05346
05347
05348 power_val[0] = value_Circuit_V[0]*~temp_current_val[0];
05349 power_val[1] = value_Circuit_V[1]*~temp_current_val[1];
05350 power_val[2] = value_Circuit_V[2]*~temp_current_val[2];
05351
05352 VA_Out = power_val[0] + power_val[1] + power_val[2];
05353 pCircuit_V_Avg = (value_Circuit_V[0].Mag() + value_Circuit_V[1].Mag() + value_Circuit_V[2].Mag() ) / 3.0;
05354
05355
05356 curr_state.dp_mea_delayed = 1.0/Tp_delay*(VA_Out.Re() - curr_state.p_mea_delayed);
05357 curr_state.dq_mea_delayed = 1.0/Tq_delay*(VA_Out.Im() - curr_state.q_mea_delayed);
05358
05359
05360 pred_state.p_mea_delayed = curr_state.p_mea_delayed + (deltat * curr_state.dp_mea_delayed);
05361 pred_state.q_mea_delayed = curr_state.q_mea_delayed + (deltat * curr_state.dq_mea_delayed);
05362
05363
05364 if (VSI_mode == VSI_ISOCHRONOUS) {
05365
05366 for(i = 0; i < 3; i++) {
05367 pred_state.dV_StateVal[i] = (V_mag_ref[i] - value_Circuit_V[i].Mag()) * ki_Vterminal;
05368 pred_state.V_StateVal[i] = curr_state.V_StateVal[i] + pred_state.dV_StateVal[i] * deltat;
05369 pred_state.e_source_mag[i] = pred_state.V_StateVal[i] + pred_state.dV_StateVal[i] * kp_Vterminal / ki_Vterminal;
05370 e_source[i] = complex(pred_state.e_source_mag[i] * cos(V_angle[i]), pred_state.e_source_mag[i] * sin(V_angle[i]));
05371
05372
05373 value_IGenerated[i] = e_source[i]/(complex(Rfilter,Xfilter) * Zbase);
05374
05375
05376 if (checkRampRate_real == true || checkRampRate_reactive == true)
05377 {
05378
05379 ramp_change = false;
05380
05381
05382 temp_current_val[i] = (value_IGenerated[i] - generator_admittance[i][0]*value_Circuit_V[0] - generator_admittance[i][1]*value_Circuit_V[1] - generator_admittance[i][2]*value_Circuit_V[2]);
05383
05384
05385 power_val[i] = value_Circuit_V[i]*~temp_current_val[i];
05386
05387
05388 if (checkRampRate_real == true) {
05389
05390
05391 power_diff_val = (power_val[i].Re() - prev_VA_out[i].Re()) / deltat;
05392
05393 if (power_val[i].Re() > prev_VA_out[i].Re())
05394 {
05395
05396 if (power_diff_val > rampUpRate_real)
05397 {
05398
05399 ramp_change = true;
05400
05401 power_val[i].SetReal(prev_VA_out[i].Re() + (rampUpRate_real * deltat));
05402 }
05403
05404 }
05405 else
05406 {
05407
05408 if (power_diff_val < -rampDownRate_real)
05409 {
05410
05411 ramp_change = true;
05412
05413 power_val[i].SetReal(prev_VA_out[i].Re() - (rampDownRate_real * deltat));
05414 }
05415
05416 }
05417 }
05418 if (checkRampRate_reactive == true) {
05419
05420
05421 power_diff_val = (power_val[i].Im() - prev_VA_out[i].Im()) / deltat;
05422
05423 if (power_val[i].Im() > prev_VA_out[i].Im())
05424 {
05425
05426 if (power_diff_val > rampUpRate_reactive)
05427 {
05428
05429 ramp_change = true;
05430
05431 power_val[i].SetImag(prev_VA_out[i].Im() + (rampUpRate_reactive * deltat));
05432 }
05433
05434 }
05435 else
05436 {
05437
05438 if (power_diff_val < -rampDownRate_reactive)
05439 {
05440
05441 ramp_change = true;
05442
05443 power_val[i].SetImag(prev_VA_out[i].Im() - (rampDownRate_reactive * deltat));
05444 }
05445
05446 }
05447 }
05448
05449
05450 if (ramp_change == true)
05451 {
05452
05453 temp_current_val[i] = ~(power_val[i] / value_Circuit_V[i]);
05454
05455
05456 value_IGenerated[i] = temp_current_val[i] + generator_admittance[i][0]*value_Circuit_V[0] + generator_admittance[i][1]*value_Circuit_V[1] + generator_admittance[i][2]*value_Circuit_V[2];
05457
05458
05459 e_source[i] = value_IGenerated[i] * (complex(Rfilter,Xfilter) * Zbase);
05460
05461
05462 }
05463
05464
05465
05466 curr_VA_out[i] = power_val[i];
05467 }
05468 }
05469 }
05470
05471
05472 else if (VSI_mode == VSI_DROOP) {
05473
05474
05475 double delta_f = (curr_state.p_mea_delayed - Pref) /p_rated / 3.0 * (R_fp / (2.0 * PI));
05476
05477
05478
05479 pred_state.dfmax_ini_StateVal = (Pmax - curr_state.p_mea_delayed /p_rated / 3.0) * kipmax / (2.0 * PI);
05480 pred_state.fmax_ini_StateVal = curr_state.fmax_ini_StateVal + pred_state.dfmax_ini_StateVal * deltat;
05481
05482
05483 if (pred_state.fmax_ini_StateVal > 0.0){
05484
05485 pred_state.fmax_ini_StateVal = 0.0;
05486
05487 }
05488
05489
05490 pred_state.fmax_StateVal = pred_state.fmax_ini_StateVal + pred_state.dfmax_ini_StateVal * kppmax / (2.0 * PI) / kipmax;
05491
05492 if (pred_state.fmax_StateVal > 0.0){
05493
05494 pred_state.fmax_StateVal = 0.0;
05495
05496 }
05497
05498
05499
05500 pred_state.dfmin_ini_StateVal = (Pmin - curr_state.p_mea_delayed / p_rated / 3.0) * kipmax / (2.0 * PI);
05501 pred_state.fmin_ini_StateVal = curr_state.fmin_ini_StateVal + pred_state.dfmin_ini_StateVal * deltat;
05502
05503
05504 if (pred_state.fmin_ini_StateVal < 0.0){
05505
05506 pred_state.fmin_ini_StateVal = 0.0;
05507
05508 }
05509
05510
05511 pred_state.fmin_StateVal = pred_state.fmin_ini_StateVal + pred_state.dfmin_ini_StateVal * kppmax / (2.0 * PI) / kipmax;
05512
05513 if (pred_state.fmin_StateVal < 0.0){
05514
05515 pred_state.fmin_StateVal = 0.0;
05516
05517 }
05518
05519 VSI_freq = freq_ref - delta_f + pred_state.fmax_StateVal + pred_state.fmin_StateVal;
05520
05521
05522
05523 V_mag[0] = V_mag_ref[0] - (pred_state.q_mea_delayed - Qref) /p_rated / 3.0 * R_vq * node_nominal_voltage;
05524
05525
05526 pred_state.dV_StateVal[0] = (V_mag[0] - pCircuit_V_Avg) * ki_Vterminal;
05527 pred_state.V_StateVal[0] = curr_state.V_StateVal[0] + pred_state.dV_StateVal[0] * deltat;
05528 pred_state.e_source_mag[0] = pred_state.V_StateVal[0] + pred_state.dV_StateVal[0] * kp_Vterminal / ki_Vterminal;
05529
05530 for(i = 0; i < 3; i++) {
05531
05532 V_angle[i] = V_angle[i] - (delta_f - pred_state.fmax_StateVal - pred_state.fmin_StateVal)* 2.0 * PI * deltat;
05533
05534 e_source[i] = complex(pred_state.e_source_mag[0] * cos(V_angle[i]), pred_state.e_source_mag[0] * sin(V_angle[i]));
05535
05536
05537 value_IGenerated[i] = e_source[i]/(complex(Rfilter,Xfilter) * Zbase);
05538
05539
05540 if (checkRampRate_real == true || checkRampRate_reactive == true)
05541 {
05542
05543 ramp_change = false;
05544
05545
05546 temp_current_val[i] = (value_IGenerated[i] - generator_admittance[i][0]*value_Circuit_V[0] - generator_admittance[i][1]*value_Circuit_V[1] - generator_admittance[i][2]*value_Circuit_V[2]);
05547
05548
05549 power_val[i] = value_Circuit_V[i]*~temp_current_val[i];
05550
05551 if (checkRampRate_real == true) {
05552
05553
05554 power_diff_val = (power_val[i].Re() - prev_VA_out[i].Re()) / deltat;
05555
05556
05557 if (power_val[i].Re() > prev_VA_out[i].Re())
05558 {
05559
05560 if (power_diff_val > rampUpRate_real)
05561 {
05562
05563 ramp_change = true;
05564
05565 power_val[i].SetReal(prev_VA_out[i].Re() + (rampUpRate_real * deltat));
05566 }
05567
05568 }
05569 else
05570 {
05571
05572 if (power_diff_val < -rampDownRate_real)
05573 {
05574
05575 ramp_change = true;
05576
05577 power_val[i].SetReal(prev_VA_out[i].Re() - (rampDownRate_real * deltat));
05578 }
05579
05580 }
05581
05582 }
05583
05584 if (checkRampRate_reactive == true) {
05585
05586
05587 power_diff_val = (power_val[i].Im() - prev_VA_out[i].Im()) / deltat;
05588
05589 if (power_val[i].Im() > prev_VA_out[i].Im())
05590 {
05591
05592 if (power_diff_val > rampUpRate_reactive)
05593 {
05594
05595 ramp_change = true;
05596
05597 power_val[i].SetImag(prev_VA_out[i].Im() + (rampUpRate_reactive * deltat));
05598 }
05599
05600 }
05601 else
05602 {
05603
05604 if (power_diff_val < -rampDownRate_reactive)
05605 {
05606
05607 ramp_change = true;
05608
05609 power_val[i].SetImag(prev_VA_out[i].Im() - (rampDownRate_reactive * deltat));
05610 }
05611
05612 }
05613 }
05614
05615
05616
05617 if (ramp_change == true)
05618 {
05619
05620 temp_current_val[i] = ~(power_val[i] / value_Circuit_V[i]);
05621
05622
05623 value_IGenerated[i] = temp_current_val[i] + generator_admittance[i][0]*value_Circuit_V[0] + generator_admittance[i][1]*value_Circuit_V[1] + generator_admittance[i][2]*value_Circuit_V[2];
05624
05625
05626 e_source[i] = value_IGenerated[i] * (complex(Rfilter,Xfilter) * Zbase);
05627
05628
05629 }
05630
05631
05632
05633 curr_VA_out[i] = power_val[i];
05634 }
05635 }
05636 }
05637 }
05638
05639 simmode_return_value = SM_DELTA_ITER;
05640 }
05641 else
05642 {
05643 if((phases & 0x10) == 0x10) {
05644
05645
05646
05647 temp_current_val[0] = value_IGenerated[0] - generator_admittance[0][0] * value_Circuit_V[0];
05648
05649
05650 VA_Out = value_Circuit_V[0] * ~temp_current_val[0];
05651
05652
05653 if (checkRampRate_real == true)
05654 {
05655
05656 power_diff_val = (VA_Out.Re() - prev_VA_out[0].Re()) / deltat;
05657
05658
05659 if (VA_Out.Re() > prev_VA_out[0].Re())
05660 {
05661
05662 if (power_diff_val > rampUpRate_real)
05663 {
05664 VA_Out.SetReal(prev_VA_out[0].Re() + (rampUpRate_real * deltat));
05665 }
05666
05667 }
05668 else
05669 {
05670
05671 if (power_diff_val < -rampDownRate_real)
05672 {
05673 VA_Out.SetReal(prev_VA_out[0].Re() - (rampDownRate_real * deltat));
05674 }
05675
05676 }
05677
05678
05679 curr_VA_out[0] = VA_Out;
05680 }
05681
05682
05683 next_state.dp_mea_delayed = 1.0/Tp_delay*(VA_Out.Re() - curr_state.p_mea_delayed);
05684 next_state.dq_mea_delayed = 1.0/Tq_delay*(VA_Out.Im() - curr_state.q_mea_delayed);
05685
05686
05687 next_state.p_mea_delayed = curr_state.p_mea_delayed + (deltat * next_state.dp_mea_delayed);
05688 next_state.q_mea_delayed = curr_state.q_mea_delayed + (deltat * next_state.dq_mea_delayed);
05689
05690
05691 if (mapped_freq_variable!=NULL)
05692 {
05693 mapped_freq_variable->setp<double>(VSI_freq,*test_rlock);
05694 }
05695
05696 if (VSI_mode == VSI_ISOCHRONOUS) {
05697 next_state.dV_StateVal[0] = (V_mag_ref[0] - value_Circuit_V[0].Mag()) * ki_Vterminal;
05698 next_state.V_StateVal[0] = curr_state.V_StateVal[0] + (pred_state.dV_StateVal[0] + next_state.dV_StateVal[0])* deltath;
05699 next_state.e_source_mag[0] = next_state.V_StateVal[0] + (pred_state.dV_StateVal[0] + next_state.dV_StateVal[0]) * 0.5 * kp_Vterminal / ki_Vterminal;
05700 e_source[0] = complex(next_state.e_source_mag[0] * cos(V_angle[0]), next_state.e_source_mag[0] * sin(V_angle[0]));
05701
05702 value_IGenerated[0] = e_source[0]/(complex(Rfilter,Xfilter) * Zbase);
05703 }
05704
05705
05706 else if (VSI_mode == VSI_DROOP) {
05707
05708
05709 double delta_f = (next_state.p_mea_delayed - Pref) /p_rated * (R_fp / (2.0 * PI));
05710 double delta_f1 = (curr_state.p_mea_delayed - Pref) /p_rated * (R_fp / (2.0 * PI));
05711
05712
05713 next_state.dfmax_ini_StateVal = (Pmax - curr_state.p_mea_delayed /p_rated) * kipmax / (2.0 * PI);
05714 next_state.fmax_ini_StateVal = curr_state.fmax_ini_StateVal +(pred_state.dfmax_ini_StateVal + next_state.dfmax_ini_StateVal) * deltath;
05715
05716
05717 if (next_state.fmax_ini_StateVal > 0.0){
05718
05719 next_state.fmax_ini_StateVal = 0.0;
05720
05721 }
05722
05723
05724 next_state.fmax_StateVal = next_state.fmax_ini_StateVal + (pred_state.dfmax_ini_StateVal + next_state.dfmax_ini_StateVal) * 0.5 * kppmax / (2.0 * PI) / kipmax;
05725
05726 if (next_state.fmax_StateVal > 0.0){
05727
05728 next_state.fmax_StateVal = 0.0;
05729
05730 }
05731
05732
05733
05734 next_state.dfmin_ini_StateVal = (Pmin - curr_state.p_mea_delayed /p_rated) * kipmax / (2.0 * PI);
05735 next_state.fmin_ini_StateVal = curr_state.fmin_ini_StateVal +(pred_state.dfmin_ini_StateVal + next_state.dfmin_ini_StateVal) * deltath;
05736
05737
05738 if (next_state.fmin_ini_StateVal < 0.0){
05739
05740 next_state.fmin_ini_StateVal = 0.0;
05741
05742 }
05743
05744
05745 next_state.fmin_StateVal = next_state.fmin_ini_StateVal + (pred_state.dfmin_ini_StateVal + next_state.dfmin_ini_StateVal) * 0.5 * kppmax / (2.0 * PI) / kipmax;
05746
05747 if (next_state.fmin_StateVal < 0.0){
05748
05749 next_state.fmin_StateVal = 0.0;
05750
05751 }
05752
05753 VSI_freq = freq_ref - delta_f + next_state.fmax_StateVal + next_state.fmin_StateVal;
05754
05755
05756 V_angle[0] = V_angle[0] + (delta_f1 - pred_state.fmax_StateVal - pred_state.fmin_StateVal) * 2.0 * PI * deltat * 0.5 - (delta_f - (next_state.fmax_StateVal + next_state.fmin_StateVal)) * 2.0 * PI * deltat * 0.5;
05757
05758
05759 V_mag[0] = V_mag_ref[0] - (next_state.q_mea_delayed - Qref) / p_rated * R_vq * node_nominal_voltage;
05760
05761 next_state.dV_StateVal[0] = (V_mag[0] - value_Circuit_V[0].Mag()) * ki_Vterminal;
05762 next_state.V_StateVal[0] = curr_state.V_StateVal[0] + (pred_state.dV_StateVal[0] + next_state.dV_StateVal[0])* deltath;
05763 next_state.e_source_mag[0] = next_state.V_StateVal[0] + (pred_state.dV_StateVal[0] + next_state.dV_StateVal[0]) * 0.5 * kp_Vterminal / ki_Vterminal;
05764 e_source[0] = complex(next_state.e_source_mag[0] * cos(V_angle[0]), next_state.e_source_mag[0] * sin(V_angle[0]));
05765
05766
05767 value_IGenerated[0] = e_source[0]/(complex(Rfilter,Xfilter) * Zbase);
05768 }
05769 }
05770
05771 if((phases & 0x07) == 0x07) {
05772
05773
05774
05775 temp_current_val[0] = (value_IGenerated[0] - generator_admittance[0][0]*value_Circuit_V[0] - generator_admittance[0][1]*value_Circuit_V[1] - generator_admittance[0][2]*value_Circuit_V[2]);
05776 temp_current_val[1] = (value_IGenerated[1] - generator_admittance[1][0]*value_Circuit_V[0] - generator_admittance[1][1]*value_Circuit_V[1] - generator_admittance[1][2]*value_Circuit_V[2]);
05777 temp_current_val[2] = (value_IGenerated[2] - generator_admittance[2][0]*value_Circuit_V[0] - generator_admittance[2][1]*value_Circuit_V[1] - generator_admittance[2][2]*value_Circuit_V[2]);
05778
05779
05780 power_val[0] = value_Circuit_V[0]*~temp_current_val[0];
05781 power_val[1] = value_Circuit_V[1]*~temp_current_val[1];
05782 power_val[2] = value_Circuit_V[2]*~temp_current_val[2];
05783
05784 VA_Out = power_val[0] + power_val[1] + power_val[2];
05785
05786 pCircuit_V_Avg = (value_Circuit_V[0].Mag() + value_Circuit_V[1].Mag() + value_Circuit_V[2].Mag()) / 3.0;
05787
05788
05789 next_state.dp_mea_delayed = 1.0/Tp_delay*(VA_Out.Re() - curr_state.p_mea_delayed);
05790 next_state.dq_mea_delayed = 1.0/Tq_delay*(VA_Out.Im() - curr_state.q_mea_delayed);
05791
05792
05793 next_state.p_mea_delayed = curr_state.p_mea_delayed + (deltat * next_state.dp_mea_delayed);
05794 next_state.q_mea_delayed = curr_state.q_mea_delayed + (deltat * next_state.dq_mea_delayed);
05795
05796
05797 if (mapped_freq_variable!=NULL)
05798 {
05799 mapped_freq_variable->setp<double>(VSI_freq,*test_rlock);
05800 }
05801
05802 if (VSI_mode == VSI_ISOCHRONOUS) {
05803 for(i = 0; i < 3; i++) {
05804 next_state.dV_StateVal[i] = (V_mag_ref[i] - value_Circuit_V[i].Mag()) * ki_Vterminal;
05805 next_state.V_StateVal[i] = curr_state.V_StateVal[i] + (pred_state.dV_StateVal[i] + next_state.dV_StateVal[i])* deltath;
05806 next_state.e_source_mag[i] = next_state.V_StateVal[i] + (pred_state.dV_StateVal[i] + next_state.dV_StateVal[i]) * 0.5 * kp_Vterminal / ki_Vterminal;
05807 e_source[i] = complex(next_state.e_source_mag[i] * cos(V_angle[i]), next_state.e_source_mag[i] * sin(V_angle[i]));
05808
05809
05810 value_IGenerated[i] = e_source[i]/(complex(Rfilter,Xfilter) * Zbase);
05811
05812
05813 if (checkRampRate_real == true || checkRampRate_reactive == true)
05814 {
05815
05816 ramp_change = false;
05817
05818
05819 temp_current_val[i] = (value_IGenerated[i] - generator_admittance[i][0]*value_Circuit_V[0] - generator_admittance[i][1]*value_Circuit_V[1] - generator_admittance[i][2]*value_Circuit_V[2]);
05820
05821
05822 power_val[i] = value_Circuit_V[i]*~temp_current_val[i];
05823
05824
05825 if (checkRampRate_real == true) {
05826
05827
05828 power_diff_val = (power_val[i].Re() - prev_VA_out[i].Re()) / deltat;
05829
05830 if (power_val[i].Re() > prev_VA_out[i].Re())
05831 {
05832
05833 if (power_diff_val > rampUpRate_real)
05834 {
05835
05836 ramp_change = true;
05837
05838 power_val[i].SetReal(prev_VA_out[i].Re() + (rampUpRate_real * deltat));
05839 }
05840
05841 }
05842 else
05843 {
05844
05845 if (power_diff_val < -rampDownRate_real)
05846 {
05847
05848 ramp_change = true;
05849
05850 power_val[i].SetReal(prev_VA_out[i].Re() - (rampDownRate_real * deltat));
05851 }
05852
05853 }
05854 }
05855 if (checkRampRate_reactive == true) {
05856
05857
05858 power_diff_val = (power_val[i].Im() - prev_VA_out[i].Im()) / deltat;
05859
05860 if (power_val[i].Im() > prev_VA_out[i].Im())
05861 {
05862
05863 if (power_diff_val > rampUpRate_reactive)
05864 {
05865
05866 ramp_change = true;
05867
05868 power_val[i].SetImag(prev_VA_out[i].Im() + (rampUpRate_reactive * deltat));
05869 }
05870
05871 }
05872 else
05873 {
05874
05875 if (power_diff_val < -rampDownRate_reactive)
05876 {
05877
05878 ramp_change = true;
05879
05880 power_val[i].SetImag(prev_VA_out[i].Im() - (rampDownRate_reactive * deltat));
05881 }
05882
05883 }
05884 }
05885
05886
05887 if (ramp_change == true)
05888 {
05889
05890 temp_current_val[i] = ~(power_val[i] / value_Circuit_V[i]);
05891
05892
05893 value_IGenerated[i] = temp_current_val[i] + generator_admittance[i][0]*value_Circuit_V[0] + generator_admittance[i][1]*value_Circuit_V[1] + generator_admittance[i][2]*value_Circuit_V[2];
05894
05895
05896 e_source[i] = value_IGenerated[i] * (complex(Rfilter,Xfilter) * Zbase);
05897
05898
05899 }
05900
05901 }
05902
05903
05904 curr_VA_out[i] = power_val[i];
05905 }
05906 }
05907
05908
05909 else if (VSI_mode == VSI_DROOP) {
05910
05911
05912 double delta_f = (next_state.p_mea_delayed - Pref) /p_rated / 3.0 * (R_fp / (2.0 * PI));
05913 double delta_f1 = (curr_state.p_mea_delayed - Pref) /p_rated / 3.0 * (R_fp / (2.0 * PI));
05914
05915 next_state.dfmax_ini_StateVal = (Pmax - curr_state.p_mea_delayed /p_rated / 3.0) * kipmax / (2.0 * PI);
05916 next_state.fmax_ini_StateVal = curr_state.fmax_ini_StateVal +(pred_state.dfmax_ini_StateVal + next_state.dfmax_ini_StateVal) * deltath;
05917
05918
05919 if (next_state.fmax_ini_StateVal > 0.0){
05920
05921 next_state.fmax_ini_StateVal = 0.0;
05922
05923 }
05924
05925
05926 next_state.fmax_StateVal = next_state.fmax_ini_StateVal + (pred_state.dfmax_ini_StateVal + next_state.dfmax_ini_StateVal) * 0.5 * kppmax / (2.0 * PI) / kipmax;
05927
05928 if (next_state.fmax_StateVal > 0.0){
05929
05930 next_state.fmax_StateVal = 0.0;
05931
05932 }
05933
05934
05935 next_state.dfmin_ini_StateVal = (Pmin - curr_state.p_mea_delayed /p_rated / 3.0) * kipmax / (2.0 * PI);
05936 next_state.fmin_ini_StateVal = curr_state.fmin_ini_StateVal +(pred_state.dfmin_ini_StateVal + next_state.dfmin_ini_StateVal) * deltath;
05937
05938
05939 if (next_state.fmin_ini_StateVal < 0.0){
05940
05941 next_state.fmin_ini_StateVal = 0.0;
05942
05943 }
05944
05945
05946 next_state.fmin_StateVal = next_state.fmin_ini_StateVal + (pred_state.dfmin_ini_StateVal + next_state.dfmin_ini_StateVal) * 0.5 * kppmax / (2.0 * PI) / kipmax;
05947
05948 if (next_state.fmin_StateVal < 0.0){
05949
05950 next_state.fmin_StateVal = 0.0;
05951
05952 }
05953
05954 VSI_freq = freq_ref - delta_f + next_state.fmax_StateVal + next_state.fmin_StateVal;
05955
05956 V_mag[0] = V_mag_ref[0] - (next_state.q_mea_delayed - Qref) / p_rated / 3.0 * R_vq * node_nominal_voltage;
05957
05958
05959 next_state.dV_StateVal[0] = (V_mag[0] - pCircuit_V_Avg) * ki_Vterminal;
05960 next_state.V_StateVal[0] = curr_state.V_StateVal[0] + (pred_state.dV_StateVal[0] + next_state.dV_StateVal[0]) * deltath;
05961 next_state.e_source_mag[0] = next_state.V_StateVal[0] + (pred_state.dV_StateVal[0] + next_state.dV_StateVal[0]) * 0.5 * kp_Vterminal / ki_Vterminal;
05962
05963 for(i = 0; i < 3; i++) {
05964
05965
05966 V_angle[i] = V_angle[i] + (delta_f1 - pred_state.fmax_StateVal - pred_state.fmin_StateVal) * 2.0 * PI * deltat * 0.5 - (delta_f - (next_state.fmax_StateVal + next_state.fmin_StateVal)) * 2.0 * PI * deltat * 0.5;
05967
05968
05969 e_source[i] = complex(next_state.e_source_mag[0] * cos(V_angle[i]), next_state.e_source_mag[0] * sin(V_angle[i]));
05970
05971
05972 value_IGenerated[i] = e_source[i]/(complex(Rfilter,Xfilter) * Zbase);
05973
05974
05975 if (checkRampRate_real == true || checkRampRate_reactive == true)
05976 {
05977
05978 ramp_change = false;
05979
05980
05981 temp_current_val[i] = (value_IGenerated[i] - generator_admittance[i][0]*value_Circuit_V[0] - generator_admittance[i][1]*value_Circuit_V[1] - generator_admittance[i][2]*value_Circuit_V[2]);
05982
05983
05984 power_val[i] = value_Circuit_V[i]*~temp_current_val[i];
05985
05986 if (checkRampRate_real == true) {
05987
05988 power_diff_val = (power_val[i].Re() - prev_VA_out[i].Re()) / deltat;
05989
05990
05991 if (power_val[i].Re() > prev_VA_out[i].Re())
05992 {
05993
05994 if (power_diff_val > rampUpRate_real)
05995 {
05996
05997 ramp_change = true;
05998
05999 power_val[i].SetReal(prev_VA_out[i].Re() + (rampUpRate_real * deltat));
06000 }
06001
06002 }
06003 else
06004 {
06005
06006 if (power_diff_val < -rampDownRate_real)
06007 {
06008
06009 ramp_change = true;
06010
06011 power_val[i].SetReal(prev_VA_out[i].Re() - (rampDownRate_real * deltat));
06012 }
06013
06014 }
06015
06016 }
06017
06018 if (checkRampRate_reactive == true) {
06019
06020
06021 power_diff_val = (power_val[i].Im() - prev_VA_out[i].Im()) / deltat;
06022
06023 if (power_val[i].Im() > prev_VA_out[i].Im())
06024 {
06025
06026 if (power_diff_val > rampUpRate_reactive)
06027 {
06028
06029 ramp_change = true;
06030
06031 power_val[i].SetImag(prev_VA_out[i].Im() + (rampUpRate_reactive * deltat));
06032 }
06033
06034 }
06035 else
06036 {
06037
06038 if (power_diff_val < -rampDownRate_reactive)
06039 {
06040
06041 ramp_change = true;
06042
06043 power_val[i].SetImag(prev_VA_out[i].Im() - (rampDownRate_reactive * deltat));
06044 }
06045
06046 }
06047 }
06048
06049
06050 if (ramp_change == true)
06051 {
06052
06053 temp_current_val[i] = ~(power_val[i] / value_Circuit_V[i]);
06054
06055
06056 value_IGenerated[i] = temp_current_val[i] + generator_admittance[i][0]*value_Circuit_V[0] + generator_admittance[i][1]*value_Circuit_V[1] + generator_admittance[i][2]*value_Circuit_V[2];
06057
06058
06059 e_source[i] = value_IGenerated[i] * (complex(Rfilter,Xfilter) * Zbase);
06060
06061
06062 }
06063
06064
06065
06066 curr_VA_out[i] = power_val[i];
06067 }
06068 }
06069 }
06070 }
06071
06072
06073 memcpy(&curr_state, &next_state, sizeof(INV_STATE));
06074
06075 simmode_return_value = SM_DELTA;
06076 }
06077 }
06078 else {
06079
06080 if (delta_time==0)
06081 {
06082 if(iteration_count_val == 0) {
06083
06084 if (inverter_droop_fp) {
06085 if (Tfreq_delay == 0) {
06086 Tfreq_delay = deltat;
06087 }
06088 }
06089
06090 if (inverter_droop_vq) {
06091 if (Tvol_delay == 0) {
06092 Tvol_delay = deltat;
06093 }
06094 }
06095
06096
06097 if (inverter_type_v == FOUR_QUADRANT && four_quadrant_control_mode == FQM_CONSTANT_PQ) {
06098 if((phases & 0x10) == 0x10) {
06099
06100 curr_state.P_Out[0] = VA_Out.Re();
06101 curr_state.Q_Out[0] = VA_Out.Im();
06102 if (value_Circuit_V[0].Mag() > 0.0)
06103 {
06104 value_Line_unrotI[i] += curr_state.Iac[0];
06105 curr_state.Iac[0] = (~(complex(curr_state.P_Out[0],curr_state.Q_Out[0])/value_Circuit_V[0]));
06106 I_Out[0]= curr_state.Iac[0];
06107 value_Line_unrotI[i] += -curr_state.Iac[0];
06108 }
06109 }
06110 if ((phases & 0x07) == 0x07) {
06111 for(i = 0; i < 3; i++) {
06112
06113 power_val[i] = value_Circuit_V[i] * ~(I_Out[i]);
06114
06115 curr_state.P_Out[i] = power_val[i].Re();
06116 curr_state.Q_Out[i] = power_val[i].Im();
06117
06118 if (value_Circuit_V[i].Mag() > 0.0)
06119 {
06120 value_Line_unrotI[i] += curr_state.Iac[i];
06121 curr_state.Iac[i] = ~(complex(curr_state.P_Out[i],curr_state.Q_Out[i])/(value_Circuit_V[i]));
06122 I_Out[i]= curr_state.Iac[i];
06123 value_Line_unrotI[i] += -curr_state.Iac[i];
06124 }
06125 }
06126 }
06127 }
06128 else {
06129
06130
06131
06132 if((phases & 0x10) == 0x10) {
06133
06134 I_Out[0]= curr_state.Iac[0];
06135 }
06136 if((phases & 0x07) == 0x07) {
06137 for(int i = 0; i < 3; i++) {
06138
06139 I_Out[i] = curr_state.Iac[i];
06140 }
06141 }
06142 }
06143
06144 simmode_return_value = SM_DELTA_ITER;
06145
06146 } else if(iteration_count_val == 1) {
06147
06148
06149 if (inverter_droop_fp) {
06150 curr_state.df_mea_delayed = 1.0/Tfreq_delay*(value_Frequency - curr_state.f_mea_delayed);
06151 }
06152
06153 if (inverter_droop_vq) {
06154 if((phases & 0x10) == 0x10) {
06155 curr_state.dV_mea_delayed[0] = 1.0/Tvol_delay*(value_Circuit_V[0].Mag() - curr_state.V_mea_delayed[0]);
06156 }
06157 if((phases & 0x07) == 0x07) {
06158 curr_state.dV_mea_delayed[0] = 1.0/Tvol_delay*(value_Circuit_V[0].Mag() - curr_state.V_mea_delayed[0]);
06159 curr_state.dV_mea_delayed[1] = 1.0/Tvol_delay*(value_Circuit_V[1].Mag() - curr_state.V_mea_delayed[1]);
06160 curr_state.dV_mea_delayed[2] = 1.0/Tvol_delay*(value_Circuit_V[2].Mag() - curr_state.V_mea_delayed[2]);
06161 }
06162 }
06163
06164
06165 if (inverter_type_v == FOUR_QUADRANT && four_quadrant_control_mode != FQM_CONSTANT_PQ) {
06166 if((phases & 0x10) == 0x10) {
06167 VA_Out = value_Circuit_V[0] * ~(I_Out[0]);
06168 curr_state.Q_Out[0] = VA_Out.Im();
06169 }
06170 if((phases & 0x07) == 0x07) {
06171 VA_Out = (value_Circuit_V[0] * ~(I_Out[0]) + (value_Circuit_V[1] * ~(I_Out[1])) + (value_Circuit_V[2] * ~(I_Out[2])));
06172 curr_state.Q_Out[0] = (value_Circuit_V[0] * ~(I_Out[0])).Im();
06173 curr_state.Q_Out[1] = (value_Circuit_V[1] * ~(I_Out[1])).Im();
06174 curr_state.Q_Out[2] = (value_Circuit_V[2] * ~(I_Out[2])).Im();
06175 }
06176 }
06177
06178
06179 if((phases & 0x10) == 0x10) {
06180
06181 curr_state.P_Out[0] = VA_Out.Re();
06182 curr_state.Q_Out[0] = VA_Out.Im();
06183 if (value_Circuit_V[0].Mag() > 0.0)
06184 {
06185 curr_state.ed[0] = ((~(complex(Pref, Qref_PI[0])/(value_Circuit_V[0]))) - (~(complex(curr_state.P_Out[0],curr_state.Q_Out[0])/(value_Circuit_V[0])))).Re();
06186 curr_state.eq[0] = ((~(complex(Pref, Qref_PI[0])/(value_Circuit_V[0]))) - (~(complex(curr_state.P_Out[0],curr_state.Q_Out[0])/(value_Circuit_V[0])))).Im();
06187 }
06188 else
06189 {
06190 curr_state.ed[0] = 0.0;
06191 curr_state.eq[0] = 0.0;
06192 }
06193
06194 curr_state.ded[0] = curr_state.ed[0] / deltat;
06195 curr_state.dmd[0] = kid * curr_state.ed[0];
06196
06197 curr_state.deq[0] = curr_state.eq[0] / deltat;
06198 curr_state.dmq[0] = kiq * curr_state.eq[0];
06199
06200 if(fabs(curr_state.ded[0]) <= inverter_convergence_criterion && fabs(curr_state.deq[0]) <= inverter_convergence_criterion) {
06201 simmode_return_value = SM_EVENT;
06202 } else {
06203 simmode_return_value = SM_DELTA;
06204 }
06205 }
06206 else if((phases & 0x07) == 0x07) {
06207 for(i = 0; i < 3; i++) {
06208
06209 power_val[i] = value_Circuit_V[i] * ~(I_Out[i]);
06210
06211 curr_state.P_Out[i] = power_val[i].Re();
06212 curr_state.Q_Out[i] = power_val[i].Im();
06213
06214 if (value_Circuit_V[i].Mag() > 0.0)
06215 {
06216 curr_state.ed[i] = ((~(complex(Pref/3.0, Qref_PI[i])/(value_Circuit_V[i]))) - (~(complex(curr_state.P_Out[i],curr_state.Q_Out[i])/(value_Circuit_V[i])))).Re();
06217 curr_state.eq[i] = ((~(complex(Pref/3.0, Qref_PI[i])/(value_Circuit_V[i]))) - (~(complex(curr_state.P_Out[i],curr_state.Q_Out[i])/(value_Circuit_V[i])))).Im();
06218 }
06219 else
06220 {
06221 curr_state.ed[i] = 0.0;
06222 curr_state.eq[i] = 0.0;
06223 }
06224
06225 curr_state.ded[i] = curr_state.ed[i] / deltat;
06226 curr_state.dmd[i] = kid * curr_state.ed[i];
06227
06228 curr_state.deq[i] = curr_state.eq[i] / deltat;
06229 curr_state.dmq[i] = kiq * curr_state.eq[i];
06230
06231 if ((fabs(curr_state.ded[i]) <= inverter_convergence_criterion) && (fabs(curr_state.deq[i]) <= inverter_convergence_criterion) && (simmode_return_value != SM_DELTA))
06232 {
06233 simmode_return_value = SM_EVENT;
06234 } else {
06235 simmode_return_value = SM_DELTA;
06236 }
06237 }
06238 }
06239 }
06240 } else if(iteration_count_val == 0) {
06241
06242 if (P_Out != Pref0) {
06243 Pref = P_Out;
06244 Pref0 = P_Out;
06245 }
06246
06247 if((phases & 0x10) == 0x10) {
06248 if (Q_Out != Qref0[0]) {
06249 Qref_PI[0] = Q_Out;
06250 Qref0[0] = Q_Out;
06251 }
06252 }
06253 else if((phases & 0x07) == 0x07) {
06254 if (Q_Out != Qref0[0]+Qref0[1]+Qref0[2]) {
06255 for(i = 0; i < 3; i++) {
06256 Qref_PI[i] = Q_Out/3;
06257 Qref0[i] = Q_Out/3;
06258 }
06259 }
06260 }
06261
06262
06263
06264 if (inverter_droop_fp) {
06265 Pref_prev = Pref;
06266
06267 curr_state.df_mea_delayed = 1.0/Tfreq_delay*(value_Frequency - curr_state.f_mea_delayed);
06268 pred_state.f_mea_delayed = curr_state.f_mea_delayed + (deltat * curr_state.df_mea_delayed);
06269
06270
06271 double delta_Pref = ((pred_state.f_mea_delayed - freq_ref)/freq_ref) * (1 / R_fp) * p_rated * 3;
06272 power_diff_val = Pref_prev - (Pref0 - delta_Pref);
06273 if (checkRampRate_real == true) {
06274 if (power_diff_val > 0 && (power_diff_val > rampDownRate_real*3)) {
06275 Pref = Pref_prev - rampDownRate_real*3;
06276 }
06277 else if (power_diff_val < 0 && (-power_diff_val > rampUpRate_real*3)) {
06278 Pref = Pref_prev + rampUpRate_real*3;
06279 }
06280 else {
06281 Pref = Pref0 - delta_Pref;
06282 }
06283 }
06284 else {
06285 Pref = Pref0 - delta_Pref;
06286 }
06287 }
06288
06289
06290 if (inverter_droop_vq) {
06291
06292 if((phases & 0x10) == 0x10) {
06293 Qref_prev[0] = Qref_PI[0];
06294 curr_state.dV_mea_delayed[0] = 1.0/Tvol_delay*(value_Circuit_V[0].Mag() - curr_state.V_mea_delayed[0]);
06295 pred_state.V_mea_delayed[0] = curr_state.V_mea_delayed[0] + (deltat * curr_state.dV_mea_delayed[0]);
06296 double delta_Qref = (pred_state.V_mea_delayed[0] - V_ref[0]) / node_nominal_voltage * (1.0 / R_vq) * p_rated ;
06297 power_diff_val = Qref_prev[0] - (Qref0[0] - delta_Qref);
06298 if (checkRampRate_reactive == true) {
06299 if (power_diff_val > 0 && (power_diff_val > rampDownRate_reactive)) {
06300 Qref_PI[0] = Qref_prev[0] - rampDownRate_reactive;
06301 }
06302 else if (power_diff_val < 0 && (-power_diff_val > rampUpRate_reactive)) {
06303 Qref_PI[0] = Qref_prev[0] + rampUpRate_reactive;
06304 }
06305 else {
06306 Qref_PI[0] = Qref0[0] - delta_Qref;
06307 }
06308 }
06309 else {
06310 Qref_PI[0] = Qref0[0] - delta_Qref;
06311 }
06312 }
06313 if((phases & 0x07) == 0x07) {
06314 double delta_Qref[3];
06315
06316 for(i = 0; i < 3; i++)
06317 {
06318
06319 curr_state.dV_mea_delayed[i] = 1.0/Tvol_delay*(value_Circuit_V[i].Mag() - curr_state.V_mea_delayed[i]);
06320
06321 Qref_prev[i] = Qref_PI[i];
06322 pred_state.V_mea_delayed[i] = curr_state.V_mea_delayed[i] + (deltat * curr_state.dV_mea_delayed[i]);
06323 delta_Qref[i] = (pred_state.V_mea_delayed[i] - V_ref[i]) / node_nominal_voltage * (1.0 / R_vq) * p_rated;
06324 power_diff_val = Qref_prev[i] - (Qref0[i] - delta_Qref[i]);
06325 if (checkRampRate_reactive == true) {
06326 if (power_diff_val > 0 && (power_diff_val > rampDownRate_reactive)) {
06327 Qref_PI[i] = Qref_prev[i] - rampDownRate_reactive;
06328 }
06329 else if (power_diff_val < 0 && (-power_diff_val > rampUpRate_reactive)) {
06330 Qref_PI[i] = Qref_prev[i] + rampUpRate_reactive;
06331 }
06332 else {
06333 Qref_PI[i] = Qref0[i] - delta_Qref[i];
06334 }
06335 }
06336 else {
06337 Qref_PI[i] = Qref0[i] - delta_Qref[i];
06338 }
06339 }
06340 }
06341
06342 }
06343
06344
06345 if (checkRampRate_real || checkRampRate_reactive == true)
06346 {
06347
06348 if ((phases & 0x10) == 0x10)
06349 {
06350 prev_VA_out[0] = curr_VA_out[0];
06351 }
06352 else
06353 {
06354
06355 prev_VA_out[0] = curr_VA_out[0];
06356 prev_VA_out[1] = curr_VA_out[1];
06357 prev_VA_out[2] = curr_VA_out[2];
06358 }
06359 }
06360
06361
06362
06363
06364
06365 if((phases & 0x10) == 0x10) {
06366 VA_Out = value_Circuit_V[0] * ~(I_Out[0]);
06367 prev_error_ed = curr_state.ed[0];
06368 prev_error_eq = curr_state.eq[0];
06369 curr_state.P_Out[0] = VA_Out.Re();
06370 curr_state.Q_Out[0] = VA_Out.Im();
06371 if (value_Circuit_V[0].Mag() > 0.0)
06372 {
06373 curr_state.ed[0] = ((~(complex(Pref, Qref_PI[0])/value_Circuit_V[0])) - (~(complex(curr_state.P_Out[0],curr_state.Q_Out[0])/value_Circuit_V[0]))).Re();
06374 curr_state.eq[0] = ((~(complex(Pref, Qref_PI[0])/value_Circuit_V[0])) - (~(complex(curr_state.P_Out[0],curr_state.Q_Out[0])/value_Circuit_V[0]))).Im();
06375 }
06376 else
06377 {
06378 curr_state.ed[0] = 0.0;
06379 curr_state.eq[0] = 0.0;
06380 }
06381
06382 curr_state.ded[0] = (curr_state.ed[0] - prev_error_ed) / deltat;
06383 curr_state.dmd[0] = (kpd * curr_state.ded[0]) + (kid * curr_state.ed[0]);
06384
06385 curr_state.deq[0] = (curr_state.eq[0] - prev_error_eq) / deltat;
06386 curr_state.dmq[0] = (kpq * curr_state.deq[0]) + (kiq * curr_state.eq[0]);
06387 } else if ((phases & 0x07) == 0x07) {
06388
06389 VA_Out = (value_Circuit_V[0] * ~(I_Out[0])) + (value_Circuit_V[1] * ~(I_Out[1])) + (value_Circuit_V[2] * ~(I_Out[2]));
06390
06391 for(i = 0; i < 3; i++) {
06392
06393
06394 work_power_vals = value_Circuit_V[i] * ~I_Out[i];
06395
06396 curr_state.P_Out[i] = work_power_vals.Re();
06397 curr_state.Q_Out[i] = work_power_vals.Im();
06398
06399 prev_error_ed = curr_state.ed[i];
06400 prev_error_eq = curr_state.eq[i];
06401
06402 if (value_Circuit_V[i].Mag() > 0.0)
06403 {
06404 curr_state.ed[i] = ((~(complex(Pref/3.0, Qref_PI[i])/(value_Circuit_V[i]))) - (~(complex(curr_state.P_Out[i],curr_state.Q_Out[i])/(value_Circuit_V[i])))).Re();
06405 curr_state.eq[i] = ((~(complex(Pref/3.0, Qref_PI[i])/(value_Circuit_V[i]))) - (~(complex(curr_state.P_Out[i],curr_state.Q_Out[i])/(value_Circuit_V[i])))).Im();
06406 }
06407 else
06408 {
06409 curr_state.ed[i] = 0.0;
06410 curr_state.eq[i] = 0.0;
06411 }
06412
06413 curr_state.ded[i] = (curr_state.ed[i] - prev_error_ed) / deltat;
06414 curr_state.dmd[i] = (kpd * curr_state.ded[i]) + (kid * curr_state.ed[i]);
06415
06416
06417 curr_state.deq[i] = (curr_state.eq[i] - prev_error_eq) / deltat;
06418 curr_state.dmq[i] = (kpq * curr_state.deq[i]) + (kiq * curr_state.eq[i]);
06419 }
06420 }
06421
06422
06423 if((phases & 0x10) == 0x10) {
06424 pred_state.md[0] = curr_state.md[0] + (deltat * curr_state.dmd[0]);
06425 pred_state.Idq[0].SetReal(pred_state.md[0] * I_In.Re());
06426 pred_state.mq[0] = curr_state.mq[0] + (deltat * curr_state.dmq[0]);
06427 pred_state.Idq[0].SetImag(pred_state.mq[0] * I_In.Re());
06428 pred_state.Iac[0] = pred_state.Idq[0];
06429
06430
06431
06432 complex VA_Out_temp = value_Circuit_V[0] * ~(pred_state.Iac[0]);
06433 if ((b_soc == -1 && VA_Out_temp.Re() < 0) || Pref == 0) {
06434 pred_state.Iac[0] = 0;
06435 }
06436
06437
06438 value_Line_unrotI[0] += I_Out[0];
06439 value_Line_unrotI[0] += -pred_state.Iac[0];
06440 I_Out[0] = pred_state.Iac[0];
06441
06442 }
06443 if((phases & 0x07) == 0x07) {
06444 for(i = 0; i < 3; i++) {
06445 pred_state.md[i] = curr_state.md[i] + (deltat * curr_state.dmd[i]);
06446 pred_state.Idq[i].SetReal(pred_state.md[i] * I_In.Re());
06447 pred_state.mq[i] = curr_state.mq[i] + (deltat * curr_state.dmq[i]);
06448 pred_state.Idq[i].SetImag(pred_state.mq[i] * I_In.Re());
06449 pred_state.Iac[i] = pred_state.Idq[i];
06450
06451
06452 power_val[i] = (value_Circuit_V[i] * ~(pred_state.Iac[i]));
06453
06454
06455 if ((checkRampRate_real == true) || (checkRampRate_reactive == true ))
06456 {
06457
06458 ramp_change = false;
06459
06460 if (checkRampRate_real == true) {
06461
06462
06463 power_diff_val = (power_val[i].Re() - prev_VA_out[i].Re()) / deltat;
06464
06465 if (power_val[i].Re() > prev_VA_out[i].Re())
06466 {
06467
06468 if (power_diff_val > rampUpRate_real)
06469 {
06470
06471 ramp_change = true;
06472
06473 power_val[i].SetReal(prev_VA_out[i].Re() + (rampUpRate_real * deltat));
06474 }
06475
06476 }
06477 else
06478 {
06479
06480 if (power_diff_val < -rampDownRate_real)
06481 {
06482
06483 ramp_change = true;
06484
06485 power_val[i].SetReal(prev_VA_out[i].Re() - (rampDownRate_real * deltat));
06486 }
06487
06488 }
06489 }
06490
06491 if (checkRampRate_reactive == true) {
06492
06493
06494 power_diff_val = (power_val[i].Im() - prev_VA_out[i].Im()) / deltat;
06495
06496 if (power_val[i].Im() > prev_VA_out[i].Im())
06497 {
06498
06499 if (power_diff_val > rampUpRate_reactive)
06500 {
06501
06502 ramp_change = true;
06503
06504 power_val[i].SetImag(prev_VA_out[i].Im() + (rampUpRate_reactive * deltat));
06505 }
06506
06507 }
06508 else
06509 {
06510
06511 if (power_diff_val < -rampDownRate_reactive)
06512 {
06513
06514 ramp_change = true;
06515
06516 power_val[i].SetImag(prev_VA_out[i].Im() - (rampDownRate_reactive * deltat));
06517 }
06518
06519 }
06520 }
06521
06522
06523 if (ramp_change == true)
06524 {
06525
06526 temp_current_val[i] = ~(power_val[i] / value_Circuit_V[i]);
06527
06528
06529 pred_state.Idq[i] = temp_current_val[i];
06530 pred_state.md[i] = pred_state.Idq[i].Re()/I_In.Re();
06531 pred_state.mq[i] = pred_state.Idq[i].Im()/I_In.Re();
06532 pred_state.Iac[i] = pred_state.Idq[i];
06533
06534 }
06535
06536
06537
06538 curr_VA_out[i] = power_val[i];
06539 }
06540 }
06541
06542
06543
06544 complex VA_Out_temp = (value_Circuit_V[0] * ~(pred_state.Iac[0])) + (value_Circuit_V[1] * ~(pred_state.Iac[1])) + (value_Circuit_V[2] * ~(pred_state.Iac[2]));
06545
06546 for (int i = 0; i< 3; i++) {
06547 if ((b_soc == -1 && VA_Out_temp.Re() < 0) || Pref == 0) {
06548 pred_state.Iac[i] = 0;
06549 }
06550
06551 value_Line_unrotI[i] += I_Out[i];
06552 value_Line_unrotI[i] += -pred_state.Iac[i];
06553 I_Out[i] = pred_state.Iac[i];
06554 }
06555 }
06556
06557
06558 update_control_references();
06559 simmode_return_value = SM_DELTA_ITER;
06560 }
06561 else if(iteration_count_val == 1)
06562 {
06563
06564
06565
06566 if (inverter_droop_fp) {
06567 pred_state.df_mea_delayed = 1.0/Tfreq_delay*(value_Frequency - pred_state.f_mea_delayed);
06568 curr_state.f_mea_delayed = curr_state.f_mea_delayed + (curr_state.df_mea_delayed + pred_state.df_mea_delayed) * deltath;
06569
06570 double delta_Pref = ((curr_state.f_mea_delayed - freq_ref)/freq_ref) * (1 / R_fp) * p_rated * 3;
06571 power_diff_val = Pref_prev - (Pref0 - delta_Pref);
06572 if (checkRampRate_real == true) {
06573 if (power_diff_val > 0 && (power_diff_val > rampDownRate_real*3)) {
06574 Pref = Pref_prev - rampDownRate_real*3;
06575 }
06576 else if (power_diff_val < 0 && (-power_diff_val > rampUpRate_real*3)) {
06577 Pref = Pref_prev + rampUpRate_real*3;
06578 }
06579 else {
06580 Pref = Pref0 - delta_Pref;
06581 }
06582 }
06583 else {
06584 Pref = Pref0 - delta_Pref;
06585 }
06586
06587 update_control_references();
06588 }
06589
06590 if (inverter_droop_vq) {
06591 if((phases & 0x10) == 0x10) {
06592 pred_state.dV_mea_delayed[0] = 1.0/Tvol_delay*(value_Circuit_V[0].Mag() - pred_state.V_mea_delayed[0]);
06593 curr_state.V_mea_delayed[0] = curr_state.V_mea_delayed[0] + (curr_state.dV_mea_delayed[0] + pred_state.dV_mea_delayed[0]) * deltath;
06594
06595 double delta_Qref = (curr_state.V_mea_delayed[0] - V_ref[0]) / node_nominal_voltage * (1.0 / R_vq) * p_rated;
06596 power_diff_val = Qref_prev[0] - (Qref0[0] - delta_Qref);
06597 if (checkRampRate_reactive == true) {
06598 if (power_diff_val > 0 && (power_diff_val > rampDownRate_reactive)) {
06599 Qref_PI[0] = Qref_prev[0] - rampDownRate_reactive;
06600 }
06601 else if (power_diff_val < 0 && (-power_diff_val > rampUpRate_reactive)) {
06602 Qref_PI[0] = Qref_prev[0] + rampUpRate_reactive;
06603 }
06604 else {
06605 Qref_PI[0] = Qref0[0] - delta_Qref;
06606 }
06607 }
06608 else {
06609 Qref_PI[0] = Qref0[0] - delta_Qref;
06610 }
06611 }
06612 if((phases & 0x07) == 0x07) {
06613 pred_state.dV_mea_delayed[0] = 1.0/Tvol_delay*(value_Circuit_V[0].Mag() - pred_state.V_mea_delayed[0]);
06614 pred_state.dV_mea_delayed[1] = 1.0/Tvol_delay*(value_Circuit_V[1].Mag() - pred_state.V_mea_delayed[1]);
06615 pred_state.dV_mea_delayed[2] = 1.0/Tvol_delay*(value_Circuit_V[2].Mag() - pred_state.V_mea_delayed[2]);
06616
06617 curr_state.V_mea_delayed[0] = curr_state.V_mea_delayed[0] + (curr_state.dV_mea_delayed[0] + pred_state.dV_mea_delayed[0]) * deltath;
06618 curr_state.V_mea_delayed[1] = curr_state.V_mea_delayed[1] + (curr_state.dV_mea_delayed[1] + pred_state.dV_mea_delayed[1]) * deltath;
06619 curr_state.V_mea_delayed[2] = curr_state.V_mea_delayed[2] + (curr_state.dV_mea_delayed[2] + pred_state.dV_mea_delayed[2]) * deltath;
06620
06621 double delta_Qref[3];
06622 for(i = 0; i < 3; i++) {
06623 delta_Qref[i] = (curr_state.V_mea_delayed[i] - V_ref[i]) / node_nominal_voltage * (1.0 / R_vq) * p_rated;
06624 power_diff_val = Qref_prev[i] - (Qref0[i] - delta_Qref[i]);
06625 if (checkRampRate_reactive == true) {
06626 if (power_diff_val > 0 && (power_diff_val > rampDownRate_reactive)) {
06627 Qref_PI[i] = Qref_prev[i] - rampDownRate_reactive;
06628 }
06629 else if (power_diff_val < 0 && (-power_diff_val > rampUpRate_reactive)) {
06630 Qref_PI[i] = Qref_prev[i] + rampUpRate_reactive;
06631 }
06632 else {
06633 Qref_PI[i] = Qref0[i] - delta_Qref[i];
06634 }
06635 }
06636 else {
06637 Qref_PI[i] = Qref0[i] - delta_Qref[i];
06638 }
06639 }
06640 }
06641
06642
06643 update_control_references();
06644 }
06645
06646
06647 if ((phases & 0x10) == 0x10) {
06648
06649 pred_state.P_Out[0] = (value_Circuit_V[0] * ~(I_Out[0])).Re();
06650 pred_state.Q_Out[0] = (value_Circuit_V[0] * ~(I_Out[0])).Im();
06651
06652 if (value_Circuit_V[0].Mag() > 0.0)
06653 {
06654 pred_state.ed[0] = ((~(complex(Pref, Qref_PI[0])/value_Circuit_V[0])) - (~(complex(pred_state.P_Out[0],pred_state.Q_Out[0])/value_Circuit_V[0]))).Re();
06655 pred_state.eq[0] = ((~(complex(Pref, Qref_PI[0])/value_Circuit_V[0])) - (~(complex(pred_state.P_Out[0],pred_state.Q_Out[0])/value_Circuit_V[0]))).Im();
06656 }
06657 else
06658 {
06659 pred_state.ed[0] = 0.0;
06660 pred_state.eq[0] = 0.0;
06661 }
06662
06663 pred_state.ded[0] = (pred_state.ed[0] - curr_state.ed[0]) / deltat;
06664 pred_state.dmd[0] = (kpd * pred_state.ded[0]) + (kid * pred_state.ed[0]);
06665 curr_state.md[0] = curr_state.md[0] + (curr_state.dmd[0] + pred_state.dmd[0]) * deltath;
06666 curr_state.Idq[0].SetReal(curr_state.md[0] * I_In.Re());
06667
06668 pred_state.deq[0] = (pred_state.eq[0] - curr_state.eq[0]) / deltat;
06669 pred_state.dmq[0] = (kpq * pred_state.deq[0]) + (kiq * pred_state.eq[0]);
06670 curr_state.mq[0] = curr_state.mq[0] + (curr_state.dmq[0] + pred_state.dmq[0]) * deltath;
06671 curr_state.Idq[0].SetImag(curr_state.mq[0] * I_In.Re());
06672 curr_state.Iac[0] = curr_state.Idq[0];
06673
06674
06675
06676 complex VA_Out_temp = value_Circuit_V[0] * ~(curr_state.Iac[0]);
06677 if ((b_soc == -1 && VA_Out_temp.Re() < 0) || Pref == 0) {
06678 curr_state.Iac[0] = 0;
06679 }
06680
06681
06682 value_Line_unrotI[0] += I_Out[0];
06683 value_Line_unrotI[0] += -curr_state.Iac[0];
06684 I_Out[0] = curr_state.Iac[0];
06685 }
06686 if((phases & 0x07) == 0x07) {
06687 for(i = 0; i < 3; i++) {
06688
06689 pred_state.P_Out[i] = (value_Circuit_V[i] * ~(I_Out[i])).Re();
06690 pred_state.Q_Out[i] = (value_Circuit_V[i] * ~(I_Out[i])).Im();
06691
06692 if (Pref > 0) {
06693 int stop_temp = 0;
06694 }
06695 if (value_Circuit_V[i].Mag() > 0.0)
06696 {
06697 pred_state.ed[i] = ((~(complex(Pref/3.0, Qref_PI[i])/(value_Circuit_V[i]))) - (~(complex(pred_state.P_Out[i],pred_state.Q_Out[i])/(value_Circuit_V[i])))).Re();
06698 pred_state.eq[i] = ((~(complex(Pref/3.0, Qref_PI[i])/(value_Circuit_V[i]))) - (~(complex(pred_state.P_Out[i],pred_state.Q_Out[i])/(value_Circuit_V[i])))).Im();
06699 }
06700 else
06701 {
06702 pred_state.ed[i] = 0.0;
06703 pred_state.eq[i] = 0.0;
06704 }
06705
06706 pred_state.ded[i] = (pred_state.ed[i] - curr_state.ed[i]) / deltat;
06707 pred_state.dmd[i] = (kpd * pred_state.ded[i]) + (kid * pred_state.ed[i]);
06708 curr_state.md[i] = curr_state.md[i] + (curr_state.dmd[i] + pred_state.dmd[i]) * deltath;
06709 curr_state.Idq[i].SetReal(curr_state.md[i] * I_In.Re());
06710
06711 pred_state.deq[i] = (pred_state.eq[i] - curr_state.eq[i]) / deltat;
06712 pred_state.dmq[i] = (kpq * pred_state.deq[i]) + (kiq * pred_state.eq[i]);
06713 curr_state.mq[i] = curr_state.mq[i] + (curr_state.dmq[i] + pred_state.dmq[i]) * deltath;
06714 curr_state.Idq[i].SetImag(curr_state.mq[i] * I_In.Re());
06715 curr_state.Iac[i] = curr_state.Idq[i];
06716
06717
06718 power_val[i] = (value_Circuit_V[i] * ~(curr_state.Iac[i]));
06719
06720
06721 if ((checkRampRate_real == true) || (checkRampRate_reactive == true ))
06722 {
06723
06724 ramp_change = false;
06725
06726 if (checkRampRate_real == true) {
06727
06728
06729 power_diff_val = (power_val[i].Re() - prev_VA_out[i].Re()) / deltat;
06730
06731 if (power_val[i].Re() > prev_VA_out[i].Re())
06732 {
06733
06734 if (power_diff_val > rampUpRate_real)
06735 {
06736
06737 ramp_change = true;
06738
06739 power_val[i].SetReal(prev_VA_out[i].Re() + (rampUpRate_real * deltat));
06740 }
06741
06742 }
06743 else
06744 {
06745
06746 if (power_diff_val < -rampDownRate_real)
06747 {
06748
06749 ramp_change = true;
06750
06751 power_val[i].SetReal(prev_VA_out[i].Re() - (rampDownRate_real * deltat));
06752 }
06753
06754 }
06755 }
06756
06757 if (checkRampRate_reactive == true) {
06758
06759
06760 power_diff_val = (power_val[i].Im() - prev_VA_out[i].Im()) / deltat;
06761
06762 if (power_val[i].Im() > prev_VA_out[i].Im())
06763 {
06764
06765 if (power_diff_val > rampUpRate_reactive)
06766 {
06767
06768 ramp_change = true;
06769
06770 power_val[i].SetImag(prev_VA_out[i].Im() + (rampUpRate_reactive * deltat));
06771 }
06772
06773 }
06774 else
06775 {
06776
06777 if (power_diff_val < -rampDownRate_reactive)
06778 {
06779
06780 ramp_change = true;
06781
06782 power_val[i].SetImag(prev_VA_out[i].Im() - (rampDownRate_reactive * deltat));
06783 }
06784
06785 }
06786 }
06787
06788
06789
06790 if (ramp_change == true)
06791 {
06792
06793 temp_current_val[i] = ~(power_val[i] / value_Circuit_V[i]);
06794
06795
06796 curr_state.Idq[i] = temp_current_val[i];
06797 curr_state.md[i] = curr_state.Idq[i].Re()/I_In.Re();
06798 curr_state.mq[i] = curr_state.Idq[i].Im()/I_In.Re();
06799 curr_state.Iac[i] = curr_state.Idq[i];
06800
06801 }
06802
06803
06804
06805 curr_VA_out[i] = power_val[i];
06806 }
06807 }
06808
06809
06810
06811 complex VA_Out_temp = (value_Circuit_V[0] * ~(curr_state.Iac[0])) + (value_Circuit_V[1] * ~(curr_state.Iac[1])) + (value_Circuit_V[2] * ~(curr_state.Iac[2]));
06812 for (int i = 0; i< 3; i++) {
06813 if ((b_soc == -1 && VA_Out_temp.Re() < 0) || Pref == 0) {
06814 curr_state.Iac[i] = 0;
06815 }
06816 value_Line_unrotI[i] += I_Out[i];
06817 value_Line_unrotI[i] += -curr_state.Iac[i];
06818 I_Out[i] = curr_state.Iac[i];
06819 }
06820 }
06821
06822
06823
06824 update_control_references();
06825
06826
06827 for(i = 0; i < 3; i++) {
06828 if ((fabs(curr_state.ded[i]) <= inverter_convergence_criterion) && (fabs(curr_state.deq[i]) <= inverter_convergence_criterion) && (simmode_return_value != SM_DELTA))
06829 {
06830 simmode_return_value = SM_EVENT;
06831 } else {
06832 simmode_return_value = SM_DELTA;
06833 }
06834 }
06835 }
06836 else
06837 {
06838
06839 for(i = 0; i < 3; i++) {
06840 if ((fabs(curr_state.ded[i]) <= inverter_convergence_criterion) && (fabs(curr_state.deq[i]) <= inverter_convergence_criterion) && (simmode_return_value != SM_DELTA))
06841 {
06842 simmode_return_value = SM_EVENT;
06843 } else {
06844 simmode_return_value = SM_DELTA;
06845 }
06846 }
06847 }
06848 }
06849 }
06850 else if (inverter_dyn_mode == PID_CONTROLLER)
06851 {
06852
06853 if (iteration_count_val == 0)
06854 {
06855
06856 prev_PID_state = curr_PID_state;
06857
06858 if ((phases & 0x10) == 0x10)
06859 {
06860
06861 curr_PID_state.phase_Pref = Pref;
06862 curr_PID_state.phase_Qref = Qref;
06863 }
06864 else
06865 {
06866
06867 curr_PID_state.phase_Pref = Pref / 3.0;
06868 curr_PID_state.phase_Qref = Qref / 3.0;
06869 }
06870
06871
06872 curr_PID_state.I_in = I_In.Re();
06873
06874
06875 update_control_references();
06876 }
06877
06878
06879
06880 curr_PID_state.max_error_val = 0.0;
06881
06882
06883 work_power_vals = complex(curr_PID_state.phase_Pref,curr_PID_state.phase_Qref);
06884
06885
06886 if ((phases & 0x10) == 0x10)
06887 {
06888 if (value_Circuit_V[0].Mag() > 0.0)
06889 {
06890
06891 curr_PID_state.current_set_raw[0] = ~(work_power_vals / value_Circuit_V[0]);
06892 }
06893 else
06894 {
06895 curr_PID_state.current_set_raw[0] = complex(0.0,0.0);
06896 }
06897
06898
06899 curr_PID_state.reference_angle[0] = value_Circuit_V[0].Arg();
06900
06901
06902 curr_PID_state.current_set[0] = curr_PID_state.current_set_raw[0] * complex_exp(-1.0 * curr_PID_state.reference_angle[0]);
06903
06904
06905 curr_PID_state.error[0] = curr_PID_state.current_set[0] - prev_PID_state.current_vals_ref[0];
06906
06907
06908 curr_PID_state.derror[0] = (curr_PID_state.error[0] - prev_PID_state.error[0]) / deltat;
06909
06910
06911 curr_PID_state.integrator_vals[0] = prev_PID_state.integrator_vals[0] + (curr_PID_state.error[0] * deltat);
06912
06913
06914 temp_val_d = kpd * curr_PID_state.error[0].Re() + kid * curr_PID_state.integrator_vals[0].Re() + kdd * curr_PID_state.derror[0].Re();
06915 temp_val_q = kpq * curr_PID_state.error[0].Im() + kiq * curr_PID_state.integrator_vals[0].Im() + kdq * curr_PID_state.derror[0].Im();
06916
06917
06918 pid_out[0] = complex(temp_val_d,temp_val_q);
06919
06920
06921 curr_PID_state.mod_vals[0] = prev_PID_state.mod_vals[0] + pid_out[0];
06922
06923
06924 curr_PID_state.current_vals_ref[0] = curr_PID_state.mod_vals[0] * curr_PID_state.I_in;
06925
06926
06927 curr_PID_state.current_vals[0] = complex(-1.0,0.0) * curr_PID_state.current_vals_ref[0] * complex_exp(curr_PID_state.reference_angle[0]);
06928
06929
06930 value_Line_unrotI[0] += -last_current[3] + curr_PID_state.current_vals[0];
06931
06932
06933 last_current[3] = curr_PID_state.current_vals[0];
06934
06935
06936 curr_PID_state.max_error_val = curr_PID_state.error[0].Mag();
06937
06938 }
06939 else
06940 {
06941
06942 for (indexval=0; indexval<3; indexval++)
06943 {
06944 if (value_Circuit_V[indexval].Mag() > 0.0)
06945 {
06946
06947 curr_PID_state.current_set_raw[indexval] = ~(work_power_vals / value_Circuit_V[indexval]);
06948 }
06949 else
06950 {
06951 curr_PID_state.current_set_raw[indexval] = complex(0.0,0.0);
06952 }
06953
06954
06955 curr_PID_state.reference_angle[indexval] = value_Circuit_V[indexval].Arg();
06956
06957
06958 curr_PID_state.current_set[indexval] = curr_PID_state.current_set_raw[indexval] * complex_exp(-1.0 * curr_PID_state.reference_angle[indexval]);
06959
06960
06961 curr_PID_state.error[indexval] = curr_PID_state.current_set[indexval] - prev_PID_state.current_vals_ref[indexval];
06962
06963
06964 curr_PID_state.derror[indexval] = (curr_PID_state.error[indexval] - prev_PID_state.error[indexval]) / deltat;
06965
06966
06967 curr_PID_state.integrator_vals[indexval] = prev_PID_state.integrator_vals[indexval] + (curr_PID_state.error[indexval] * deltat);
06968
06969
06970 temp_val_d = kpd * curr_PID_state.error[indexval].Re() + kid * curr_PID_state.integrator_vals[indexval].Re() + kdd * curr_PID_state.derror[indexval].Re();
06971 temp_val_q = kpq * curr_PID_state.error[indexval].Im() + kiq * curr_PID_state.integrator_vals[indexval].Im() + kdq * curr_PID_state.derror[indexval].Im();
06972
06973
06974 pid_out[indexval] = complex(temp_val_d,temp_val_q);
06975
06976
06977 curr_PID_state.mod_vals[indexval] = prev_PID_state.mod_vals[indexval] + pid_out[indexval];
06978
06979
06980 curr_PID_state.current_vals_ref[indexval] = curr_PID_state.mod_vals[indexval] * curr_PID_state.I_in;
06981
06982
06983 curr_PID_state.current_vals[indexval] = complex(-1.0,0.0) * curr_PID_state.current_vals_ref[indexval] * complex_exp(curr_PID_state.reference_angle[indexval]);
06984
06985
06986 value_Line_unrotI[indexval] += -last_current[indexval] + curr_PID_state.current_vals[indexval];
06987
06988
06989 last_current[indexval] = curr_PID_state.current_vals[indexval];
06990
06991
06992 if (curr_PID_state.error[indexval].Mag() > curr_PID_state.max_error_val)
06993 {
06994 curr_PID_state.max_error_val = curr_PID_state.error[indexval].Mag();
06995 }
06996 }
06997 }
06998
06999
07000 if (curr_PID_state.max_error_val > inverter_convergence_criterion)
07001 {
07002 simmode_return_value = SM_DELTA;
07003 }
07004 else
07005 {
07006 simmode_return_value = SM_EVENT;
07007 }
07008 }
07009 else
07010 {
07011 simmode_return_value = SM_EVENT;
07012 }
07013 }
07014 else
07015 {
07016
07017 if (inverter_dyn_mode == PI_CONTROLLER)
07018 {
07019 if (four_quadrant_control_mode == FQM_VSI)
07020 {
07021 if((phases & 0x10) == 0x10){
07022 value_IGenerated[0] = complex(0.0,0.0);
07023
07024
07025 I_Out[0] = complex(0.0,0.0);
07026 }
07027 else if((phases & 0x07) == 0x07)
07028 {
07029 value_IGenerated[0] = complex(0.0,0.0);
07030 value_IGenerated[1] = complex(0.0,0.0);
07031 value_IGenerated[2] = complex(0.0,0.0);
07032
07033
07034 I_Out[0] = I_Out[1] = I_Out[2] = complex(0.0,0.0);
07035 }
07036 }
07037 else
07038 {
07039 if((phases & 0x10) == 0x10){
07040 value_Line_unrotI[0] += I_Out[0];
07041
07042
07043 I_Out[0] = complex(0.0,0.0);
07044 } else if((phases & 0x07) == 0x07) {
07045 value_Line_unrotI[0] += I_Out[0];
07046 value_Line_unrotI[1] += I_Out[1];
07047 value_Line_unrotI[2] += I_Out[2];
07048
07049
07050 I_Out[0] = I_Out[1] = I_Out[2] = complex(0.0,0.0);
07051 }
07052 }
07053 }
07054 else if (inverter_dyn_mode == PID_CONTROLLER)
07055 {
07056 if((phases & 0x10) == 0x10)
07057 {
07058 value_Line_unrotI[0] -= last_current[3];
07059
07060
07061 last_current[3] = complex(0.0,0.0);
07062 }
07063 else if((phases & 0x07) == 0x07)
07064 {
07065 value_Line_unrotI[0] -= last_current[0];
07066 value_Line_unrotI[1] -= last_current[1];
07067 value_Line_unrotI[2] -= last_current[2];
07068
07069
07070 last_current[0] = last_current[1] = last_current[2] = complex(0.0,0.0);
07071 }
07072 }
07073
07074
07075
07076 simmode_return_value = SM_EVENT;
07077 }
07078
07079
07080 if (parent_is_a_meter == true)
07081 {
07082 push_complex_powerflow_values();
07083 }
07084
07085
07086 if (enable_1547_compliance == true)
07087 {
07088
07089 if ((ieee_1547_double > 0.0) && (ieee_1547_double < 1.7) && (simmode_return_value == SM_EVENT))
07090 {
07091
07092 return SM_DELTA;
07093 }
07094 else
07095 {
07096 return simmode_return_value;
07097 }
07098 }
07099 else
07100 {
07101 return simmode_return_value;
07102 }
07103 }
07104
07105
07106
07107
07108 STATUS inverter::post_deltaupdate(complex *useful_value, unsigned int mode_pass)
07109 {
07110
07111 if (parent_is_a_meter == true)
07112 {
07113 reset_complex_powerflow_accumulators();
07114 }
07115
07116 if (inverter_dyn_mode == PI_CONTROLLER)
07117 {
07118 if (four_quadrant_control_mode != FQM_VSI) {
07119 if((phases & 0x10) == 0x10){
07120 value_Line_unrotI[0] = I_Out[0];
07121 } else if((phases & 0x07) == 0x07) {
07122 value_Line_unrotI[0] = I_Out[0];
07123 value_Line_unrotI[1] = I_Out[1];
07124 value_Line_unrotI[2] = I_Out[2];
07125 }
07126 }
07127 else {
07128
07129 VA_Out_past = VA_Out;
07130
07131 if (VSI_mode == VSI_DROOP) {
07132
07133
07134 P_Out = VA_Out.Re();
07135 Q_Out = VA_Out.Im();
07136
07137 }
07138 }
07139 }
07140 else if (inverter_dyn_mode == PID_CONTROLLER)
07141 {
07142 if((phases & 0x10) == 0x10){
07143 value_Line_unrotI[0] -= last_current[3];
07144 } else if((phases & 0x07) == 0x07) {
07145 value_Line_unrotI[0] -= last_current[0];
07146 value_Line_unrotI[1] -= last_current[1];
07147 value_Line_unrotI[2] -= last_current[2];
07148 }
07149 }
07150
07151
07152
07153 if ((inverter_dyn_mode == PI_CONTROLLER) || (inverter_dyn_mode == PID_CONTROLLER))
07154 {
07155
07156 if (parent_is_a_meter == true)
07157 {
07158 push_complex_powerflow_values();
07159 }
07160 }
07161
07162 return SUCCESS;
07163 }
07164
07165
07166
07167
07168 STATUS inverter::init_PI_dynamics(INV_STATE *curr_time)
07169 {
07170 complex prev_Idq[3];
07171 complex temp_current_val[3];
07172
07173
07174 if (parent_is_a_meter == true)
07175 {
07176 reset_complex_powerflow_accumulators();
07177
07178 pull_complex_powerflow_values();
07179 }
07180
07181 if (four_quadrant_control_mode != FQM_VSI)
07182 {
07183
07184
07185 if((phases & 0x10) == 0x10) {
07186 Pref = VA_Out.Re();
07187 Pref0 = Pref;
07188 prev_Idq[0] = last_I_Out[0];
07189
07190 if(last_I_In > 1e-9) {
07191 curr_time->md[0] = prev_Idq[0].Re()/last_I_In;
07192 } else {
07193 curr_time->md[0] = 0.0;
07194 }
07195 curr_time->Idq[0].SetReal(curr_time->md[0] * I_In.Re());
07196
07197 Qref = VA_Out.Im();
07198 if(last_I_In > 1e-9) {
07199 curr_time->mq[0] = prev_Idq[0].Im()/last_I_In;
07200 } else {
07201 curr_time->mq[0] = 0.0;
07202 }
07203 curr_time->Idq[0].SetImag(curr_time->mq[0] * I_In.Re());
07204 curr_time->Iac[0] = curr_time->Idq[0];
07205
07206
07207 if (four_quadrant_control_mode != FQM_VSI)
07208 {
07209 value_Line_unrotI[0] = -curr_time->Iac[0];
07210 }
07211 else {
07212 value_IGenerated[0] = -curr_time->Iac[0];
07213 }
07214
07215 } else if((phases & 0x07) == 0x07) {
07216 Pref = VA_Out.Re();
07217 Qref = VA_Out.Im();
07218 Pref0 = Pref;
07219
07220 for(int i = 0; i < 3; i++){
07221
07222
07223 last_I_Out[i] = I_Out[i];
07224
07225 prev_Idq[i] = last_I_Out[i];
07226
07227 if(last_I_In > 1e-9) {
07228 curr_time->md[i] = prev_Idq[i].Re()/last_I_In;
07229 curr_time->mq[i] = prev_Idq[i].Im()/last_I_In;
07230 } else {
07231 curr_time->md[i] = 0.0;
07232 curr_time->mq[i] = 0.0;
07233 }
07234 curr_time->Idq[i].SetReal(curr_time->md[i] * I_In.Re());
07235 curr_time->Idq[i].SetImag(curr_time->mq[i] * I_In.Re());
07236 curr_time->Iac[i] = curr_time->Idq[i];
07237
07238
07239 if (four_quadrant_control_mode != FQM_VSI)
07240 {
07241 value_Line_unrotI[i] = -curr_time->Iac[i];
07242 }
07243 else {
07244 value_IGenerated[i] = -curr_time->Iac[i];
07245 }
07246 }
07247 }
07248
07249
07250 if (checkRampRate_real == true || checkRampRate_reactive == true)
07251 {
07252 if ((phases & 0x10) == 0x10)
07253 {
07254 curr_VA_out[0] = value_Circuit_V[0] * ~(I_Out[0]);
07255
07256
07257 prev_VA_out[0] = curr_VA_out[0];
07258 }
07259 else if ((phases & 0x07) == 0x07)
07260 {
07261 curr_VA_out[0] = value_Circuit_V[0] * ~(I_Out[0]);
07262 curr_VA_out[1] = value_Circuit_V[1] * ~(I_Out[1]);
07263 curr_VA_out[2] = value_Circuit_V[2] * ~(I_Out[2]);
07264
07265
07266 prev_VA_out[0] = curr_VA_out[0];
07267 prev_VA_out[1] = curr_VA_out[1];
07268 prev_VA_out[2] = curr_VA_out[2];
07269 }
07270 }
07271
07272
07273 if((phases & 0x10) == 0x10) {
07274 Qref0[0] = (value_Circuit_V[0] * ~(I_Out[0])).Im();
07275 Qref_PI[0] = Qref0[0];
07276 Qref_PI[1] = 0;
07277 Qref_PI[2] = 0;
07278 }
07279 if((phases & 0x07) == 0x07) {
07280 Qref0[0] = (value_Circuit_V[0] * ~(I_Out[0])).Im();
07281 Qref0[1] = (value_Circuit_V[1] * ~(I_Out[1])).Im();
07282 Qref0[2] = (value_Circuit_V[2] * ~(I_Out[2])).Im();
07283 Qref_PI[0] = (value_Circuit_V[0] * ~(I_Out[0])).Im();
07284 Qref_PI[1] = (value_Circuit_V[1] * ~(I_Out[1])).Im();
07285 Qref_PI[2] = (value_Circuit_V[2] * ~(I_Out[2])).Im();
07286
07287 }
07288
07289
07290 P_Out = Pref0;
07291 Q_Out = Qref0[0] + Qref0[1] + Qref0[2];
07292
07293
07294 if (inverter_droop_fp) {
07295 curr_time->f_mea_delayed = value_Frequency;
07296 }
07297
07298
07299 if((phases & 0x10) == 0x10) {
07300 curr_time->V_mea_delayed[0] = value_Circuit_V[0].Mag();
07301 V_ref[0] = value_Circuit_V[0].Mag();
07302 }
07303 if((phases & 0x07) == 0x07) {
07304 curr_time->V_mea_delayed[0] = value_Circuit_V[0].Mag();
07305 curr_time->V_mea_delayed[1] = value_Circuit_V[1].Mag();
07306 curr_time->V_mea_delayed[2] = value_Circuit_V[2].Mag();
07307 V_ref[0] = value_Circuit_V[0].Mag();
07308 V_ref[1] = value_Circuit_V[1].Mag();
07309 V_ref[2] = value_Circuit_V[2].Mag();
07310 }
07311 }
07312 else {
07313 if((phases & 0x10) == 0x10) {
07314
07315
07316 temp_current_val[0] = value_IGenerated[0] - generator_admittance[0][0] * value_Circuit_V[0];
07317
07318
07319 VA_Out = value_Circuit_V[0]*~temp_current_val[0];
07320
07321
07322 if (checkRampRate_real == true || checkRampRate_reactive == true)
07323 {
07324 curr_VA_out[0] = VA_Out;
07325
07326
07327 prev_VA_out[0] = curr_VA_out[0];
07328 }
07329
07330 e_source[0] = (value_IGenerated[0] * complex(Rfilter,Xfilter) * Zbase);
07331 V_angle[0] = (e_source[0]).Arg();
07332 V_angle_past[0] = V_angle[0];
07333
07334 if (VSI_mode == VSI_DROOP)
07335 {
07336 V_mag_ref[0] = value_Circuit_V[0].Mag() + (VA_Out.Im() - Qref) / p_rated / 3.0 * R_vq * node_nominal_voltage ;
07337 curr_time->V_StateVal[0] = e_source[0].Mag();
07338 curr_time->e_source_mag[0] = e_source[0].Mag();
07339 }
07340 else {
07341 V_mag_ref[0] = value_Circuit_V[0].Mag();
07342 V_mag[0] = V_mag_ref[0];
07343 curr_time->V_StateVal[0] = e_source[0].Mag();
07344 curr_time->e_source_mag[0] = e_source[0].Mag();
07345 }
07346 }
07347 if((phases & 0x07) == 0x07) {
07348
07349
07350 temp_current_val[0] = (value_IGenerated[0] - generator_admittance[0][0]*value_Circuit_V[0] - generator_admittance[0][1]*value_Circuit_V[1] - generator_admittance[0][2]*value_Circuit_V[2]);
07351 temp_current_val[1] = (value_IGenerated[1] - generator_admittance[1][0]*value_Circuit_V[0] - generator_admittance[1][1]*value_Circuit_V[1] - generator_admittance[1][2]*value_Circuit_V[2]);
07352 temp_current_val[2] = (value_IGenerated[2] - generator_admittance[2][0]*value_Circuit_V[0] - generator_admittance[2][1]*value_Circuit_V[1] - generator_admittance[2][2]*value_Circuit_V[2]);
07353
07354
07355 power_val[0] = value_Circuit_V[0]*~temp_current_val[0];
07356 power_val[1] = value_Circuit_V[1]*~temp_current_val[1];
07357 power_val[2] = value_Circuit_V[2]*~temp_current_val[2];
07358
07359 VA_Out = power_val[0] + power_val[1] + power_val[2];
07360
07361
07362 if (checkRampRate_real == true || checkRampRate_reactive == true)
07363 {
07364 curr_VA_out[0] = power_val[0];
07365 curr_VA_out[1] = power_val[1];
07366 curr_VA_out[2] = power_val[2];
07367
07368
07369 prev_VA_out[0] = curr_VA_out[0];
07370 prev_VA_out[1] = curr_VA_out[1];
07371 prev_VA_out[2] = curr_VA_out[2];
07372 }
07373
07374
07375 pCircuit_V_Avg = (value_Circuit_V[0].Mag() + value_Circuit_V[1].Mag() + value_Circuit_V[2].Mag()) / 3.0;
07376
07377 for (int i = 0; i < 3; i++) {
07378 e_source[i] = (value_IGenerated[i] * complex(Rfilter,Xfilter) * Zbase);
07379 V_angle[i] = (e_source[i]).Arg();
07380 V_angle_past[i] = V_angle[i];
07381 if (VSI_mode == VSI_DROOP) {
07382 V_mag_ref[i] = pCircuit_V_Avg + (VA_Out.Im() - Qref) / p_rated / 3.0 * R_vq * node_nominal_voltage;
07383 curr_time->V_StateVal[i] = e_source[i].Mag();
07384 curr_time->e_source_mag[i] = e_source[i].Mag();
07385 }
07386 else {
07387 V_mag_ref[i] = value_Circuit_V[i].Mag();
07388 V_mag[i] = V_mag_ref[i];
07389 curr_time->V_StateVal[i] = e_source[i].Mag();
07390 curr_time->e_source_mag[i] = e_source[i].Mag();
07391 }
07392 }
07393 }
07394
07395
07396 curr_time->p_mea_delayed = VA_Out.Re();
07397 curr_time->q_mea_delayed = VA_Out.Im();
07398 Pref = VA_Out.Re();
07399 Qref = VA_Out.Im();
07400
07401 VA_Out_past = VA_Out;
07402 }
07403
07404
07405 if (parent_is_a_meter == true)
07406 {
07407 push_complex_powerflow_values();
07408 }
07409
07410 return SUCCESS;
07411 }
07412
07413
07414
07415
07416 STATUS inverter::init_PID_dynamics(void)
07417 {
07418 int indexx;
07419
07420
07421 if (parent_is_a_meter == true)
07422 {
07423 reset_complex_powerflow_accumulators();
07424
07425 pull_complex_powerflow_values();
07426 }
07427
07428
07429 Pref = VA_Out.Re();
07430 Qref = VA_Out.Im();
07431
07432
07433 curr_PID_state.I_in = I_In.Re();
07434
07435
07436 if ( (phases & 0x10) == 0x10 )
07437 {
07438
07439 curr_PID_state.phase_Pref = VA_Out.Re();
07440 curr_PID_state.phase_Qref = VA_Out.Im();
07441
07442
07443 if (checkRampRate_real == true)
07444 {
07445 curr_VA_out[0] = VA_Out;
07446
07447
07448 prev_VA_out[0] = curr_VA_out[0];
07449 }
07450
07451
07452 for (indexx=0; indexx<3; indexx++)
07453 {
07454
07455 curr_PID_state.reference_angle[indexx] = 0.0;
07456 curr_PID_state.error[indexx] = complex(0.0,0.0);
07457 curr_PID_state.integrator_vals[indexx] = complex(0.0,0.0);
07458 curr_PID_state.derror[indexx] = complex(0.0,0.0);
07459 curr_PID_state.current_set_raw[indexx] = complex(0.0,0.0);
07460 curr_PID_state.current_set[indexx] = complex(0.0,0.0);
07461 curr_PID_state.current_vals[indexx] = complex(0.0,0.0);
07462 curr_PID_state.current_vals_ref[indexx] = complex(0.0,0.0);
07463 curr_PID_state.mod_vals[indexx] = complex(0.0,0.0);
07464 }
07465
07466
07467 curr_PID_state.reference_angle[0] = value_Circuit_V[0].Arg();
07468
07469 if (value_Circuit_V[0].Mag() > 0.0)
07470 {
07471
07472 curr_PID_state.current_set_raw[0] = ~(complex(curr_PID_state.phase_Pref,curr_PID_state.phase_Qref)/value_Circuit_V[0]);
07473 }
07474 else
07475 {
07476 curr_PID_state.current_set_raw[0] = complex(0.0,0.0);
07477 }
07478
07479
07480 curr_PID_state.current_set[0] = curr_PID_state.current_set_raw[0] * complex_exp(-1.0 * curr_PID_state.reference_angle[0]);
07481
07482
07483 curr_PID_state.current_vals[0] = last_current[3];
07484
07485
07486 curr_PID_state.current_vals_ref[0] = complex(-1.0,0.0) * curr_PID_state.current_vals[0] * complex_exp(-1.0 * curr_PID_state.reference_angle[0]);
07487
07488
07489 curr_PID_state.mod_vals[0] = complex((curr_PID_state.current_vals_ref[0].Re() / curr_PID_state.I_in),(curr_PID_state.current_vals_ref[0].Im() / curr_PID_state.I_in));
07490
07491
07492 value_Line_unrotI[0] = last_current[3];
07493
07494 }
07495 else
07496 {
07497
07498 curr_PID_state.phase_Pref = VA_Out.Re() / 3.0;
07499 curr_PID_state.phase_Qref = VA_Out.Im() / 3.0;
07500
07501
07502 if (checkRampRate_real == true)
07503 {
07504 curr_VA_out[0] = complex(curr_PID_state.phase_Pref,curr_PID_state.phase_Qref);
07505 curr_VA_out[1] = complex(curr_PID_state.phase_Pref,curr_PID_state.phase_Qref);
07506 curr_VA_out[2] = complex(curr_PID_state.phase_Pref,curr_PID_state.phase_Qref);
07507
07508
07509 prev_VA_out[0] = curr_VA_out[0];
07510 prev_VA_out[1] = curr_VA_out[1];
07511 prev_VA_out[1] = curr_VA_out[2];
07512 }
07513
07514
07515 for (indexx=0; indexx<3; indexx++)
07516 {
07517
07518 curr_PID_state.error[indexx] = complex(0.0,0.0);
07519 curr_PID_state.integrator_vals[indexx] = complex(0.0,0.0);
07520 curr_PID_state.derror[indexx] = complex(0.0,0.0);
07521
07522
07523 curr_PID_state.reference_angle[indexx] = value_Circuit_V[indexx].Arg();
07524
07525
07526 if (value_Circuit_V[indexx].Mag() > 0.0)
07527 {
07528
07529 curr_PID_state.current_set_raw[indexx] = ~(complex(curr_PID_state.phase_Pref,curr_PID_state.phase_Qref)/value_Circuit_V[indexx]);
07530 }
07531 else
07532 {
07533 curr_PID_state.current_set_raw[indexx] = complex(0.0,0.0);
07534 }
07535
07536
07537 curr_PID_state.current_set[indexx] = curr_PID_state.current_set_raw[indexx] * complex_exp(-1.0 * curr_PID_state.reference_angle[indexx]);
07538
07539
07540 curr_PID_state.current_vals[indexx] = last_current[indexx];
07541
07542
07543 curr_PID_state.current_vals_ref[indexx] = complex(-1.0,0.0) * curr_PID_state.current_vals[indexx] * complex_exp(-1.0 * curr_PID_state.reference_angle[indexx]);
07544
07545
07546 if (curr_PID_state.I_in != 0.0)
07547 {
07548 curr_PID_state.mod_vals[indexx] = complex((curr_PID_state.current_vals_ref[indexx].Re() / curr_PID_state.I_in),(curr_PID_state.current_vals_ref[indexx].Im() / curr_PID_state.I_in));
07549 }
07550 else
07551 {
07552 curr_PID_state.mod_vals[indexx] = complex(0.0,0.0);
07553 }
07554
07555
07556 value_Line_unrotI[indexx] = last_current[indexx];
07557 }
07558 }
07559
07560
07561 if (parent_is_a_meter == true)
07562 {
07563 push_complex_powerflow_values();
07564 }
07565
07566 return SUCCESS;
07567 }
07568
07569
07570 void inverter::update_control_references(void)
07571 {
07572
07573 double VA_Efficiency, temp_PF, temp_QVal;
07574 complex temp_VA, VA_Outref;
07575 complex battery_power_out = complex(0,0);
07576 OBJECT *obj = OBJECTHDR(this);
07577 bool VA_changed = false;
07578
07579
07580 VA_In = V_In * ~ I_In;
07581
07582
07583 if(use_multipoint_efficiency == false)
07584 {
07585
07586 VA_Efficiency = VA_In.Re() * efficiency;
07587 }
07588 else
07589 {
07590
07591 if(VA_In.Mag() <= p_so)
07592 {
07593 VA_Efficiency = 0.0;
07594 }
07595 else
07596 {
07597
07598 if(V_In.Mag() > v_dco)
07599 {
07600 gl_warning("The dc voltage is greater than the specified maximum for the inverter. Efficiency model may be inaccurate.");
07601
07602
07603
07604
07605 }
07606
07607
07608 C1 = p_dco*(1+c_1*(V_In.Re()-v_dco));
07609 C2 = p_so*(1+c_2*(V_In.Re()-v_dco));
07610 C3 = c_o*(1+c_3*(V_In.Re()-v_dco));
07611
07612
07613 VA_Efficiency = (((p_max/(C1-C2))-C3*(C1-C2))*(VA_In.Re()-C2)+C3*(VA_In.Re()-C2)*(VA_In.Re()-C2));
07614 }
07615 }
07616
07617
07618 if(four_quadrant_control_mode == FQM_CONSTANT_PF)
07619 {
07620 if(power_factor != 0.0)
07621 {
07622 if (VA_In<0.0)
07623 {
07624
07625 VA_Outref.SetReal(VA_Efficiency*-1.0);
07626 }
07627 else if (VA_In>0.0)
07628 {
07629
07630 VA_Outref.SetReal(VA_Efficiency);
07631 }
07632 else
07633 {
07634 VA_Outref.SetReal(0.0);
07635 }
07636
07637
07638
07639 if (power_factor < 0)
07640 {
07641 VA_Outref.SetImag((VA_Efficiency/sqrt(power_factor*power_factor))*sqrt(1.0-(power_factor*power_factor)));
07642 }
07643 else
07644 {
07645 VA_Outref.SetImag((VA_Efficiency/sqrt(power_factor*power_factor))*-1.0*sqrt(1.0-(power_factor*power_factor)));
07646 }
07647 }
07648 else
07649 {
07650 VA_Outref = complex(0.0,VA_Efficiency);
07651 }
07652 }
07653 else if (four_quadrant_control_mode == FQM_CONSTANT_PQ)
07654 {
07655
07656 if (b_soc == -1) {
07657 if (Pref < 0) {
07658 Pref = 0;
07659 }
07660 }
07661
07662
07663 if (inverter_dyn_mode == PI_CONTROLLER) {
07664 temp_VA = complex(Pref,Qref_PI[0]+Qref_PI[1]+Qref_PI[2]);
07665 }
07666 else {
07667 temp_VA = complex(Pref, Qref);
07668 }
07669
07670
07671
07672 if ((b_soc >= 1.0) && (temp_VA.Re() < 0) && (b_soc != -1))
07673 {
07674 gl_warning("inverter:%s - battery full - no charging allowed",obj->name);
07675 temp_VA.SetReal(0.0);
07676 VA_changed = true;
07677 }
07678 else if ((b_soc <= soc_reserve) && (temp_VA.Re() > 0) && (b_soc != -1))
07679 {
07680 gl_warning("inverter:%s - battery at or below the SOC reserve - no discharging allowed",obj->name);
07681 temp_VA.SetReal(0.0);
07682 VA_changed = true;
07683 }
07684
07685
07686 if (fabs(temp_VA.Mag()) > p_max ){
07687 VA_changed = true;
07688 if (p_max > fabs(temp_VA.Re()))
07689 {
07690
07691 temp_QVal = sqrt((p_max*p_max) - (temp_VA.Re()*temp_VA.Re()));
07692
07693
07694 if (temp_VA.Im() < 0.0)
07695 {
07696 VA_Outref = complex(temp_VA.Re(),-temp_QVal);
07697 }
07698 else
07699 {
07700 VA_Outref = complex(temp_VA.Re(),temp_QVal);
07701 }
07702 }
07703 else
07704 {
07705
07706 if (temp_VA.Re() < 0.0)
07707 {
07708 VA_Outref = complex(-p_max,0.0);
07709 }
07710 else
07711 {
07712 VA_Outref = complex(p_max,0.0);
07713 }
07714 }
07715 }
07716 else
07717 {
07718 VA_Outref = temp_VA;
07719 }
07720
07721
07722
07723
07724 if (VA_Outref.Re() > 0.0)
07725 {
07726 p_in = VA_Outref.Re()/inv_eta;
07727 }
07728 else if (VA_Outref.Re() == 0.0)
07729 {
07730 p_in = 0.0;
07731 }
07732 else
07733 {
07734 p_in = VA_Outref.Re()*inv_eta;
07735 }
07736 }
07737
07738
07739 if(VA_Outref.Mag() > p_max)
07740 {
07741 VA_changed = true;
07742
07743 excess_input_power = (VA_Outref.Mag() - p_max);
07744
07745
07746 if (four_quadrant_control_mode == FQM_CONSTANT_PF)
07747 {
07748 temp_PF = power_factor;
07749 }
07750 else
07751 {
07752 temp_PF = VA_Outref.Re()/VA_Outref.Mag();
07753 }
07754
07755
07756 temp_VA = complex(fabs(p_max*temp_PF),fabs(p_max*sqrt(1.0-(temp_PF*temp_PF))));
07757
07758
07759 if ((VA_Outref.Re()<0) && (VA_Outref.Im()<0))
07760 {
07761 VA_Outref = -temp_VA;
07762 }
07763 else if ((VA_Outref.Re()<0) && (VA_Outref.Im()>=0))
07764 {
07765 VA_Outref = complex(-temp_VA.Re(),temp_VA.Im());
07766 }
07767 else if ((VA_Outref.Re()>=0) && (VA_Outref.Im()<0))
07768 {
07769 VA_Outref = complex(temp_VA.Re(),-temp_VA.Im());
07770 }
07771 else
07772 {
07773 VA_Outref = temp_VA;
07774 }
07775 }
07776 else
07777 {
07778 excess_input_power = 0.0;
07779 }
07780
07781 Pref = VA_Outref.Re();
07782 Qref = VA_Outref.Im();
07783
07784
07785 if (VA_changed == true) {
07786 if((phases & 0x10) == 0x10) {
07787 Qref_PI[0] = VA_Outref.Im();
07788 Qref_PI[1] = 0;
07789 Qref_PI[2] = 0;
07790 }
07791 if((phases & 0x07) == 0x07) {
07792 Qref_PI[0] = VA_Outref.Im()/3;
07793 Qref_PI[1] = VA_Outref.Im()/3;
07794 Qref_PI[2] = VA_Outref.Im()/3;
07795 }
07796 }
07797 }
07798
07799
07800 STATUS inverter::initalize_IEEE_1547_checks(OBJECT *parent)
07801 {
07802 OBJECT *obj = OBJECTHDR(this);
07803 gld_property *temp_nominal_pointer;
07804
07805
07806
07807 if (gl_object_isa(parent,"node","powerflow") || gl_object_isa(parent,"load","powerflow") || gl_object_isa(parent,"meter","powerflow") || gl_object_isa(parent,"triplex_node","powerflow") || gl_object_isa(parent,"triplex_load","powerflow") || gl_object_isa(parent,"triplex_load","powerflow"))
07808 {
07809
07810 temp_nominal_pointer = new gld_property(parent,"nominal_voltage");
07811
07812
07813 if ((temp_nominal_pointer->is_valid() != true) || (temp_nominal_pointer->is_double() != true))
07814 {
07815 gl_error("Inverter:%d %s failed to map the nominal_voltage property",obj->id, (obj->name ? obj->name : "Unnamed"));
07816
07817
07818
07819
07820
07821 return FAILED;
07822 }
07823
07824
07825
07826 node_nominal_voltage = temp_nominal_pointer->get_double();
07827
07828
07829 delete temp_nominal_pointer;
07830
07831
07832 if (ieee_1547_version == IEEE1547)
07833 {
07834
07835 over_freq_high_band_setpoint = 70.0;
07836 over_freq_high_band_delay = 0.16;
07837 over_freq_low_band_setpoint = 60.5;
07838 over_freq_low_band_delay = 0.16;
07839
07840
07841 if (p_rated > 30000.0)
07842 {
07843 under_freq_high_band_setpoint = 59.5;
07844 under_freq_high_band_delay = 300.0;
07845 under_freq_low_band_setpoint = 57.0;
07846 under_freq_low_band_delay = 0.16;
07847 }
07848 else
07849 {
07850 under_freq_high_band_setpoint = 59.3;
07851 under_freq_high_band_delay = 0.16;
07852 under_freq_low_band_setpoint = 47.0;
07853 under_freq_low_band_delay = 0.16;
07854 }
07855
07856
07857 under_voltage_lowest_voltage_setpoint = 0.40;
07858 under_voltage_middle_voltage_setpoint = 0.50;
07859 under_voltage_high_voltage_setpoint = 0.88;
07860 over_voltage_low_setpoint = 1.10;
07861 over_voltage_high_setpoint = 1.20;
07862
07863 under_voltage_lowest_delay = 0.16;
07864 under_voltage_middle_delay = 0.16;
07865 under_voltage_high_delay = 2.0;
07866 over_voltage_low_delay = 1.0;
07867 over_voltage_high_delay = 0.16;
07868 }
07869 }
07870 else
07871 {
07872
07873 enable_1547_compliance = false;
07874
07875 gl_warning("Inverter:%d %s does not have a valid parent - 1547 checks have been disabled",obj->id,(obj->name ? obj->name : "Unnamed"));
07876
07877
07878
07879
07880 }
07881
07882
07883 return SUCCESS;
07884 }
07885
07886
07887 double inverter::perform_1547_checks(double timestepvalue)
07888 {
07889 bool voltage_violation, frequency_violation, trigger_disconnect, check_phase;
07890 bool uv_low_hit, uv_mid_hit, uv_high_hit, ov_low_hit, ov_high_hit;
07891 double temp_pu_voltage;
07892 double return_time_freq, return_time_volt, return_value;
07893 char indexval;
07894
07895
07896 return_time_freq = -1.0;
07897 return_time_volt = -1.0;
07898 return_value = -1.0;
07899
07900
07901 if (parent_is_a_meter == true)
07902 {
07903 reset_complex_powerflow_accumulators();
07904
07905 pull_complex_powerflow_values();
07906 }
07907
07908
07909 if ((value_Frequency > over_freq_low_band_setpoint) || (value_Frequency < under_freq_high_band_setpoint))
07910 {
07911
07912 frequency_violation = true;
07913
07914
07915 out_of_violation_time_total = 0.0;
07916
07917
07918 if (value_Frequency > over_freq_high_band_setpoint)
07919 {
07920
07921 over_freq_high_band_viol_time += timestepvalue;
07922 over_freq_low_band_viol_time += timestepvalue;
07923
07924
07925 under_freq_high_band_viol_time = 0.0;
07926 under_freq_low_band_viol_time = 0.0;
07927
07928 if (over_freq_high_band_viol_time >= over_freq_high_band_delay)
07929 {
07930 trigger_disconnect = true;
07931 return_time_freq = reconnect_time;
07932
07933
07934 ieee_1547_trip_method = IEEE_1547_HIGH_OF;
07935 }
07936 else if (over_freq_low_band_viol_time >= over_freq_low_band_delay)
07937 {
07938 trigger_disconnect = true;
07939 return_time_freq = reconnect_time;
07940
07941
07942 ieee_1547_trip_method = IEEE_1547_LOW_OF;
07943 }
07944 else
07945 {
07946 trigger_disconnect = false;
07947
07948
07949 if ((over_freq_high_band_delay - over_freq_high_band_viol_time) < (over_freq_low_band_delay - over_freq_low_band_viol_time))
07950 {
07951 return_time_freq = over_freq_high_band_delay - over_freq_high_band_viol_time;
07952 }
07953 else
07954 {
07955 return_time_freq = over_freq_low_band_delay - over_freq_low_band_viol_time;
07956 }
07957 }
07958 }
07959 else if (value_Frequency < under_freq_low_band_setpoint)
07960 {
07961
07962 under_freq_high_band_viol_time += timestepvalue;
07963 under_freq_low_band_viol_time += timestepvalue;
07964
07965
07966 over_freq_high_band_viol_time = 0.0;
07967 over_freq_low_band_viol_time = 0.0;
07968
07969 if (under_freq_low_band_viol_time >= under_freq_low_band_delay)
07970 {
07971 trigger_disconnect = true;
07972 return_time_freq = reconnect_time;
07973
07974
07975 ieee_1547_trip_method = IEEE_1547_LOW_UF;
07976 }
07977 else if (under_freq_high_band_viol_time >= under_freq_high_band_delay)
07978 {
07979 trigger_disconnect = true;
07980 return_time_freq = reconnect_time;
07981
07982
07983 ieee_1547_trip_method = IEEE_1547_HIGH_UF;
07984 }
07985 else
07986 {
07987 trigger_disconnect = false;
07988
07989
07990 if ((under_freq_high_band_delay - under_freq_high_band_viol_time) < (under_freq_low_band_delay - under_freq_low_band_viol_time))
07991 {
07992 return_time_freq = under_freq_high_band_delay - under_freq_high_band_viol_time;
07993 }
07994 else
07995 {
07996 return_time_freq = under_freq_low_band_delay - under_freq_low_band_viol_time;
07997 }
07998 }
07999 }
08000 else if ((value_Frequency < under_freq_high_band_setpoint) && (value_Frequency >= under_freq_low_band_setpoint))
08001 {
08002
08003 under_freq_high_band_viol_time += timestepvalue;
08004
08005
08006 under_freq_low_band_viol_time = 0.0;
08007
08008
08009 over_freq_high_band_viol_time = 0.0;
08010 over_freq_low_band_viol_time = 0.0;
08011
08012 if (under_freq_high_band_viol_time >= under_freq_high_band_delay)
08013 {
08014 trigger_disconnect = true;
08015 return_time_freq = reconnect_time;
08016
08017
08018 ieee_1547_trip_method = IEEE_1547_HIGH_UF;
08019 }
08020 else
08021 {
08022 trigger_disconnect = false;
08023 return_time_freq = under_freq_high_band_delay - under_freq_high_band_viol_time;
08024 }
08025 }
08026 else if ((value_Frequency <= over_freq_high_band_setpoint) && (value_Frequency > over_freq_low_band_setpoint))
08027 {
08028
08029 over_freq_low_band_viol_time += timestepvalue;
08030
08031
08032 over_freq_high_band_viol_time = 0.0;
08033
08034
08035 under_freq_high_band_viol_time = 0.0;
08036 under_freq_low_band_viol_time = 0.0;
08037
08038 if (over_freq_low_band_viol_time >= over_freq_low_band_delay)
08039 {
08040 trigger_disconnect = true;
08041 return_time_freq = reconnect_time;
08042
08043
08044 ieee_1547_trip_method = IEEE_1547_LOW_OF;
08045 }
08046 else
08047 {
08048 trigger_disconnect = false;
08049 return_time_freq = over_freq_low_band_delay - over_freq_low_band_viol_time;
08050 }
08051 }
08052 else
08053 {
08054 gl_error("Inverter 1547 Checks - invalid state!");
08055
08056
08057
08058
08059 }
08060 }
08061 else
08062 {
08063
08064 frequency_violation = false;
08065 trigger_disconnect = false;
08066
08067
08068 over_freq_high_band_viol_time = 0.0;
08069 over_freq_low_band_viol_time = 0.0;
08070 under_freq_high_band_viol_time = 0.0;
08071 under_freq_low_band_viol_time = 0.0;
08072
08073
08074 return_time_freq = -1.0;
08075 }
08076
08077
08078 voltage_violation = false;
08079
08080
08081 uv_low_hit = false;
08082 uv_mid_hit = false;
08083 uv_high_hit = false;
08084 ov_low_hit = false;
08085 ov_high_hit = false;
08086
08087
08088
08089 for (indexval = 0; indexval < 3; indexval++)
08090 {
08091
08092 if ((phases & PHASE_S) == PHASE_S)
08093 {
08094
08095 if (indexval < 2)
08096 {
08097 check_phase = true;
08098 }
08099 else
08100 {
08101 check_phase = false;
08102 break;
08103 }
08104 }
08105 else if ((indexval == 0) && ((phases & PHASE_A) == PHASE_A))
08106 {
08107 check_phase = true;
08108 }
08109 else if ((indexval == 1) && ((phases & PHASE_B) == PHASE_B))
08110 {
08111 check_phase = true;
08112 }
08113 else if ((indexval == 2) && ((phases & PHASE_C) == PHASE_C))
08114 {
08115 check_phase = true;
08116 }
08117 else
08118 {
08119 check_phase = false;
08120 }
08121
08122
08123 if (check_phase == true)
08124 {
08125
08126 temp_pu_voltage = value_Circuit_V[indexval].Mag()/node_nominal_voltage;
08127
08128
08129 if ((temp_pu_voltage < under_voltage_high_voltage_setpoint) || (temp_pu_voltage > over_voltage_low_setpoint))
08130 {
08131
08132 voltage_violation = true;
08133
08134
08135 out_of_violation_time_total = 0.0;
08136
08137
08138 if (temp_pu_voltage < under_voltage_lowest_voltage_setpoint)
08139 {
08140
08141 if (uv_low_hit == false)
08142 {
08143 under_voltage_lowest_viol_time += timestepvalue;
08144 uv_low_hit = true;
08145 }
08146
08147 }
08148 else if ((temp_pu_voltage >= under_voltage_lowest_voltage_setpoint) && (temp_pu_voltage < under_voltage_middle_voltage_setpoint))
08149 {
08150
08151
08152 if (uv_mid_hit == false)
08153 {
08154 under_voltage_middle_viol_time += timestepvalue;
08155 uv_mid_hit = true;
08156 }
08157
08158 }
08159 else if ((temp_pu_voltage >= under_voltage_middle_voltage_setpoint) && (temp_pu_voltage < under_voltage_high_voltage_setpoint))
08160 {
08161
08162 if (uv_high_hit == false)
08163 {
08164 under_voltage_high_viol_time += timestepvalue;
08165 uv_high_hit = true;
08166 }
08167
08168 }
08169 else if ((temp_pu_voltage > over_voltage_low_setpoint) && (temp_pu_voltage < over_voltage_high_setpoint))
08170 {
08171
08172 if (ov_low_hit == false)
08173 {
08174 over_voltage_low_viol_time += timestepvalue;
08175 ov_low_hit = true;
08176 }
08177
08178 }
08179 else if (temp_pu_voltage >= over_voltage_high_setpoint)
08180 {
08181
08182 if (ov_high_hit == false)
08183 {
08184 over_voltage_high_viol_time += timestepvalue;
08185 ov_high_hit = true;
08186 }
08187
08188 }
08189 else
08190 {
08191 gl_error("Inverter 1547 Checks - invalid state!");
08192
08193 }
08194 }
08195
08196 }
08197
08198
08199
08200 }
08201
08202
08203 if (voltage_violation == true)
08204 {
08205
08206 if (uv_low_hit == true)
08207 {
08208 if (under_voltage_lowest_viol_time >= under_voltage_lowest_delay)
08209 {
08210 trigger_disconnect = true;
08211 return_time_volt = reconnect_time;
08212
08213
08214 ieee_1547_trip_method = IEEE_1547_LOWEST_UV;
08215 }
08216 else if (under_voltage_middle_viol_time >= under_voltage_middle_delay)
08217 {
08218 trigger_disconnect = true;
08219 return_time_volt = reconnect_time;
08220
08221
08222 ieee_1547_trip_method = IEEE_1547_MIDDLE_UV;
08223 }
08224
08225 else if (under_voltage_high_viol_time >= under_voltage_high_delay)
08226 {
08227 trigger_disconnect = true;
08228 return_time_volt = reconnect_time;
08229
08230
08231 ieee_1547_trip_method = IEEE_1547_HIGH_UV;
08232 }
08233 else
08234 {
08235 trigger_disconnect = false;
08236 return_time_volt = under_voltage_lowest_delay - under_voltage_lowest_viol_time;
08237 }
08238 }
08239 else if (uv_mid_hit == true)
08240 {
08241 if (under_voltage_middle_viol_time >= under_voltage_middle_delay)
08242 {
08243 trigger_disconnect = true;
08244 return_time_volt = reconnect_time;
08245
08246
08247 ieee_1547_trip_method = IEEE_1547_MIDDLE_UV;
08248 }
08249 else if (under_voltage_high_viol_time >= under_voltage_high_delay)
08250 {
08251 trigger_disconnect = true;
08252 return_time_volt = reconnect_time;
08253
08254
08255 ieee_1547_trip_method = IEEE_1547_HIGH_UV;
08256 }
08257 else
08258 {
08259 trigger_disconnect = false;
08260 return_time_volt = under_voltage_middle_delay - under_voltage_middle_viol_time;
08261 }
08262 }
08263 else if (uv_high_hit == true)
08264 {
08265 if (under_voltage_high_viol_time >= under_voltage_high_delay)
08266 {
08267 trigger_disconnect = true;
08268 return_time_volt = reconnect_time;
08269
08270
08271 ieee_1547_trip_method = IEEE_1547_HIGH_UV;
08272 }
08273 else
08274 {
08275 trigger_disconnect = false;
08276 return_time_volt = under_voltage_high_delay - under_voltage_high_viol_time;
08277 }
08278 }
08279 else if (ov_low_hit == true)
08280 {
08281 if (over_voltage_low_viol_time >= over_voltage_low_delay)
08282 {
08283 trigger_disconnect = true;
08284 return_time_volt = reconnect_time;
08285
08286
08287 ieee_1547_trip_method = IEEE_1547_LOW_OV;
08288 }
08289 else
08290 {
08291 trigger_disconnect = false;
08292 return_time_volt = over_voltage_low_delay - over_voltage_low_viol_time;
08293 }
08294 }
08295 else if (ov_high_hit == true)
08296 {
08297 if (over_voltage_high_viol_time >= over_voltage_high_delay)
08298 {
08299 trigger_disconnect = true;
08300 return_time_volt = reconnect_time;
08301
08302
08303 ieee_1547_trip_method = IEEE_1547_HIGH_OV;
08304 }
08305 else if (over_voltage_low_viol_time >= over_voltage_low_delay)
08306 {
08307 trigger_disconnect = true;
08308 return_time_volt = reconnect_time;
08309
08310
08311 ieee_1547_trip_method = IEEE_1547_LOW_OV;
08312 }
08313 else
08314 {
08315 trigger_disconnect = false;
08316 return_time_volt = over_voltage_high_delay - over_voltage_high_viol_time;
08317 }
08318 }
08319 else
08320 {
08321 gl_error("Inverter 1547 Checks - invalid state!");
08322
08323 }
08324 }
08325 else
08326 {
08327
08328 under_voltage_lowest_viol_time = 0.0;
08329 under_voltage_middle_viol_time = 0.0;
08330 under_voltage_high_viol_time = 0.0;
08331 over_voltage_low_viol_time = 0.0;
08332 over_voltage_high_viol_time = 0.0;
08333
08334 return_time_volt = -1.0;
08335 }
08336
08337
08338 if ((return_time_volt > 0.0) && (return_time_freq > 0.0))
08339 {
08340
08341 if (return_time_volt < return_time_freq)
08342 {
08343 return_value = return_time_volt;
08344 }
08345 else
08346 {
08347 return_value = return_time_freq;
08348 }
08349 }
08350 else if ((return_time_volt > 0.0) && (return_time_freq < 0.0))
08351 {
08352 return_value = return_time_volt;
08353 }
08354 else if ((return_time_volt < 0.0) && (return_time_freq > 0.0))
08355 {
08356 return_value = return_time_freq;
08357 }
08358 else
08359 {
08360 return_value = -1.0;
08361 }
08362
08363
08364 if ((frequency_violation == true) || (voltage_violation == true))
08365 {
08366
08367 out_of_violation_time_total = 0.0;
08368 }
08369 else
08370 {
08371
08372 out_of_violation_time_total += timestepvalue;
08373 }
08374
08375
08376 if (inverter_1547_status == false)
08377 {
08378 if (out_of_violation_time_total >= reconnect_time)
08379 {
08380
08381 inverter_1547_status = true;
08382
08383
08384 ieee_1547_trip_method = IEEE_1547_NONE;
08385
08386
08387 return -1.0;
08388 }
08389 else
08390 {
08391 inverter_1547_status = false;
08392
08393
08394 return_value = reconnect_time - out_of_violation_time_total;
08395
08396
08397 return return_value;
08398 }
08399 }
08400 else
08401 {
08402 if (trigger_disconnect == true)
08403 {
08404 inverter_1547_status = false;
08405
08406
08407 return return_value;
08408 }
08409 else
08410 {
08411
08412 ieee_1547_trip_method = IEEE_1547_NONE;
08413
08414
08415 return return_value;
08416 }
08417 }
08418 }
08419
08420
08421
08422 complex inverter::complex_exp(double angle)
08423 {
08424 complex output_val;
08425
08426
08427 output_val = complex(cos(angle),sin(angle));
08428
08429 return output_val;
08430 }
08431
08432
08433 gld_property *inverter::map_complex_value(OBJECT *obj, char *name)
08434 {
08435 gld_property *pQuantity;
08436 OBJECT *objhdr = OBJECTHDR(this);
08437
08438
08439 pQuantity = new gld_property(obj,name);
08440
08441
08442 if ((pQuantity->is_valid() != true) || (pQuantity->is_complex() != true))
08443 {
08444 GL_THROW("inverter:%d %s - Unable to map property %s from object:%d %s",objhdr->id,(objhdr->name ? objhdr->name : "Unnamed"),name,obj->id,(obj->name ? obj->name : "Unnamed"));
08445
08446
08447
08448
08449 }
08450
08451
08452 return pQuantity;
08453 }
08454
08455
08456 gld_property *inverter::map_double_value(OBJECT *obj, char *name)
08457 {
08458 gld_property *pQuantity;
08459 OBJECT *objhdr = OBJECTHDR(this);
08460
08461
08462 pQuantity = new gld_property(obj,name);
08463
08464
08465 if ((pQuantity->is_valid() != true) || (pQuantity->is_double() != true))
08466 {
08467 GL_THROW("inverter:%d %s - Unable to map property %s from object:%d %s",objhdr->id,(objhdr->name ? objhdr->name : "Unnamed"),name,obj->id,(obj->name ? obj->name : "Unnamed"));
08468
08469
08470
08471
08472 }
08473
08474
08475 return pQuantity;
08476 }
08477
08478
08479 void inverter::pull_complex_powerflow_values(void)
08480 {
08481
08482
08483 value_Circuit_V[0] = pCircuit_V[0]->get_complex();
08484 value_Circuit_V[1] = pCircuit_V[1]->get_complex();
08485 value_Circuit_V[2] = pCircuit_V[2]->get_complex();
08486 value_MeterStatus = pMeterStatus->get_enumeration();
08487
08488
08489 value_Frequency = pFrequency->get_double();
08490
08491
08492 if (VSI_mode == VSI_ISOCHRONOUS || VSI_mode == VSI_DROOP)
08493 {
08494
08495 if (parent_is_triplex == true)
08496 {
08497 value_IGenerated[0] = pIGenerated[0]->get_complex();
08498 }
08499 else
08500 {
08501 value_IGenerated[0] = pIGenerated[0]->get_complex();
08502 value_IGenerated[1] = pIGenerated[1]->get_complex();
08503 value_IGenerated[2] = pIGenerated[2]->get_complex();
08504 }
08505 }
08506 }
08507
08508
08509 void inverter::reset_complex_powerflow_accumulators(void)
08510 {
08511 int indexval;
08512
08513
08514 if (parent_is_triplex == false)
08515 {
08516
08517 for (indexval=0; indexval<3; indexval++)
08518 {
08519
08520 value_Line_I[indexval] = complex(0.0,0.0);
08521
08522
08523 value_Power[indexval] = complex(0.0,0.0);
08524
08525
08526 value_Line_unrotI[indexval] = complex(0.0,0.0);
08527 }
08528 }
08529 else
08530 {
08531
08532
08533
08534 value_Line12 = complex(0.0,0.0);
08535
08536
08537 value_Power12 = complex(0.0,0.0);
08538
08539
08540 value_Line_unrotI[0] = complex(0.0,0.0);
08541 }
08542 }
08543
08544
08545 void inverter::push_complex_powerflow_values(void)
08546 {
08547 complex temp_complex_val;
08548 gld_wlock *test_rlock;
08549 int indexval;
08550
08551
08552 if (parent_is_triplex == false)
08553 {
08554
08555 for (indexval=0; indexval<3; indexval++)
08556 {
08557
08558
08559 temp_complex_val = pLine_I[indexval]->get_complex();
08560
08561
08562 temp_complex_val += value_Line_I[indexval];
08563
08564
08565 pLine_I[indexval]->setp<complex>(temp_complex_val,*test_rlock);
08566
08567
08568
08569 temp_complex_val = pPower[indexval]->get_complex();
08570
08571
08572 temp_complex_val += value_Power[indexval];
08573
08574
08575 pPower[indexval]->setp<complex>(temp_complex_val,*test_rlock);
08576
08577
08578
08579 temp_complex_val = pLine_unrotI[indexval]->get_complex();
08580
08581
08582 temp_complex_val += value_Line_unrotI[indexval];
08583
08584
08585 pLine_unrotI[indexval]->setp<complex>(temp_complex_val,*test_rlock);
08586
08587 if ((VSI_mode == VSI_ISOCHRONOUS) || (VSI_mode == VSI_DROOP))
08588 {
08589
08590
08591 pIGenerated[indexval]->setp<complex>(value_IGenerated[indexval],*test_rlock);
08592 }
08593 }
08594 }
08595 else
08596 {
08597
08598
08599
08600
08601 temp_complex_val = pLine12->get_complex();
08602
08603
08604 temp_complex_val += value_Line12;
08605
08606
08607 pLine12->setp<complex>(temp_complex_val,*test_rlock);
08608
08609
08610
08611 temp_complex_val = pPower12->get_complex();
08612
08613
08614 temp_complex_val += value_Power12;
08615
08616
08617 pPower12->setp<complex>(temp_complex_val,*test_rlock);
08618
08619
08620
08621 temp_complex_val = pLine_unrotI[0]->get_complex();
08622
08623
08624 temp_complex_val += value_Line_unrotI[0];
08625
08626
08627 pLine_unrotI[0]->setp<complex>(temp_complex_val,*test_rlock);
08628
08629
08630 if ((VSI_mode == VSI_ISOCHRONOUS) || (VSI_mode == VSI_DROOP))
08631 {
08632
08633 pIGenerated[0]->setp<complex>(value_IGenerated[0],*test_rlock);
08634 }
08635 }
08636 }
08637
08638
08639 double inverter::lin_eq_volt(double volt, double m, double b)
08640 {
08641 double Q;
08642
08643 Q = (m * volt) + b;
08644 return Q;
08645 }
08646
08647
08648 STATUS inverter::updateCurrInjection()
08649 {
08650 complex temp_current_val[3];
08651 double power_diff_val;
08652 bool ramp_change;
08653 double deltat, temp_time;
08654 char idx;
08655 OBJECT *obj = OBJECTHDR(this);
08656
08657 if (deltatimestep_running > 0.0)
08658 {
08659
08660 temp_time = gl_globaldeltaclock;
08661 }
08662 else
08663 {
08664
08665 temp_time = (double)gl_globalclock;
08666 }
08667
08668
08669 if (parent_is_a_meter == true)
08670 {
08671
08672 reset_complex_powerflow_accumulators();
08673
08674
08675 pull_complex_powerflow_values();
08676 }
08677
08678
08679 if (prev_time_dbl != temp_time)
08680 {
08681
08682 event_deltat = temp_time - prev_time_dbl;
08683
08684
08685
08686 if ((four_quadrant_control_mode == FQM_VSI) && (checkRampRate_real == true || checkRampRate_reactive == true))
08687 {
08688
08689 if ((phases & 0x10) == 0x10)
08690 {
08691 prev_VA_out[0] = curr_VA_out[0];
08692 }
08693 else
08694 {
08695
08696 prev_VA_out[0] = curr_VA_out[0];
08697 prev_VA_out[1] = curr_VA_out[1];
08698 prev_VA_out[2] = curr_VA_out[2];
08699 }
08700 }
08701
08702
08703 prev_time_dbl = temp_time;
08704 }
08705
08706
08707 if (deltatimestep_running > 0.0)
08708 {
08709
08710 deltat = deltatimestep_running;
08711 }
08712 else
08713 {
08714
08715 deltat = event_deltat;
08716 }
08717
08718
08719
08720
08721 if ((four_quadrant_control_mode == FQM_VSI) && (checkRampRate_real == true || checkRampRate_reactive == true))
08722 {
08723
08724 if ((phases & 0x10) == 0x10)
08725 {
08726
08727 GL_THROW("inverter:%d - %s - VSI mode was attempted on a triplex-connected inverter! This is not permitted!",obj->id,(obj->name ? obj->name : "Unnamed"));
08728
08729
08730
08731
08732
08733 return FAILED;
08734 }
08735 else
08736 {
08737
08738 for(idx = 0; idx < 3; idx++)
08739 {
08740
08741 if (checkRampRate_real == true || checkRampRate_reactive == true)
08742 {
08743
08744 ramp_change = false;
08745
08746
08747 temp_current_val[idx] = (value_IGenerated[idx] - generator_admittance[idx][0]*value_Circuit_V[0] - generator_admittance[idx][1]*value_Circuit_V[1] - generator_admittance[idx][2]*value_Circuit_V[2]);
08748
08749
08750 power_val[idx] = value_Circuit_V[idx]*~temp_current_val[idx];
08751
08752
08753 if (checkRampRate_real == true) {
08754
08755
08756 power_diff_val = (power_val[idx].Re() - prev_VA_out[idx].Re()) / deltat;
08757
08758 if (power_val[idx].Re() > prev_VA_out[idx].Re())
08759 {
08760
08761
08762 if (power_diff_val > rampUpRate_real)
08763 {
08764
08765 ramp_change = true;
08766
08767 power_val[idx].SetReal(prev_VA_out[idx].Re() + (rampUpRate_real * deltat));
08768 }
08769
08770 }
08771 else
08772 {
08773
08774 if (power_diff_val < -rampDownRate_real)
08775 {
08776
08777 ramp_change = true;
08778
08779 power_val[idx].SetReal(prev_VA_out[idx].Re() - (rampDownRate_real * deltat));
08780 }
08781
08782 }
08783 }
08784
08785
08786 if (ramp_change == true)
08787 {
08788
08789 temp_current_val[idx] = ~(power_val[idx] / value_Circuit_V[idx]);
08790
08791
08792 value_IGenerated[idx] = temp_current_val[idx] + generator_admittance[idx][0]*value_Circuit_V[0] + generator_admittance[idx][1]*value_Circuit_V[1] + generator_admittance[idx][2]*value_Circuit_V[2];
08793
08794
08795 e_source[idx] = value_IGenerated[idx] * (complex(Rfilter,Xfilter) * Zbase);
08796
08797
08798 }
08799
08800
08801
08802 curr_VA_out[idx] = power_val[idx];
08803 }
08804 }
08805 }
08806 }
08807
08808
08809 if (parent_is_a_meter == true)
08810 {
08811 push_complex_powerflow_values();
08812 }
08813
08814
08815 return SUCCESS;
08816 }
08817
08818
08820
08822
08823 EXPORT int create_inverter(OBJECT **obj, OBJECT *parent)
08824 {
08825 try
08826 {
08827 *obj = gl_create_object(inverter::oclass);
08828 if (*obj!=NULL)
08829 {
08830 inverter *my = OBJECTDATA(*obj,inverter);
08831 gl_set_parent(*obj,parent);
08832 return my->create();
08833 }
08834 else
08835 return 0;
08836 }
08837 CREATE_CATCHALL(inverter);
08838 }
08839
08840 EXPORT int init_inverter(OBJECT *obj, OBJECT *parent)
08841 {
08842 try
08843 {
08844 if (obj!=NULL)
08845 return OBJECTDATA(obj,inverter)->init(parent);
08846 else
08847 return 0;
08848 }
08849 INIT_CATCHALL(inverter);
08850 }
08851
08852 EXPORT TIMESTAMP sync_inverter(OBJECT *obj, TIMESTAMP t1, PASSCONFIG pass)
08853 {
08854 TIMESTAMP t2 = TS_NEVER;
08855 inverter *my = OBJECTDATA(obj,inverter);
08856 try
08857 {
08858 switch (pass) {
08859 case PC_PRETOPDOWN:
08860 t2 = my->presync(obj->clock,t1);
08861 break;
08862 case PC_BOTTOMUP:
08863 t2 = my->sync(obj->clock,t1);
08864 break;
08865 case PC_POSTTOPDOWN:
08866 t2 = my->postsync(obj->clock,t1);
08867 break;
08868 default:
08869 GL_THROW("invalid pass request (%d)", pass);
08870 break;
08871 }
08872 if (pass==clockpass)
08873 obj->clock = t1;
08874 }
08875 SYNC_CATCHALL(inverter);
08876 return t2;
08877 }
08878
08879 EXPORT STATUS preupdate_inverter(OBJECT *obj, TIMESTAMP t0, unsigned int64 delta_time)
08880 {
08881 inverter *my = OBJECTDATA(obj,inverter);
08882 STATUS status_output = FAILED;
08883
08884 try
08885 {
08886 status_output = my->pre_deltaupdate(t0,delta_time);
08887 return status_output;
08888 }
08889 catch (char *msg)
08890 {
08891 gl_error("preupdate_inverter(obj=%d;%s): %s",obj->id, (obj->name ? obj->name : "unnamed"), msg);
08892 return status_output;
08893 }
08894 }
08895
08896 EXPORT SIMULATIONMODE interupdate_inverter(OBJECT *obj, unsigned int64 delta_time, unsigned long dt, unsigned int iteration_count_val)
08897 {
08898 inverter *my = OBJECTDATA(obj,inverter);
08899 SIMULATIONMODE status = SM_ERROR;
08900 try
08901 {
08902 status = my->inter_deltaupdate(delta_time,dt,iteration_count_val);
08903 return status;
08904 }
08905 catch (char *msg)
08906 {
08907 gl_error("interupdate_inverter(obj=%d;%s): %s", obj->id, obj->name?obj->name:"unnamed", msg);
08908 return status;
08909 }
08910 }
08911
08912 EXPORT STATUS postupdate_inverter(OBJECT *obj, complex *useful_value, unsigned int mode_pass)
08913 {
08914 inverter *my = OBJECTDATA(obj,inverter);
08915 STATUS status = FAILED;
08916 try
08917 {
08918 status = my->post_deltaupdate(useful_value, mode_pass);
08919 return status;
08920 }
08921 catch (char *msg)
08922 {
08923 gl_error("postupdate_inverter(obj=%d;%s): %s", obj->id, obj->name?obj->name:"unnamed", msg);
08924 return status;
08925 }
08926 }
08927
08928
08929 EXPORT STATUS inverter_NR_current_injection_update(OBJECT *obj)
08930 {
08931 STATUS temp_status;
08932
08933
08934 inverter *my = OBJECTDATA(obj,inverter);
08935
08936
08937 temp_status = my->updateCurrInjection();
08938
08939
08940 return temp_status;
08941
08942 }
08943
08944
08945
08946
08947