00001
00021 #include <stdlib.h>
00022 #include <stdio.h>
00023 #include <errno.h>
00024 #include <math.h>
00025
00026 #include "house_a.h"
00027 #include "dryer.h"
00028
00030
00032 CLASS* dryer::oclass = NULL;
00033 CLASS* dryer::pclass = NULL;
00034 dryer *dryer::defaults = NULL;
00035
00036 dryer::dryer(MODULE *module) : residential_enduse(module)
00037 {
00038
00039 if (oclass==NULL)
00040 {
00041
00042 oclass = gl_register_class(module,"dryer",sizeof(dryer),PC_BOTTOMUP);
00043 if (oclass==NULL)
00044 GL_THROW("unable to register object class implemented by %s",__FILE__);
00045
00046
00047 if (gl_publish_variable(oclass,
00048 PT_INHERIT, "residential_enduse",
00049 PT_double,"motor_power[W]",PADDR(motor_power),
00050 PT_double,"coil_power[W]",PADDR(coil_power),
00051 PT_double,"circuit_split",PADDR(circuit_split),
00052 PT_double,"demand[unit/day]",PADDR(enduse_demand), PT_DESCRIPTION, "number of loads accumulating daily",
00053 PT_double,"queue[unit]",PADDR(enduse_queue), PT_DESCRIPTION, "number of loads accumulated",
00054 PT_double,"stall_voltage[V]", PADDR(stall_voltage),
00055 PT_double,"start_voltage[V]", PADDR(start_voltage),
00056 PT_complex,"stall_impedance[Ohm]", PADDR(stall_impedance),
00057 PT_double,"trip_delay[s]", PADDR(trip_delay),
00058 PT_double,"reset_delay[s]", PADDR(reset_delay),
00059 PT_enumeration,"state", PADDR(state),
00060 PT_KEYWORD,"STOPPED",STOPPED,
00061 PT_KEYWORD,"RUNNING",RUNNING,
00062 PT_KEYWORD,"STALLED",STALLED,
00063 PT_KEYWORD,"TRIPPED",TRIPPED,
00064 NULL)<1)
00065 GL_THROW("unable to publish properties in %s",__FILE__);
00066 }
00067 }
00068
00069 dryer::~dryer()
00070 {
00071 }
00072
00073 int dryer::create()
00074 {
00075 int res = residential_enduse::create();
00076
00077
00078 load.name = oclass->name;
00079
00080 load.power = load.admittance = load.current = load.total = complex(0,0,J);
00081 load.voltage_factor = 1.0;
00082 load.power_factor = 0.95;
00083 load.power_fraction = 1.0;
00084
00085 gl_warning("explicit %s model is experimental", OBJECTHDR(this)->oclass->name);
00086
00087 return res;
00088 }
00089
00090 int dryer::init(OBJECT *parent)
00091 {
00092 int rv = 0;
00093
00094 if (motor_power==0) motor_power = gl_random_uniform(150,350);
00095 if (heat_fraction==0) heat_fraction = 0.2;
00096 if (stall_voltage==0) stall_voltage = 0.6*120;
00097 if (trip_delay==0) trip_delay = 10;
00098 if (reset_delay==0) reset_delay = 60;
00099 if (coil_power==-1) coil_power = gl_random_uniform(3500,5000);
00100
00101 OBJECT *hdr = OBJECTHDR(this);
00102 hdr->flags |= OF_SKIPSAFE;
00103
00104 load.power_factor = 0.95;
00105 load.breaker_amps = 30;
00106
00107
00108 rv = residential_enduse::init(parent);
00109
00110
00111 if (rv==SUCCESS) update_state();
00112
00113 return rv;
00114 }
00115
00116 int dryer::isa(char *classname)
00117 {
00118 return (strcmp(classname,"dryer")==0 || residential_enduse::isa(classname));
00119 }
00120
00121
00122 TIMESTAMP dryer::sync(TIMESTAMP t0, TIMESTAMP t1)
00123 {
00124
00125 double dt = gl_toseconds(t0>0?t1-t0:0);
00126
00127
00128 if (t0>TS_ZERO && t1>t0)
00129 {
00130
00131 load.energy += load.total * dt/3600.0;
00132 }
00133
00134
00135 dt = update_state(dt);
00136
00137 return dt>0?-(TIMESTAMP)(dt*TS_SECOND+t1):TS_NEVER;
00138 }
00139
00140 double dryer::update_state(double dt)
00141 {
00142
00143 switch(state) {
00144 case STOPPED:
00145 if (enduse_queue>1)
00146 {
00147 state = RUNNING;
00148 enduse_queue--;
00149 cycle_time = cycle_duration>0 ? cycle_duration : gl_random_uniform(20,40)*60;
00150 state_time = 0;
00151 }
00152 break;
00153 case RUNNING:
00154 if (cycle_time<=0)
00155 {
00156 state = STOPPED;
00157 cycle_time = state_time = 0;
00158 }
00159 else if (pCircuit->pV->Mag()<stall_voltage)
00160 {
00161 state = STALLED;
00162 state_time = 0;
00163 }
00164 break;
00165 case STALLED:
00166 if (pCircuit->pV->Mag()>start_voltage)
00167 {
00168 state = RUNNING;
00169 state_time = cycle_time;
00170 }
00171 else if (state_time>trip_delay)
00172 {
00173 state = TRIPPED;
00174 state_time = 0;
00175 }
00176 break;
00177 case TRIPPED:
00178 if (state_time>reset_delay)
00179 {
00180 if (pCircuit->pV->Mag()>start_voltage)
00181 state = RUNNING;
00182 else
00183 state = STALLED;
00184 state_time = 0;
00185 }
00186 break;
00187 }
00188
00189
00190 state_time += dt;
00191
00192
00193 enduse_queue += enduse_demand * dt/3600/24;
00194
00195
00196 switch(state) {
00197 case STOPPED:
00198
00199
00200 load.power = load.current = load.admittance = complex(0,0,J);
00201
00202
00203 dt = (enduse_demand<=0) ? -1 : dt = 3600/enduse_demand;
00204
00205 break;
00206
00207 case RUNNING:
00208
00209
00210 cycle_time -= dt;
00211
00212
00213 load.power.SetPowerFactor(motor_power/1000, load.power_factor);
00214 load.admittance = complex(0,0,J);
00215 load.current = complex(0,0,J);
00216
00217
00218 dt = cycle_time>300?300:cycle_time;
00219
00220 break;
00221 case STALLED:
00222
00223
00224 load.power = load.current = complex(0,0,J);
00225 load.admittance = complex(1)/stall_impedance;
00226
00227
00228 dt = trip_delay;
00229
00230 break;
00231 case TRIPPED:
00232
00233
00234 load.power = load.current = load.admittance = complex(0,0,J);
00235
00236
00237 dt = reset_delay;
00238
00239 break;
00240 default:
00241 throw "unexpected motor state";
00242
00243
00244
00245
00246 break;
00247 }
00248
00249
00250 load.total = load.power + ~(load.current + load.admittance**pCircuit->pV)**pCircuit->pV/1000;
00251
00252
00253 load.heatgain = load.total.Mag() * heat_fraction;
00254
00255 return dt;
00256 }
00257
00259
00261
00262 EXPORT int create_dryer(OBJECT **obj, OBJECT *parent)
00263 {
00264 *obj = gl_create_object(dryer::oclass);
00265 if (*obj!=NULL)
00266 {
00267 dryer *my = OBJECTDATA(*obj,dryer);
00268 gl_set_parent(*obj,parent);
00269 my->create();
00270 return 1;
00271 }
00272 return 0;
00273 }
00274
00275 EXPORT int init_dryer(OBJECT *obj)
00276 {
00277 dryer *my = OBJECTDATA(obj,dryer);
00278 return my->init(obj->parent);
00279 }
00280
00281 EXPORT int isa_dryer(OBJECT *obj, char *classname)
00282 {
00283 if(obj != 0 && classname != 0){
00284 return OBJECTDATA(obj,dryer)->isa(classname);
00285 } else {
00286 return 0;
00287 }
00288 }
00289
00290 EXPORT TIMESTAMP sync_dryer(OBJECT *obj, TIMESTAMP t0)
00291 {
00292 dryer *my = OBJECTDATA(obj, dryer);
00293 TIMESTAMP t1 = my->sync(obj->clock, t0);
00294 obj->clock = t0;
00295 return t1;
00296 }
00297