00001
00018 #include <stdlib.h>
00019 #include <stdio.h>
00020 #include <errno.h>
00021 #include <math.h>
00022 #include <iostream>
00023 using namespace std;
00024
00025 #include "transformer.h"
00026
00027 CLASS* transformer::oclass = NULL;
00028 CLASS* transformer::pclass = NULL;
00029
00030
00031 double default_outdoor_temperature = 74;
00032
00033 transformer::transformer(MODULE *mod) : link_object(mod)
00034 {
00035 if(oclass == NULL)
00036 {
00037 pclass = link_object::oclass;
00038
00039 oclass = gl_register_class(mod,"transformer",sizeof(transformer),PC_PRETOPDOWN|PC_BOTTOMUP|PC_POSTTOPDOWN|PC_UNSAFE_OVERRIDE_OMIT|PC_AUTOLOCK);
00040 if (oclass==NULL)
00041 throw "unable to register class transformer";
00042 else
00043 oclass->trl = TRL_PROVEN;
00044
00045 if(gl_publish_variable(oclass,
00046 PT_INHERIT, "link",
00047 PT_object, "configuration", PADDR(configuration),PT_DESCRIPTION,"Configuration library used for transformer setup",
00048 PT_object, "climate", PADDR(climate),PT_DESCRIPTION,"climate object used to describe thermal model ambient temperature",
00049 PT_double, "ambient_temperature[degC]", PADDR(amb_temp),PT_DESCRIPTION,"ambient temperature in degrees C",
00050 PT_double, "top_oil_hot_spot_temperature[degC]", PADDR(theta_TO),PT_DESCRIPTION,"top-oil hottest-spot temperature, degrees C",
00051 PT_double, "winding_hot_spot_temperature[degC]", PADDR(theta_H),PT_DESCRIPTION,"winding hottest-spot temperature, degrees C",
00052 PT_double, "percent_loss_of_life", PADDR(life_loss),PT_DESCRIPTION,"the percent loss of life",
00053 PT_double, "aging_constant", PADDR(B_age),PT_DESCRIPTION,"the aging rate slope for the transformer insulation",
00054 PT_bool, "use_thermal_model", PADDR(use_thermal_model),PT_DESCRIPTION,"boolean to enable use of thermal model",
00055 PT_double, "transformer_replacement_count", PADDR(transformer_replacements), PT_DESCRIPTION,"counter of the number times the transformer has been replaced due to lifetime failure",
00056 PT_double, "aging_granularity[s]", PADDR(aging_step),PT_DESCRIPTION,"maximum timestep before updating thermal and aging model in seconds",
00057
00058 PT_double, "phase_A_primary_flux_value[Wb]", PADDR(flux_vals_inst[0]), PT_DESCRIPTION, "instantaneous magnetic flux in phase A on the primary side of the transformer during saturation calculations",
00059 PT_double, "phase_B_primary_flux_value[Wb]", PADDR(flux_vals_inst[1]), PT_DESCRIPTION, "instantaneous magnetic flux in phase B on the primary side of the transformer during saturation calculations",
00060 PT_double, "phase_C_primary_flux_value[Wb]", PADDR(flux_vals_inst[2]), PT_DESCRIPTION, "instantaneous magnetic flux in phase C on the primary side of the transformer during saturation calculations",
00061 PT_double, "phase_A_secondary_flux_value[Wb]", PADDR(flux_vals_inst[3]), PT_DESCRIPTION, "instantaneous magnetic flux in phase A on the secondary side of the transformer during saturation calculations",
00062 PT_double, "phase_B_secondary_flux_value[Wb]", PADDR(flux_vals_inst[4]), PT_DESCRIPTION, "instantaneous magnetic flux in phase B on the secondary side of the transformer during saturation calculations",
00063 PT_double, "phase_C_secondary_flux_value[Wb]", PADDR(flux_vals_inst[5]), PT_DESCRIPTION, "instantaneous magnetic flux in phase C on the secondary side of the transformer during saturation calculations",
00064 NULL) < 1) GL_THROW("unable to publish properties in %s",__FILE__);
00065
00066 if (gl_publish_function(oclass,"power_calculation",(FUNCTIONADDR)power_calculation)==NULL)
00067 GL_THROW("Unable to publish fuse state change function");
00068
00069
00070 if (gl_publish_function(oclass, "interupdate_pwr_object", (FUNCTIONADDR)interupdate_link)==NULL)
00071 GL_THROW("Unable to publish transformer deltamode function");
00072
00073
00074 if (gl_publish_function(oclass, "recalc_transformer_matrices", (FUNCTIONADDR)recalc_transformer_mat)==NULL)
00075 GL_THROW("Unable to publish transformer in-rush update function");
00076 if (gl_publish_function(oclass, "recalc_deltamode_saturation", (FUNCTIONADDR)recalc_deltamode_saturation)==NULL)
00077 GL_THROW("Unable to publish transformer in-rush powerflow update function");
00078
00079
00080 if (gl_publish_function(oclass, "update_power_pwr_object", (FUNCTIONADDR)updatepowercalc_link)==NULL)
00081 GL_THROW("Unable to publish transformer external power calculation function");
00082 if (gl_publish_function(oclass, "check_limits_pwr_object", (FUNCTIONADDR)calculate_overlimit_link)==NULL)
00083 GL_THROW("Unable to publish transformer external power limit calculation function");
00084 }
00085 }
00086
00087 int transformer::isa(char *classname)
00088 {
00089 return strcmp(classname,"transformer")==0 || link_object::isa(classname);
00090 }
00091
00092 int transformer::create()
00093 {
00094 int result = link_object::create();
00095 configuration = NULL;
00096 ptheta_A = NULL;
00097 transformer_replacements = 0;
00098 phi_base_Pri = 0.0;
00099 phi_base_Sec = 0.0;
00100 I_base_Pri = 0.0;
00101 I_base_Sec = 0.0;
00102
00103
00104 flux_vals_inst[0] = 0.0;
00105 flux_vals_inst[1] = 0.0;
00106 flux_vals_inst[2] = 0.0;
00107 flux_vals_inst[3] = 0.0;
00108 flux_vals_inst[4] = 0.0;
00109 flux_vals_inst[5] = 0.0;
00110
00111 return result;
00112 }
00113
00114 void transformer::fetch_double(double **prop, char *name, OBJECT *parent){
00115 OBJECT *hdr = OBJECTHDR(this);
00116 *prop = gl_get_double_by_name(parent, name);
00117 if(*prop == NULL){
00118 char tname[32];
00119 char *namestr = (hdr->name ? hdr->name : tname);
00120 char msg[256];
00121 sprintf(tname, "transformer:%i", hdr->id);
00122 if(*name == NULL)
00123 sprintf(msg, "%s: transformer unable to find property: name is NULL", namestr);
00124 else
00125 sprintf(msg, "%s: transformer unable to find %s", namestr, name);
00126 throw(msg);
00127 }
00128 }
00129
00130 int transformer::init(OBJECT *parent)
00131 {
00132 int idex;
00133
00134 if (!configuration)
00135 GL_THROW("no transformer configuration specified.");
00136
00137
00138
00139
00140 if (!gl_object_isa(configuration, "transformer_configuration","powerflow"))
00141 GL_THROW("invalid transformer configuration");
00142
00143
00144
00145
00146
00147 if((configuration->flags & OF_INIT) != OF_INIT){
00148 char objname[256];
00149 gl_verbose("transformer::init(): deferring initialization on %s", gl_name(configuration, objname, 255));
00150 return 2;
00151 }
00152 double V_base,za_basehi,za_baselo,V_basehi;
00153 double sa_base;
00154 double nt, nt_a, nt_b, nt_c, inv_nt_a, inv_nt_b, inv_nt_c;
00155 complex zt, zt_a, zt_b, zt_c, z0, z1, z2, zc;
00156 FINDLIST *climate_list = NULL;
00157
00158 config = OBJECTDATA(configuration,transformer_configuration);
00159
00160 if (config->connect_type==2)
00161 SpecialLnk = DELTADELTA;
00162 else if (config->connect_type==3)
00163 SpecialLnk = DELTAGWYE;
00164 else if (config->connect_type==5)
00165 SpecialLnk = SPLITPHASE;
00166 else
00167 SpecialLnk = WYEWYE;
00168
00169
00170 link_rating[0][0] = config->kVA_rating;
00171 link_rating[1][0] = config->kVA_rating;
00172
00173 link_object::init(parent);
00174 OBJECT *obj = OBJECTHDR(this);
00175
00176 V_base = config->V_secondary;
00177 voltage_ratio = nt = config->V_primary / config->V_secondary;
00178 zt = (config->impedance * V_base * V_base) / (config->kVA_rating * 1000.0);
00179 zc = complex(V_base * V_base,0) / (config->kVA_rating * 1000.0) * complex(config->shunt_impedance.Re(),0) * complex(0,config->shunt_impedance.Im()) / complex(config->shunt_impedance.Re(),config->shunt_impedance.Im());
00180
00181 for (int i = 0; i < 3; i++)
00182 {
00183 for (int j = 0; j < 3; j++)
00184 {
00185 a_mat[i][j] = b_mat[i][j] = c_mat[i][j] = d_mat[i][j] = A_mat[i][j] = B_mat[i][j] = complex(0.0,0.0);
00186 base_admittance_mat[i][j] = complex(0.0,0.0);
00187 }
00188 }
00189
00190 switch (config->connect_type) {
00191 case transformer_configuration::WYE_WYE:
00192 case transformer_configuration::SINGLE_PHASE:
00193 if (has_phase(PHASE_A))
00194 {
00195 nt_a = nt;
00196 zt_a = zt * nt_a;
00197 inv_nt_a = 1 / nt_a;
00198 c_mat[0][0] = complex(1,0) / ( complex(nt_a,0) * zc);
00199 }
00200 else
00201 {
00202 nt_a = inv_nt_a = 0.0;
00203 zt_a = complex(0,0);
00204 }
00205
00206 if (has_phase(PHASE_B))
00207 {
00208 nt_b = nt;
00209 zt_b = zt * nt_b;
00210 inv_nt_b = 1 / nt_b;
00211 c_mat[1][1] = complex(1,0) / ( complex(nt_b,0) * zc);
00212 }
00213 else
00214 {
00215 nt_b = inv_nt_b = 0.0;
00216 zt_b = complex(0,0);
00217 }
00218
00219 if (has_phase(PHASE_C))
00220 {
00221 nt_c = nt;
00222 zt_c = zt * nt_c;
00223 inv_nt_c = 1 / nt_c;
00224 c_mat[2][2] = complex(1,0) / ( complex(nt_c,0) * zc);
00225 }
00226 else
00227 {
00228 nt_c = inv_nt_c = 0.0;
00229 zt_c = complex(0,0);
00230 }
00231
00232 if (solver_method==SM_FBS)
00233 {
00234 if (has_phase(PHASE_A))
00235 {
00236 A_mat[0][0] = zc / ((zt + zc) * complex(nt,0));
00237 a_mat[0][0] = complex(nt,0) * (zt + zc)/zc;
00238 b_mat[0][0] = complex(nt_a,0) * zt_a;
00239 d_mat[0][0] = 1/nt;
00240
00241
00242
00243
00244
00245 }
00246
00247 if (has_phase(PHASE_B))
00248 {
00249 A_mat[1][1] = zc / ((zt + zc) * complex(nt,0));
00250 a_mat[1][1] = complex(nt,0) * (zt + zc)/zc;
00251 b_mat[1][1] = complex(nt_b,0) * zt_b;
00252 d_mat[1][1] = 1/nt;
00253
00254
00255
00256
00257 }
00258
00259 if (has_phase(PHASE_C))
00260 {
00261 A_mat[2][2] = zc / ((zt + zc) * complex(nt,0));
00262 a_mat[2][2] = complex(nt,0) * (zt + zc)/zc;
00263 b_mat[2][2] = complex(nt_c,0) * zt_c;
00264 d_mat[2][2] = 1/nt;
00265
00266
00267
00268
00269 }
00270 }
00271 else if (solver_method==SM_NR)
00272 {
00273 complex Izt = complex(1,0) / zt;
00274
00275
00276 if (enable_inrush_calculations == true)
00277 {
00278
00279
00280
00281
00282 YBase_Full = (complex *)gl_malloc(36*sizeof(complex));
00283
00284
00285 if (YBase_Full == NULL)
00286 {
00287 GL_THROW("Transformer:%s failed to allocate space for deltamode inrush history term",obj->name?obj->name:"unnamed");
00288
00289
00290
00291
00292
00293 }
00294
00295
00296 for (idex=0; idex<36; idex++)
00297 {
00298 YBase_Full[idex] = complex(0.0,0.0);
00299 }
00300
00301
00302 if ((config->magnetization_location == config->PRI_MAG) || (config->magnetization_location == config->BOTH_MAG))
00303 {
00304
00305 LinkHistTermCf = (complex *)gl_malloc(6*sizeof(complex));
00306
00307
00308 if (LinkHistTermCf == NULL)
00309 {
00310 GL_THROW("Transformer:%s failed to allocate space for deltamode inrush history term",obj->name?obj->name:"unnamed");
00311
00312 }
00313
00314
00315 LinkHistTermCf[0] = complex(0.0,0.0);
00316 LinkHistTermCf[1] = complex(0.0,0.0);
00317 LinkHistTermCf[2] = complex(0.0,0.0);
00318 LinkHistTermCf[3] = complex(0.0,0.0);
00319 LinkHistTermCf[4] = complex(0.0,0.0);
00320 LinkHistTermCf[5] = complex(0.0,0.0);
00321
00322
00323 YBase_Pri = (complex *)gl_malloc(9*sizeof(complex));
00324
00325
00326 if (YBase_Pri == NULL)
00327 {
00328 GL_THROW("Transformer:%s failed to allocate space for deltamode inrush history term",obj->name?obj->name:"unnamed");
00329
00330 }
00331
00332
00333 for (idex=0; idex<9; idex++)
00334 {
00335 YBase_Pri[idex] = complex(0.0,0.0);
00336 }
00337 }
00338 else
00339 {
00340
00341 LinkHistTermCf = NULL;
00342 YBase_Pri = NULL;
00343 }
00344
00345 if ((config->magnetization_location == config->SEC_MAG) || (config->magnetization_location == config->BOTH_MAG))
00346 {
00347
00348 LinkHistTermCt = (complex *)gl_malloc(6*sizeof(complex));
00349
00350
00351 if (LinkHistTermCt == NULL)
00352 {
00353 GL_THROW("Transformer:%s failed to allocate space for deltamode inrush history term",obj->name?obj->name:"unnamed");
00354
00355 }
00356
00357
00358 LinkHistTermCt[0] = complex(0.0,0.0);
00359 LinkHistTermCt[1] = complex(0.0,0.0);
00360 LinkHistTermCt[2] = complex(0.0,0.0);
00361 LinkHistTermCt[3] = complex(0.0,0.0);
00362 LinkHistTermCt[4] = complex(0.0,0.0);
00363 LinkHistTermCt[5] = complex(0.0,0.0);
00364
00365
00366 YBase_Sec = (complex *)gl_malloc(9*sizeof(complex));
00367
00368
00369 if (YBase_Sec == NULL)
00370 {
00371 GL_THROW("Transformer:%s failed to allocate space for deltamode inrush history term",obj->name?obj->name:"unnamed");
00372
00373 }
00374
00375
00376 for (idex=0; idex<9; idex++)
00377 {
00378 YBase_Sec[idex] = complex(0.0,0.0);
00379 }
00380 }
00381 else
00382 {
00383
00384 LinkHistTermCt = NULL;
00385 YBase_Sec = NULL;
00386 }
00387
00388
00389 if (config->model_inrush_saturation == true)
00390 {
00391
00392 hphi = (complex *)gl_malloc(12*sizeof(complex));
00393
00394
00395 if (hphi == NULL)
00396 {
00397 GL_THROW("Transformer:%s failed to allocate space for deltamode inrush history term",obj->name?obj->name:"unnamed");
00398
00399 }
00400
00401
00402 for (idex=0; idex<12; idex++)
00403 {
00404 hphi[idex] = complex(0.0,0.0);
00405 }
00406 }
00407 else
00408 {
00409 hphi = NULL;
00410 }
00411 }
00412
00413
00414 if (has_phase(PHASE_A))
00415 {
00416
00417 base_admittance_mat[0][0] = complex(1,0) / zt;
00418 b_mat[0][0] = zt;
00419 }
00420 if (has_phase(PHASE_B))
00421 {
00422
00423 base_admittance_mat[1][1] = complex(1,0) / zt;
00424 b_mat[1][1] = zt;
00425 }
00426 if (has_phase(PHASE_C))
00427 {
00428
00429 base_admittance_mat[2][2] = complex(1,0) / zt;
00430 b_mat[2][2] = zt;
00431 }
00432
00433
00434 A_mat[0][1] = A_mat[0][2] = A_mat[1][0] = A_mat[1][2] = A_mat[2][0] = A_mat[2][1] = 0.0;
00435 a_mat[0][1] = a_mat[0][2] = a_mat[1][0] = a_mat[1][2] = a_mat[2][0] = a_mat[2][1] = 0.0;
00436 c_mat[0][1] = c_mat[0][2] = c_mat[1][0] = c_mat[1][2] = c_mat[2][0] = c_mat[2][1] = 0.0;
00437
00438 if (has_phase(PHASE_A))
00439 {
00440
00441 a_mat[0][0] = 0;
00442 d_mat[0][0] = Izt / nt / nt;
00443 A_mat[0][0] = complex(nt,0);
00444 c_mat[0][0] = nt;
00445 }
00446 if (has_phase(PHASE_B))
00447 {
00448
00449 a_mat[1][1] = 0;
00450 d_mat[1][1] = Izt / nt / nt;
00451 A_mat[1][1] = complex(nt,0);
00452 c_mat[1][1] = nt;
00453 }
00454 if (has_phase(PHASE_C))
00455 {
00456
00457 a_mat[2][2] = 0;
00458 d_mat[2][2] = Izt / nt / nt;
00459 A_mat[2][2] = complex(nt,0);
00460 c_mat[2][2] = nt;
00461 }
00462 }
00463 else
00464 {
00465 GL_THROW("Unsupported solver method");
00466
00467
00468
00469
00470
00471 }
00472
00473 B_mat[0][0] = zt*zc/(zt+zc);
00474 B_mat[1][1] = zt*zc/(zt+zc);
00475 B_mat[2][2] = zt*zc/(zt+zc);
00476
00477 break;
00478 case transformer_configuration::DELTA_DELTA:
00479
00480 if (solver_method==SM_FBS)
00481 {
00482 a_mat[0][0] = a_mat[1][1] = a_mat[2][2] = nt * 2.0 / 3.0;
00483 a_mat[0][1] = a_mat[0][2] = a_mat[1][0] = a_mat[1][2] = a_mat[2][0] = a_mat[2][1] = -nt / 3.0;
00484
00485 b_mat[0][0] = b_mat[1][1] = zt * nt;
00486 b_mat[2][0] = b_mat[2][1] = zt * -nt;
00487
00488 d_mat[0][0] = d_mat[1][1] = d_mat[2][2] = complex(1.0) / nt;
00489
00490 A_mat[0][0] = A_mat[1][1] = A_mat[2][2] = complex(2.0) / (nt * 3.0);
00491 A_mat[0][1] = A_mat[0][2] = A_mat[1][0] = A_mat[1][2] = A_mat[2][0] = A_mat[2][1] = complex(-1.0) / (nt * 3.0);
00492
00493 B_mat[0][0] = B_mat[1][1] = zt;
00494 B_mat[2][0] = B_mat[2][1] = -zt;
00495 }
00496 else if (solver_method==SM_NR)
00497 {
00498
00499
00500
00501 complex Izt = complex(1,0) / zt;
00502
00503 base_admittance_mat[0][0] = base_admittance_mat[1][1] = base_admittance_mat[2][2] = Izt;
00504
00505
00506 b_mat[0][0] = b_mat[1][1] = b_mat[2][2] = zt;
00507
00508
00509
00510
00511
00512 d_mat[0][0] = Izt / nt / nt;
00513 d_mat[1][1] = Izt / nt / nt;
00514 d_mat[2][2] = Izt / nt / nt;
00515
00516
00517 A_mat[0][0] = A_mat[1][1] = A_mat[2][2] = nt;
00518
00519 }
00520 else
00521 {
00522 GL_THROW("Unsupported solver method");
00523
00524
00525
00526
00527 }
00528 break;
00529 case transformer_configuration::DELTA_GWYE:
00530
00531 if (solver_method==SM_FBS)
00532 {
00533 if (nt>1.0)
00534 {
00535 nt *= sqrt(3.0);
00536
00537 a_mat[0][1] = a_mat[1][2] = a_mat[2][0] = -nt * 2.0 / 3.0;
00538 a_mat[0][2] = a_mat[1][0] = a_mat[2][1] = -nt / 3.0;
00539
00540 b_mat[0][1] = b_mat[1][2] = b_mat[2][0] = zt * -nt * 2.0 / 3.0;
00541 b_mat[0][2] = b_mat[1][0] = b_mat[2][1] = zt * -nt / 3.0;
00542
00543 d_mat[0][0] = d_mat[1][1] = d_mat[2][2] = complex(1.0) / nt;
00544 d_mat[0][1] = d_mat[1][2] = d_mat[2][0] = complex(-1.0) / nt;
00545
00546 A_mat[0][0] = A_mat[1][1] = A_mat[2][2] = complex(1.0) / nt;
00547 A_mat[0][2] = A_mat[1][0] = A_mat[2][1] = complex(-1.0) / nt;
00548
00549 B_mat[0][0] = B_mat[1][1] = B_mat[2][2] = zt;
00550 }
00551 else {
00552 nt *= sqrt(3.0);
00553
00554 a_mat[0][0] = a_mat[1][1] = a_mat[2][2] = nt * 2.0 / 3.0;
00555 a_mat[0][1] = a_mat[1][2] = a_mat[2][0] = nt / 3.0;
00556
00557 b_mat[0][0] = b_mat[1][1] = b_mat[2][2] = zt * nt * 2.0 / 3.0;
00558 b_mat[0][1] = b_mat[1][2] = b_mat[2][0] = zt * nt/ 3.0;
00559
00560 d_mat[0][0] = d_mat[1][1] = d_mat[2][2] = complex(1.0) / nt;
00561 d_mat[0][2] = d_mat[1][0] = d_mat[2][1] = complex(-1.0) / nt;
00562
00563 A_mat[0][0] = A_mat[1][1] = A_mat[2][2] = complex(1.0) / nt;
00564 A_mat[0][1] = A_mat[1][2] = A_mat[2][0] = complex(-1.0) / nt;
00565
00566 B_mat[0][0] = B_mat[1][1] = B_mat[2][2] = zt;
00567 }
00568 }
00569 else if (solver_method==SM_NR)
00570 {
00571 complex Izt = complex(1.0,0) / zt;
00572
00573 complex alphaval = voltage_ratio * sqrt(3.0);
00574
00575 nt *= sqrt(3.0);
00576
00577
00578 b_mat[0][0] = b_mat[1][1] = b_mat[2][2] = zt;
00579
00580 if (voltage_ratio>1.0)
00581 {
00582
00583 c_mat[0][0] = c_mat[1][1] = c_mat[2][2] = complex(1.0) / alphaval;
00584 c_mat[0][2] = c_mat[1][0] = c_mat[2][1] = complex(-1.0) / alphaval;
00585 c_mat[0][1] = c_mat[1][2] = c_mat[2][0] = 0.0;
00586
00587
00588 base_admittance_mat[0][0] = base_admittance_mat[1][1] = base_admittance_mat[2][2] = Izt;
00589 base_admittance_mat[0][1] = base_admittance_mat[0][2] = base_admittance_mat[1][0] = 0.0;
00590 base_admittance_mat[1][2] = base_admittance_mat[2][0] = base_admittance_mat[2][1] = 0.0;
00591
00592
00593 B_mat[0][0] = B_mat[1][1] = B_mat[2][2] = complex(1.0) / alphaval;
00594 B_mat[0][1] = B_mat[1][2] = B_mat[2][0] = complex(-1.0) / alphaval;
00595 B_mat[0][2] = B_mat[1][0] = B_mat[2][1] = 0.0;
00596
00597
00598 equalm(c_mat,a_mat);
00599 equalm(B_mat,d_mat);
00600
00601 A_mat[0][0] = A_mat[1][1] = A_mat[2][2] = complex(1.0) / nt;
00602 A_mat[0][2] = A_mat[1][0] = A_mat[2][1] = complex(-1.0) / nt;
00603 }
00604 else
00605 {
00606
00607 c_mat[0][0] = c_mat[1][1] = c_mat[2][2] = complex(1.0) / alphaval;
00608 c_mat[0][1] = c_mat[1][2] = c_mat[2][0] = complex(-1.0) / alphaval;
00609 c_mat[0][2] = c_mat[1][0] = c_mat[2][1] = 0.0;
00610
00611
00612 base_admittance_mat[0][0] = base_admittance_mat[1][1] = base_admittance_mat[2][2] = Izt;
00613 base_admittance_mat[0][1] = base_admittance_mat[0][2] = base_admittance_mat[1][0] = 0.0;
00614 base_admittance_mat[1][2] = base_admittance_mat[2][0] = base_admittance_mat[2][1] = 0.0;
00615
00616
00617 B_mat[0][0] = B_mat[1][1] = B_mat[2][2] = complex(1.0) / alphaval;
00618 B_mat[0][2] = B_mat[1][0] = B_mat[2][1] = complex(-1.0) / alphaval;
00619 B_mat[0][1] = B_mat[1][2] = B_mat[2][0] = 0.0;
00620
00621
00622 equalm(c_mat,a_mat);
00623 equalm(B_mat,d_mat);
00624
00625 A_mat[0][0] = A_mat[1][1] = A_mat[2][2] = complex(1.0) / nt;
00626 A_mat[0][1] = A_mat[1][2] = A_mat[2][0] = complex(-1.0) / nt;
00627 }
00628 }
00629 else
00630 {
00631 GL_THROW("Unsupported solver method");
00632
00633
00634
00635
00636 }
00637
00638 break;
00639 case transformer_configuration::SINGLE_PHASE_CENTER_TAPPED:
00640 if (solver_method==SM_FBS)
00641 {
00642 if (has_phase(PHASE_A|PHASE_B))
00643 {
00644 GL_THROW("delta split tap is not supported yet");
00645
00646
00647
00648 }
00649 else if (has_phase(PHASE_B|PHASE_C))
00650 {
00651 GL_THROW("delta split tap is not supported yet");
00652
00653
00654
00655 }
00656 else if (has_phase(PHASE_A|PHASE_C))
00657 {
00658 GL_THROW("delta split tap is not supported yet");
00659
00660
00661
00662 }
00663 else if (has_phase(PHASE_A))
00664 {
00665 V_basehi = config->V_primary;
00666 sa_base = config->phaseA_kVA_rating;
00667 if (sa_base==0)
00668 GL_THROW("Split-phase tranformer:%d trying to attach to phase A not defined in the configuration",obj->id);
00669
00670
00671
00672
00673
00674
00675 za_basehi = (V_basehi*V_basehi)/(sa_base*1000);
00676 za_baselo = (V_base * V_base)/(sa_base*1000);
00677
00678 if (config->impedance1.Re() == 0.0 && config->impedance1.Im() == 0.0)
00679 {
00680 z0 = complex(0.5 * config->impedance.Re(),0.8*config->impedance.Im()) * complex(za_basehi,0);
00681 z1 = complex(config->impedance.Re(),0.4 * config->impedance.Im()) * complex(za_baselo,0);
00682 z2 = complex(config->impedance.Re(),0.4 * config->impedance.Im()) * complex(za_baselo,0);
00683 }
00684 else
00685 {
00686 z0 = complex(config->impedance.Re(),config->impedance.Im()) * complex(za_basehi,0);
00687 z1 = complex(config->impedance1.Re(),config->impedance1.Im()) * complex(za_baselo,0);
00688 z2 = complex(config->impedance2.Re(),config->impedance2.Im()) * complex(za_baselo,0);
00689 }
00690
00691 zc = complex(za_basehi,0) * complex(config->shunt_impedance.Re(),0) * complex(0,config->shunt_impedance.Im()) / complex(config->shunt_impedance.Re(),config->shunt_impedance.Im());
00692 zt_b = complex(0,0);
00693 zt_c = complex(0,0);
00694
00695 a_mat[0][0] = a_mat[1][0] = (z0 / zc + complex(1,0))*nt;
00696
00697 c_mat[0][0] = complex(1,0)*nt / zc;
00698
00699 d_mat[0][0] = complex(1,0)/nt + complex(nt,0)*z1 / zc;
00700 d_mat[0][1] = complex(-1,0)/nt;
00701
00702 A_mat[0][0] = A_mat[1][0] = (zc / (zc + z0) ) * complex(1,0)/nt;
00703 }
00704
00705 else if (has_phase(PHASE_B))
00706 {
00707 V_basehi = config->V_primary;
00708 sa_base = config->phaseB_kVA_rating;
00709 if (sa_base==0)
00710 GL_THROW("Split-phase tranformer:%d trying to attach to phase B not defined in the configuration",obj->id);
00711
00712
00713
00714
00715
00716
00717 za_basehi = (V_basehi*V_basehi)/(sa_base*1000);
00718 za_baselo = (V_base * V_base)/(sa_base*1000);
00719
00720 if (config->impedance1.Re() == 0.0 && config->impedance1.Im() == 0.0)
00721 {
00722 z0 = complex(0.5 * config->impedance.Re(),0.8*config->impedance.Im()) * complex(za_basehi,0);
00723 z1 = complex(config->impedance.Re(),0.4 * config->impedance.Im()) * complex(za_baselo,0);
00724 z2 = complex(config->impedance.Re(),0.4 * config->impedance.Im()) * complex(za_baselo,0);
00725 }
00726 else
00727 {
00728 z0 = complex(config->impedance.Re(),config->impedance.Im()) * complex(za_basehi,0);
00729 z1 = complex(config->impedance1.Re(),config->impedance1.Im()) * complex(za_baselo,0);
00730 z2 = complex(config->impedance2.Re(),config->impedance2.Im()) * complex(za_baselo,0);
00731 }
00732
00733 zc = complex(za_basehi,0) * complex(config->shunt_impedance.Re(),0) * complex(0,config->shunt_impedance.Im()) / complex(config->shunt_impedance.Re(),config->shunt_impedance.Im());
00734 zt_b = complex(0,0);
00735 zt_c = complex(0,0);
00736
00737 a_mat[0][1] = a_mat[1][1] = (z0 / zc + complex(1,0))*nt;
00738
00739 c_mat[1][0] = complex(1,0)*nt / zc;
00740
00741 d_mat[1][0] = complex(1,0)/nt + complex(nt,0)*z1 / zc;
00742 d_mat[1][1] = complex(-1,0)/nt;
00743
00744 A_mat[0][1] = A_mat[1][1] = (zc / (zc + z0) ) * complex(1,0)/nt;
00745 }
00746 else if (has_phase(PHASE_C))
00747 {
00748 V_basehi = config->V_primary;
00749 sa_base = config->phaseC_kVA_rating;
00750 if (sa_base==0)
00751 GL_THROW("Split-phase tranformer:%d trying to attach to phase C not defined in the configuration",obj->id);
00752
00753
00754
00755
00756
00757
00758 za_basehi = (V_basehi*V_basehi)/(sa_base*1000);
00759 za_baselo = (V_base * V_base)/(sa_base*1000);
00760
00761 if (config->impedance1.Re() == 0.0 && config->impedance1.Im() == 0.0)
00762 {
00763 z0 = complex(0.5 * config->impedance.Re(),0.8*config->impedance.Im()) * complex(za_basehi,0);
00764 z1 = complex(config->impedance.Re(),0.4 * config->impedance.Im()) * complex(za_baselo,0);
00765 z2 = complex(config->impedance.Re(),0.4 * config->impedance.Im()) * complex(za_baselo,0);
00766 }
00767 else
00768 {
00769 z0 = complex(config->impedance.Re(),config->impedance.Im()) * complex(za_basehi,0);
00770 z1 = complex(config->impedance1.Re(),config->impedance1.Im()) * complex(za_baselo,0);
00771 z2 = complex(config->impedance2.Re(),config->impedance2.Im()) * complex(za_baselo,0);
00772 }
00773
00774 zc = complex(za_basehi,0) * complex(config->shunt_impedance.Re(),0) * complex(0,config->shunt_impedance.Im()) / complex(config->shunt_impedance.Re(),config->shunt_impedance.Im());
00775 zt_b = complex(0,0);
00776 zt_c = complex(0,0);
00777
00778 a_mat[0][2] = a_mat[1][2] = (z0 / zc + complex(1,0))*nt;
00779
00780 c_mat[2][0] = complex(1,0)*nt / zc;
00781
00782 d_mat[2][0] = complex(1,0)/nt + complex(nt,0)*z1 / zc;
00783 d_mat[2][1] = complex(-1,0)/nt;
00784
00785 A_mat[0][2] = A_mat[1][2] = (zc / (zc + z0) ) * complex(1,0)/nt;
00786
00787 }
00788
00789 b_mat[0][0] = (z0 / zc + complex(1,0))*(z1*nt) + z0/nt;
00790 b_mat[0][1] = complex(-1,0) * (z0/nt);
00791 b_mat[0][2] = complex(0,0);
00792 b_mat[1][0] = (z0/nt);
00793 b_mat[1][1] = -(z0 / zc + complex(1,0))*(z2*nt) - z0/nt;
00794 b_mat[1][2] = complex(0,0);
00795 b_mat[2][0] = complex(0,0);
00796 b_mat[2][1] = complex(0,0);
00797 b_mat[2][2] = complex(0,0);
00798
00799 B_mat[0][0] = (z1) + (z0*zc/((zc + z0)*nt*nt));
00800 B_mat[0][1] = -(z0*zc/((zc + z0)*nt*nt));
00801 B_mat[1][0] = (z0*zc/((zc + z0)*nt*nt));
00802 B_mat[1][1] = complex(-1,0) * ((z2) + (z0*zc/((zc + z0)*nt*nt)));
00803 B_mat[1][2] = complex(0,0);
00804 B_mat[2][0] = complex(0,0);
00805 B_mat[2][1] = complex(0,0);
00806 B_mat[2][2] = complex(0,0);
00807 }
00808 else if (solver_method==SM_GS)
00809 {
00810 GL_THROW("Gauss-Seidel Implementation of Split-Phase is not complete");
00811
00812
00813
00814
00815 }
00816 else if (solver_method==SM_NR)
00817 {
00818 V_basehi = config->V_primary;
00819
00820 if (has_phase(PHASE_A))
00821 {
00822 sa_base = config->phaseA_kVA_rating;
00823 if (sa_base==0)
00824 GL_THROW("Split-phase tranformer:%d trying to attach to phase A not defined in the configuration",obj->id);
00825
00826
00827
00828
00829
00830 }
00831 else if (has_phase(PHASE_B))
00832 {
00833 sa_base = config->phaseB_kVA_rating;
00834 if (sa_base==0)
00835 GL_THROW("Split-phase tranformer:%d trying to attach to phase B not defined in the configuration",obj->id);
00836
00837
00838
00839
00840
00841 }
00842 else if (has_phase(PHASE_C))
00843 {
00844 sa_base = config->phaseC_kVA_rating;
00845 if (sa_base==0)
00846 GL_THROW("Split-phase tranformer:%d trying to attach to phase C not defined in the configuration",obj->id);
00847
00848
00849
00850
00851
00852 }
00853
00854 za_basehi = (V_basehi*V_basehi)/(sa_base*1000);
00855 za_baselo = (V_base * V_base)/(sa_base*1000);
00856
00857 if (config->impedance1.Re() == 0.0 && config->impedance1.Im() == 0.0)
00858 {
00859 z0 = complex(0.5 * config->impedance.Re(),0.8*config->impedance.Im()) * complex(za_basehi,0);
00860 z1 = complex(config->impedance.Re(),0.4 * config->impedance.Im()) * complex(za_baselo,0);
00861 z2 = complex(config->impedance.Re(),0.4 * config->impedance.Im()) * complex(za_baselo,0);
00862 }
00863 else
00864 {
00865 z0 = complex(config->impedance.Re(),config->impedance.Im()) * complex(za_basehi,0);
00866 z1 = complex(config->impedance1.Re(),config->impedance1.Im()) * complex(za_baselo,0);
00867 z2 = complex(config->impedance2.Re(),config->impedance2.Im()) * complex(za_baselo,0);
00868 }
00869
00870
00871
00872 zc = complex(za_basehi,0) * complex(config->shunt_impedance.Re(),0) * complex(0,config->shunt_impedance.Im()) / complex(config->shunt_impedance.Re(),config->shunt_impedance.Im());
00873
00874
00875 complex indet;
00876 indet=complex(1.0)/(z1*z2*zc*nt*nt+z0*(z2*zc+z1*zc+z1*z2*nt*nt));
00877
00878
00879
00880
00881
00882
00883
00884
00885
00886
00887
00888
00889
00890
00891 base_admittance_mat[0][0] = (-(z2*zc*nt*nt+z0*zc+z0*z2*nt*nt))*indet;
00892 base_admittance_mat[0][1] = (z0*zc)*indet;
00893 base_admittance_mat[1][0] = (-z0*zc)*indet;
00894 base_admittance_mat[1][1] = (z1*zc*nt*nt+z0*zc+z0*z1*nt*nt)*indet;
00895
00896
00897 base_admittance_mat[0][2] = (z2*zc*nt)*indet;
00898 base_admittance_mat[1][2] = (-z1*zc*nt)*indet;
00899
00900
00901 base_admittance_mat[2][0] = (-z2*zc*nt)*indet;
00902 base_admittance_mat[2][1] = (-z1*zc*nt)*indet;
00903
00904
00905 base_admittance_mat[2][2] = (z2*zc+z1*zc+z1*z2*nt*nt)*indet;
00906
00907
00908 b_mat[0][0] = (z1) + (z0*zc/((zc + z0)*nt*nt));
00909 b_mat[0][1] = -(z0*zc/((zc + z0)*nt*nt));
00910 b_mat[1][0] = (z0*zc/((zc + z0)*nt*nt));
00911 b_mat[1][1] = complex(-1,0) * ((z2) + (z0*zc/((zc + z0)*nt*nt)));
00912 b_mat[1][2] = complex(0,0);
00913 b_mat[2][0] = complex(0,0);
00914 b_mat[2][1] = complex(0,0);
00915 b_mat[2][2] = complex(0,0);
00916 }
00917 else
00918 {
00919 GL_THROW("Unsupported solver method");
00920
00921
00922
00923
00924 }
00925
00926 break;
00927 default:
00928 throw "unknown transformer connect type";
00929
00930
00931
00932
00933
00934 }
00935
00936 #ifdef _TESTING
00937 extern bool show_matrix_values;
00938 if (show_matrix_values)
00939 {
00940 gl_testmsg("transformer:\ta matrix");
00941 print_matrix(a_mat);
00942 gl_testmsg("transformer:\tA matrix");
00943 print_matrix(A_mat);
00944 gl_testmsg("transformer:\tb matrix");
00945 print_matrix(b_mat);
00946 gl_testmsg("transformer:\tB matrix");
00947 print_matrix(B_mat);
00948 gl_testmsg("transformer:\td matrix");
00949 print_matrix(d_mat);
00950 }
00951 #endif
00952
00953
00954 if(use_thermal_model && config->coolant_type!=1){
00955 GL_THROW("transformer:%d (%s) coolant_type specified is not handled",obj->id,obj->name);
00956
00957
00958
00959
00960 }
00961 if(use_thermal_model) {
00962 if (config->coolant_type==1){
00963 if(config->core_coil_weight<=0){
00964 GL_THROW("weight of the core and coil assembly for transformer configuration %s must be greater than zero",configuration->name);
00965
00966
00967
00968
00969 }
00970 if(config->tank_fittings_weight<=0){
00971 GL_THROW("weight of the tank fittings for transformer configuration %s must be greater than zero",configuration->name);
00972
00973
00974
00975
00976 }
00977 if(config->oil_vol<=0){
00978 GL_THROW("the oil volume for transformer configuration %s must be greater than zero",configuration->name);
00979
00980
00981
00982
00983 }
00984
00985 if(config->cooling_type==1 || config->cooling_type==2){
00986 thermal_capacity = (0.06 * config->core_coil_weight) + (0.04 * config->tank_fittings_weight) + (1.33 * config->oil_vol);
00987 if(config->cooling_type==1){
00988 m = n = 0.8;
00989 } else if(config->cooling_type==2){
00990 m = 0.8;
00991 n = 0.9;
00992 } else {
00993 GL_THROW("cooling_type not specified for transformer configuration %s",configuration->name);
00994
00995
00996
00997
00998 }
00999 } else if(config->cooling_type>2){
01000 thermal_capacity = (0.06 * config->core_coil_weight) + (0.06 * config->tank_fittings_weight) + (1.93 * config->oil_vol);
01001 if(config->cooling_type==3 || config->cooling_type==4){
01002 m = 0.8;
01003 n = 0.9;
01004 } else if(config->cooling_type==5 || config->cooling_type==6){
01005 m = n = 1.0;
01006 } else {
01007 GL_THROW("cooling_type not specified for transformer configuration %s",configuration->name);
01008
01009
01010
01011
01012 }
01013 } else {
01014 GL_THROW("cooling_type not specified for transformer configuration %s",configuration->name);
01015
01016
01017
01018
01019 }
01020 if(config->full_load_loss==0 && config->no_load_loss==0 && config->impedance.Re()==0 && config->shunt_impedance.Re()==0){
01021 GL_THROW("full-load and no-load losses for transformer configuration %s must be nonzero",configuration->name);
01022
01023
01024
01025 } else if(config->full_load_loss!=0 && config->no_load_loss!=0){
01026 R = config->full_load_loss/config->no_load_loss;
01027 } else if(config->impedance.Re()!=0 && config->shunt_impedance.Re()!=0)
01028 R = config->impedance.Re()*config->shunt_impedance.Re();
01029 if(config->t_W==NULL || config->dtheta_TO_R==NULL){
01030 GL_THROW("winding time constant or rated top-oil hotspot rise for transformer configuration %s must be nonzero",configuration->name);
01031
01032
01033
01034
01035 }
01036 if(config->t_W<=0){
01037 GL_THROW("%s: transformer_configuration winding time constant must be greater than zero",configuration->name);
01038
01039
01040
01041
01042 }
01043
01044
01045 if(climate==NULL){
01046
01047 climate_list = gl_find_objects(FL_NEW,FT_CLASS,SAME,"climate",FT_END);
01048
01049 if (climate_list==NULL)
01050 {
01051
01052 gl_warning("No climate data found - using static temperature");
01053
01054
01055
01056
01057
01058
01059
01060 ptheta_A = &default_outdoor_temperature;
01061 }
01062 else if (climate_list->hit_count >= 1)
01063 {
01064
01065 climate = gl_find_next(climate_list,NULL);
01066
01067
01068 if (climate==NULL)
01069 {
01070
01071 gl_warning("No climate data found - using static temperature");
01072
01073
01074
01075
01076
01077
01078
01079 ptheta_A = &default_outdoor_temperature;
01080 }
01081 else
01082 {
01083
01084 fetch_double(&ptheta_A, "temperature", climate);
01085
01086
01087 if (ptheta_A == NULL)
01088 {
01089
01090 gl_warning("No climate data found - using static temperature");
01091
01092
01093
01094
01095
01096
01097
01098 ptheta_A = &default_outdoor_temperature;
01099 }
01100 }
01101 }
01102 else
01103 {
01104
01105 gl_warning("No climate data found - using static temperature");
01106
01107
01108
01109
01110
01111
01112
01113 ptheta_A = &default_outdoor_temperature;
01114 }
01115
01116 } else {
01117 fetch_double(&ptheta_A, "temperature", climate);
01118
01119
01120 if (ptheta_A == NULL)
01121 {
01122
01123 gl_warning("No climate data found - using static temperature");
01124
01125
01126
01127
01128
01129
01130
01131 ptheta_A = &default_outdoor_temperature;
01132 }
01133 }
01134 temp_A = *ptheta_A;
01135 amb_temp = (temp_A-32.0)*(5.0/9.0);
01136 if(B_age==0)
01137 B_age = 15000;
01138
01139 if(theta_TO==0)
01140 theta_TO = amb_temp;
01141 if(theta_H==0)
01142 theta_H = theta_TO;
01143 if(config->dtheta_H_AR==0)
01144 config->dtheta_H_AR = 80;
01145
01146 return_at = gl_globalclock;
01147 if(aging_step<1)
01148 aging_step = 300;
01149 t_TOR = thermal_capacity*(config->dtheta_TO_R)/((config->full_load_loss)*(config->kVA_rating)*1000);
01150 dtheta_H_R = config->dtheta_H_AR - config->dtheta_TO_R;
01151 }
01152 else {
01153
01154 GL_THROW("transformer:%d (%s) coolant_type specified is not handled",obj->id,obj->name);
01155
01156
01157
01158
01159 }
01160 }
01161
01162 simulation_start_time = gl_globalclock;
01163
01164 return 1;
01165 }
01166
01167 TIMESTAMP transformer::postsync(TIMESTAMP t0)
01168 {
01169 OBJECT *obj = OBJECTHDR(this);
01170 double time_left;
01171 TIMESTAMP trans_end;
01172 if(use_thermal_model){
01173 TIMESTAMP result = link_object::postsync(t0);
01174 temp_A = *ptheta_A;
01175 amb_temp = (temp_A-32.0)*(5.0/9.0);
01176 if((t0 >= simulation_start_time) && (t0 != time_before)){
01177 if(time_before != 0){
01178 dt = (double)((t0-time_before)*TS_SECOND)/3600;
01179
01180
01181 if(config->installed_insulation_life<=0) {
01182 gl_error("%s: transformer configuration installed insulation life must be greater than zero",configuration->name);
01183
01184
01185
01186
01187
01188 return TS_INVALID;
01189 }
01190 life_loss += F_AA*dt*100/config->installed_insulation_life;
01191 if(life_loss < 100){
01192
01193 dtheta_TO = (dtheta_TO_U - dtheta_TO_i)*(1-exp(-dt/t_TO))+dtheta_TO_i;
01194 theta_TO = last_temp + dtheta_TO;
01195
01196
01197 dtheta_H = (dtheta_H_U - dtheta_H_i)*(1-exp(-dt/config->t_W))+dtheta_H_i;
01198 theta_H = last_temp + dtheta_TO + dtheta_H;
01199
01200
01201 K = power_out.Mag()/(1000*config->kVA_rating);
01202
01203
01204 dtheta_TO_i = dtheta_TO;
01205 dtheta_H_i = dtheta_H;
01206
01207 dtheta_TO_U = (config->dtheta_TO_R)*pow(((K*K*R+1)/(R+1)),n);
01208 t_TO = t_TOR*(((dtheta_TO_U/config->dtheta_TO_R)-(dtheta_TO_i/config->dtheta_TO_R))/(pow((dtheta_TO_U/config->dtheta_TO_R),(1/n)) - pow((dtheta_TO_i/config->dtheta_TO_R),(1/n))));
01209 dtheta_H_U = dtheta_H_R*pow(K,2*m);
01210 } else if(life_loss >= 100){
01211 gl_warning("%s: The transformer has reached its operational lifespan. Resetting transformer lifetime parameters.",obj->name);
01212
01213
01214
01215
01216
01217 life_loss = 0;
01218 dtheta_TO_i = 0;
01219 dtheta_H_i = 0;
01220 theta_TO = amb_temp;
01221 theta_H = amb_temp;
01222 dtheta_TO_U = (config->dtheta_TO_R)*pow(((K*K*R+1)/(R+1)),n);
01223 t_TO = t_TOR*(((dtheta_TO_U/config->dtheta_TO_R)-(dtheta_TO_i/config->dtheta_TO_R))/(pow((dtheta_TO_U/config->dtheta_TO_R),(1/n)) - pow((dtheta_TO_i/config->dtheta_TO_R),(1/n))));
01224 dtheta_H_U = dtheta_H_R*pow(K,2*m);
01225 transformer_replacements += 1;
01226 }
01227 last_temp = amb_temp;
01228
01229 } else {
01230
01231 K = power_out.Mag()/(1000*config->kVA_rating);
01232
01233
01234 dtheta_TO_i = theta_TO - amb_temp;
01235 if(dtheta_TO_i < 0){
01236 theta_TO = amb_temp;
01237 dtheta_TO_i = 0;
01238 }
01239 dtheta_H_i = theta_H - theta_TO;
01240
01241
01242 dtheta_TO_U = (config->dtheta_TO_R)*pow(((K*K*R+1)/(R+1)),n);
01243 t_TO = t_TOR*(((dtheta_TO_U/config->dtheta_TO_R)-(dtheta_TO_i/config->dtheta_TO_R))/(pow((dtheta_TO_U/config->dtheta_TO_R),(1/n)) - pow((dtheta_TO_i/config->dtheta_TO_R),(1/n))));
01244 dtheta_H_U = dtheta_H_R*pow(K,2*m);
01245
01246 last_temp = amb_temp;
01247 }
01248 time_before = t0;
01249 }
01250
01251 F_AA = exp((B_age/383.14)-(B_age/(theta_H+273.14)));
01252 time_left = (config->installed_insulation_life)*(100-life_loss)/(100*F_AA)*3600;
01253 if(time_left < 1){
01254 time_left = 1;
01255 }
01256 trans_end = t0 + (TIMESTAMP)(floor(time_left+0.5));
01257
01258 if(t0>=return_at){
01259 return_at += (TIMESTAMP)(floor(aging_step + 0.5));
01260 if(trans_end<return_at){
01261 return_at = trans_end;
01262 }
01263 if(return_at<t0){
01264 gl_error("%s: transformer granularity is too small for the minimum timestep specified",obj->name);
01265
01266
01267
01268
01269
01270
01271 return TS_INVALID;
01272 }
01273 if(result<return_at){
01274 return result;
01275 } else {
01276 return return_at;
01277 }
01278 } else {
01279 if(trans_end<return_at){
01280 return_at = trans_end;
01281 }
01282 if(result<return_at){
01283 return result;
01284 } else {
01285 return return_at;
01286 }
01287 }
01288 } else {
01289 return link_object::postsync(t0);
01290 }
01291 }
01292
01293
01294
01295
01296
01297
01298
01299
01300
01301
01302
01303 int transformer::transformer_inrush_mat_update(void)
01304 {
01305 int idex_val, jdex_val;
01306 double Np, Ns, Rd, Xd, XM, Rprim, Xprim, Lprim;
01307 complex Zprim[8][8], ZMprim[8][8],zp_trafo[8][8],zhp_trafo[8][8],zmp_trafo[8][8],zmhp_trafo[8][8];
01308 complex zh_trafo[8][8], zmh_trafo[8][8];
01309 complex temp_mat[8][8], yp_trafo[8][8], y_trafo[8][8], ym_trafo[8][8], temp_store_mat[8][8];
01310 complex aval_mat[8][8], avaltran_mat[8][8];
01311 complex temp_mat_small[6][6], temp_other_mat_small[6][6];
01312 complex Zo;
01313 double A_sat, B_sat, C_sat;
01314 complex work_val_cplex;
01315 OBJECT *obj = OBJECTHDR(this);
01316
01317
01318 Zo = 1e8;
01319
01320
01321 for (idex_val=0; idex_val<8; idex_val++)
01322 {
01323 for (jdex_val=0; jdex_val<8; jdex_val++)
01324 {
01325 Zprim[idex_val][jdex_val] = complex(0.0,0.0);
01326 ZMprim[idex_val][jdex_val] = complex(0.0,0.0);
01327 zp_trafo[idex_val][jdex_val] = complex(0.0,0.0);
01328 zhp_trafo[idex_val][jdex_val] = complex(0.0,0.0);
01329 zmp_trafo[idex_val][jdex_val] = complex(0.0,0.0);
01330 zmhp_trafo[idex_val][jdex_val] = complex(0.0,0.0);
01331 zh_trafo[idex_val][jdex_val] = complex(0.0,0.0);
01332 zmh_trafo[idex_val][jdex_val] = complex(0.0,0.0);
01333 temp_mat[idex_val][jdex_val] = complex(0.0,0.0);
01334 yp_trafo[idex_val][jdex_val] = complex(0.0,0.0);
01335 y_trafo[idex_val][jdex_val] = complex(0.0,0.0);
01336 ym_trafo[idex_val][jdex_val] = complex(0.0,0.0);
01337 temp_store_mat[idex_val][jdex_val] = complex(0.0,0.0);
01338 aval_mat[idex_val][jdex_val] = complex(0.0,0.0);
01339 avaltran_mat[idex_val][jdex_val] = complex(0.0,0.0);
01340 }
01341 }
01342
01343
01344 for (idex_val=0; idex_val<6; idex_val++)
01345 {
01346 for (jdex_val=0; jdex_val<6; jdex_val++)
01347 {
01348 temp_mat_small[idex_val][jdex_val] = complex(0.0,0.0);
01349 temp_other_mat_small[idex_val][jdex_val] = complex(0.0,0.0);
01350 }
01351 }
01352
01353
01354 Np = config->V_primary/sqrt(3.0);
01355 Ns = config->V_secondary/sqrt(3.0);
01356
01357
01358 Rd = config->impedance.Re()*config->V_secondary*config->V_secondary/(config->kVA_rating*1000.0);
01359 Xd = config->impedance.Im()*config->V_secondary*config->V_secondary/(config->kVA_rating*1000.0*2.0);
01360 XM = config->V_secondary*config->V_secondary/(config->kVA_rating*1000.0*config->IM_pu)-Xd;
01361
01362
01363
01364 A_phi = complex((deltatimestep_running * 2.0 * config->TD_val),0.0)/complex((4.0*config->TD_val+deltatimestep_running),(4.0*PI*nominal_frequency*config->TD_val*deltatimestep_running));
01365
01366
01367 B_phi = complex((4.0*config->TD_val-deltatimestep_running),(-4.0*PI*nominal_frequency*config->TD_val*deltatimestep_running));
01368
01369
01370 work_val_cplex=complex((4.0*config->TD_val+deltatimestep_running),4.0*PI*nominal_frequency*config->TD_val*deltatimestep_running);
01371
01372
01373 B_phi = B_phi/work_val_cplex;
01374
01375
01376 A_sat = config->LA_pu/(config->phiK_pu*config->phiK_pu);
01377 B_sat = (config->LA_pu*config->IM_pu - config->phiM_pu)/config->phiK_pu;
01378 C_sat = config->IM_pu*(config->LA_pu*config->IM_pu - config->phiM_pu + config->phiK_pu);
01379 D_sat = (-1.0*B_sat - sqrt((B_sat*B_sat - 4.0*A_sat*C_sat)))/(2.0*A_sat);
01380
01381
01382 if (config->model_inrush_saturation == true)
01383 {
01384
01385 phi_base_Pri = config->V_primary / (sqrt(3.0) * 2.0 * PI * nominal_frequency);
01386 I_base_Pri = (config->kVA_rating*1000.0) / (sqrt(3.0) * config->V_primary);
01387
01388 phi_base_Sec = config->V_secondary / (sqrt(3.0) * 2.0 * PI * nominal_frequency);
01389 I_base_Sec = (config->kVA_rating*1000.0) / (sqrt(3.0) * config->V_secondary);
01390 }
01391 else
01392 {
01393 phi_base_Pri = 0.0;
01394 phi_base_Sec = 0.0;
01395 I_base_Pri = 0.0;
01396 I_base_Sec = 0.0;
01397 }
01398
01399
01400
01401
01402 Zprim[0][0] = complex((Rd*(Np/Ns)*(Np/Ns)),(Xd*(Np/Ns)*(Np/Ns) + (Np*Np)/(Ns*Ns)*1e+9));
01403 Zprim[1][1] = Zprim[0][0];
01404 Zprim[2][2] = Zprim[0][0];
01405 Zprim[3][3] = 1e8;
01406
01407 Zprim[4][4] = complex(Rd,(Xd + 1e+9));
01408 Zprim[5][5] = Zprim[4][4];
01409 Zprim[6][6] = Zprim[4][4];
01410 Zprim[7][7] = 1e8;
01411
01412 Zprim[0][4] = complex(0.0,(Np/Ns*1e+9));
01413 Zprim[1][5] = Zprim[0][4];
01414 Zprim[2][6] = Zprim[0][4];
01415 Zprim[4][0] = Zprim[0][4];
01416 Zprim[5][1] = Zprim[0][4];
01417 Zprim[6][2] = Zprim[0][4];
01418
01419
01420 ZMprim[0][0] = complex(0.0,((Np*Np)/(Ns*Ns)*XM));
01421 ZMprim[1][1] = ZMprim[0][0];
01422 ZMprim[2][2] = ZMprim[0][0];
01423 ZMprim[3][3] = 1e8;
01424
01425 ZMprim[4][4] = complex(0.0,XM);
01426 ZMprim[5][5] = ZMprim[4][4];
01427 ZMprim[6][6] = ZMprim[4][4];
01428 ZMprim[7][7] = 1e8;
01429
01430
01431 if (deltatimestep_running>0)
01432 {
01433
01434 for (idex_val=0; idex_val<8; idex_val++)
01435 {
01436 for (jdex_val=0; jdex_val<8; jdex_val++)
01437 {
01438
01439 Rprim = Zprim[idex_val][jdex_val].Re();
01440 Xprim = Zprim[idex_val][jdex_val].Im();
01441 Lprim = Xprim/(2*PI*nominal_frequency);
01442
01443
01444 zp_trafo[idex_val][jdex_val] = complex((Rprim+(2.0*Lprim/deltatimestep_running)),Xprim);
01445 zhp_trafo[idex_val][jdex_val] = complex((Rprim-(2.0*Lprim/deltatimestep_running)),Xprim);
01446
01447
01448 Rprim = ZMprim[idex_val][jdex_val].Re();
01449 Xprim = ZMprim[idex_val][jdex_val].Im();
01450 Lprim = Xprim/(2*PI*nominal_frequency);
01451
01452
01453 zmp_trafo[idex_val][jdex_val] = complex((Rprim+(2.0*Lprim/deltatimestep_running)),Xprim);
01454 zmhp_trafo[idex_val][jdex_val] = complex((Rprim-(2.0*Lprim/deltatimestep_running)),Xprim);
01455 }
01456 }
01457
01458
01459 for (idex_val=0; idex_val<8; idex_val++)
01460 {
01461 aval_mat[idex_val][idex_val] = complex(1.0,0.0);
01462 avaltran_mat[idex_val][idex_val] = complex(1.0,0.0);
01463 }
01464 aval_mat[0][3] = aval_mat[1][3] = aval_mat[2][3] = complex(-1.0,0.0);
01465 aval_mat[4][7] = aval_mat[5][7] = aval_mat[6][7] = complex(-1.0,0.0);
01466
01467 avaltran_mat[3][0] = avaltran_mat[3][1] = avaltran_mat[3][2] = complex(-1.0,0.0);
01468 avaltran_mat[7][4] = avaltran_mat[7][5] = avaltran_mat[7][6] = complex(-1.0,0.0);
01469
01470
01471 lu_matrix_inverse(&zp_trafo[0][0],&temp_mat[0][0],8);
01472 lmatrix_mult(&avaltran_mat[0][0],&temp_mat[0][0],&temp_store_mat[0][0],8);
01473 lmatrix_mult(&temp_store_mat[0][0],&aval_mat[0][0],&y_trafo[0][0],8);
01474
01475
01476 for (idex_val=0; idex_val<3; idex_val++)
01477 {
01478 for (jdex_val=0; jdex_val<3; jdex_val++)
01479 {
01480 YBase_Full[idex_val*6+jdex_val] = y_trafo[idex_val][jdex_val];
01481 YBase_Full[idex_val*6+jdex_val+3] = y_trafo[idex_val][jdex_val+4];
01482 YBase_Full[idex_val*6+jdex_val+18] = y_trafo[idex_val+4][jdex_val];
01483 YBase_Full[idex_val*6+jdex_val+21] = y_trafo[idex_val+4][jdex_val+4];
01484 }
01485 }
01486
01487
01488
01489 lu_matrix_inverse(&zhp_trafo[0][0],&temp_mat[0][0],8);
01490 lmatrix_mult(&avaltran_mat[0][0],&temp_mat[0][0],&temp_store_mat[0][0],8);
01491 lmatrix_mult(&temp_store_mat[0][0],&aval_mat[0][0],&temp_mat[0][0],8);
01492 lu_matrix_inverse(&temp_mat[0][0],&zh_trafo[0][0],8);
01493
01494
01495
01496
01497
01498
01499 lmatrix_mult(&zh_trafo[0][0],&y_trafo[0][0],&temp_mat[0][0],8);
01500
01501
01502 for (idex_val=0; idex_val<8; idex_val++)
01503 {
01504 temp_mat[idex_val][idex_val] -= 1.0;
01505 }
01506
01507
01508 lmatrix_mult(&y_trafo[0][0],&temp_mat[0][0],&temp_store_mat[0][0],8);
01509
01510
01511 for (idex_val=0; idex_val<3; idex_val++)
01512 {
01513 for (jdex_val=0; jdex_val<3; jdex_val++)
01514 {
01515 ahrlstore[idex_val*6+jdex_val] = temp_store_mat[idex_val][jdex_val];
01516 ahrlstore[idex_val*6+jdex_val+3] = temp_store_mat[idex_val][jdex_val+4];
01517 ahrlstore[idex_val*6+jdex_val+18] = temp_store_mat[idex_val+4][jdex_val];
01518 ahrlstore[idex_val*6+jdex_val+21] = temp_store_mat[idex_val+4][jdex_val+4];
01519 }
01520 }
01521
01522
01523 lmatrix_mult(&y_trafo[0][0],&zh_trafo[0][0],&temp_store_mat[0][0],8);
01524
01525
01526 for (idex_val=0; idex_val<3; idex_val++)
01527 {
01528 for (jdex_val=0; jdex_val<3; jdex_val++)
01529 {
01530 bhrlstore[idex_val*6+jdex_val] = temp_store_mat[idex_val][jdex_val];
01531 bhrlstore[idex_val*6+jdex_val+3] = temp_store_mat[idex_val][jdex_val+4];
01532 bhrlstore[idex_val*6+jdex_val+18] = temp_store_mat[idex_val+4][jdex_val];
01533 bhrlstore[idex_val*6+jdex_val+21] = temp_store_mat[idex_val+4][jdex_val+4];
01534 }
01535 }
01536
01537
01538
01539 lu_matrix_inverse(&zmp_trafo[0][0],&temp_mat[0][0],8);
01540 lmatrix_mult(&avaltran_mat[0][0],&temp_mat[0][0],&temp_store_mat[0][0],8);
01541 lmatrix_mult(&temp_store_mat[0][0],&aval_mat[0][0],&ym_trafo[0][0],8);
01542
01543
01544
01545
01546
01547 lu_matrix_inverse(&zmhp_trafo[0][0],&temp_mat[0][0],8);
01548 lmatrix_mult(&avaltran_mat[0][0],&temp_mat[0][0],&temp_store_mat[0][0],8);
01549 lmatrix_mult(&temp_store_mat[0][0],&aval_mat[0][0],&temp_mat[0][0],8);
01550 lu_matrix_inverse(&temp_mat[0][0],&zmh_trafo[0][0],8);
01551
01552
01553
01554
01555 lmatrix_mult(&zmh_trafo[0][0],&ym_trafo[0][0],&temp_mat[0][0],8);
01556
01557
01558 for (idex_val=0; idex_val<8; idex_val++)
01559 {
01560 temp_mat[idex_val][idex_val] -= 1.0;
01561 }
01562
01563
01564 lmatrix_mult(&ym_trafo[0][0],&temp_mat[0][0],&temp_store_mat[0][0],8);
01565
01566
01567 for (idex_val=0; idex_val<3; idex_val++)
01568 {
01569 for (jdex_val=0; jdex_val<3; jdex_val++)
01570 {
01571 ahmstore[idex_val*3+jdex_val] = temp_store_mat[idex_val][jdex_val];
01572 ahmstore[idex_val*3+jdex_val+9] = temp_store_mat[idex_val+4][jdex_val+4];
01573 }
01574 }
01575
01576
01577 lmatrix_mult(&ym_trafo[0][0],&zmh_trafo[0][0],&temp_store_mat[0][0],8);
01578
01579
01580 for (idex_val=0; idex_val<3; idex_val++)
01581 {
01582 for (jdex_val=0; jdex_val<3; jdex_val++)
01583 {
01584 bhmstore[idex_val*3+jdex_val] = temp_store_mat[idex_val][jdex_val];
01585 bhmstore[idex_val*3+jdex_val+9] = temp_store_mat[idex_val+4][jdex_val+4];
01586 }
01587 }
01588 }
01589 else
01590 {
01591
01592 for (idex_val=0; idex_val<3; idex_val++)
01593 {
01594 for (jdex_val=0; jdex_val<3; jdex_val++)
01595 {
01596 temp_mat_small[idex_val][jdex_val] = Zprim[idex_val][jdex_val];
01597 temp_mat_small[idex_val][jdex_val+3] = Zprim[idex_val][jdex_val+4];
01598 temp_mat_small[idex_val+3][jdex_val] = Zprim[idex_val+4][jdex_val];
01599 temp_mat_small[idex_val+3][jdex_val+3] = Zprim[idex_val+4][jdex_val+4];
01600 }
01601 }
01602
01603
01604 lu_matrix_inverse(&temp_mat_small[0][0],YBase_Full,6);
01605
01606
01607 for (idex_val=0; idex_val<3; idex_val++)
01608 {
01609 for (jdex_val=0; jdex_val<3; jdex_val++)
01610 {
01611 temp_mat_small[idex_val][jdex_val] = ZMprim[idex_val][jdex_val];
01612 temp_mat_small[idex_val][jdex_val+3] = ZMprim[idex_val][jdex_val+4];
01613 temp_mat_small[idex_val+3][jdex_val] = ZMprim[idex_val+4][jdex_val];
01614 temp_mat_small[idex_val+3][jdex_val+3] = ZMprim[idex_val+4][jdex_val+4];
01615 }
01616 }
01617
01618
01619 lu_matrix_inverse(&temp_mat_small[0][0],&temp_other_mat_small[0][0],6);
01620
01621
01622 for (idex_val=0; idex_val<3; idex_val++)
01623 {
01624 for (jdex_val=0; jdex_val<3; jdex_val++)
01625 {
01626 ym_trafo[idex_val][jdex_val] = temp_other_mat_small[idex_val][jdex_val];
01627 ym_trafo[idex_val][jdex_val+4] = temp_other_mat_small[idex_val][jdex_val+3];
01628 ym_trafo[idex_val+4][jdex_val] = temp_other_mat_small[idex_val+3][jdex_val];
01629 ym_trafo[idex_val+4][jdex_val+4] = temp_other_mat_small[idex_val+3][jdex_val+3];
01630 }
01631 }
01632
01633
01634 }
01635
01636
01637
01638 for (idex_val=0; idex_val<3; idex_val++)
01639 {
01640 for (jdex_val=0; jdex_val<3; jdex_val++)
01641 {
01642 YSfrom[idex_val*3+jdex_val] = YBase_Full[idex_val*6+jdex_val];
01643 }
01644 }
01645
01646
01647 for (idex_val=0; idex_val<3; idex_val++)
01648 {
01649 for (jdex_val=0; jdex_val<3; jdex_val++)
01650 {
01651 From_Y[idex_val][jdex_val] = -YBase_Full[idex_val*6+jdex_val+3] - ym_trafo[idex_val][jdex_val+4];
01652 }
01653 }
01654
01655
01656 for (idex_val=0; idex_val<3; idex_val++)
01657 {
01658 for (jdex_val=0; jdex_val<3; jdex_val++)
01659 {
01660 To_Y[idex_val][jdex_val] = -YBase_Full[idex_val*6+jdex_val+18] - ym_trafo[idex_val+4][jdex_val];
01661 }
01662 }
01663
01664
01665 for (idex_val=0; idex_val<3; idex_val++)
01666 {
01667 for (jdex_val=0; jdex_val<3; jdex_val++)
01668 {
01669 YSto[idex_val*3+jdex_val] = YBase_Full[idex_val*6+jdex_val+21];
01670 }
01671 }
01672
01673
01674 if ((config->magnetization_location == config->PRI_MAG) || (config->magnetization_location == config->BOTH_MAG))
01675 {
01676
01677 for (idex_val=0; idex_val<3; idex_val++)
01678 {
01679 for (jdex_val=0; jdex_val<3; jdex_val++)
01680 {
01681 YSfrom[idex_val*3+jdex_val] += ym_trafo[idex_val][jdex_val];
01682 YBase_Pri[idex_val*3+jdex_val] = ym_trafo[idex_val][jdex_val];
01683 }
01684 }
01685 }
01686
01687 if ((config->magnetization_location == config->SEC_MAG) || (config->magnetization_location == config->BOTH_MAG))
01688 {
01689
01690 for (idex_val=0; idex_val<3; idex_val++)
01691 {
01692 for (jdex_val=0; jdex_val<3; jdex_val++)
01693 {
01694 YSto[idex_val*3+jdex_val] += ym_trafo[idex_val+4][jdex_val+4];
01695 YBase_Sec[idex_val*3+jdex_val] = ym_trafo[idex_val+4][jdex_val+4];
01696 }
01697 }
01698 }
01699
01700
01701 return 1;
01702 }
01703
01704
01705 int transformer::transformer_saturation_update(bool *deltaIsat)
01706 {
01707 OBJECT *obj = OBJECTHDR(this);
01708 int index_loop;
01709 complex work_values_voltages[6], phi_values[6];
01710 double phi_mag, phi_ang, angle_offset, imag_phi_value, imag_phi_value_pu;
01711 double Isat_pu_imag_full, Isat_pu_imag, curr_delta_timestep_val, temp_double;
01712 complex Isat_pu, Isat_diff;
01713 double diff_val, max_diff, global_time_dbl_val;
01714 TIMESTAMP global_time_int_val;
01715
01716 if ((config->connect_type == config->WYE_WYE) && (enable_inrush_calculations==true) && (config->model_inrush_saturation == true))
01717 {
01718
01719 if (deltaIsat == NULL)
01720 {
01721
01722 saturation_calculated_vals = (complex *)gl_malloc(12*sizeof(complex));
01723
01724
01725 if (saturation_calculated_vals == NULL)
01726 {
01727 GL_THROW("Transformer:%d %s failed to allocate memory for inrush saturation tracking",obj->id,obj->name ? obj->name : "Unnamed");
01728
01729
01730
01731
01732
01733 }
01734
01735
01736 for (index_loop=0; index_loop<12; index_loop++)
01737 {
01738 saturation_calculated_vals[index_loop] = complex(0.0,0.0);
01739 }
01740
01741
01742
01743 if (config->magnetization_location == config->PRI_MAG)
01744 {
01745 return 1;
01746 }
01747 else if (config->magnetization_location == config->SEC_MAG)
01748 {
01749 return 2;
01750 }
01751 else if (config->magnetization_location == config->BOTH_MAG)
01752 {
01753 return 3;
01754 }
01755 else
01756 {
01757 gl_warning("transformer:%d %s is set to model saturation, but has no magnetization location",obj->id,obj->name ? obj->name : "Unnamed");
01758
01759
01760
01761
01762
01763
01764
01765
01766 return -1;
01767 }
01768 }
01769 else
01770 {
01771
01772 curr_delta_timestep_val = gl_globaldeltaclock;
01773
01774
01775 global_time_int_val = gl_globalclock;
01776 global_time_dbl_val = (double)(global_time_int_val);
01777
01778
01779 max_diff = 0.0;
01780
01781
01782 work_values_voltages[0] = NR_busdata[NR_branchdata[NR_branch_reference].from].V[0];
01783 work_values_voltages[1] = NR_busdata[NR_branchdata[NR_branch_reference].from].V[1];
01784 work_values_voltages[2] = NR_busdata[NR_branchdata[NR_branch_reference].from].V[2];
01785 work_values_voltages[3] = NR_busdata[NR_branchdata[NR_branch_reference].to].V[0];
01786 work_values_voltages[4] = NR_busdata[NR_branchdata[NR_branch_reference].to].V[1];
01787 work_values_voltages[5] = NR_busdata[NR_branchdata[NR_branch_reference].to].V[2];
01788
01789
01790
01791 for (index_loop = 0; index_loop < 6; index_loop++)
01792 {
01793 phi_values[index_loop] = A_phi*work_values_voltages[index_loop] + hphi[index_loop];
01794 saturation_calculated_vals[index_loop+6] = saturation_calculated_vals[index_loop];
01795 }
01796
01797
01798
01799
01800
01801
01802 angle_offset = 2.0*PI*nominal_frequency*(curr_delta_timestep_val-global_time_dbl_val);
01803
01804
01805 if ((config->magnetization_location == config->PRI_MAG) || (config->magnetization_location == config->BOTH_MAG))
01806 {
01807
01808 for (index_loop=0; index_loop<3; index_loop++)
01809 {
01810
01811 phi_mag = phi_values[index_loop].Mag();
01812 phi_ang = phi_values[index_loop].Arg();
01813
01814
01815 imag_phi_value = (phi_mag*sin(phi_ang + angle_offset));
01816
01817
01818
01819 flux_vals_inst[index_loop] = imag_phi_value;
01820
01821
01822 if (imag_phi_value <0)
01823 {
01824 imag_phi_value = -imag_phi_value;
01825 }
01826
01827
01828 imag_phi_value_pu = imag_phi_value / phi_base_Pri;
01829
01830
01831
01832 temp_double = imag_phi_value_pu-config->phiK_pu;
01833 Isat_pu_imag_full = temp_double*temp_double + 4.0*D_sat*config->LA_pu;
01834 temp_double = sqrt(Isat_pu_imag_full);
01835 temp_double += imag_phi_value_pu - config->phiK_pu;
01836 Isat_pu_imag_full = temp_double / (2.0 * config->LA_pu);
01837 temp_double = D_sat / config->phiK_pu;
01838 Isat_pu_imag_full -= temp_double;
01839
01840
01841 if (imag_phi_value_pu <= config->phiM_pu)
01842 {
01843 Isat_pu_imag = 0.0;
01844 }
01845 else
01846 {
01847 Isat_pu_imag = Isat_pu_imag_full - config->IM_pu;
01848 }
01849
01850
01851 Isat_pu = complex(cos(phi_ang),sin(phi_ang));
01852
01853
01854 saturation_calculated_vals[index_loop] = Isat_pu * (Isat_pu_imag * I_base_Pri);
01855
01856
01857 Isat_diff = saturation_calculated_vals[index_loop] - saturation_calculated_vals[index_loop+6];
01858 diff_val = Isat_diff.Mag();
01859
01860
01861 if (diff_val > max_diff)
01862 {
01863 max_diff = diff_val;
01864 }
01865
01866
01867 NR_busdata[NR_branchdata[NR_branch_reference].from].BusSatTerm[index_loop] += saturation_calculated_vals[index_loop] - saturation_calculated_vals[index_loop+6];
01868 }
01869 }
01870
01871 if ((config->magnetization_location == config->SEC_MAG) || (config->magnetization_location == config->BOTH_MAG))
01872 {
01873
01874 for (index_loop=3; index_loop<6; index_loop++)
01875 {
01876
01877 phi_mag = phi_values[index_loop].Mag();
01878 phi_ang = phi_values[index_loop].Arg();
01879
01880
01881 imag_phi_value = (phi_mag*sin(phi_ang + angle_offset));
01882
01883
01884 if (imag_phi_value <0)
01885 {
01886 imag_phi_value = -imag_phi_value;
01887 }
01888
01889
01890 imag_phi_value_pu = imag_phi_value / phi_base_Sec;
01891
01892
01893
01894 temp_double = imag_phi_value_pu-config->phiK_pu;
01895 Isat_pu_imag_full = temp_double*temp_double + 4.0*D_sat*config->LA_pu;
01896 temp_double = sqrt(Isat_pu_imag_full);
01897 temp_double += imag_phi_value_pu - config->phiK_pu;
01898 Isat_pu_imag_full = temp_double / (2.0 * config->LA_pu);
01899 temp_double = D_sat / config->phiK_pu;
01900 Isat_pu_imag_full -= temp_double;
01901
01902
01903 if (imag_phi_value_pu <= config->phiM_pu)
01904 {
01905 Isat_pu_imag = 0.0;
01906 }
01907 else
01908 {
01909 Isat_pu_imag = Isat_pu_imag_full - config->IM_pu;
01910 }
01911
01912
01913 Isat_pu = complex(cos(phi_ang),sin(phi_ang));
01914
01915
01916 saturation_calculated_vals[index_loop] = Isat_pu * (Isat_pu_imag * I_base_Sec);
01917
01918
01919 Isat_diff = saturation_calculated_vals[index_loop] - saturation_calculated_vals[index_loop+6];
01920 diff_val = Isat_diff.Mag();
01921
01922
01923 if (diff_val > max_diff)
01924 {
01925 max_diff = diff_val;
01926 }
01927
01928
01929 NR_busdata[NR_branchdata[NR_branch_reference].to].BusSatTerm[index_loop-3] += saturation_calculated_vals[index_loop] - saturation_calculated_vals[index_loop+6];
01930 }
01931 }
01932
01933
01934 if (max_diff > inrush_tol_value)
01935 {
01936
01937 if (*deltaIsat == false)
01938 {
01939 *deltaIsat = true;
01940 }
01941
01942 }
01943
01944
01945
01946 return 1;
01947 }
01948 }
01949 else
01950 {
01951 return -1;
01952 }
01953 }
01954
01956
01958
01969
01970
01971
01972
01973
01974
01975
01976
01977
01978
01979
01980
01981
01982
01983 EXPORT int create_transformer(OBJECT **obj, OBJECT *parent)
01984 {
01985 try
01986 {
01987 *obj = gl_create_object(transformer::oclass);
01988 if (*obj!=NULL)
01989 {
01990 transformer *my = OBJECTDATA(*obj,transformer);
01991 gl_set_parent(*obj,parent);
01992 return my->create();
01993 }
01994 else
01995 return 0;
01996 }
01997 CREATE_CATCHALL(transformer);
01998 }
01999
02000
02001
02008 EXPORT int init_transformer(OBJECT *obj)
02009 {
02010 try {
02011 transformer *my = OBJECTDATA(obj,transformer);
02012 return my->init(obj->parent);
02013 }
02014 INIT_CATCHALL(transformer);
02015 }
02016
02025 EXPORT TIMESTAMP sync_transformer(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
02026 {
02027 try {
02028 transformer *pObj = OBJECTDATA(obj,transformer);
02029 TIMESTAMP t1 = TS_NEVER;
02030 switch (pass) {
02031 case PC_PRETOPDOWN:
02032 return pObj->presync(t0);
02033 case PC_BOTTOMUP:
02034 return pObj->sync(t0);
02035 case PC_POSTTOPDOWN:
02036 t1 = pObj->postsync(t0);
02037 obj->clock = t0;
02038 return t1;
02039 default:
02040 throw "invalid pass request";
02041 }
02042 }
02043 SYNC_CATCHALL(transformer);
02044 }
02045
02046 EXPORT void power_calculation(OBJECT *thisobj)
02047 {
02048 transformer *transformerobj = OBJECTDATA(thisobj,transformer);
02049 transformerobj->calculate_power();
02050 }
02051
02052 EXPORT int recalc_transformer_mat(OBJECT *obj)
02053 {
02054 int result;
02055 result = OBJECTDATA(obj,transformer)->transformer_inrush_mat_update();
02056 return result;
02057 }
02058
02059 EXPORT int recalc_deltamode_saturation(OBJECT *obj,bool *deltaIsat)
02060 {
02061 int result;
02062 result = OBJECTDATA(obj,transformer)->transformer_saturation_update(deltaIsat);
02063 return result;
02064 }
02065
02066 EXPORT int isa_transformer(OBJECT *obj, char *classname)
02067 {
02068 return OBJECTDATA(obj,transformer)->isa(classname);
02069 }
02070