00001
00012 #include <stdlib.h>
00013 #include <stdio.h>
00014 #include <errno.h>
00015 #include <math.h>
00016
00017 #include "pqload.h"
00018
00019 SCHED_LIST *new_slist(){
00020 SCHED_LIST *l = (SCHED_LIST *)gl_malloc(sizeof(SCHED_LIST));
00021 memset(l, 0, sizeof(SCHED_LIST));
00022 return l;
00023 }
00024
00025 int delete_slist(SCHED_LIST *l){
00026 int rv = 0;
00027 if(l == NULL){
00028 return -1;
00029 }
00030 if(l->next != NULL){
00031 rv = delete_slist(l->next);
00032 }
00033 gl_free(l);
00034 return rv;
00035 }
00036
00037 CLASS *pqload::oclass = NULL;
00038 CLASS *pqload::pclass = NULL;
00039 pqload *pqload::defaults = NULL;
00040 double pqload::zero_F = -459.67;
00041
00042 pqload::pqload(MODULE *mod) : load(mod)
00043 {
00044 if(oclass == NULL){
00045 pclass = load::oclass;
00046
00047 oclass = gl_register_class(mod, "pqload", sizeof(pqload), PC_PRETOPDOWN | PC_BOTTOMUP | PC_POSTTOPDOWN | PC_UNSAFE_OVERRIDE_OMIT|PC_AUTOLOCK);
00048 if (oclass==NULL)
00049 throw "unable to register class pqload";
00050 else
00051 oclass->trl = TRL_PROTOTYPE;
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
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.get_string();
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 char moh_v[257], moh_w[257], hod_v[257], hod_w[257], dom_v[257], dom_w[257], moy_v[257], moy_w[257], dow_v[257], lpu[257], sc[257];
00150 scanct = sscanf(start, "%256[-0-9*]%256[ \t]%256[-0-9*]%256[ \t]%256[-0-9*]%256[ \t]%256[-0-9*]%256[ \t]%256[-0-9*]:%256[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
00178 static FINDLIST *climates = NULL;
00179 OBJECT *hdr = OBJECTHDR(this);
00180 int not_found = 0;
00181 if (climates==NULL && not_found==0)
00182 {
00183 climates = gl_find_objects(FL_NEW,FT_CLASS,SAME,"climate",FT_END);
00184 if (climates==NULL)
00185 {
00186 not_found = 1;
00187 gl_warning("pqload: no climate data found");
00188 }
00189 else if (climates->hit_count>1)
00190 {
00191 gl_warning("pqload: %d climates found, using first one defined", climates->hit_count);
00192 }
00193 }
00194 if (climates!=NULL)
00195 {
00196 if (climates->hit_count==0)
00197 {
00198
00199 }
00200 else
00201 {
00202
00203 OBJECT *obj = gl_find_next(climates,NULL);
00204 if(weather == NULL){
00205 weather = NULL;
00206 } else {
00207 if (obj->rank<=hdr->rank)
00208 gl_set_dependent(obj,hdr);
00209 weather = obj;
00210 }
00211 }
00212 }
00213
00214
00215 if(weather != NULL){
00216 temperature = gl_get_property(weather, "temperature");
00217 if(temperature == NULL){
00218 gl_error("Unable to find temperature property in weather object!");
00219 ++w_rv;
00220 }
00221
00222 humidity = gl_get_property(weather, "humidity");
00223 if(humidity == NULL){
00224 gl_error("Unable to find humidity property in weather object!");
00225 ++w_rv;
00226 }
00227
00228 solar = gl_get_property(weather, "solar_flux");
00229 if(solar == NULL){
00230 gl_error("Unable to find solar_flux property in weather object!");
00231 ++w_rv;
00232 }
00233
00234 wind = gl_get_property(weather, "wind_speed");
00235 if(wind == NULL){
00236 gl_error("Unable to find wind_speed property in weather object!");
00237 ++w_rv;
00238 }
00239
00240 rain = gl_get_property(weather, "rainfall");
00241 if(rain == NULL){
00242 gl_error("Unable to find rainfall property in weather object!");
00243
00244 }
00245 }
00246
00247 rv = load::init(parent);
00248
00249 return w_rv ? 0 : rv;
00250 }
00251
00252 TIMESTAMP pqload::presync(TIMESTAMP t0)
00253 {
00254 TIMESTAMP result = 0;
00255
00256
00257 result = load::presync(t0);
00258
00259 return result;
00260 }
00261
00262 TIMESTAMP pqload::sync(TIMESTAMP t0)
00263 {
00264 TIMESTAMP result = TS_NEVER;
00265 double SysFreq = 376.991118431;
00266
00267 int i = 0;
00268
00269
00270 if(weather != NULL){
00271 if(temperature != NULL){
00272 input[0] = *gl_get_double(weather, temperature);
00273 } else {
00274 input[0] = 0.0;
00275 }
00276 if(humidity != NULL){
00277 input[1] = *gl_get_double(weather, humidity);
00278 } else {
00279 input[1] = 0.0;
00280 }
00281 if(solar != NULL){
00282 input[2] = *gl_get_double(weather, solar);
00283 } else {
00284 input[2] = 0.0;
00285 }
00286 if(wind != NULL){
00287 input[3] = *gl_get_double(weather, wind);
00288 } else {
00289 input[3] = 0.0;
00290 }
00291 if(rain != NULL){
00292 input[4] = *gl_get_double(weather, rain);
00293 } else {
00294 input[4] = 0.0;
00295 }
00296 } else {
00297 input[0] = input[1] = input[2] = input[3] = input[4] = 0.0;
00298 }
00299 input[5] = 1.0;
00300
00301 output[0] = output[1] = output[2] = output[3] = output[4] = output[5] = 0.0;
00302 for(i = 0; i < 6; ++i){
00303 output[0] += imped_p[i] * input[i];
00304 output[1] += input[i] * imped_q[i];
00305 output[2] += current_m[i] * input[i];
00306 output[3] += current_a[i] * input[i];
00307 output[4] += power_p[i] * input[i];
00308 output[5] += power_q[i] * input[i];
00309 }
00310
00311 kZ.SetRect(output[0], output[1]);
00312 kI.SetPolar(output[2], output[3] * PI/180.0);
00313 kP.SetRect(output[4], output[5]);
00314
00315
00316
00317 constant_power[0] = constant_power[1] = constant_power[2] = kP;
00318
00319
00320 for(i = 0; i < 3; ++i){
00321 double v_angle = voltage[i].Arg();
00322 constant_current[i].SetPolar(output[2], output[3] * PI/180.0 + v_angle);
00323 }
00324
00325 if (kZ != 0.0)
00326 constant_impedance[0] = constant_impedance[1] = constant_impedance[2] = kZ;
00327
00328
00329 result = load::sync(t0);
00330
00331 return result;
00332 }
00333
00334 int pqload::isa(char *classname)
00335 {
00336 return strcmp(classname,"pqload")==0 || load::isa(classname);
00337 }
00338
00340
00342
00350 EXPORT int create_pqload(OBJECT **obj, OBJECT *parent)
00351 {
00352 try
00353 {
00354 *obj = gl_create_object(pqload::oclass);
00355 if (*obj!=NULL)
00356 {
00357 pqload *my = OBJECTDATA(*obj,pqload);
00358 gl_set_parent(*obj,parent);
00359 return my->create();
00360 }
00361 else
00362 return 0;
00363 }
00364 CREATE_CATCHALL(pqload);
00365 }
00366
00373 EXPORT int init_pqload(OBJECT *obj)
00374 {
00375 try {
00376 pqload *my = OBJECTDATA(obj,pqload);
00377 return my->init(obj->parent);
00378 }
00379 INIT_CATCHALL(pqload);
00380 }
00381
00390 EXPORT TIMESTAMP sync_pqload(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00391 {
00392 try {
00393 pqload *pObj = OBJECTDATA(obj,pqload);
00394 TIMESTAMP t1 = TS_NEVER;
00395 switch (pass) {
00396 case PC_PRETOPDOWN:
00397 return pObj->presync(t0);
00398 case PC_BOTTOMUP:
00399 return pObj->sync(t0);
00400 case PC_POSTTOPDOWN:
00401 t1 = pObj->postsync(t0);
00402 obj->clock = t0;
00403 return t1;
00404 default:
00405 throw "invalid pass request";
00406 }
00407 }
00408 SYNC_CATCHALL(pqload);
00409 }
00410
00411 EXPORT int isa_pqload(OBJECT *obj, char *classname)
00412 {
00413 return OBJECTDATA(obj,pqload)->isa(classname);
00414 }
00415