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