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