00001
00010 #include <stdlib.h>
00011 #include <stdio.h>
00012 #include <errno.h>
00013 #include <math.h>
00014
00015 #include "battery.h"
00016
00017 #define HOUR 3600 * TS_SECOND
00018
00019 CLASS *battery::oclass = NULL;
00020 battery *battery::defaults = NULL;
00021
00022 static PASSCONFIG passconfig = PC_BOTTOMUP|PC_POSTTOPDOWN;
00023 static PASSCONFIG clockpass = PC_BOTTOMUP;
00024
00025
00026 battery::battery(MODULE *module)
00027 {
00028 if (oclass==NULL)
00029 {
00030 oclass = gl_register_class(module,"battery",sizeof(battery),PC_PRETOPDOWN|PC_BOTTOMUP|PC_POSTTOPDOWN|PC_AUTOLOCK);
00031 if (oclass==NULL)
00032 throw "unable to register class battery";
00033 else
00034 oclass->trl = TRL_PROOF;
00035
00036 if (gl_publish_variable(oclass,
00037 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.",
00038 PT_KEYWORD,"UNKNOWN",(enumeration)GM_UNKNOWN,
00039 PT_KEYWORD,"CONSTANT_V",(enumeration)GM_CONSTANT_V,
00040 PT_KEYWORD,"CONSTANT_PQ",(enumeration)GM_CONSTANT_PQ,
00041 PT_KEYWORD,"CONSTANT_PF",(enumeration)GM_CONSTANT_PF,
00042 PT_KEYWORD,"SUPPLY_DRIVEN",(enumeration)GM_SUPPLY_DRIVEN,
00043 PT_KEYWORD,"POWER_DRIVEN",(enumeration)GM_POWER_DRIVEN,
00044 PT_KEYWORD,"VOLTAGE_CONTROLLED",(enumeration)GM_VOLTAGE_CONTROLLED,
00045 PT_KEYWORD,"POWER_VOLTAGE_HYBRID",(enumeration)GM_POWER_VOLTAGE_HYBRID,
00046
00047 PT_enumeration,"additional_controls",PADDR(additional_controls), PT_DESCRIPTION, "LEGACY MODEL: In conjunction with POWER_DRIVEN, VOLTAGE_CONTROLLED, and POWER_VOLTAGE_HYBRID, this will activate control set points that adjust with temperature",
00048 PT_KEYWORD,"NONE",(enumeration)AC_NONE,
00049 PT_KEYWORD,"LINEAR_TEMPERATURE",(enumeration)AC_LINEAR_TEMPERATURE,
00050
00051 PT_enumeration,"generator_status",PADDR(gen_status_v), PT_DESCRIPTION, "describes whether the generator is online or offline",
00052 PT_KEYWORD,"OFFLINE",(enumeration)OFFLINE,
00053 PT_KEYWORD,"ONLINE",(enumeration)ONLINE,
00054
00055 PT_enumeration,"rfb_size", PADDR(rfb_size_v), PT_DESCRIPTION, "Default settings for certain sizes of batteries",
00056 PT_KEYWORD, "HOUSEHOLD", (enumeration)HOUSEHOLD,
00057 PT_KEYWORD, "SMALL", (enumeration)SMALL,
00058 PT_KEYWORD, "MED_COMMERCIAL", (enumeration)MED_COMMERCIAL,
00059 PT_KEYWORD, "MED_HIGH_ENERGY", (enumeration)MED_HIGH_ENERGY,
00060 PT_KEYWORD, "LARGE", (enumeration)LARGE,
00061
00062 PT_enumeration,"power_type",PADDR(power_type_v), PT_DESCRIPTION, "LEGACY MODEL: Not currently used",
00063 PT_KEYWORD,"AC",(enumeration)AC,
00064 PT_KEYWORD,"DC",(enumeration)DC,
00065
00066 PT_enumeration,"battery_state",PADDR(battery_state), PT_DESCRIPTION, "Describes the current state of the battery",
00067 PT_KEYWORD,"CHARGING",(enumeration)BS_CHARGING,
00068 PT_KEYWORD,"DISCHARGING",(enumeration)BS_DISCHARGING,
00069 PT_KEYWORD,"WAITING",(enumeration)BS_WAITING,
00070 PT_KEYWORD,"FULL",(enumeration)BS_FULL,
00071 PT_KEYWORD,"EMPTY",(enumeration)BS_EMPTY,
00072 PT_KEYWORD,"CONFLICTED",(enumeration)BS_CONFLICTED,
00073
00074 PT_double, "number_battery_state_changes", PADDR(no_of_cycles),PT_DESCRIPTION, "LEGACY MODEL: Number of times battery switches between charging and discharging",
00075
00076
00077 PT_double, "monitored_power[W]", PADDR(check_power), PT_DESCRIPTION, "LEGACY MODEL: output only; power output value of parent meter when performing load following modes (POWER_DRIVEN)",
00078 PT_double, "power_set_high[W]", PADDR(power_set_high), PT_DESCRIPTION, "LEGACY MODEL: high set point of dead band for load following (POWER_DRIVEN)",
00079 PT_double, "power_set_low[W]", PADDR(power_set_low), PT_DESCRIPTION, "LEGACY MODEL: low set point of dead band for load following (POWER_DRIVEN)",
00080 PT_double, "power_set_high_highT[W]", PADDR(power_set_high_highT), PT_DESCRIPTION, "LEGACY MODEL: high set point of dead band for load following at higher temperatures (POWER_DRIVEN + LINEAR_TEMPERATURE)",
00081 PT_double, "power_set_low_highT[W]", PADDR(power_set_low_highT), PT_DESCRIPTION, "LEGACY MODEL: low set point of dead band for load following at higher temperatures (POWER_DRIVEN + LINEAR_TEMPERATURE)",
00082 PT_double, "check_power_low[W]", PADDR(check_power_low), PT_DESCRIPTION, "LEGACY MODEL: high set point of dead band for load following at lower temperatures (POWER_DRIVEN + LINEAR_TEMPERATURE)",
00083 PT_double, "check_power_high[W]", PADDR(check_power_high), PT_DESCRIPTION, "LEGACY MODEL: low set point of dead band for load following at lower temperatures (POWER_DRIVEN + LINEAR_TEMPERATURE)",
00084 PT_double, "voltage_set_high[V]", PADDR(voltage_set_high), PT_DESCRIPTION, "LEGACY MODEL: high set point for voltage control",
00085 PT_double, "voltage_set_low[V]", PADDR(voltage_set_low), PT_DESCRIPTION, "LEGACY MODEL: low set point for voltage control",
00086 PT_double, "deadband[V]", PADDR(deadband), PT_DESCRIPTION, "LEGACY MODEL: voltage deadband",
00087 PT_double, "sensitivity", PADDR(sensitivity), PT_DESCRIPTION, "LEGACY MODEL: describes how sensitive the control is to temperature excursions; defines slope of linear control",
00088 PT_double, "high_temperature", PADDR(high_temperature), PT_DESCRIPTION, "LEGACY MODEL: high temperature of linear control; defines slope",
00089 PT_double, "midpoint_temperature", PADDR(midpoint_temperature), PT_DESCRIPTION, "LEGACY MODEL: midpoint temperature of linear control; defines slope",
00090 PT_double, "low_temperature", PADDR(low_temperature), PT_DESCRIPTION, "LEGACY MODEL: low temperature of linear control; defines slope",
00091
00092
00093 PT_double, "scheduled_power[W]", PADDR(B_scheduled_power), PT_DESCRIPTION, "LEGACY MODEL: real power output of battery/inverter system",
00094
00095 PT_double, "Rinternal[Ohm]", PADDR(Rinternal), PT_DESCRIPTION, "LEGACY MODEL: the internal resistance of the battery.",
00096 PT_double, "V_Max[V]", PADDR(V_Max), PT_DESCRIPTION, "LEGACY MODEL: the maximum terminal voltage of the battery.",
00097 PT_complex, "I_Max[A]", PADDR(I_Max), PT_DESCRIPTION, "LEGACY MODEL: the maximum current output of the battery.",
00098 PT_double, "E_Max[Wh]", PADDR(E_Max), PT_DESCRIPTION, "LEGACY MODEL: the maximum capacity of the battery.",
00099 PT_double, "P_Max[W]", PADDR(Max_P), PT_DESCRIPTION, "LEGACY MODEL: the maximum power output of the battery.",
00100 PT_double, "power_factor", PADDR(pf), PT_DESCRIPTION, "LEGACY MODEL: the power factor output of the battery.",
00101 PT_double, "Energy[Wh]",PADDR(Energy), PT_DESCRIPTION, "LEGACY MODEL: the available capacity of the battery.",
00102 PT_double, "efficiency[unit]", PADDR(efficiency), PT_DESCRIPTION, "LEGACY MODEL: the efficiency of the battery.",
00103 PT_double, "base_efficiency[unit]", PADDR(base_efficiency), PT_DESCRIPTION, "LEGACY MODEL: the efficiency of the battery at rated voltaged and current.",
00104 PT_double, "parasitic_power_draw[W]", PADDR(parasitic_power_draw), PT_DESCRIPTION, "LEGACY MODEL: the parasytic power draw of the battery when idle.",
00105
00106
00107
00108
00109 PT_double, "Rated_kVA[kVA]", PADDR(Rated_kVA), PT_DESCRIPTION, "LEGACY MODEL: the rated power of the battery.",
00110
00111 PT_complex, "V_Out[V]", PADDR(V_Out), PT_DESCRIPTION, "LEGACY MODEL: the AC voltage at the terminals of the battery.",
00112 PT_complex, "I_Out[A]", PADDR(I_Out), PT_DESCRIPTION, "LEGACY MODEL: the AC current output of the battery.",
00113 PT_complex, "VA_Out[VA]", PADDR(VA_Out), PT_DESCRIPTION, "LEGACY MODEL: the power output of the battery.",
00114 PT_complex, "V_In[V]", PADDR(V_In), PT_DESCRIPTION, "LEGACY MODEL: the voltage at the terminals of the battery.",
00115 PT_complex, "I_In[A]", PADDR(I_In), PT_DESCRIPTION, "LEGACY MODEL: the current flowing into the battery of the battery.",
00116 PT_complex, "V_Internal[V]", PADDR(V_Internal), PT_DESCRIPTION, "LEGACY MODEL: the internal voltage of the battery.",
00117 PT_complex, "I_Internal[A]",PADDR(I_Internal), PT_DESCRIPTION, "LEGACY MODEL: the internal current of the battery.",
00118 PT_complex, "I_Prev[A]", PADDR(I_Prev), PT_DESCRIPTION, "LEGACY MODEL: the previous current output of the battery.",
00119
00120 PT_double,"power_transferred",PADDR(power_transferred), PT_DESCRIPTION, "LEGACY MODEL: the power output of the battery.",
00121
00122
00123
00124
00125 PT_bool,"use_internal_battery_model", PADDR(use_internal_battery_model), PT_DESCRIPTION, "Enables the INTERNAL BATTERY MODEL.",
00126 PT_enumeration,"battery_type", PADDR(battery_type), PT_DESCRIPTION, "INTERNAL BATTERY MODEL: the type of the battery. Used to determine the soc vs voltage curve.",
00127 PT_KEYWORD, "UNKNOWON", (enumeration)UNKNOWN,
00128 PT_KEYWORD, "LI_ION", (enumeration)LI_ION,
00129 PT_KEYWORD, "LEAD_ACID", (enumeration)LEAD_ACID,
00130
00131 PT_double,"nominal_voltage[V]", PADDR(v_max), PT_DESCRIPTION, "INTERNAL BATTERY MODEL: the rated DC voltage at the terminals of the battery.",
00132 PT_double,"rated_power[W]", PADDR(p_max), PT_DESCRIPTION, "INTERNAL BATTERY MODEL: the rated power output of the battery.",
00133 PT_double,"battery_capacity[Wh]", PADDR(e_max), PT_DESCRIPTION, "INTERNAL BATTERY MODEL: the rated battery capacity of the battery.",
00134 PT_double,"round_trip_efficiency[pu]", PADDR(eta_rt), PT_DESCRIPTION, "INTERNAL BATTERY MODEL: the round trip efficiency of the battery according to a full discharge/charge cycle.",
00135 PT_double,"state_of_charge[pu]", PADDR(soc), PT_DESCRIPTION, "INTERNAL BATTERY MODEL: the current state of charge of the battery.",
00136 PT_double,"battery_load[W]", PADDR(bat_load), PT_DESCRIPTION, "INTERNAL BATTERY MODEL: the current power output of the battery.",
00137 PT_double,"reserve_state_of_charge[pu]", PADDR(b_soc_reserve), PT_DESCRIPTION, "INTERNAL BATTERY MODEL: the reserve state of charge the battery can reach.",
00138 NULL)<1) GL_THROW("unable to publish properties in %s",__FILE__);
00139 defaults = this;
00140 memset(this,0,sizeof(battery));
00141
00142 if (gl_publish_function(oclass, "preupdate_battery_object", (FUNCTIONADDR)preupdate_battery)==NULL)
00143 GL_THROW("Unable to publish battery deltamode function");
00144 if (gl_publish_function(oclass, "interupdate_battery_object", (FUNCTIONADDR)interupdate_battery)==NULL)
00145 GL_THROW("Unable to publish battery deltamode function");
00146 if (gl_publish_function(oclass, "postupdate_battery_object", (FUNCTIONADDR)postupdate_battery)==NULL)
00147 GL_THROW("Unable to publish battery deltamode function");
00148
00149
00150
00151 }
00152 }
00153
00154
00155 int battery::create(void)
00156 {
00157 memcpy(this,defaults,sizeof(*this));
00158
00159 gen_status_v = ONLINE;
00160
00161
00162 Rinternal = 10;
00163 V_Max = 0;
00164 I_Max = 0;
00165 E_Max = 0;
00166 Energy = -1;
00167 recalculate = true;
00168 margin = 1000;
00169
00170 no_of_cycles = 0;
00171 deadband = 0;
00172 parasitic_power_draw = 0;
00173 additional_controls = AC_NONE;
00174 midpoint_temperature = 50;
00175 low_temperature = 0;
00176 high_temperature = 100;
00177 sensitivity = 0.5;
00178
00179 Max_P = 0;
00180 Min_P = 0;
00181
00182 Rated_kVA = 1;
00183
00184 efficiency = 0;
00185 base_efficiency = 0;
00186 Iteration_Toggle = false;
00187
00188 E_Next = 0;
00189 connected = true;
00190 complex VA_Internal;
00191
00192 use_internal_battery_model = false;
00193 soc = -1;
00194 b_soc_reserve = 0;
00195 state_change_time = 0;
00196
00197 first_run = true;
00198 enableDelta = false;
00199 state_change_time_delta = 0;
00200 Pout_delta = 0;
00201 pCircuit_V[0] = pCircuit_V[1] = pCircuit_V[2] = NULL;
00202 pLine_I[0] = pLine_I[1] = pLine_I[2] = NULL;
00203 pLine12 = NULL;
00204 pPower = NULL;
00205 pTout = NULL;
00206 pSoc = NULL;
00207 pBatteryLoad = NULL;
00208 pSocReserve = NULL;
00209 pRatedPower = NULL;
00210 peff = NULL;
00211 pinverter_VA_Out = NULL;
00212
00213 value_Circuit_V[0] = value_Circuit_V[1] = value_Circuit_V[2] = complex(0.0,0.0);
00214 value_Line_I[0] = value_Line_I[1] = value_Line_I[2] = complex(0.0,0.0);
00215 value_Line12 = complex(0.0,0.0);
00216
00217 value_Tout = 0.0;
00218
00219 parent_is_meter = false;
00220 parent_is_triplex = false;
00221 parent_is_inverter = false;
00222 climate_object_found = false;
00223
00224
00225 return 1;
00226 }
00227
00228
00229 int battery::init(OBJECT *parent)
00230 {
00231 OBJECT *obj = OBJECTHDR(this);
00232 gld_property *temp_property_pointer;
00233 double temp_value_SocReserve;
00234 enumeration temp_value_control_mode;
00235
00236 if(parent != NULL){
00237 if((parent->flags & OF_INIT) != OF_INIT){
00238 char objname[256];
00239 gl_verbose("battery::init(): deferring initialization on %s", gl_name(parent, objname, 255));
00240 return 2;
00241 }
00242 }
00243
00244
00245 if ((obj->flags & OF_DELTAMODE) == OF_DELTAMODE)
00246 {
00247 deltamode_inclusive = true;
00248 }
00249
00250
00251 if (deltamode_inclusive)
00252 {
00253
00254 if (enable_subsecond_models!=true)
00255 {
00256 gl_warning("battery:%s indicates it wants to run deltamode, but the module-level flag is not set!",obj->name?obj->name:"unnamed");
00257
00258
00259
00260
00261 }
00262 else
00263 {
00264 gen_object_count++;
00265 }
00266 }
00267
00268 else
00269 {
00270 if (enable_subsecond_models == true)
00271 {
00272 gl_warning("battery:%d %s - Deltamode is enabled for the module, but not this generator!",obj->id,(obj->name ? obj->name : "Unnamed"));
00273
00274
00275
00276
00277
00278 }
00279 }
00280
00281 if(use_internal_battery_model == FALSE)
00282 {
00283
00284 if (parent!=NULL)
00285 {
00286 if (gl_object_isa(parent,"meter","powerflow") == true)
00287 {
00288
00289 parent_is_meter = true;
00290 parent_is_triplex = false;
00291 parent_is_inverter = false;
00292
00293
00294 pCircuit_V[0] = map_complex_value(parent,"voltage_A");
00295 pCircuit_V[1] = map_complex_value(parent,"voltage_B");
00296 pCircuit_V[2] = map_complex_value(parent,"voltage_C");
00297
00298 pLine_I[0] = map_complex_value(parent,"current_A");
00299 pLine_I[1] = map_complex_value(parent,"current_B");
00300 pLine_I[2] = map_complex_value(parent,"current_C");
00301
00302 pLine12 = NULL;
00303
00304 pPower = map_complex_value(parent,"measured_power");
00305
00306
00307 temp_property_pointer = new gld_property(parent,"phases");
00308
00309
00310 if ((temp_property_pointer->is_valid() != true) || (temp_property_pointer->is_set() != true))
00311 {
00312 GL_THROW("Unable to map phases property - ensure the parent is a meter or triplex_meter");
00313
00314
00315
00316
00317
00318 }
00319
00320
00321 phases = temp_property_pointer->get_set();
00322
00323
00324 delete temp_property_pointer;
00325
00326 if ( (phases & 0x07) == 0x07 ){
00327 number_of_phases_out = 3;
00328 }
00329 else if ( ((phases & 0x03) == 0x03) || ((phases & 0x05) == 0x05) || ((phases & 0x06) == 0x06) ){
00330 number_of_phases_out = 2;
00331 GL_THROW("Battery %d: The battery can only be connected to a meter with all three phases. Please check parent meter's phases.",obj->id);
00332
00333
00334
00335 }
00336 else if ( ((phases & 0x01) == 0x01) || ((phases & 0x02) == 0x02) || ((phases & 0x04) == 0x04) ){
00337 number_of_phases_out = 1;
00338 GL_THROW("Battery %d: The battery can only be connected to a meter with all three phases. Please check parent meter's phases.",obj->id);
00339
00340
00341
00342 }
00343 else
00344 {
00345
00346 GL_THROW("Invalid phase configuration specified!");
00347
00348
00349
00350
00351 }
00352
00353
00354 value_Circuit_V[0] = pCircuit_V[0]->get_complex();
00355 value_Circuit_V[1] = pCircuit_V[1]->get_complex();
00356 value_Circuit_V[2] = pCircuit_V[2]->get_complex();
00357 }
00358 else if (gl_object_isa(parent,"triplex_meter","powerflow") == true)
00359 {
00360
00361 parent_is_meter = true;
00362 parent_is_triplex = true;
00363 parent_is_inverter = false;
00364
00365
00366 pCircuit_V[0] = map_complex_value(parent,"voltage_12");
00367 pCircuit_V[1] = map_complex_value(parent,"voltage_1N");
00368 pCircuit_V[2] = map_complex_value(parent,"voltage_2N");
00369
00370 pLine_I[0] = map_complex_value(parent,"current_1");
00371 pLine_I[1] = map_complex_value(parent,"current_2");
00372 pLine_I[2] = map_complex_value(parent,"current_N");
00373
00374 pLine12 = map_complex_value(parent,"current_12");
00375
00376 pPower = map_complex_value(parent,"measured_power");
00377
00378
00379 temp_property_pointer = new gld_property(parent,"phases");
00380
00381
00382 if ((temp_property_pointer->is_valid() != true) || (temp_property_pointer->is_set() != true))
00383 {
00384 GL_THROW("Unable to map phases property - ensure the parent is a meter or triplex_meter");
00385
00386 }
00387
00388
00389 phases = temp_property_pointer->get_set();
00390
00391
00392 delete temp_property_pointer;
00393
00394 number_of_phases_out = 1;
00395
00396
00397 value_Circuit_V[0] = pCircuit_V[0]->get_complex();
00398 value_Circuit_V[1] = pCircuit_V[1]->get_complex();
00399 value_Circuit_V[2] = pCircuit_V[2]->get_complex();
00400 }
00401 else if (gl_object_isa(parent,"inverter","generators") == true)
00402 {
00403
00404 parent_is_meter = true;
00405 parent_is_triplex = false;
00406 parent_is_inverter = true;
00407
00408 number_of_phases_out = 0;
00409 phases = 0x00;
00410
00411
00412 pCircuit_V[0] = map_complex_value(parent,"V_In");
00413 pCircuit_V[1] = NULL;
00414 pCircuit_V[2] = NULL;
00415
00416 pLine_I[0] = map_complex_value(parent,"I_In");
00417 pLine_I[1] = NULL;
00418 pLine_I[2] = NULL;
00419
00420 peff = map_double_value(parent,"inverter_efficiency");
00421 pinverter_VA_Out = map_complex_value(parent,"VA_Out");
00422
00423
00424 value_Circuit_V[0] = pCircuit_V[0]->get_complex();
00425 }
00426 else
00427 {
00428 GL_THROW("Battery must have a meter or triplex meter or inverter as it's parent");
00429
00430
00431
00432
00433
00434 }
00435 }
00436 else
00437 {
00438 parent_is_meter = false;
00439 parent_is_triplex = false;
00440 parent_is_inverter = false;
00441
00442 number_of_phases_out = 3;
00443 phases = 0x07;
00444
00445 gl_warning("Battery:%d has no parent meter object defined; using static voltages", obj->id);
00446
00447
00448 value_Circuit_V[0].SetPolar(default_line_voltage,0);
00449 value_Circuit_V[1].SetPolar(default_line_voltage,-2.0/3.0*PI);
00450 value_Circuit_V[2].SetPolar(default_line_voltage,2.0/3.0*PI);
00451 }
00452
00453 if (gen_mode_v==GM_UNKNOWN)
00454 {
00455 GL_THROW("Generator (id:%d) generator_mode is not specified",obj->id);
00456 }
00457 else if (gen_mode_v == GM_VOLTAGE_CONTROLLED)
00458 {
00459 GL_THROW("VOLTAGE_CONTROLLED generator_mode is not yet implemented.");
00460 }
00461 else if (gen_mode_v == GM_CONSTANT_PF)
00462 {
00463 GL_THROW("CONSTANT_PF generator_mode is not yet implemented.");
00464 }
00465 else if (gen_mode_v == GM_SUPPLY_DRIVEN)
00466 {
00467 GL_THROW("SUPPLY_DRIVEN generator_mode is not yet implemented.");
00468 }
00469
00470 if (additional_controls == AC_LINEAR_TEMPERATURE)
00471 {
00472 FINDLIST *climates = NULL;
00473
00474 climates = gl_find_objects(FL_NEW,FT_CLASS,SAME,"climate",FT_END);
00475
00476 if (climates==NULL)
00477 {
00478 climate_object_found = false;
00479
00480 gl_warning("battery: no climate data found, using static data");
00481
00482
00483 value_Tout = default_temperature_value;
00484 }
00485 if (climates!=NULL)
00486 {
00487 if (climates->hit_count==0)
00488 {
00489 climate_object_found = false;
00490
00491
00492 value_Tout = default_temperature_value;
00493 }
00494 else
00495 {
00496 climate_object_found = true;
00497
00498 OBJECT *clim = gl_find_next(climates,NULL);
00499
00500 if (clim->rank<=obj->rank)
00501 gl_set_dependent(clim,obj);
00502
00503
00504 pTout = map_double_value(clim,"temperature");
00505 }
00506 }
00507 }
00508
00509 if (gen_status_v == OFFLINE)
00510 {
00511
00512 gl_warning("Generator (id:%d) is out of service!",obj->id);
00513 }
00514 else
00515 {
00516 switch(rfb_size_v)
00517 {
00518 case HOUSEHOLD:
00519 V_Max = 260;
00520 I_Max = 15;
00521 Max_P = V_Max.Mag()*I_Max.Mag();
00522 E_Max = 6*Max_P;
00523 base_efficiency = 0.9;
00524 break;
00525 case SMALL:
00526 V_Max = 75.2;
00527 I_Max = 250;
00528 Max_P = 18800;
00529 E_Max = 160000;
00530 base_efficiency = 0.7;
00531 break;
00532 case MED_COMMERCIAL:
00533 V_Max = 115;
00534 I_Max = 435;
00535 Max_P = 50000;
00536 E_Max = 175000;
00537 base_efficiency = 0.8;
00538 break;
00539 case MED_HIGH_ENERGY:
00540 V_Max = 115;
00541 I_Max = 435;
00542 Max_P = 50000;
00543 E_Max = 400000;
00544 base_efficiency = 0.8;
00545 break;
00546 case LARGE:
00547 V_Max = 8000;
00548 I_Max = 30;
00549 Max_P = V_Max.Mag()*I_Max.Mag();
00550 E_Max = 24*Max_P;
00551 base_efficiency = 0.9;
00552 break;
00553 default:
00554 if (V_Max == 0)
00555 {
00556 gl_warning("V_max was not given -- using default value (battery: %d)",obj->id);
00557 V_Max = 115;
00558 }
00559 if (I_Max == 0)
00560 {
00561 gl_warning("I_max was not given -- using default value (battery: %d)",obj->id);
00562 I_Max = 435;
00563 }
00564 if (Max_P == 0)
00565 {
00566 gl_warning("Max_P was not given -- using default value (battery: %d)",obj->id);
00567 Max_P = V_Max.Re()*I_Max.Re();
00568 }
00569 if (E_Max == 0)
00570 {
00571 gl_warning("E_max was not given -- using default value (battery: %d)",obj->id);
00572 E_Max = 6*Max_P;
00573 }
00574 if (base_efficiency == 0)
00575 {
00576 gl_warning("base_efficiency was not given -- using default value (battery: %d)",obj->id);
00577 base_efficiency = 0.8;
00578 }
00579 break;
00580 }
00581 }
00582 if (power_set_high <= power_set_low && (gen_mode_v == GM_POWER_DRIVEN || gen_mode_v == GM_POWER_VOLTAGE_HYBRID))
00583 gl_warning("power_set_high is less than power_set_low -- oscillations will most likely occur");
00584
00585 if (Energy < 0)
00586 {
00587 gl_warning("Initial Energy was not set, or set to a negative number. Randomizing initial value.");
00588 Energy = gl_random_normal(RNGSTATE,E_Max/2,E_Max/20);
00589 }
00590
00591 recalculate = true;
00592 power_transferred = 0;
00593
00594 first_time_step = 0;
00595 }
00596 else
00597 {
00598 if (parent!=NULL)
00599 {
00600
00601 gl_set_rank(parent,obj->rank+1);
00602 }
00603
00604
00605 if(parent == NULL)
00606 {
00607 GL_THROW("Battery must have an inverter as it's parent when using the internal battery model");
00608
00609
00610
00611
00612 }
00613 else if (gl_object_isa(parent,"inverter","generators") == false)
00614 {
00615 GL_THROW("Battery must have an inverter as it's parent");
00616
00617 }
00618
00619 switch(rfb_size_v)
00620 {
00621 case HOUSEHOLD:
00622 v_max = 260;
00623 p_max = 3900;
00624 e_max = 23400;
00625 eta_rt = 0.9;
00626 break;
00627 case SMALL:
00628 v_max = 75.2;
00629 p_max = 18800;
00630 e_max = 160000;
00631 eta_rt = 0.7;
00632 break;
00633 case MED_COMMERCIAL:
00634 v_max = 115;
00635 p_max = 50000;
00636 e_max = 175000;
00637 eta_rt = 0.8;
00638 break;
00639 case MED_HIGH_ENERGY:
00640 v_max = 115;
00641 p_max = 50000;
00642 e_max = 400000;
00643 eta_rt = 0.8;
00644 break;
00645 case LARGE:
00646 v_max = 8000;
00647 p_max = 240000;
00648 e_max = 5760000;
00649 eta_rt = 0.9;
00650 break;
00651 default:
00652 if (v_max == 0)
00653 {
00654 gl_warning("v_max was not given -- using default value (battery: %d)",obj->id);
00655 v_max = 115;
00656 }
00657 if (e_max == 0)
00658 {
00659 gl_warning("e_max was not given -- using default value (battery: %d)",obj->id);
00660 e_max = 400000;
00661 }
00662 if (eta_rt == 0)
00663 {
00664 gl_warning("eta_rt was not given -- using default value (battery: %d)",obj->id);
00665 eta_rt = 0.8;
00666 }
00667 break;
00668 }
00669
00670
00671 if (battery_type == UNKNOWN){
00672 gl_warning("(battery: %s) the battery type is unknown. Using static voltage curve",obj->name);
00673 } else if (battery_type == LI_ION){
00674 n_series = floor(v_max/4.1);
00675 } else {
00676
00677 }
00678
00679
00680 pSocReserve = map_double_value(parent,"soc_reserve");
00681 pSoc = map_double_value(parent,"battery_soc");
00682 pBatteryLoad = map_double_value(parent,"power_in");
00683 pRatedPower = map_double_value(parent,"rated_battery_power");
00684
00685
00686 temp_property_pointer = new gld_property(parent,"four_quadrant_control_mode");
00687
00688
00689 if ((temp_property_pointer->is_valid() != true) || (temp_property_pointer->is_enumeration() != true))
00690 {
00691 GL_THROW("battery:%d - %s - Unable to map the parent inverter four_quadrant_control_mode",obj->id,(obj->name ? obj->name : "Unnamed"));
00692
00693
00694
00695
00696 }
00697
00698
00699 temp_value_control_mode = temp_property_pointer->get_enumeration();
00700
00701
00702 delete temp_property_pointer;
00703
00704
00705 temp_value_SocReserve = pSocReserve->get_double();
00706
00707 if(temp_value_SocReserve == 0){
00708 b_soc_reserve = 0;
00709 } else {
00710 b_soc_reserve = temp_value_SocReserve;
00711 }
00712 if(battery_state == BS_EMPTY && soc != b_soc_reserve){
00713 soc = b_soc_reserve;
00714 }
00715 if(battery_state == BS_FULL && soc != 1){
00716 soc = 1;
00717 }
00718 if(soc < 0){
00719 gl_warning("no initial state of charge given -- using default value (battery: %s)",obj->name);
00720 soc = 1;
00721 battery_state = BS_FULL;
00722 } else if(soc > 1){
00723 gl_warning("initial state of charge is greater than 1 setting to 1 (battery: %s)",obj->name);
00724 soc = 1;
00725 battery_state = BS_FULL;
00726 }
00727
00728
00729 if ((temp_value_control_mode == 1) || (temp_value_control_mode == 9)) {
00730 enableDelta = true;
00731 }
00732 }
00733
00734 return 1;
00735 }
00736
00737
00738 complex battery::calculate_v_terminal(complex v, complex i){
00739 return v - (i * Rinternal);
00740 }
00741
00742 TIMESTAMP battery::rfb_event_time(TIMESTAMP t0, complex power, double e){
00743 if((e < margin) && (power < 0)){
00744 return TS_NEVER;
00745 }
00746 if((e > E_Max - margin)&& (power > 0)){
00747 return TS_NEVER;
00748 }
00749
00750 if(power < 0){
00751 double t1 = (e) / power.Re();
00752 t1 = t1 * 60 * 60;
00753 return t0 + (TIMESTAMP)(t1 * TS_SECOND);
00754 }else if(power > 0){
00755 double t1 = (E_Max - e) / power.Re();
00756 t1 = t1 * 60 * 60;
00757 return t0 + (TIMESTAMP)(t1 * TS_SECOND);
00758 }else{
00759 return TS_NEVER;
00760 }
00761
00762 }
00763
00764
00765 double battery::calculate_efficiency(complex voltage, complex current){
00766 if(voltage.Mag() == 0 || current.Mag() == 0){
00767 return 1;
00768 }
00769 else if(current.Mag() < 5){
00770 return 0.95;
00771 }
00772 else if(current.Mag() < 10){
00773 return 0.9;
00774 }
00775 else if(current.Mag() < 20){
00776 return 0.8;
00777 }else{
00778 return 0.7;
00779 }
00780
00781 }
00782
00783
00784 TIMESTAMP battery::presync(TIMESTAMP t0, TIMESTAMP t1)
00785 {
00786 gld_wlock *test_rlock;
00787
00788 if(use_internal_battery_model == TRUE){
00789 double dt;
00790 if(t0 != 0){
00791
00792
00793 b_soc_reserve = pSocReserve->get_double();
00794 if(battery_state == BS_DISCHARGING || battery_state == BS_CHARGING){
00795 dt = (double)(t1-t0);
00796 if(soc >= 0 && soc <= 1){
00797 soc += (internal_battery_load*dt/3600)/e_max;
00798 internal_battery_load = 0;
00799 if(soc <= 0){
00800 battery_state = BS_EMPTY;
00801 soc = 0;
00802 } else if(soc >= 1){
00803 battery_state = BS_FULL;
00804 soc = 1;
00805 } else if(soc <= b_soc_reserve && t1 == state_change_time){
00806 battery_state = BS_EMPTY;
00807 soc = b_soc_reserve;
00808 }
00809 }
00810 }
00811 }
00812
00813
00814 pSoc->setp<double>(soc,*test_rlock);
00815 }
00816 TIMESTAMP t2 = TS_NEVER;
00817
00818 return t2;
00819 }
00820
00821
00822 TIMESTAMP battery::sync(TIMESTAMP t0, TIMESTAMP t1)
00823 {
00824 complex temp_complex_value;
00825 OBJECT *obj = OBJECTHDR(this);
00826
00827
00828 if (first_run == true)
00829 {
00830
00831 if (deltamode_inclusive && enable_subsecond_models )
00832 {
00833 if (((gen_object_current == -1) || (delta_objects==NULL)) && (enable_subsecond_models == true))
00834 {
00835
00836 allocate_deltamode_arrays();
00837 }
00838
00839
00840 if (gen_object_current>=gen_object_count)
00841 {
00842 GL_THROW("Too many objects tried to populate deltamode objects array in the generators module!");
00843
00844
00845
00846
00847
00848 }
00849
00850
00851 delta_objects[gen_object_current] = obj;
00852
00853
00854 delta_functions[gen_object_current] = (FUNCTIONADDR)(gl_get_function(obj,"interupdate_battery_object"));
00855
00856
00857 if (delta_functions[gen_object_current] == NULL)
00858 {
00859 GL_THROW("Failure to map deltamode function for device:%s",obj->name);
00860
00861
00862
00863
00864
00865 }
00866
00867
00868 post_delta_functions[gen_object_current] = (FUNCTIONADDR)(gl_get_function(obj,"postupdate_battery_object"));
00869
00870
00871 if (post_delta_functions[gen_object_current] == NULL)
00872 {
00873 GL_THROW("Failure to map post-deltamode function for device:%s",obj->name);
00874
00875
00876
00877
00878
00879 }
00880
00881
00882 delta_preupdate_functions[gen_object_current] = (FUNCTIONADDR)(gl_get_function(obj,"preupdate_battery_object"));
00883
00884
00885 if (delta_preupdate_functions[gen_object_current] == NULL)
00886 {
00887 GL_THROW("Failure to map pre-deltamode function for device:%s",obj->name);
00888
00889
00890
00891
00892
00893 }
00894
00895
00896 gen_object_current++;
00897
00898 }
00899
00900
00901 first_run = false;
00902
00903 return t1;
00904 }
00905
00906 if(use_internal_battery_model == FALSE){
00907 if (gen_mode_v == GM_POWER_DRIVEN || gen_mode_v == GM_POWER_VOLTAGE_HYBRID)
00908 {
00909 if (number_of_phases_out == 3)
00910 {
00911 if (gen_mode_v == GM_POWER_VOLTAGE_HYBRID)
00912 GL_THROW("generator_mode POWER_VOLTAGE_HYBRID is not supported in 3-phase yet (only split phase is supported");
00913
00914 complex volt[3];
00915 TIMESTAMP dt,t_energy_limit;
00916
00917 for (int i=0;i<3;i++)
00918 {
00919 volt[i] = pCircuit_V[i]->get_complex();
00920 }
00921
00922 if (first_time_step == 0)
00923 {
00924 dt = 0;
00925 }
00926 else if (prev_time == 0)
00927 {
00928 prev_time = t1;
00929 dt = 0;
00930 }
00931 else if (prev_time < t1)
00932 {
00933 dt = t1 - prev_time;
00934 prev_time = t1;
00935 }
00936 else
00937 dt = 0;
00938
00939 if (prev_state == -1)
00940 {
00941 Energy = Energy - (1 / base_efficiency) * power_transferred * (double)dt / 3600;
00942 if (Energy < 0)
00943 Energy = 0;
00944 }
00945 else if (prev_state == 1)
00946 Energy = Energy + base_efficiency * power_transferred * (double)dt / 3600;
00947
00948
00949 temp_complex_value = pPower->get_complex();
00950 check_power = temp_complex_value.Mag();
00951
00952 if (first_time_step > 0)
00953 {
00954 if (volt[0].Mag() > V_Max.Mag() || volt[1].Mag() > V_Max.Mag() || volt[2].Mag() > V_Max.Mag())
00955 {
00956 gl_warning("The voltages at the batteries meter are higher than rated. No power output.");
00957 battery_state = BS_WAITING;
00958
00959 last_current[0].SetPolar(parasitic_power_draw/3/volt[0].Mag(),volt[0].Arg());
00960 last_current[1].SetPolar(parasitic_power_draw/3/volt[1].Mag(),volt[1].Arg());
00961 last_current[2].SetPolar(parasitic_power_draw/3/volt[2].Mag(),volt[2].Arg());
00962
00963 value_Line_I[0] = last_current[0];
00964 value_Line_I[1] = last_current[1];
00965 value_Line_I[2] = last_current[2];
00966
00967
00968 push_powerflow_currents();
00969
00970 return TS_NEVER;
00971 }
00972 else if (check_power > power_set_high && Energy > 0)
00973 {
00974 prev_state = -1;
00975 battery_state = BS_DISCHARGING;
00976
00977 double test_current = Max_P / (volt[0].Mag() + volt[1].Mag() + volt[2].Mag());
00978 if (test_current > I_Max.Mag()/3)
00979 test_current = I_Max.Mag()/3;
00980
00981 last_current[0].SetPolar(-test_current + parasitic_power_draw/3/volt[0].Mag(),volt[0].Arg());
00982 last_current[1].SetPolar(-test_current + parasitic_power_draw/3/volt[1].Mag(),volt[1].Arg());
00983 last_current[2].SetPolar(-test_current + parasitic_power_draw/3/volt[2].Mag(),volt[2].Arg());
00984
00985 value_Line_I[0] = last_current[0];
00986 value_Line_I[1] = last_current[1];
00987 value_Line_I[2] = last_current[2];
00988
00989
00990 push_powerflow_currents();
00991
00992 power_transferred = 0;
00993
00994 for (int i=0;i<3;i++)
00995 {
00996 power_transferred += last_current[i].Mag()*volt[i].Mag();
00997 }
00998
00999 VA_Out = power_transferred;
01000
01001 t_energy_limit = TIMESTAMP(3600 * Energy / power_transferred);
01002 if (t_energy_limit == 0)
01003 t_energy_limit = 1;
01004
01005 return -(t1 + t_energy_limit);
01006 }
01007 else if (check_power < power_set_low && Energy < E_Max)
01008 {
01009 prev_state = 1;
01010 battery_state = BS_CHARGING;
01011
01012 double test_current = Max_P / (volt[0].Mag() + volt[1].Mag() + volt[2].Mag());
01013 if (test_current > I_Max.Mag()/3)
01014 test_current = I_Max.Mag()/3;
01015
01016 last_current[0].SetPolar(test_current + parasitic_power_draw/3/volt[0].Mag(),volt[0].Arg());
01017 last_current[1].SetPolar(test_current + parasitic_power_draw/3/volt[1].Mag(),volt[1].Arg());
01018 last_current[2].SetPolar(test_current + parasitic_power_draw/3/volt[2].Mag(),volt[2].Arg());
01019
01020 value_Line_I[0] = last_current[0];
01021 value_Line_I[1] = last_current[1];
01022 value_Line_I[2] = last_current[2];
01023
01024
01025 push_powerflow_currents();
01026
01027 power_transferred = 0;
01028
01029 for (int i=0;i<3;i++)
01030 {
01031 power_transferred += last_current[i].Mag()*volt[i].Mag();
01032 }
01033
01034 VA_Out = power_transferred;
01035
01036 t_energy_limit = TIMESTAMP(3600 * (E_Max - Energy) / power_transferred);
01037 if (t_energy_limit == 0)
01038 t_energy_limit = 1;
01039
01040 return -(t1 + t_energy_limit);
01041 }
01042 else if ( (check_power < power_set_high - Max_P) && (prev_state == 1) && (Energy < E_Max) )
01043 {
01044 prev_state = 1;
01045 battery_state = BS_CHARGING;
01046
01047 double test_current = Max_P / (volt[0].Mag() + volt[1].Mag() + volt[2].Mag());
01048 if (test_current > I_Max.Mag()/3)
01049 test_current = I_Max.Mag()/3;
01050
01051 last_current[0].SetPolar(test_current + parasitic_power_draw/3/volt[0].Mag(),volt[0].Arg());
01052 last_current[1].SetPolar(test_current + parasitic_power_draw/3/volt[1].Mag(),volt[1].Arg());
01053 last_current[2].SetPolar(test_current + parasitic_power_draw/3/volt[2].Mag(),volt[2].Arg());
01054
01055 value_Line_I[0] = last_current[0];
01056 value_Line_I[1] = last_current[1];
01057 value_Line_I[2] = last_current[2];
01058
01059
01060 push_powerflow_currents();
01061
01062 power_transferred = 0;
01063
01064 for (int i=0;i<3;i++)
01065 {
01066 power_transferred += last_current[i].Mag()*volt[i].Mag();
01067 }
01068
01069 VA_Out = power_transferred;
01070
01071 t_energy_limit = TIMESTAMP(3600 * (E_Max - Energy) / power_transferred);
01072 if (t_energy_limit == 0)
01073 t_energy_limit = 1;
01074
01075 return -(t1 + t_energy_limit);
01076 }
01077 else if ( (check_power > power_set_low + Max_P) && (prev_state == -1) && (Energy > 0) )
01078 {
01079 prev_state = -1;
01080 battery_state = BS_DISCHARGING;
01081
01082 double test_current = Max_P / (volt[0].Mag() + volt[1].Mag() + volt[2].Mag());
01083 if (test_current > I_Max.Mag()/3)
01084 test_current = I_Max.Mag()/3;
01085
01086 last_current[0].SetPolar(-test_current + parasitic_power_draw/3/volt[0].Mag(),volt[0].Arg());
01087 last_current[1].SetPolar(-test_current + parasitic_power_draw/3/volt[1].Mag(),volt[1].Arg());
01088 last_current[2].SetPolar(-test_current + parasitic_power_draw/3/volt[2].Mag(),volt[2].Arg());
01089
01090 value_Line_I[0] = last_current[0];
01091 value_Line_I[1] = last_current[1];
01092 value_Line_I[2] = last_current[2];
01093
01094
01095 push_powerflow_currents();
01096
01097 power_transferred = 0;
01098
01099 for (int i=0;i<3;i++)
01100 {
01101 power_transferred += last_current[i].Mag()*volt[i].Mag();
01102 }
01103
01104 VA_Out = -power_transferred;
01105
01106 t_energy_limit = TIMESTAMP(3600 * Energy / power_transferred);
01107
01108 if (t_energy_limit == 0)
01109 t_energy_limit = 1;
01110
01111 return -(t1 + t_energy_limit);
01112 }
01113 else
01114 {
01115 if (Energy <= 0)
01116 battery_state = BS_EMPTY;
01117 else if (Energy >= E_Max)
01118 battery_state = BS_FULL;
01119 else
01120 battery_state = BS_WAITING;
01121
01122 last_current[0].SetPolar(parasitic_power_draw/3/volt[0].Mag(),volt[0].Arg());
01123 last_current[1].SetPolar(parasitic_power_draw/3/volt[1].Mag(),volt[1].Arg());
01124 last_current[2].SetPolar(parasitic_power_draw/3/volt[2].Mag(),volt[2].Arg());
01125
01126 value_Line_I[0] = last_current[0];
01127 value_Line_I[1] = last_current[1];
01128 value_Line_I[2] = last_current[2];
01129
01130
01131 push_powerflow_currents();
01132
01133 prev_state = 0;
01134 power_transferred = 0;
01135 VA_Out = power_transferred;
01136 return TS_NEVER;
01137 }
01138 }
01139 else
01140 {
01141 if (Energy <= 0)
01142 battery_state = BS_EMPTY;
01143 else if (Energy >= E_Max)
01144 battery_state = BS_FULL;
01145 else
01146 battery_state = BS_WAITING;
01147
01148 first_time_step = 1;
01149 return TS_NEVER;
01150 }
01151 }
01152 else if ( ((phases & 0x0010) == 0x0010) && (number_of_phases_out == 1) )
01153 {
01154 complex volt;
01155 TIMESTAMP dt,t_energy_limit;
01156
01157 volt = pCircuit_V[0]->get_complex();
01158
01159 if (first_time_step == 0)
01160 {
01161 dt = 0;
01162 }
01163 else if (prev_time == 0)
01164 {
01165 prev_time = t1;
01166 dt = 0;
01167 }
01168 else if (prev_time < t1)
01169 {
01170 dt = t1 - prev_time;
01171 prev_time = t1;
01172 }
01173 else
01174 dt = 0;
01175
01176 if (prev_state == -1)
01177 {
01178 Energy = Energy - (1 / base_efficiency) * power_transferred * (double)dt / 3600;
01179 if (Energy < 0)
01180 Energy = 0;
01181 }
01182 else if (prev_state == 1)
01183 {
01184 Energy = Energy + base_efficiency * power_transferred * (double)dt / 3600;
01185 if (Energy > E_Max)
01186 Energy = E_Max;
01187 }
01188
01189
01190 temp_complex_value = pPower->get_complex();
01191 check_power = temp_complex_value.Mag();
01192
01193 if (additional_controls == AC_LINEAR_TEMPERATURE)
01194 {
01195 double sens2 = (1 - sensitivity)/(-sensitivity);
01196
01197
01198 double slope1_hi = power_set_high_highT / (high_temperature - midpoint_temperature * sens2);
01199 double yint1_hi = -midpoint_temperature * sens2 * slope1_hi;
01200
01201
01202 double slope1_lo = (power_set_high - (slope1_hi * midpoint_temperature + yint1_hi)) / (low_temperature - midpoint_temperature);
01203 double yint1_lo = power_set_high - low_temperature * slope1_lo;
01204
01205
01206 double slope2_hi = power_set_low_highT / (high_temperature - midpoint_temperature * sens2);
01207 double yint2_hi = -midpoint_temperature * sens2 * slope2_hi;
01208
01209
01210 double slope2_lo = (power_set_low - (slope2_hi * midpoint_temperature + yint2_hi)) / (low_temperature - midpoint_temperature);
01211 double yint2_lo = power_set_low - low_temperature * slope2_lo;
01212
01213
01214 if (climate_object_found == true)
01215 {
01216 value_Tout = pTout->get_double();
01217 }
01218
01219 if (value_Tout > midpoint_temperature)
01220 {
01221 check_power_high = slope1_hi * value_Tout + yint1_hi;
01222 check_power_low = slope2_hi * value_Tout + yint2_hi;
01223 }
01224 else
01225 {
01226 check_power_high = slope1_lo * value_Tout + yint1_lo;
01227 check_power_low = slope2_lo * value_Tout + yint2_lo;
01228 }
01229 }
01230 else
01231 {
01232 check_power_high = power_set_high;
01233 check_power_low = power_set_low;
01234 }
01235
01236 if (first_time_step > 0)
01237 {
01238 if (volt.Mag() > V_Max.Mag() || volt.Mag()/240 < 0.9 || volt.Mag()/240 > 1.1)
01239 {
01240 gl_verbose("The voltages at the batteries meter are higher than rated, or outside of ANSI emergency specifications. No power output.");
01241 battery_state = BS_WAITING;
01242
01243 last_current[0].SetPolar(parasitic_power_draw/volt.Mag(),volt.Arg());
01244 value_Line12 = last_current[0];
01245
01246
01247 push_powerflow_currents();
01248
01249 return TS_NEVER;
01250 }
01251
01252
01253 else if ((check_power > check_power_high || (volt.Mag() < voltage_set_low && gen_mode_v == GM_POWER_VOLTAGE_HYBRID)) && Energy > 0)
01254 {
01255 if (volt.Mag() > voltage_set_high)
01256 {
01257 if (prev_state != 0)
01258 no_of_cycles += 1;
01259
01260 last_current[0].SetPolar(parasitic_power_draw/volt.Mag(),volt.Arg());
01261 value_Line12 = last_current[0];
01262
01263
01264 push_powerflow_currents();
01265
01266 VA_Out = power_transferred = 0;
01267 battery_state = BS_CONFLICTED;
01268
01269 return TS_NEVER;
01270 }
01271 else
01272 {
01273 if (prev_state != -1)
01274 no_of_cycles +=1;
01275
01276 prev_state = -1;
01277 battery_state = BS_DISCHARGING;
01278 double power_desired = check_power - check_power_high;
01279 if (power_desired <= 0)
01280 {
01281 last_current[0].SetPolar(-I_Max.Mag(),volt.Arg());
01282 value_Line12 = last_current[0];
01283
01284 }
01285 else
01286 {
01287 if (power_desired >= Max_P)
01288 power_desired = Max_P;
01289
01290 double current_desired = -power_desired/volt.Mag();
01291 last_current[0].SetPolar(current_desired,volt.Arg());
01292 value_Line12 = last_current[0];
01293 }
01294
01295
01296 push_powerflow_currents();
01297
01298 power_transferred = last_current[0].Mag()*volt.Mag();
01299
01300 VA_Out = power_transferred;
01301
01302 t_energy_limit = TIMESTAMP(3600 * Energy / power_transferred);
01303 if (t_energy_limit == 0)
01304 t_energy_limit = 1;
01305
01306 return -(t1 + t_energy_limit);
01307 }
01308 }
01309
01310
01311 else if ((check_power < check_power_low || (gen_mode_v == GM_POWER_VOLTAGE_HYBRID && volt.Mag() > voltage_set_high)) && Energy < E_Max)
01312 {
01313 if (volt.Mag() < voltage_set_low)
01314 {
01315 if (prev_state != 0)
01316 no_of_cycles += 1;
01317 last_current[0].SetPolar(parasitic_power_draw/volt.Mag(),volt.Arg());
01318 value_Line12 = last_current[0];
01319
01320
01321 push_powerflow_currents();
01322
01323 VA_Out = power_transferred = 0;
01324 battery_state = BS_CONFLICTED;
01325
01326 return TS_NEVER;
01327 }
01328 else
01329 {
01330 if (prev_state != 1)
01331 no_of_cycles +=1;
01332
01333 prev_state = 1;
01334 battery_state = BS_CHARGING;
01335 double power_desired = check_power_low - check_power;
01336
01337 if (power_desired <= 0)
01338 {
01339 last_current[0].SetPolar(I_Max.Mag(),volt.Arg());
01340 value_Line12 = last_current[0];
01341
01342 }
01343 else
01344 {
01345 if (power_desired >= Max_P)
01346 power_desired = Max_P;
01347
01348 double current_desired = power_desired/volt.Mag();
01349 last_current[0].SetPolar(current_desired,volt.Arg());
01350 value_Line12 = last_current[0];
01351 }
01352
01353
01354 push_powerflow_currents();
01355
01356 power_transferred = last_current[0].Mag()*volt.Mag();
01357
01358 VA_Out = power_transferred;
01359
01360 t_energy_limit = TIMESTAMP(3600 * (E_Max - Energy) / power_transferred);
01361 if (t_energy_limit == 0)
01362 t_energy_limit = 1;
01363
01364 return -(t1 + t_energy_limit);
01365 }
01366 }
01367
01368 else if ((check_power < check_power_low || (gen_mode_v == GM_POWER_VOLTAGE_HYBRID && volt.Mag() > voltage_set_high - deadband))&& prev_state == 1 && Energy < E_Max)
01369 {
01370 if (volt.Mag() < voltage_set_low)
01371 {
01372 if (prev_state != 0)
01373 no_of_cycles += 1;
01374
01375 last_current[0].SetPolar(parasitic_power_draw/volt.Mag(),volt.Arg());
01376 value_Line12 = last_current[0];
01377
01378
01379 push_powerflow_currents();
01380
01381 VA_Out = power_transferred = 0;
01382 battery_state = BS_CONFLICTED;
01383
01384 return TS_NEVER;
01385 }
01386 else
01387 {
01388 if (prev_state != 1)
01389 no_of_cycles +=1;
01390
01391 prev_state = 1;
01392 battery_state = BS_CHARGING;
01393
01394 double power_desired = check_power_low - check_power;
01395
01396 if (power_desired <= 0)
01397 {
01398 last_current[0].SetPolar(I_Max.Mag(),volt.Arg());
01399 value_Line12 = last_current[0];
01400
01401 }
01402 else
01403 {
01404 if (power_desired >= Max_P)
01405 power_desired = Max_P;
01406
01407 double current_desired = power_desired/volt.Mag();
01408 last_current[0].SetPolar(current_desired, volt.Arg());
01409 value_Line12 = last_current[0];
01410 }
01411
01412
01413 push_powerflow_currents();
01414
01415 power_transferred = last_current[0].Mag()*volt.Mag();
01416
01417 VA_Out = power_transferred;
01418
01419 t_energy_limit = TIMESTAMP(3600 * (E_Max - Energy) / power_transferred);
01420 if (t_energy_limit == 0)
01421 t_energy_limit = 1;
01422
01423 return -(t1 + t_energy_limit);
01424 }
01425 }
01426
01427 else if ((check_power > check_power_high || (gen_mode_v == GM_POWER_VOLTAGE_HYBRID && volt.Mag() < voltage_set_low + deadband)) && prev_state == -1 && Energy > 0)
01428 {
01429 if (volt.Mag() > voltage_set_high)
01430 {
01431 if (prev_state != 0)
01432 no_of_cycles += 1;
01433
01434 last_current[0].SetPolar(parasitic_power_draw/volt.Mag(),volt.Arg());
01435 value_Line12 = last_current[0];
01436
01437
01438 push_powerflow_currents();
01439
01440 VA_Out = power_transferred = 0;
01441 battery_state = BS_CONFLICTED;
01442
01443 return TS_NEVER;
01444 }
01445 else
01446 {
01447 if (prev_state != -1)
01448 no_of_cycles +=1;
01449
01450 prev_state = -1;
01451 battery_state = BS_DISCHARGING;
01452
01453 double power_desired = check_power - check_power_high;
01454 if (power_desired <= 0)
01455 {
01456 last_current[0].SetPolar(-I_Max.Mag(),volt.Arg());
01457 value_Line12 = last_current[0];
01458
01459 }
01460 else
01461 {
01462 if (power_desired >= Max_P)
01463 power_desired = Max_P;
01464
01465 double current_desired = -power_desired/volt.Mag();
01466 last_current[0].SetPolar(current_desired,volt.Arg());
01467 value_Line12 = last_current[0];
01468 }
01469
01470
01471 push_powerflow_currents();
01472
01473 power_transferred = last_current[0].Mag()*volt.Mag();
01474
01475 VA_Out = power_transferred;
01476
01477 t_energy_limit = TIMESTAMP(3600 * Energy / power_transferred);
01478
01479 if (t_energy_limit == 0)
01480 t_energy_limit = 1;
01481
01482 return -(t1 + t_energy_limit);
01483 }
01484 }
01485 else
01486 {
01487 if (prev_state != 0)
01488 no_of_cycles +=1;
01489
01490 last_current[0].SetPolar(parasitic_power_draw/volt.Mag(),volt.Arg());
01491 value_Line12 = last_current[0];
01492
01493
01494 push_powerflow_currents();
01495
01496 prev_state = 0;
01497 if (Energy <= 0)
01498 battery_state = BS_EMPTY;
01499 else if (Energy >= E_Max)
01500 battery_state = BS_FULL;
01501 else
01502 battery_state = BS_WAITING;
01503
01504 power_transferred = 0;
01505 VA_Out = power_transferred;
01506 return TS_NEVER;
01507 }
01508 }
01509 else
01510 {
01511 if (Energy <= 0)
01512 battery_state = BS_EMPTY;
01513 else if (Energy >= E_Max)
01514 battery_state = BS_FULL;
01515 else
01516 battery_state = BS_WAITING;
01517
01518 first_time_step = 1;
01519 return TS_NEVER;
01520 }
01521 }
01522 }
01523 else if (gen_mode_v == GM_CONSTANT_PQ)
01524 {
01525 if (number_of_phases_out == 3)
01526 {
01527 complex volt[3];
01528 double high_voltage = 0, low_voltage = 999999999;
01529 TIMESTAMP dt,t_energy_limit;
01530
01531 for (int jj=0; jj<3; jj++)
01532 {
01533 if (parent_is_meter == true)
01534 {
01535 value_Circuit_V[jj] = pCircuit_V[jj]->get_complex();
01536 }
01537
01538 volt[jj] = value_Circuit_V[jj];
01539 if (volt[jj].Mag() > high_voltage)
01540 high_voltage = volt[jj].Mag();
01541 if (volt[jj].Mag() < low_voltage)
01542 low_voltage = volt[jj].Mag();
01543 }
01544 if (first_time_step == 0)
01545 {
01546 dt = 0;
01547 }
01548 else if (prev_time == 0)
01549 {
01550 prev_time = t1;
01551 dt = 0;
01552 }
01553 else if (prev_time < t1)
01554 {
01555 dt = t1 - prev_time;
01556 prev_time = t1;
01557 }
01558 else
01559 dt = 0;
01560
01561 if (prev_state == -1)
01562 {
01563 Energy = Energy - (1 / base_efficiency) * power_transferred * (double)dt / 3600;
01564 if (Energy < 0)
01565 Energy = 0;
01566 }
01567 else if (prev_state == 1)
01568 {
01569 Energy = Energy + base_efficiency * power_transferred * (double)dt / 3600;
01570 if (Energy > E_Max)
01571 Energy = E_Max;
01572 }
01573
01574 if (first_time_step > 0)
01575 {
01576 if (high_voltage > V_Max.Mag())
01577 {
01578 gl_verbose("The voltages at the battery meter are higher than rated. No power output.");
01579 battery_state = BS_WAITING;
01580 prev_state = 0;
01581
01582 for (int jj=0; jj<3; jj++)
01583 {
01584 last_current[jj].SetPolar(parasitic_power_draw/3/volt[jj].Mag(),volt[jj].Arg());
01585 value_Line_I[jj] = last_current[jj];
01586 }
01587
01588
01589 push_powerflow_currents();
01590
01591 return TS_NEVER;
01592 }
01593 else
01594 {
01595 double power_desired;
01596 if (fabs(B_scheduled_power) < fabs(Max_P))
01597 power_desired = B_scheduled_power;
01598 else
01599 power_desired = Max_P;
01600
01601 if (power_desired < 0.0 && Energy < E_Max)
01602 {
01603 battery_state = BS_CHARGING;
01604 prev_state = 1;
01605
01606 VA_Out = power_transferred = 0;
01607 for (int jj=0; jj<3; jj++)
01608 {
01609 last_current[jj].SetPolar((-power_desired + parasitic_power_draw)/3/volt[jj].Mag(),volt[jj].Arg());
01610 value_Line_I[jj] = last_current[jj];
01611 VA_Out += last_current[jj].Mag()*volt[jj].Mag();
01612 }
01613
01614
01615 push_powerflow_currents();
01616
01617 power_transferred = VA_Out.Mag();
01618
01619 t_energy_limit = TIMESTAMP(3600 * (E_Max - Energy) / power_transferred);
01620
01621 if (t_energy_limit == 0)
01622 t_energy_limit = 1;
01623
01624 return -(t1 + t_energy_limit);
01625 }
01626 else if (power_desired > 0.0 && Energy > 0.0)
01627 {
01628 battery_state = BS_DISCHARGING;
01629 prev_state = -1;
01630
01631 VA_Out = power_transferred = 0;
01632 for (int jj=0; jj<3; jj++)
01633 {
01634 last_current[jj].SetPolar((-power_desired + parasitic_power_draw)/3/volt[jj].Mag(),volt[jj].Arg());
01635 value_Line_I[jj] = last_current[jj];
01636 VA_Out += last_current[jj].Mag()*volt[jj].Mag();
01637 }
01638
01639
01640 push_powerflow_currents();
01641
01642 power_transferred = VA_Out.Mag();
01643
01644 t_energy_limit = TIMESTAMP(3600 * Energy / power_transferred);
01645
01646 if (t_energy_limit == 0)
01647 t_energy_limit = 1;
01648
01649 return -(t1 + t_energy_limit);
01650 }
01651 else if (Energy <= 0.0)
01652 {
01653 battery_state = BS_EMPTY;
01654 prev_state = 0;
01655
01656 VA_Out = power_transferred = 0.0;
01657 last_current[0] = last_current[1] = last_current[2] = complex(0,0);
01658 return TS_NEVER;
01659 }
01660 else if (Energy >= E_Max)
01661 {
01662 battery_state = BS_FULL;
01663 prev_state = -1;
01664
01665 VA_Out = power_transferred = 0;
01666 for (int jj=0; jj<3; jj++)
01667 {
01668 last_current[jj].SetPolar((parasitic_power_draw)/3/volt[jj].Mag(),volt[jj].Arg());
01669 value_Line_I[jj] = last_current[jj];
01670 VA_Out += last_current[jj].Mag()*volt[jj].Mag();
01671 }
01672
01673
01674 push_powerflow_currents();
01675
01676 power_transferred = VA_Out.Mag();
01677 t_energy_limit = TIMESTAMP(3600 * Energy / power_transferred);
01678
01679 if (t_energy_limit == 0)
01680 t_energy_limit = 1;
01681
01682 return -(t1 + t_energy_limit);
01683 }
01684 else
01685 {
01686 battery_state = BS_WAITING;
01687 prev_state = -1;
01688
01689 VA_Out = power_transferred = 0;
01690 for (int jj=0; jj<3; jj++)
01691 {
01692 last_current[jj].SetPolar((parasitic_power_draw)/3/volt[jj].Mag(),volt[jj].Arg());
01693 value_Line_I[jj] = last_current[jj];
01694 VA_Out += last_current[jj].Mag()*volt[jj].Mag();
01695 }
01696
01697
01698 push_powerflow_currents();
01699
01700 power_transferred = VA_Out.Mag();
01701
01702 t_energy_limit = TIMESTAMP(3600 * Energy / power_transferred);
01703
01704 if (t_energy_limit == 0)
01705 t_energy_limit = 1;
01706
01707 return -(t1 + t_energy_limit);
01708 }
01709 }
01710 }
01711 else
01712 {
01713 if (Energy <= 0)
01714 {
01715 battery_state = BS_EMPTY;
01716 prev_state = 0;
01717 }
01718 else if (Energy >= E_Max)
01719 {
01720 battery_state = BS_FULL;
01721 prev_state = -1;
01722 }
01723 else
01724 {
01725 battery_state = BS_WAITING;
01726 prev_state = 0;
01727 }
01728
01729 first_time_step = 1;
01730 return TS_NEVER;
01731 }
01732 }
01733 else if ( ((phases & 0x0010) == 0x0010) && (number_of_phases_out == 1) )
01734 {
01735 complex volt;
01736 TIMESTAMP dt,t_energy_limit;
01737
01738 if ((parent_is_meter == true) && (parent_is_triplex == true))
01739 {
01740 value_Circuit_V[0] = pCircuit_V[0]->get_complex();
01741 }
01742
01743 volt = value_Circuit_V[0];
01744
01745 if (first_time_step == 0)
01746 {
01747 dt = 0;
01748 }
01749 else if (prev_time == 0)
01750 {
01751 prev_time = t1;
01752 dt = 0;
01753 }
01754 else if (prev_time < t1)
01755 {
01756 dt = t1 - prev_time;
01757 prev_time = t1;
01758 }
01759 else
01760 dt = 0;
01761
01762 if (prev_state == -1)
01763 {
01764 Energy = Energy - (1 / base_efficiency) * power_transferred * (double)dt / 3600;
01765 if (Energy < 0)
01766 Energy = 0;
01767 }
01768 else if (prev_state == 1)
01769 {
01770 Energy = Energy + base_efficiency * power_transferred * (double)dt / 3600;
01771 if (Energy > E_Max)
01772 Energy = E_Max;
01773 }
01774
01775 if (first_time_step > 0)
01776 {
01777 if (volt.Mag() > V_Max.Mag() || volt.Mag()/240 < 0.9 || volt.Mag()/240 > 1.1)
01778 {
01779 gl_verbose("The voltages at the battery meter are higher than rated, or outside of ANSI emergency specifications. No power output.");
01780 battery_state = BS_WAITING;
01781 prev_state = -1;
01782
01783 last_current[0].SetPolar(parasitic_power_draw/volt.Mag(),volt.Arg());
01784 value_Line12 = last_current[0];
01785
01786
01787 push_powerflow_currents();
01788
01789 return TS_NEVER;
01790 }
01791 else
01792 {
01793 double power_desired;
01794 if (fabs(B_scheduled_power) < fabs(Max_P))
01795 power_desired = B_scheduled_power;
01796 else
01797 power_desired = Max_P;
01798
01799 if (power_desired < 0.0 && Energy < E_Max)
01800 {
01801 battery_state = BS_CHARGING;
01802 prev_state = 1;
01803
01804 double current_desired = -(power_desired - parasitic_power_draw) / volt.Mag();
01805 last_current[0].SetPolar(current_desired,volt.Arg());
01806 value_Line12 = last_current[0];
01807
01808
01809 push_powerflow_currents();
01810
01811 VA_Out = power_transferred = last_current[0].Mag()*volt.Mag();
01812
01813 t_energy_limit = TIMESTAMP(3600 * (E_Max - Energy) / power_transferred);
01814
01815 if (t_energy_limit == 0)
01816 t_energy_limit = 1;
01817
01818 return -(t1 + t_energy_limit);
01819 }
01820 else if (power_desired > 0.0 && Energy > 0.0)
01821 {
01822 battery_state = BS_DISCHARGING;
01823 prev_state = -1;
01824
01825 double current_desired = -(power_desired - parasitic_power_draw) / volt.Mag();
01826 last_current[0].SetPolar(current_desired,volt.Arg());
01827 value_Line12 = last_current[0];
01828
01829
01830 push_powerflow_currents();
01831
01832 VA_Out = power_transferred = last_current[0].Mag()*volt.Mag();
01833
01834 t_energy_limit = TIMESTAMP(3600 * Energy / power_transferred);
01835
01836 if (t_energy_limit == 0)
01837 t_energy_limit = 1;
01838
01839 return -(t1 + t_energy_limit);
01840 }
01841 else if (Energy <= 0.0)
01842 {
01843 battery_state = BS_EMPTY;
01844 prev_state = 0;
01845
01846 VA_Out = power_transferred = 0.0;
01847 last_current[0] = complex(0,0);
01848 return TS_NEVER;
01849 }
01850 else if (Energy >= E_Max)
01851 {
01852 battery_state = BS_FULL;
01853 prev_state = -1;
01854
01855 double current_desired = (parasitic_power_draw) / volt.Mag();
01856 last_current[0].SetPolar(current_desired,volt.Arg());
01857 value_Line12 = last_current[0];
01858
01859
01860 push_powerflow_currents();
01861
01862 VA_Out = power_transferred = last_current[0].Mag()*volt.Mag();
01863
01864 t_energy_limit = TIMESTAMP(3600 * Energy / power_transferred);
01865
01866 if (t_energy_limit == 0)
01867 t_energy_limit = 1;
01868
01869 return -(t1 + t_energy_limit);
01870 }
01871 else
01872 {
01873 battery_state = BS_WAITING;
01874 prev_state = -1;
01875
01876 double current_desired = (parasitic_power_draw) / volt.Mag();
01877 last_current[0].SetPolar(current_desired,volt.Arg());
01878 value_Line12 = last_current[0];
01879
01880
01881 push_powerflow_currents();
01882
01883 VA_Out = power_transferred = last_current[0].Mag()*volt.Mag();
01884
01885 t_energy_limit = TIMESTAMP(3600 * Energy / power_transferred);
01886
01887 if (t_energy_limit == 0)
01888 t_energy_limit = 1;
01889
01890 return -(t1 + t_energy_limit);
01891 }
01892 }
01893 }
01894 else
01895 {
01896 if (Energy <= 0)
01897 {
01898 battery_state = BS_EMPTY;
01899 prev_state = 0;
01900 }
01901 else if (Energy >= E_Max)
01902 {
01903 battery_state = BS_FULL;
01904 prev_state = -1;
01905 }
01906 else
01907 {
01908 battery_state = BS_WAITING;
01909 prev_state = 0;
01910 }
01911
01912 first_time_step = 1;
01913 return TS_NEVER;
01914 }
01915 }
01916 }
01917 else
01918 {
01919
01920
01921
01923
01924
01925 if (pCircuit_V[0] != NULL)
01926 {
01927 value_Circuit_V[0] = pCircuit_V[0]->get_complex();
01928 }
01929
01930 if (pLine_I[0] != NULL)
01931 {
01932 value_Line_I[0] = pLine_I[0]->get_complex();
01933 }
01934
01935 V_Out = value_Circuit_V[0];
01936 I_Out = value_Line_I[0];
01937
01938
01939
01940
01941
01942 V_In = V_Out;
01943
01944 V_Internal = calculate_v_terminal(V_Out, I_Out);
01945
01946
01947
01948 efficiency = base_efficiency * calculate_efficiency(V_Out, I_Out);
01949
01950
01951
01952
01953 if (I_Out > 0){
01954 I_Internal = I_Out * efficiency;
01955 }
01956
01957 if(I_Out < 0){
01958 I_Internal = I_Out / efficiency;
01959 }
01960
01961
01962
01963
01964
01965
01966 VA_Out = V_Out * (~I_Out);
01967 VA_Internal = V_Internal * I_Internal;
01968
01969
01970
01971
01972
01973
01974 if(!recalculate){
01975
01976 if(t0 == prev_time){
01977
01978 Energy = E_Next;
01979
01980
01981
01982 recalculate = true;
01983
01984 return battery::sync(t0, t1);
01985 }else{
01986
01987
01988
01989 Energy = E_Next;
01990
01991
01992 recalculate = true;
01993
01994 return battery::sync(prev_time, t1);
01995 }
01996
01997 }else{
01999
02000
02001
02002
02003
02005
02006 double t2 = (gl_tohours((TIMESTAMP)t1) - gl_tohours((TIMESTAMP)t0));
02007
02008 if(fabs((double)V_Out.Re()) > fabs((double)V_Max.Re())){
02009
02010 V_Out = V_Max;
02011 V_In = V_Out;
02012 V_Internal = V_Out - (I_Out * Rinternal);
02013 }
02014
02015 if(fabs((double)I_Out.Re()) > fabs((double)I_Max.Re())){
02016
02017 I_Out = I_Max;
02018 }
02019
02020 if(fabs((double)VA_Out.Re()) > fabs((double)Max_P)){
02021
02022 VA_Out = complex(Max_P , 0);
02023 VA_Internal = VA_Out - (I_Out * I_Out * Rinternal);
02024 }
02025
02026
02027
02028 prev_time = t1;
02029
02030 if(VA_Out < 0){
02031
02032 if(Energy == 0 || Energy <= margin){
02033
02034 if(connected){
02035
02036 I_In = I_Max + complex(fabs(I_Out.Re()), fabs(I_Out.Im()));
02037 I_Prev = I_Max / efficiency;
02038
02039 recalculate = false;
02040 E_Next = Energy + (((I_In - complex(fabs(I_Out.Re()), fabs(I_Out.Im()))) * V_Internal / efficiency) * t2).Re();
02041 TIMESTAMP t3 = rfb_event_time(t0, (I_In - complex(fabs(I_Out.Re()), fabs(I_Out.Im()))) * V_Internal / efficiency, Energy);
02042 return t3;
02043 }
02044 else{
02045
02046 I_In = 0;
02047 I_Prev = 0;
02048 V_In = V_Out;
02049 VA_Out = 0;
02050 E_Next = 0;
02051 recalculate = false;
02052 return TS_NEVER;
02053 }
02054 }
02055
02056 if((Energy + (V_Internal * I_Prev.Re()).Re() * t2) <= margin){
02057
02058 if(connected){
02059
02060 I_In = I_Max + complex(fabs(I_Out.Re()), fabs(I_Out.Im()));
02061 I_Prev = I_Max / efficiency;
02062
02063 E_Next = margin;
02064 recalculate = false;
02065 TIMESTAMP t3 = rfb_event_time(t0, (I_In - complex(fabs(I_Out.Re()), fabs(I_Out.Im()))) * V_Internal / efficiency, Energy);
02066 return t3;
02067 }else{
02068
02069 TIMESTAMP t3 = rfb_event_time(t0, VA_Internal, Energy);
02070 E_Next = 0;
02071 I_In = 0;
02072 I_Prev = 0;
02073 recalculate = false;
02074 return t3;
02075 }
02076 }else{
02077
02078 E_Next = Energy + (VA_Internal.Re() * t2);
02079 I_In = 0;
02080 I_Prev = 0;
02081 recalculate = false;
02082 TIMESTAMP t3 = rfb_event_time(t0, VA_Internal, Energy);
02083 return t3;
02084 }
02085 }else if (VA_Out > 0){
02086 if(Energy >= (E_Max - margin)){
02087
02088 if(connected){
02089
02090
02091 E_Next = Energy;
02092 I_In = I_Out = 0;
02093 I_Prev = 0;
02094 recalculate = false;
02095 return TS_NEVER;
02096 }else{
02097
02098 I_In = I_Out = 0;
02099 I_Prev = 0;
02100 V_Out = V_Out;
02101 VA_Out = 0;
02102 E_Next = Energy;
02103 return TS_NEVER;
02104 }
02105 }
02106
02107 if(Energy + ((V_Internal * I_Prev.Re()) * efficiency * t2).Re() >= (E_Max - margin)){
02108
02109 TIMESTAMP t3 = rfb_event_time(t0, VA_Internal, Energy);
02110 I_In = 0;
02111 I_Prev = 0;
02112 E_Next = E_Max - margin;
02113 recalculate = false;
02114 return t3;
02115 }else{
02116 if(connected){
02117
02118
02119 I_In = I_Max - I_Out;
02120 I_Prev = I_Max * efficiency;
02121 E_Next = Energy + ((I_Max * V_Internal) * efficiency * t2).Re();
02122 recalculate = false;
02123 TIMESTAMP t3 = rfb_event_time(t0, (I_Max * V_Internal * efficiency), Energy);
02124 return t3;
02125 }else{
02126
02127 I_In = 0;
02128 I_Prev = 0;
02129 E_Next = Energy + (VA_Internal * t2).Re();
02130 recalculate = false;
02131 TIMESTAMP t3 = rfb_event_time(t0, VA_Internal, Energy);
02132 return t3;
02133 }
02134 }
02135 }else{
02136
02137 recalculate = false;
02138 I_In = 0;
02139 I_Prev = 0;
02140 E_Next = Energy;
02141 return TS_NEVER;
02142 }
02143
02144 }
02145 }
02146 }
02147 return TS_NEVER;
02148 }
02149
02150
02151 TIMESTAMP battery::postsync(TIMESTAMP t0, TIMESTAMP t1)
02152 {
02153 double temp_double_value;
02154
02155 if(use_internal_battery_model == FALSE){
02156 TIMESTAMP result;
02157
02158 Iteration_Toggle = !Iteration_Toggle;
02159 if (number_of_phases_out == 3)
02160 {
02161 value_Line_I[0] = -last_current[0];
02162 value_Line_I[1] = -last_current[1];
02163 value_Line_I[2] = -last_current[2];
02164 }
02165 else if ( ((phases & 0x0010) == 0x0010) && (number_of_phases_out == 1) )
02166 {
02167 value_Line12 = -last_current[0];
02168 }
02169 result = TS_NEVER;
02170
02171
02172 push_powerflow_currents();
02173
02174 if (Iteration_Toggle == true)
02175 return result;
02176 else
02177 return TS_NEVER;
02178 } else {
02179
02180 temp_double_value = pBatteryLoad->get_double();
02181 bat_load = -temp_double_value;
02182 p_max = pRatedPower->get_double();
02183
02184 if(t0 != 0 && bat_load != 0){
02185 if(bat_load < 0 && battery_state != BS_EMPTY){
02186 if(bat_load < -p_max){
02187 gl_warning("battery_load is greater than rated. Setting to plate rating.");
02188 bat_load = -p_max;
02189 }
02190 battery_state = BS_DISCHARGING;
02191 p_br = p_max/pow(eta_rt,0.5);
02192 } else if(bat_load > 0 && battery_state != BS_FULL){
02193 if(bat_load > p_max){
02194 gl_warning("battery_load is greater than rated. Setting to plate rating.");
02195 bat_load = p_max;
02196 }
02197 battery_state = BS_CHARGING;
02198 p_br = p_max*pow(eta_rt,0.5);
02199 } else {
02200 return TS_NEVER;
02201 }
02202 if(battery_type == LI_ION){
02203 if(soc <= 1 && soc > 0.1){
02204 v_oc = n_series*(((4.1-3.6)/0.9)*soc + (4.1-((4.1-3.6)/0.9)));
02205 } else if(soc <= 0.1 && soc >= 0){
02206 v_oc = n_series*(((3.6-3.2)/0.1)*soc + 3.2);
02207 }
02208 } else if(battery_type == LEAD_ACID){
02209 v_oc = v_max;
02210 } else {
02211 v_oc = v_max;
02212 }
02213 r_in = v_oc*v_oc*fabs(p_br-p_max)/(p_br*p_br);
02214 v_t = (v_oc+pow((v_oc*v_oc+(4*bat_load*r_in)),0.5))/2;
02215 internal_battery_load = v_oc*bat_load/v_t;
02216
02217
02218 b_soc_reserve = pSocReserve->get_double();
02219 if(internal_battery_load < 0){
02220 state_change_time = t1 + (TIMESTAMP)ceil((b_soc_reserve-soc)*e_max*3600/internal_battery_load);
02221 } else if(internal_battery_load > 0){
02222 state_change_time = t1 + (TIMESTAMP)ceil((1-soc)*e_max*3600/internal_battery_load);
02223 }
02224 return state_change_time;
02225 }
02226 return TS_NEVER;
02227 }
02228 }
02229
02230
02231 gld_property *battery::map_complex_value(OBJECT *obj, char *name)
02232 {
02233 gld_property *pQuantity;
02234 OBJECT *objhdr = OBJECTHDR(this);
02235
02236
02237 pQuantity = new gld_property(obj,name);
02238
02239
02240 if ((pQuantity->is_valid() != true) || (pQuantity->is_complex() != true))
02241 {
02242 GL_THROW("battery:%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"));
02243
02244
02245
02246
02247 }
02248
02249
02250 return pQuantity;
02251 }
02252
02253
02254 gld_property *battery::map_double_value(OBJECT *obj, char *name)
02255 {
02256 gld_property *pQuantity;
02257 OBJECT *objhdr = OBJECTHDR(this);
02258
02259
02260 pQuantity = new gld_property(obj,name);
02261
02262
02263 if ((pQuantity->is_valid() != true) || (pQuantity->is_double() != true))
02264 {
02265 GL_THROW("battery:%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"));
02266
02267
02268
02269
02270 }
02271
02272
02273 return pQuantity;
02274 }
02275
02276
02277
02278 void battery::push_powerflow_currents(void)
02279 {
02280 complex temp_complex_val;
02281 gld_wlock *test_rlock;
02282 int indexval;
02283
02284 if (parent_is_meter==true)
02285 {
02286
02287 if (parent_is_triplex == true)
02288 {
02289
02290 if (pLine12 != NULL)
02291 {
02292
02293
02294 temp_complex_val = pLine12->get_complex();
02295
02296
02297 temp_complex_val += value_Line12;
02298
02299
02300 pLine12->setp<complex>(temp_complex_val,*test_rlock);
02301 }
02302
02303 }
02304 else
02305 {
02306 for (indexval=0; indexval<3; indexval++)
02307 {
02308
02309 if (pLine_I[indexval] != NULL)
02310 {
02311
02312
02313 temp_complex_val = pLine_I[indexval]->get_complex();
02314
02315
02316 temp_complex_val += value_Line_I[indexval];
02317
02318
02319 pLine_I[indexval]->setp<complex>(temp_complex_val,*test_rlock);
02320 }
02321
02322 }
02323 }
02324 }
02325
02326 }
02328
02330
02331
02332 STATUS battery::pre_deltaupdate(TIMESTAMP t0, unsigned int64 delta_time)
02333 {
02334 STATUS stat_val;
02335 OBJECT *obj = OBJECTHDR(this);
02336
02337
02338 if (enableDelta == true) {
02339
02340 }
02341 else {
02342
02343 gl_warning("battery:%s does not use internal_battery_model, or its parent inverter is not FQM_CONSTANT_PQ. No actions executed for this battery during delta mode",obj->name?obj->name:"unnamed");
02344
02345 }
02346
02347 return SUCCESS;
02348 }
02349
02350
02351 SIMULATIONMODE battery::inter_deltaupdate(unsigned int64 delta_time, unsigned long dt, unsigned int iteration_count_val)
02352 {
02353 SIMULATIONMODE simmode_return_value = SM_EVENT;
02354
02355
02356 deltat = (double)dt/(double)DT_SECOND;
02357
02358 if(enableDelta == TRUE){
02359
02360
02361 if ((delta_time==0) && (iteration_count_val==0))
02362 {
02363
02364 update_soc(delta_time);
02365
02366
02367 state_change_time_delta = check_state_change_time_delta(delta_time, dt);
02368
02369 simmode_return_value = SM_DELTA_ITER;
02370 }
02371
02372 else if ((delta_time != 0) && (iteration_count_val == 0)) {
02373
02374
02375 update_soc(delta_time);
02376
02377 simmode_return_value = SM_DELTA_ITER;
02378 }
02379
02380
02381 else if ((delta_time != 0) && (iteration_count_val == 1)) {
02382
02383
02384 state_change_time_delta = check_state_change_time_delta(delta_time, dt);
02385
02386 simmode_return_value = SM_DELTA_ITER;
02387
02388 }
02389
02390 }
02391
02392
02393
02394 return simmode_return_value;
02395
02396 }
02397
02398 void battery::update_soc(unsigned int64 delta_time)
02399 {
02400 gld_wlock *test_rlock;
02401
02402 b_soc_reserve = pSocReserve->get_double();
02403 if(battery_state == BS_DISCHARGING || battery_state == BS_CHARGING){
02404 if(soc >= 0 && soc <= 1){
02405 soc += (internal_battery_load*deltat/3600)/e_max;
02406 internal_battery_load = 0;
02407 if(soc <= 0){
02408 battery_state = BS_EMPTY;
02409 soc = 0;
02410 } else if(soc >= 1){
02411 battery_state = BS_FULL;
02412 soc = 1;
02413 } else if(soc <= b_soc_reserve && delta_time >= state_change_time_delta){
02414 battery_state = BS_EMPTY;
02415 soc = b_soc_reserve;
02416 }
02417 }
02418 }
02419 pre_soc = soc;
02420
02421 pSoc->setp<double>(soc,*test_rlock);
02422 }
02423
02424 double battery::check_state_change_time_delta(unsigned int64 delta_time, unsigned long dt)
02425 {
02426 double time_return;
02427 complex inv_VA_out_value;
02428 double inv_eff_value;
02429
02430
02431 if (parent_is_inverter == true)
02432 {
02433 inv_VA_out_value = pinverter_VA_Out->get_complex();
02434 inv_eff_value = peff->get_double();
02435 }
02436
02437
02438 if (inv_VA_out_value.Re() > 0.0)
02439 {
02440 Pout_delta = inv_VA_out_value.Re()/inv_eff_value;
02441 }
02442 else if (inv_VA_out_value.Re() == 0.0)
02443 {
02444 Pout_delta = 0.0;
02445 }
02446 else
02447 {
02448 Pout_delta = inv_VA_out_value.Re()*inv_eff_value;
02449 }
02450
02451
02452 bat_load = -(Pout_delta);
02453 p_max = pRatedPower->get_double();
02454
02455 if(bat_load != 0){
02456 if(bat_load < 0 && battery_state != BS_EMPTY){
02457 if(bat_load < -p_max){
02458 gl_warning("battery_load is greater than rated. Setting to plate rating.");
02459 bat_load = -p_max;
02460 }
02461 battery_state = BS_DISCHARGING;
02462 p_br = p_max/pow(eta_rt,0.5);
02463 } else if(bat_load > 0 && battery_state != BS_FULL){
02464 if(bat_load > p_max){
02465 gl_warning("battery_load is greater than rated. Setting to plate rating.");
02466 bat_load = p_max;
02467 }
02468 battery_state = BS_CHARGING;
02469 p_br = p_max*pow(eta_rt,0.5);
02470 } else {
02471 return TS_NEVER;
02472 }
02473 if(battery_type == LI_ION){
02474 if(soc <= 1 && soc > 0.1){
02475 v_oc = n_series*(((4.1-3.6)/0.9)*soc + (4.1-((4.1-3.6)/0.9)));
02476 } else if(soc <= 0.1 && soc >= 0){
02477 v_oc = n_series*(((3.6-3.2)/0.1)*soc + 3.2);
02478 }
02479 } else if(battery_type == LEAD_ACID){
02480 v_oc = v_max;
02481 } else {
02482 v_oc = v_max;
02483 }
02484 r_in = v_oc*v_oc*fabs(p_br-p_max)/(p_br*p_br);
02485 v_t = (v_oc+pow((v_oc*v_oc+(4*bat_load*r_in)),0.5))/2;
02486 internal_battery_load = v_oc*bat_load/v_t;
02487 b_soc_reserve = pSocReserve->get_double();
02488 if(internal_battery_load < 0){
02489 time_return = (delta_time) + (TIMESTAMP)ceil((b_soc_reserve-soc)*e_max*3600/internal_battery_load);
02490 } else if(internal_battery_load > 0){
02491 time_return = (delta_time) + (TIMESTAMP)ceil((1-soc)*e_max*3600/internal_battery_load);
02492 }
02493 return time_return;
02494 }
02495
02496 return TS_NEVER;
02497
02498 }
02499
02500 STATUS battery::post_deltaupdate(complex *useful_value, unsigned int mode_pass)
02501 {
02502 return SUCCESS;
02503 }
02504
02506
02508
02509 EXPORT int create_battery(OBJECT **obj, OBJECT *parent)
02510 {
02511 try
02512 {
02513 *obj = gl_create_object(battery::oclass);
02514 if (*obj!=NULL)
02515 {
02516 battery *my = OBJECTDATA(*obj,battery);
02517 gl_set_parent(*obj,parent);
02518 return my->create();
02519 }
02520 else
02521 return 0;
02522 }
02523 CREATE_CATCHALL(battery);
02524 }
02525
02526 EXPORT int init_battery(OBJECT *obj, OBJECT *parent)
02527 {
02528 try
02529 {
02530 if (obj!=NULL)
02531 return OBJECTDATA(obj,battery)->init(parent);
02532 else
02533 return 0;
02534 }
02535 INIT_CATCHALL(battery);
02536 }
02537
02538 EXPORT TIMESTAMP sync_battery(OBJECT *obj, TIMESTAMP t1, PASSCONFIG pass)
02539 {
02540 TIMESTAMP t2 = TS_NEVER;
02541 battery *my = OBJECTDATA(obj,battery);
02542 try
02543 {
02544 switch (pass) {
02545 case PC_PRETOPDOWN:
02546 t2 = my->presync(obj->clock,t1);
02547 break;
02548 case PC_BOTTOMUP:
02549 t2 = my->sync(obj->clock,t1);
02550 break;
02551 case PC_POSTTOPDOWN:
02552 t2 = my->postsync(obj->clock,t1);
02553 break;
02554 default:
02555 GL_THROW("invalid pass request (%d)", pass);
02556 break;
02557 }
02558 if (pass==clockpass)
02559 obj->clock = t1;
02560 }
02561 SYNC_CATCHALL(battery);
02562 return t2;
02563 }
02564
02565 EXPORT STATUS preupdate_battery(OBJECT *obj, TIMESTAMP t0, unsigned int64 delta_time)
02566 {
02567 battery *my = OBJECTDATA(obj,battery);
02568 STATUS status_output = FAILED;
02569
02570 try
02571 {
02572 status_output = my->pre_deltaupdate(t0,delta_time);
02573 return status_output;
02574 }
02575 catch (char *msg)
02576 {
02577 gl_error("preupdate_battery(obj=%d;%s): %s",obj->id, (obj->name ? obj->name : "unnamed"), msg);
02578 return status_output;
02579 }
02580 }
02581
02582 EXPORT SIMULATIONMODE interupdate_battery(OBJECT *obj, unsigned int64 delta_time, unsigned long dt, unsigned int iteration_count_val)
02583 {
02584 battery *my = OBJECTDATA(obj,battery);
02585 SIMULATIONMODE status = SM_ERROR;
02586 try
02587 {
02588 status = my->inter_deltaupdate(delta_time,dt,iteration_count_val);
02589 return status;
02590 }
02591 catch (char *msg)
02592 {
02593 gl_error("interupdate_battery(obj=%d;%s): %s", obj->id, obj->name?obj->name:"unnamed", msg);
02594 return status;
02595 }
02596 }
02597
02598 EXPORT STATUS postupdate_battery(OBJECT *obj, complex *useful_value, unsigned int mode_pass)
02599 {
02600 battery *my = OBJECTDATA(obj,battery);
02601 STATUS status = FAILED;
02602 try
02603 {
02604 status = my->post_deltaupdate(useful_value, mode_pass);
02605 return status;
02606 }
02607 catch (char *msg)
02608 {
02609 gl_error("postupdate_battery(obj=%d;%s): %s", obj->id, obj->name?obj->name:"unnamed", msg);
02610 return status;
02611 }
02612 }