00001
00010 #include <stdlib.h>
00011 #include <stdio.h>
00012 #include <errno.h>
00013 #include <math.h>
00014
00015 #include "generators.h"
00016 #include "microturbine.h"
00017 #include "timestamp.h"
00018
00019
00020
00021 #define HOUR 3600 * TS_SECOND
00022
00023 CLASS *microturbine::oclass = NULL;
00024 microturbine *microturbine::defaults = NULL;
00025
00026 static PASSCONFIG passconfig = PC_PRETOPDOWN|PC_BOTTOMUP|PC_POSTTOPDOWN;
00027 static PASSCONFIG clockpass = PC_BOTTOMUP;
00028
00029
00030 microturbine::microturbine(MODULE *module)
00031 {
00032 if (oclass==NULL)
00033 {
00034 oclass = gl_register_class(module,"microturbine",sizeof(microturbine),passconfig);
00035 if (oclass==NULL)
00036 GL_THROW("unable to register object class implemented by %s", __FILE__);
00037
00038 if (gl_publish_variable(oclass,
00039 PT_enumeration,"generator_mode",PADDR(gen_mode_v),
00040 PT_KEYWORD,"UNKNOWN",UNKNOWN,
00041 PT_KEYWORD,"CONSTANT_V",CONSTANT_V,
00042 PT_KEYWORD,"CONSTANT_PQ",CONSTANT_PQ,
00043 PT_KEYWORD,"CONSTANT_PF",CONSTANT_PF,
00044 PT_KEYWORD,"SUPPLY_DRIVEN",SUPPLY_DRIVEN,
00045
00046 PT_enumeration,"generator_status",PADDR(gen_status_v),
00047 PT_KEYWORD,"OFFLINE",OFFLINE,
00048 PT_KEYWORD,"ONLINE",ONLINE,
00049
00050 PT_enumeration,"power_type",PADDR(power_type_v),
00051 PT_KEYWORD,"AC",AC,
00052 PT_KEYWORD,"DC",DC,
00053
00054
00055 PT_double, "Rinternal", PADDR(Rinternal),
00056 PT_double, "Rload", PADDR(Rload),
00057 PT_double, "V_Max[V]", PADDR(V_Max),
00058 PT_complex, "I_Max[A]", PADDR(I_Max),
00059
00060 PT_double, "frequency[Hz]", PADDR(frequency),
00061 PT_double, "Max_Frequency[Hz]", PADDR(Max_Frequency),
00062 PT_double, "Min_Frequency[Hz]", PADDR(Min_Frequency),
00063 PT_double, "Fuel_Used[kVA]", PADDR(Fuel_Used),
00064 PT_double, "Heat_Out[kVA]", PADDR(Heat_Out),
00065 PT_double, "KV", PADDR(KV),
00066 PT_double, "Power_Angle", PADDR(Power_Angle),
00067
00068
00069 PT_double, "Max_P[kW]", PADDR(Max_P),
00070 PT_double, "Min_P[kW]", PADDR(Min_P),
00071
00072
00073
00074
00075 PT_complex, "phaseA_V_Out[kV]", PADDR(phaseA_V_Out),
00076 PT_complex, "phaseB_V_Out[kV]", PADDR(phaseB_V_Out),
00077 PT_complex, "phaseC_V_Out[kV]", PADDR(phaseC_V_Out),
00078
00079
00080
00081 PT_complex, "phaseA_I_Out[A]", PADDR(phaseA_I_Out),
00082 PT_complex, "phaseB_I_Out[A]", PADDR(phaseB_I_Out),
00083 PT_complex, "phaseC_I_Out[A]", PADDR(phaseC_I_Out),
00084
00085
00086
00087 PT_complex, "power_A_Out", PADDR(power_A_Out),
00088 PT_complex, "power_B_Out", PADDR(power_B_Out),
00089 PT_complex, "power_C_Out", PADDR(power_C_Out),
00090
00091 PT_complex, "VA_Out", PADDR(VA_Out),
00092
00093 PT_double, "pf_Out", PADDR(pf_Out),
00094 PT_complex, "E_A_Internal", PADDR(E_A_Internal),
00095 PT_complex, "E_B_Internal", PADDR(E_B_Internal),
00096 PT_complex, "E_C_Internal", PADDR(E_C_Internal),
00097
00098 PT_double, "efficiency", PADDR(efficiency),
00099
00100
00101 PT_double, "Rated_kVA[kVA]", PADDR(Rated_kVA),
00102
00103
00104
00105
00106
00107
00108 PT_set, "phases", PADDR(phases),
00109
00110 PT_KEYWORD, "A",(set)PHASE_A,
00111 PT_KEYWORD, "B",(set)PHASE_B,
00112 PT_KEYWORD, "C",(set)PHASE_C,
00113 PT_KEYWORD, "N",(set)PHASE_N,
00114 PT_KEYWORD, "S",(set)PHASE_S,
00115 NULL)<1) GL_THROW("unable to publish properties in %s",__FILE__);
00116 defaults = this;
00117
00118
00119
00120
00121 memset(this,0,sizeof(microturbine));
00122
00123 }
00124 }
00125
00126
00127
00128 int microturbine::create(void)
00129 {
00130 memcpy(this,defaults,sizeof(*this));
00131
00132 return 1;
00133 }
00134
00135
00136 double microturbine::determine_power_angle (complex power_out){
00137 Power_Angle = acos((double) (power_out.Re() / power_out.Mag()));
00138 return Power_Angle;
00139
00140 }
00141
00142 complex microturbine::determine_source_voltage(complex voltage_out, double r_internal, double r_load){
00143
00144 complex Vs = complex(((r_internal + r_load)/(r_load)) * voltage_out.Re(), ((r_internal + r_load)/(r_load)) * voltage_out.Im());
00145 return Vs;
00146
00147 }
00148
00149 double microturbine::determine_frequency(complex power_out){
00150
00151
00152
00153 double f = power_out.Mag() * 1.5 + 55000;\
00154 f = f/60;
00155 return f;
00156 }
00157
00158 double microturbine::calculate_loss(double frequency_out){
00159
00160 return 0;
00161 }
00162
00163 double microturbine::determine_heat(complex power_out, double heat_loss){
00164
00165 Heat_Out = power_out.Mag() * heat_loss;
00166 return Heat_Out;
00167 }
00168
00169
00170
00171
00172
00173
00174
00175 int microturbine::init(OBJECT *parent)
00176 {
00177
00178
00179
00180 gen_status_v = ONLINE;
00181
00182 Rinternal = 0.05;
00183 Rload = 1;
00184 V_Max = complex(10000);
00185 I_Max = complex(1000);
00186
00187 frequency = 0;
00188 Max_Frequency = 2000;
00189 Min_Frequency = 0;
00190 Fuel_Used = 0;
00191 Heat_Out = 0;
00192 KV = 1;
00193 Power_Angle = 1;
00194
00195 Max_P = 100;
00196 Min_P = 0;
00197
00198 Max_Q = 100;
00199 Min_Q = 0;
00200 Rated_kVA = 150;
00201
00202
00203 efficiency = 0;
00204 pf_Out = 1;
00205
00206 gl_verbose("microturbine init: finished initializing variables");
00207
00208 struct {
00209 complex **var;
00210 char *varname;
00211 } map[] = {
00212
00213 {&pCircuit_V_A, "phaseA_V_In"},
00214 {&pCircuit_V_B, "phaseB_V_In"},
00215 {&pCircuit_V_C, "phaseC_V_In"},
00216 {&pLine_I_A, "phaseA_I_In"},
00217 {&pLine_I_B, "phaseB_I_In"},
00218 {&pLine_I_C, "phaseC_I_In"},
00220 };
00221
00222
00223
00224
00225 static complex default_line_voltage[1], default_line_current[1];
00226 int i;
00227
00228
00229 if (parent!=NULL && strcmp(parent->oclass->name,"meter")==0)
00230 {
00231 for (i=0; i<sizeof(map)/sizeof(map[0]); i++)
00232 *(map[i].var) = get_complex(parent,map[i].varname);
00233
00234 gl_verbose("microturbine init: mapped METER objects to internal variables");
00235 }
00236 else if (parent!=NULL && strcmp(parent->oclass->name,"rectifier")==0){
00237 gl_verbose("microturbine init: parent WAS found, is an rectifier!");
00238
00240
00241 for (i=0; i<sizeof(map)/sizeof(map[0]); i++){
00242 *(map[i].var) = get_complex(parent,map[i].varname);
00243 }
00244 gl_verbose("microturbine init: mapped RECTIFIER objects to internal variables");
00245 }
00246 else{
00247
00248
00250 gl_verbose("microturbine init: mapped meter objects to internal variables");
00251
00252 OBJECT *obj = OBJECTHDR(this);
00253 gl_verbose("microturbine init: no parent meter defined, parent is not a meter");
00254 gl_warning("microturbine:%d %s", obj->id, parent==NULL?"has no parent meter defined":"parent is not a meter");
00255
00256
00257 *(map[0].var) = &default_line_voltage[0];
00258 *(map[1].var) = &default_line_current[0];
00259
00260
00261 default_line_voltage[0] = complex(V_Max.Re()/sqrt(3.0),0);
00262 default_line_current[0] = complex(I_Max.Re());
00263
00264
00265
00266 }
00267
00268 gl_verbose("microturbine init: finished connecting with meter");
00269
00270
00271
00272
00273
00274
00275
00276 if (gen_mode_v==UNKNOWN)
00277 {
00278 OBJECT *obj = OBJECTHDR(this);
00279 throw("Generator control mode is not specified");
00280 }
00281 if (gen_status_v==0)
00282 {
00283
00284 throw("Generator is out of service!");
00285 }else
00286 {
00287 return 1;
00288
00289 }
00290 return 1;
00291 }
00292
00293
00294
00295
00296
00297 complex *microturbine::get_complex(OBJECT *obj, char *name)
00298 {
00299 PROPERTY *p = gl_get_property(obj,name);
00300 if (p==NULL || p->ptype!=PT_complex)
00301 return NULL;
00302 return (complex*)GETADDR(obj,p);
00303 }
00304
00305
00306
00307
00308
00309 TIMESTAMP microturbine::presync(TIMESTAMP t0, TIMESTAMP t1)
00310 {
00311
00312 TIMESTAMP t2 = TS_NEVER;
00313 Heat_Out = Fuel_Used = frequency = 0.0;
00314
00315 return t2;
00316 }
00317
00318
00319 TIMESTAMP microturbine::sync(TIMESTAMP t0, TIMESTAMP t1)
00320 {
00321
00322
00323
00324
00325
00326
00327
00328 phaseA_V_Out = pCircuit_V_A[0];
00329 phaseB_V_Out = pCircuit_V_B[0];
00330 phaseC_V_Out = pCircuit_V_C[0];
00331
00332 phaseA_I_Out = pLine_I_A[0];
00333 phaseB_I_Out = pLine_I_B[0];
00334 phaseC_I_Out = pLine_I_C[0];
00335
00336 gl_verbose("microturbine sync: phaseA_V_Out from parent is: (%f , %f)", phaseA_V_Out.Re(), phaseA_V_Out.Im());
00337 gl_verbose("microturbine sync: phaseB_V_Out from parent is: (%f , %f)", phaseB_V_Out.Re(), phaseB_V_Out.Im());
00338 gl_verbose("microturbine sync: phaseC_V_Out from parent is: (%f , %f)", phaseC_V_Out.Re(), phaseC_V_Out.Im());
00339
00340 gl_verbose("microturbine sync: phaseA_I_Out from parent is: (%f , %f)", phaseA_I_Out.Re(), phaseA_I_Out.Im());
00341 gl_verbose("microturbine sync: phaseB_I_Out from parent is: (%f , %f)", phaseB_I_Out.Re(), phaseB_I_Out.Im());
00342 gl_verbose("microturbine sync: phaseC_I_Out from parent is: (%f , %f)", phaseC_I_Out.Re(), phaseC_I_Out.Im());
00343
00344 power_A_Out = (~phaseA_I_Out) * phaseA_V_Out;
00345 power_B_Out = (~phaseB_I_Out) * phaseB_V_Out;
00346 power_C_Out = (~phaseC_I_Out) * phaseC_V_Out;
00347
00348
00349 gl_verbose("microturbine sync: power_A_Out from parent is: (%f , %f)", power_A_Out.Re(), power_A_Out.Im());
00350 gl_verbose("microturbine sync: power_B_Out from parent is: (%f , %f)", power_B_Out.Re(), power_B_Out.Im());
00351 gl_verbose("microturbine sync: power_C_Out from parent is: (%f , %f)", power_C_Out.Re(), power_C_Out.Im());
00352
00353
00354 VA_Out = power_A_Out + power_B_Out + power_C_Out;
00355
00356 E_A_Internal = determine_source_voltage(phaseA_V_Out, Rinternal, Rload);
00357 E_B_Internal = determine_source_voltage(phaseB_V_Out, Rinternal, Rload);
00358 E_C_Internal = determine_source_voltage(phaseC_V_Out, Rinternal, Rload);
00359
00360
00361
00362 gl_verbose("microturbine sync: E_A_Internal calc is: (%f , %f)", E_A_Internal.Re(), E_A_Internal.Im());
00363 gl_verbose("microturbine sync: E_B_Internal calc is: (%f , %f)", E_B_Internal.Re(), E_B_Internal.Im());
00364 gl_verbose("microturbine sync: E_C_Internal calc is: (%f , %f)", E_C_Internal.Re(), E_C_Internal.Im());
00365
00366
00367 frequency = determine_frequency(VA_Out);
00368
00369 gl_verbose("microturbine sync: determined frequency is: %f", frequency);
00370
00371 if(frequency > Max_Frequency){
00372 throw ("the frequency asked for from the microturbine is too high!");
00373 }
00374 if(frequency < Min_Frequency){
00375 throw ("the frequency asked for from the microturbine is too low!");
00376 }
00377
00378
00379 double loss = calculate_loss(frequency);
00380 efficiency = 1 - loss;
00381 Heat_Out = determine_heat(VA_Out, loss);
00382 Fuel_Used = Heat_Out + VA_Out.Mag();
00383
00384 gl_verbose("microturbine sync: about to exit");
00385
00386 return TS_NEVER;
00387 }
00388
00389
00390 TIMESTAMP microturbine::postsync(TIMESTAMP t0, TIMESTAMP t1)
00391 {
00392 TIMESTAMP t2 = TS_NEVER;
00393
00394 Heat_Out = Fuel_Used = frequency = 0.0;
00395
00396 return t2;
00397 }
00398
00400
00402
00403 EXPORT int create_microturbine(OBJECT **obj, OBJECT *parent)
00404 {
00405 try
00406 {
00407 *obj = gl_create_object(microturbine::oclass);
00408 if (*obj!=NULL)
00409 {
00410 microturbine *my = OBJECTDATA(*obj,microturbine);
00411 gl_set_parent(*obj,parent);
00412 return my->create();
00413 }
00414 }
00415 catch (char *msg)
00416 {
00417 gl_error("create_microturbine: %s", msg);
00418 }
00419 return 0;
00420 }
00421
00422 EXPORT int init_microturbine(OBJECT *obj, OBJECT *parent)
00423 {
00424 try
00425 {
00426 if (obj!=NULL)
00427 return OBJECTDATA(obj,microturbine)->init(parent);
00428 }
00429 catch (char *msg)
00430 {
00431 gl_error("init_microturbine(obj=%d;%s): %s", obj->id, obj->name?obj->name:"unnamed", msg);
00432 }
00433 return 0;
00434 }
00435
00436 EXPORT TIMESTAMP sync_microturbine(OBJECT *obj, TIMESTAMP t1, PASSCONFIG pass)
00437 {
00438 TIMESTAMP t2 = TS_NEVER;
00439 microturbine *my = OBJECTDATA(obj,microturbine);
00440 try
00441 {
00442 switch (pass) {
00443 case PC_PRETOPDOWN:
00444 t2 = my->presync(obj->clock,t1);
00445 break;
00446 case PC_BOTTOMUP:
00447 t2 = my->sync(obj->clock,t1);
00448 break;
00449 case PC_POSTTOPDOWN:
00450 t2 = my->postsync(obj->clock,t1);
00451 break;
00452 default:
00453 GL_THROW("invalid pass request (%d)", pass);
00454 break;
00455 }
00456 if (pass==clockpass)
00457 obj->clock = t1;
00458 }
00459 catch (char *msg)
00460 {
00461 gl_error("sync_microturbine(obj=%d;%s): %s", obj->id, obj->name?obj->name:"unnamed", msg);
00462 }
00463 return t2;
00464 }