00001
00012 #include <stdlib.h>
00013 #include <stdio.h>
00014 #include <errno.h>
00015 #include <math.h>
00016
00017 #include "node.h"
00018 #include "meter.h"
00019 #include "pqload.h"
00020
00021 SCHED_LIST *new_slist(){
00022 SCHED_LIST *l = (SCHED_LIST *)malloc(sizeof(SCHED_LIST));
00023 memset(l, 0, sizeof(SCHED_LIST));
00024 return l;
00025 }
00026
00027 int delete_slist(SCHED_LIST *l){
00028 int rv = 0;
00029 if(l == NULL){
00030 return -1;
00031 }
00032 if(l->next != NULL){
00033 rv = delete_slist(l->next);
00034 }
00035 free(l);
00036 return rv;
00037 }
00038
00039 CLASS *pqload::oclass = NULL;
00040 CLASS *pqload::pclass = NULL;
00041 pqload *pqload::defaults = NULL;
00042 double pqload::zero_F = -459.67;
00043
00044 pqload::pqload(MODULE *mod) : load(mod)
00045 {
00046 if(oclass == NULL){
00047 pclass = load::oclass;
00048
00049 oclass = gl_register_class(mod, "pqload", sizeof(pqload), PC_PRETOPDOWN | PC_BOTTOMUP | PC_POSTTOPDOWN | PC_UNSAFE_OVERRIDE_OMIT);
00050 if(oclass == NULL)
00051 GL_THROW("unable to register object class implemented by %s",__FILE__);
00052
00053 if(gl_publish_variable(oclass,
00054 PT_INHERIT, "load",
00055 PT_object, "weather", PADDR(weather),
00056 PT_double, "T_nominal[degF]", PADDR(temp_nom),
00057 PT_double, "Zp_T[ohm/degF]", PADDR(imped_p[0]),
00058 PT_double, "Zp_H[ohm/%]", PADDR(imped_p[1]),
00059 PT_double, "Zp_S[ohm.h/Btu]", PADDR(imped_p[2]),
00060 PT_double, "Zp_W[ohm/mph]", PADDR(imped_p[3]),
00061 PT_double, "Zp_R[ohm.h/in]", PADDR(imped_p[4]),
00062 PT_double, "Zp[ohm]", PADDR(imped_p[5]),
00063 PT_double, "Zq_T[F/degF]", PADDR(imped_q[0]),
00064 PT_double, "Zq_H[F/%]", PADDR(imped_q[1]),
00065 PT_double, "Zq_S[F.h/Btu]", PADDR(imped_q[2]),
00066 PT_double, "Zq_W[F/mph]", PADDR(imped_q[3]),
00067 PT_double, "Zq_R[F.h/in]", PADDR(imped_q[4]),
00068 PT_double, "Zq[F]", PADDR(imped_q[5]),
00069 PT_double, "Im_T[A/degF]", PADDR(current_m[0]),
00070 PT_double, "Im_H[A/%]", PADDR(current_m[1]),
00071 PT_double, "Im_S[A.h/Btu]", PADDR(current_m[2]),
00072 PT_double, "Im_W[A/mph]", PADDR(current_m[3]),
00073 PT_double, "Im_R[A.h/in]", PADDR(current_m[4]),
00074 PT_double, "Im[A]", PADDR(current_m[5]),
00075 PT_double, "Ia_T[deg/degF]", PADDR(current_a[0]),
00076 PT_double, "Ia_H[deg/%]", PADDR(current_a[1]),
00077 PT_double, "Ia_S[deg.h/Btu]", PADDR(current_a[2]),
00078 PT_double, "Ia_W[deg/mph]", PADDR(current_a[3]),
00079 PT_double, "Ia_R[deg.h/in]", PADDR(current_a[4]),
00080 PT_double, "Ia[deg]", PADDR(current_a[5]),
00081 PT_double, "Pp_T[W/degF]", PADDR(power_p[0]),
00082 PT_double, "Pp_H[W/%]", PADDR(power_p[1]),
00083 PT_double, "Pp_S[W.h/Btu]", PADDR(power_p[2]),
00084 PT_double, "Pp_W[W/mph]", PADDR(power_p[3]),
00085 PT_double, "Pp_R[W.h/in]", PADDR(power_p[4]),
00086 PT_double, "Pp[W]", PADDR(power_p[5]),
00087 PT_double, "Pq_T[VAr/degF]", PADDR(power_q[0]),
00088 PT_double, "Pq_H[VAr/%]", PADDR(power_q[1]),
00089 PT_double, "Pq_S[VAr.h/Btu]", PADDR(power_q[2]),
00090 PT_double, "Pq_W[VAr/mph]", PADDR(power_q[3]),
00091 PT_double, "Pq_R[VAr.h/in]", PADDR(power_q[4]),
00092 PT_double, "Pq[VAr]", PADDR(power_q[5]),
00093 PT_double, "input_temp[degF]", PADDR(input[0]), PT_ACCESS, PA_REFERENCE,
00094 PT_double, "input_humid[%]", PADDR(input[1]), PT_ACCESS, PA_REFERENCE,
00095 PT_double, "input_solar[Btu/h]", PADDR(input[2]), PT_ACCESS, PA_REFERENCE,
00096 PT_double, "input_wind[mph]", PADDR(input[3]), PT_ACCESS, PA_REFERENCE,
00097 PT_double, "input_rain[in/h]", PADDR(input[4]), PT_ACCESS, PA_REFERENCE,
00098 PT_double, "output_imped_p[Ohm]", PADDR(output[0]), PT_ACCESS, PA_REFERENCE,
00099 PT_double, "output_imped_q[Ohm]", PADDR(output[1]), PT_ACCESS, PA_REFERENCE,
00100 PT_double, "output_current_m[A]", PADDR(output[2]), PT_ACCESS, PA_REFERENCE,
00101 PT_double, "output_current_a[deg]", PADDR(output[3]), PT_ACCESS, PA_REFERENCE,
00102 PT_double, "output_power_p[W]", PADDR(output[4]), PT_ACCESS, PA_REFERENCE,
00103 PT_double, "output_power_q[VAr]", PADDR(output[5]), PT_ACCESS, PA_REFERENCE,
00104 PT_complex, "output_impedance[ohm]", PADDR(kZ), PT_ACCESS, PA_REFERENCE,
00105 PT_complex, "output_current[A]", PADDR(kI), PT_ACCESS, PA_REFERENCE,
00106 PT_complex, "output_power[VA]", PADDR(kP), PT_ACCESS, PA_REFERENCE,
00107 NULL) < 1){
00108 GL_THROW("unable to publish properties in %s",__FILE__);
00109 }
00110 defaults = this;
00111 memset(this,0,sizeof(pqload));
00112 input[5] = 1.0;
00113 imped_p[5] = INFINITY;
00114 strcpy(schedule, "* * * * *:1.0;");
00115 temp_nom = zero_F;
00116 load_class = LC_UNKNOWN;
00117 sched_until = TS_NEVER;
00118 }
00119 }
00120
00121 int pqload::build_sched(char *instr = NULL, SCHED_LIST *end = NULL){
00122 char *sc_end = 0;
00123 char *start = instr ? instr : schedule;
00124 int rv = 0, scanct = 0;
00125 SCHED_LIST *endptr = NULL;
00126
00127
00128 while(*start == ' '){
00129 ++start;
00130 }
00131
00132
00133 if(*start == '\n' || *start == 0){
00134 return 1;
00135 }
00136
00137
00138 if(sched == NULL){
00139 sched = endptr = new_slist();
00140 } else {
00141 endptr = new_slist();
00142 }
00143
00144
00145 sc_end = strchr(start, ';');
00146 if(sc_end == NULL){
00147 gl_error("schedule token \"%s\" not semicolon terminated", start);
00148 }
00149 char256 moh_v, moh_w, hod_v, hod_w, dom_v, dom_w, moy_v, moy_w, dow_v, lpu, sc;
00150 scanct = sscanf(start, "%[-0-9*]%[ \t]%[-0-9*]%[ \t]%[-0-9*]%[ \t]%[-0-9*]%[ \t]%[-0-9*]:%[0-9\\.]%[;]",
00151 moh_v, moh_w, hod_v, hod_w, dom_v, dom_w, moy_v, moy_w, dow_v, lpu, sc);
00152
00153
00154
00155 rv = build_sched(sc_end + 1, endptr);
00156 if(rv > 0)
00157 return rv + 1;
00158 else
00159 return rv - 1;
00160 }
00161
00162 int pqload::create(void)
00163 {
00164 int res = 0;
00165
00166 memcpy(this, defaults, sizeof(pqload));
00167
00168 res = node::create();
00169
00170 return res;
00171 }
00172
00173 int pqload::init(OBJECT *parent){
00174 int rv = 0;
00175 int w_rv = 0;
00176
00177 if(weather != NULL){
00178 temperature = gl_get_property(weather, "temperature");
00179 if(temperature == NULL){
00180 gl_error("Unable to find temperature property in weather object!");
00181 ++w_rv;
00182 }
00183
00184 humidity = gl_get_property(weather, "humidity");
00185 if(humidity == NULL){
00186 gl_error("Unable to find humidity property in weather object!");
00187 ++w_rv;
00188 }
00189
00190 solar = gl_get_property(weather, "solar_flux");
00191 if(solar == NULL){
00192 gl_error("Unable to find solar_flux property in weather object!");
00193 ++w_rv;
00194 }
00195
00196 wind = gl_get_property(weather, "wind_speed");
00197 if(wind == NULL){
00198 gl_error("Unable to find wind_speed property in weather object!");
00199 ++w_rv;
00200 }
00201
00202 rain = gl_get_property(weather, "rainfall");
00203 if(rain == NULL){
00204 gl_error("Unable to find rainfall property in weather object!");
00205
00206 }
00207 }
00208
00209 rv = load::init(parent);
00210
00211 return w_rv ? 0 : rv;
00212 }
00213
00214 TIMESTAMP pqload::presync(TIMESTAMP t0)
00215 {
00216 TIMESTAMP result = 0;
00217
00218
00219 result = load::presync(t0);
00220
00221 return result;
00222 }
00223
00224 TIMESTAMP pqload::sync(TIMESTAMP t0)
00225 {
00226 TIMESTAMP result = TS_NEVER;
00227 double SysFreq = 376.991118431;
00228
00229 int i = 0;
00230
00231
00232 if(weather != NULL){
00233 if(temperature != NULL){
00234 input[0] = *gl_get_double(weather, temperature);
00235 } else {
00236 input[0] = 0.0;
00237 }
00238 if(humidity != NULL){
00239 input[1] = *gl_get_double(weather, humidity);
00240 } else {
00241 input[1] = 0.0;
00242 }
00243 if(solar != NULL){
00244 input[2] = *gl_get_double(weather, solar);
00245 } else {
00246 input[2] = 0.0;
00247 }
00248 if(wind != NULL){
00249 input[3] = *gl_get_double(weather, wind);
00250 } else {
00251 input[3] = 0.0;
00252 }
00253 if(rain != NULL){
00254 input[4] = *gl_get_double(weather, rain);
00255 } else {
00256 input[4] = 0.0;
00257 }
00258 } else {
00259 input[0] = input[1] = input[2] = input[3] = input[4] = 0.0;
00260 }
00261 input[5] = 1.0;
00262
00263 output[0] = output[1] = output[2] = output[3] = output[4] = output[5] = 0.0;
00264 for(i = 0; i < 6; ++i){
00265 output[0] += imped_p[i] * input[i];
00266 output[1] -= (imped_q[i]!=0.0) ? input[i] / (SysFreq*imped_q[i]) : 0;
00267 output[2] += current_m[i] * input[i];
00268 output[3] += current_a[i] * input[i];
00269 output[4] += power_p[i] * input[i];
00270 output[5] += power_q[i] * input[i];
00271 }
00272
00273 kZ.SetRect(output[0], output[1]);
00274 kI.SetPolar(output[2], output[3] * PI/180.0);
00275 kP.SetRect(output[4], output[5]);
00276
00277
00278
00279 constant_power[0] = constant_power[1] = constant_power[2] = kP;
00280 constant_current[0] = constant_current[1] = constant_current[2] = kI;
00281 constant_impedance[0] = constant_impedance[1] = constant_impedance[2] = kZ;
00282
00283
00284 result = load::sync(t0);
00285
00286 return result;
00287 }
00288
00289 int pqload::isa(char *classname)
00290 {
00291 return strcmp(classname,"pqload")==0 || load::isa(classname);
00292 }
00293
00295
00297
00305 EXPORT int create_pqload(OBJECT **obj, OBJECT *parent)
00306 {
00307 try
00308 {
00309 *obj = gl_create_object(pqload::oclass);
00310 if (*obj!=NULL)
00311 {
00312 pqload *my = OBJECTDATA(*obj,pqload);
00313 gl_set_parent(*obj,parent);
00314 return my->create();
00315 }
00316 }
00317 catch (const char *msg)
00318 {
00319 gl_error("create_pqload: %s", msg);
00320 }
00321 return 0;
00322 }
00323
00330 EXPORT int init_pqload(OBJECT *obj)
00331 {
00332 int result = 1;
00333 try {
00334 result = ((pqload*) (obj + 1))->init(obj->parent);
00335 } catch (const char *error) {
00336 GL_THROW("%s:%d: %s", obj->oclass->name, obj->id, error);
00337 return 0;
00338 } catch (...) {
00339 GL_THROW("%s:%d: %s", obj->oclass->name, obj->id, "unknown exception");
00340 return 0;
00341 }
00342 return result;
00343 }
00344
00353 EXPORT TIMESTAMP sync_pqload(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00354 {
00355 try {
00356 pqload *pObj = OBJECTDATA(obj,pqload);
00357 TIMESTAMP t1 = TS_NEVER;
00358 switch (pass) {
00359 case PC_PRETOPDOWN:
00360 return pObj->presync(t0);
00361 case PC_BOTTOMUP:
00362 return pObj->sync(t0);
00363 case PC_POSTTOPDOWN:
00364 t1 = pObj->postsync(t0);
00365 obj->clock = t0;
00366 return t1;
00367 default:
00368 throw "invalid pass request";
00369 }
00370 } catch (const char *error) {
00371 GL_THROW("%s (pqload:%d): %s", obj->name, obj->oclass->name, obj->id, error);
00372 return 0;
00373 } catch (...) {
00374 GL_THROW("%s (pqload:%d): %s", obj->name, obj->oclass->name, obj->id, "unknown exception");
00375 return 0;
00376 }
00377 }
00378
00379 EXPORT int isa_pqload(OBJECT *obj, char *classname)
00380 {
00381 return OBJECTDATA(obj,pqload)->isa(classname);
00382 }
00383