00001
00054
00055
00056 #include <stdlib.h>
00057 #include <stdio.h>
00058 #include <errno.h>
00059 #include <math.h>
00060 #include "network.h"
00061
00062
00063
00065
00067
00068 CLASS* node::oclass = NULL;
00069 CLASS* node::pclass = NULL;
00070 node *node::defaults = NULL;
00071
00072
00073 node::node(MODULE *mod)
00074 {
00075
00076
00077 if (oclass==NULL)
00078 {
00079
00080 node_class = oclass = gl_register_class(mod,"node",PC_BOTTOMUP);
00081 if (oclass==NULL)
00082 GL_THROW("unable to register object class implemented by %s",__FILE__);
00083
00084
00085 if (gl_publish_variable(oclass,
00086 PT_complex, "V", PADDR(V),
00087 PT_complex, "S", PADDR(S),
00088 PT_double, "G", PADDR(G),
00089 PT_double, "B", PADDR(B),
00090 PT_double, "Qmax_MVAR", PADDR(Qmax_MVAR),
00091 PT_double, "Qmin_MVAR", PADDR(Qmin_MVAR),
00092 PT_enumeration,"type",PADDR(type),
00093 PT_KEYWORD,"PQ",PQ,
00094 PT_KEYWORD,"PQV",PQV,
00095 PT_KEYWORD,"PV",PV,
00096 PT_KEYWORD,"SWING",SWING,
00097 PT_int16, "bus_id", PADDR(bus_id),
00098 PT_char32, "busname", PADDR(name),
00099 PT_int16, "flow_area_num", PADDR(flow_area_num),
00100 PT_double, "base_kV", PADDR(base_kV),
00101 PT_complex, "Vobs", PADDR(Vobs),
00102 PT_double, "Vstdev", PADDR(Vstdev),
00103 NULL)<1) GL_THROW("unable to publish properties in %s",__FILE__);
00104
00105
00106 defaults = this;
00107 type = PQ;
00108 V = complex(1,0,A);
00109 S = complex(0,0,J);
00110 G = 0;
00111 B = 0;
00112 Qmax_MVAR = 0.0;
00113 Qmin_MVAR = 0.0;
00114 Ys = 0.0;
00115 YVs = 0.0;
00116 type = PQ;
00117 name[0] = '\0';
00118 bus_id = 0;
00119 flow_area_num=1;
00120 loss_zone_num=1;
00121 base_kV=0;
00122 desired_kV=0;
00123 remote_bus_id=NULL;
00124
00125 Vobs = complex(0,0,A);
00126 Vstdev = 0.0;
00127 r2 = 0.0;
00128 n_obs = 0;
00129 Sr2 = 0.0;
00130 n_inj = 0;
00131 }
00132 }
00133
00134 node::~node()
00135 {
00136 }
00137
00138 int node::create()
00139 {
00140
00141
00142
00143
00144
00145
00146
00147
00148
00149
00150
00151
00152
00153
00154
00155
00156
00157
00158
00159
00160
00161
00162
00163
00164
00165 memcpy(this,defaults,sizeof(*this));
00166 return 1;
00167 }
00168
00169 int node::init(OBJECT *parent)
00170 {
00171
00172 OBJECT *hdr = OBJECTHDR(this);
00173 node *swing = parent?OBJECTDATA(parent,node):this;
00174 OBJECT *swing_hdr = OBJECTHDR(swing);
00175 if (swing_hdr->oclass!=hdr->oclass || swing->type!=SWING)
00176 {
00177 gl_error("node %s:%d parent is not a swing bus",hdr->oclass->name,hdr->id);
00178 return 0;
00179 }
00180 #ifdef HYBRID
00181
00182 if (Vstdev>0)
00183 swing->add_obs_residual(this);
00184
00185
00186 swing->add_inj_residual(this);
00187 #endif
00188
00189 YVs=complex(0,0);
00190 Ys=complex(0,0);
00191 return 1;
00192 }
00193
00194 #ifdef HYBRID
00195 void node::add_inj_residual(node *pNode)
00196 {
00197 if (pNode!=this)
00198 {
00199 pNode->Sr2 = (~(~pNode->V*((pNode->Ys + complex(pNode->G,pNode->B))*pNode->V + pNode->YVs)) - pNode->S).Mag();
00200 Sr2 += pNode->Sr2*pNode->Sr2;
00201 n_inj++;
00202 }
00203 }
00204
00205 void node::del_inj_residual(node *pNode)
00206 {
00207 if (pNode!=this)
00208 {
00209 Sr2 -= pNode->Sr2*pNode->Sr2;
00210 n_inj--;
00211 }
00212 }
00213
00214 double node::get_inj_residual(void) const
00215 {
00216 if (Sr2>0 && n_inj>0)
00217 return sqrt(Sr2/n_inj);
00218 else
00219 return Sr2;
00220 }
00221
00222 void node::add_obs_residual(node *pNode)
00223 {
00224 double r = (pNode->V - pNode->Vobs).Mag() / pNode->Vstdev;
00225 r*=r;
00226 if (pNode!=this)
00227 {
00228 pNode->r2 = r;
00229 pNode->n_obs = 1;
00230 }
00231 r2 += r;
00232 n_obs++;
00233 }
00234
00235 void node::del_obs_residual(node *pNode)
00236 {
00237 if (pNode!=this)
00238 r2 -= pNode->r2;
00239 else
00240 {
00241 double r = (pNode->V - pNode->Vobs).Mag() / pNode->Vstdev;
00242 r2 -= r*r;
00243 }
00244 n_obs--;
00245 }
00246
00247 double node::get_obs_residual(void) const
00248 {
00249 if (r2>0 && n_obs>0)
00250 return sqrt(r2/n_obs);
00251 else
00252 return r2;
00253 }
00254
00255 double node::get_obs_probability(void) const
00256 {
00257 if (r2<0)
00258 return 1;
00259 double pr = exp(-0.5*r2);
00260 if (pr>1)
00261 gl_warning("node:%d observation probability exceeds 1!", OBJECTHDR(this)->id);
00262 return pr;
00263 }
00264 #endif
00265
00266 TIMESTAMP node::sync(TIMESTAMP t0)
00267 {
00268 OBJECT *hdr = OBJECTHDR(this);
00269 node *swing = hdr->parent?OBJECTDATA(hdr->parent,node):this;
00270 complex dV(0.0);
00271 complex YY = Ys + complex(G,B);
00272 #ifdef HYBRID
00273 swing->del_inj_residual(this);
00274 #endif
00275 if (!YY.IsZero() || type==SWING)
00276 {
00277 switch (type) {
00278 case PV:
00279 S.Im() = -((~V*(YY*V+YVs)).Im());
00280 if (Qmin_MVAR<Qmax_MVAR && S.Im()<Qmin_MVAR)
00281 S.Im() = Qmin_MVAR;
00282 else if (Qmax_MVAR>Qmin_MVAR && S.Im()>Qmax_MVAR)
00283 S.Im() = Qmax_MVAR;
00284 else
00285 {
00286 complex Vnew = (~S/~V - YVs) / YY;
00287 Vnew.SetPolar(V.Mag(),Vnew.Arg());
00288 #ifdef HYBRID
00289 if (Vstdev>0)
00290 {
00291 double pr = swing->get_obs_probability();
00292 swing->del_obs_residual(this);
00293 dV = Vobs*(1-pr) + (Vnew)*pr - V;
00294 V += dV;
00295 swing->add_obs_residual(this);
00296 }
00297 else
00298 #endif
00299 {
00300 dV = Vnew - V;
00301 V = Vnew;
00302 }
00303 break;
00304 }
00305
00306 case PQ:
00307 if (!V.IsZero())
00308 {
00309 complex Vnew = (~S/~V - YVs) / YY;
00310 #ifdef HYBRID
00311 if (Vstdev>0)
00312 {
00313 double pr = swing->get_obs_probability();
00314 swing->del_obs_residual(this);
00315 dV = Vobs*(1-pr) + (Vnew)*pr - V;
00316 V += dV;
00317 swing->add_obs_residual(this);
00318 }
00319 else
00320 #endif
00321 {
00322 dV = (Vnew - V)*acceleration_factor;
00323 V += dV;
00324 }
00325 V.Notation() = A;
00326 }
00327 break;
00328 case SWING:
00329 S = ~(~V*(YY*V + YVs));
00330 S.Notation() = J;
00331 break;
00332 default:
00333
00334 gl_error("invalid bus type");
00335 return TS_ZERO;
00336 }
00337 }
00338 #ifdef HYBRID
00339 swing->add_inj_residual(this);
00340 #endif
00341
00342 #ifdef _DEBUG
00343
00344 if (debug_node>0)
00345 {
00346 OBJECT* obj = OBJECTHDR(this);
00347 static int first=-1;
00348 if (first==-1) first = obj->id;
00349 if (obj->id==first)
00350 {
00351 printf("\n");
00352 printf("Node Type V Vobs Stdev Power G B dV Pr{Vobs} r2 Sr2\n");
00353 printf("============== ===== ================= ================= ======== ================= ======== ======== ======== ======== ====== ======\n");
00354 }
00355 if (((debug_node&1)==1 && dV.Mag()>convergence_limit )
00356 #ifdef HYBRID
00357 || ((debug_node&2)==2 && Vstdev>0 )
00358 || ((debug_node&4)==4 && get_inj_residual()>0.001)
00359 #endif
00360 )
00361 {
00362 printf("%2d (%-9.9s) %5s %+8.4f%+8.3fd %+8.4f%+8.3fd %8.5f %+8.4f%+8.4fj %+8.5f ",
00363 obj->id, name, type==SWING?"SWING":(type==PQ?"PQ ":"PV"),
00364 V.Mag(),V.Arg()*180/3.1416,
00365 Vobs.Mag(), Vobs.Arg()*180/3.1416, Vstdev,
00366 S.Re(), S.Im(),
00367 G, B,
00368 dV.Mag());
00369 #ifdef HYBRID
00370 printf("%+8.5f %8.5f ", get_obs_probability(), r2);
00371 if (Vstdev>0)
00372 printf("%8.5f %6.3f %6.3f\n", get_obs_probability(), r2, get_inj_residual());
00373 else
00374 printf(" -- -- %6.3f\n",get_inj_residual());
00375 #else
00376 printf("\n");
00377 #endif
00378 }
00379 }
00380 #endif // _DEBUG
00381
00382 Ys = 0;
00383 YVs = 0;
00384 if (dV.Mag()>convergence_limit)
00385 return t0;
00386 else
00387 return TS_NEVER;
00388 }
00389
00391
00393
00394 EXPORT int create_node(OBJECT **obj, OBJECT *parent)
00395 {
00396 *obj = gl_create_object(node_class,sizeof(node));
00397 if (*obj!=NULL)
00398 {
00399 last_node = *obj;
00400 node *my = OBJECTDATA(*obj,node);
00401 gl_set_parent(*obj,parent);
00402 my->create();
00403 return 1;
00404 }
00405 return 0;
00406 }
00407
00408 EXPORT int init_node(OBJECT *obj)
00409 {
00410 return OBJECTDATA(obj,node)->init(obj->parent);
00411 }
00412
00413 EXPORT TIMESTAMP sync_node(OBJECT *obj, TIMESTAMP t0)
00414 {
00415 TIMESTAMP t1 = OBJECTDATA(obj,node)->sync(t0);
00416 obj->clock = t0;
00417 return t1;
00418 }
00419