00001
00052 #include <stdlib.h>
00053 #include <stdio.h>
00054 #include <errno.h>
00055 #include <math.h>
00056
00057 #include "house_a.h"
00058 #include "freezer.h"
00059
00061
00063 CLASS* freezer::oclass = NULL;
00064 CLASS* freezer::pclass = NULL;
00065
00066
00067
00068 freezer::freezer(MODULE *module) : residential_enduse(module)
00069 {
00070
00071 if (oclass == NULL)
00072 {
00073 oclass = gl_register_class(module,"freezer",sizeof(freezer),PC_PRETOPDOWN | PC_BOTTOMUP);
00074 if (oclass==NULL)
00075 GL_THROW("unable to register object class implemented by %s",__FILE__);
00076
00077
00078 if (gl_publish_variable(oclass,
00079 PT_INHERIT, "residential_enduse",
00080 PT_double, "size[cf]", PADDR(size),
00081 PT_double, "rated_capacity[Btu/h]", PADDR(rated_capacity),
00082 PT_double,"temperature[degF]",PADDR(Tair),
00083 PT_double,"setpoint[degF]",PADDR(Tset),
00084 PT_double,"deadband[degF]",PADDR(thermostat_deadband),
00085 PT_timestamp,"next_time",PADDR(last_time),
00086 PT_double,"output",PADDR(Qr),
00087 PT_double,"event_temp",PADDR(Tevent),
00088 PT_double,"UA[Btu.h/degF]",PADDR(UA),
00089 PT_enumeration,"state",PADDR(motor_state),
00090 PT_KEYWORD,"OFF",S_OFF,
00091 PT_KEYWORD,"ON",S_ON,
00092 NULL) < 1)
00093 GL_THROW("unable to publish properties in %s", __FILE__);
00094 }
00095 }
00096
00097 freezer::~freezer()
00098 {
00099 }
00100
00101 int freezer::create()
00102 {
00103 int res = residential_enduse::create();
00104
00105
00106 load.name = oclass->name;
00107
00108 gl_warning("explicit %s model is experimental", OBJECTHDR(this)->oclass->name);
00109
00110 return res;
00111 }
00112
00113 int freezer::init(OBJECT *parent)
00114 {
00115
00116 if (size==0) size = gl_random_uniform(20,40);
00117 if (thermostat_deadband==0) thermostat_deadband = gl_random_uniform(2,3);
00118 if (Tset==0) Tset = gl_random_uniform(10,20);
00119 if (UA == 0) UA = 0.3;
00120 if (UAr==0) UAr = UA+size/40*gl_random_uniform(0.9,1.1);
00121 if (UAf==0) UAf = gl_random_uniform(0.9,1.1);
00122 if (COPcoef==0) COPcoef = gl_random_uniform(0.9,1.1);
00123 if (Tout==0) Tout = 59.0;
00124 if (power_factor==0) power_factor = 0.95;
00125
00126 OBJECT *hdr = OBJECTHDR(this);
00127 hdr->flags |= OF_SKIPSAFE;
00128
00129
00130 pTempProp = gl_get_property(parent, "air_temperature");
00131 if(pTempProp == NULL){
00132 GL_THROW("Parent house of freezer lacks property \'air_temperature\'");
00133 }
00134
00135
00136 Tair = gl_random_uniform(Tset-thermostat_deadband/2, Tset+thermostat_deadband/2);
00137
00138
00139
00140 Cf = size/10.0 * RHOWATER * CWATER;
00141
00142 rated_capacity = BTUPHPW * size*10;
00143
00144
00145 if (gl_random_bernoulli(0.04)){
00146 Qr = rated_capacity;
00147 } else {
00148 Qr = 0;
00149 }
00150
00151
00152 load.total = Qr * KWPBTUPH;
00153
00154 return residential_enduse::init(parent);
00155 }
00156
00157 int freezer::isa(char *classname)
00158 {
00159 return (strcmp(classname,"freezer")==0 || residential_enduse::isa(classname));
00160 }
00161
00162 TIMESTAMP freezer::presync(TIMESTAMP t0, TIMESTAMP t1){
00163 OBJECT *hdr = OBJECTHDR(this);
00164 double *pTout = 0, t = 0.0, dt = 0.0;
00165 double nHours = (gl_tohours(t1)- gl_tohours(t0))/TS_SECOND;
00166
00167 pTout = gl_get_double(hdr->parent, pTempProp);
00168 if(pTout == NULL){
00169 GL_THROW("Parent house of freezer lacks property \'air_temperature\' at sync time?");
00170 }
00171 Tout = *pTout;
00172
00173 if(nHours > 0 && t0 > 0){
00174 const double COP = COPcoef*((-3.5/45)*(Tout-70)+4.5);
00175
00176 if(t1 == next_time){
00177
00178 load.heatgain = -((Tair - Tout) * exp(-(UAr+UAf)/Cf) + Tout - Tair) * Cf * nHours + Qr * nHours * COP;
00179 Tair = Tevent;
00180 } else {
00181
00182 const double C1 = Cf/(UAr+UAf);
00183 const double C2 = Tout - Qr/UAr;
00184 load.heatgain = -((Tair - Tout) * exp(-(UAr+UAf)/Cf) + Tout - Tair) * Cf * nHours + Qr * nHours * COP;
00185 Tair = (Tair-C2)*exp(-nHours/C1)+C2;
00186 }
00187 if (Tair < 0 || Tair > 32){
00188 gl_warning("freezer air temperature out of control");
00189
00190 }
00191 last_time = t1;
00192 }
00193
00194 return TS_NEVER;
00195 }
00196
00197
00198
00199
00200 void freezer::thermostat(TIMESTAMP t0, TIMESTAMP t1){
00201 const double Ton = Tset+thermostat_deadband / 2;
00202 const double Toff = Tset-thermostat_deadband / 2;
00203
00204
00205 if(motor_state == S_OFF){
00206
00207 if(Tair >= Ton){
00208 motor_state = S_ON;
00209 Tevent = Toff;
00210 } else {
00211 Tevent = Ton;
00212 }
00213 } else if(motor_state == S_ON){
00214
00215 if(Tair <= Toff){
00216 motor_state = S_OFF;
00217 Tevent = Ton;
00218 } else {
00219 Tevent = Toff;
00220 }
00221 }
00222 }
00223
00224 TIMESTAMP freezer::sync(TIMESTAMP t0, TIMESTAMP t1)
00225 {
00226 double nHours = (gl_tohours(t1)- gl_tohours(t0))/TS_SECOND;
00227 double t = 0.0, dt = 0.0;
00228
00229 const double COP = COPcoef*((-3.5/45)*(Tout-70)+4.5);
00230
00231
00232 load.energy += load.total * nHours;
00233
00234
00235 if(motor_state == S_ON){
00236 Qr = rated_capacity;
00237 } else if(motor_state == S_OFF){
00238 Qr = 0;
00239 } else{
00240 throw "freezer motor state is ambiguous";
00241 }
00242
00243 load.total = Qr * KWPBTUPH * COP;
00244
00245 if(pCircuit->pV->Mag() < (120.0 * 0.6) ){
00246 gl_verbose("freezer motor has stalled");
00247 motor_state = S_OFF;
00248 Qr = 0;
00249 return TS_NEVER;
00250 }
00251
00252
00253 const double C1 = Cf/(UAr+UAf);
00254 const double C2 = Tout - Qr/UAr;
00255
00256
00257 dt = t = -log((Tevent - C2)/(Tair-C2))*C1;
00258
00259 if(t == 0){
00260 GL_THROW("freezer control logic error, dt = 0");
00261 } else if(t < 0){
00262 GL_THROW("freezer control logic error, dt < 0");
00263 }
00264
00265
00266 next_time = (TIMESTAMP)(t1 + (t > 0 ? t : -t) * (3600.0/TS_SECOND) + 1);
00267 return next_time > TS_NEVER ? TS_NEVER : -next_time;
00268 }
00269
00270 TIMESTAMP freezer::postsync(TIMESTAMP t0, TIMESTAMP t1){
00271 return TS_NEVER;
00272 }
00273
00274
00276
00278 EXPORT int create_freezer(OBJECT **obj, OBJECT *parent)
00279 {
00280 *obj = gl_create_object(freezer::oclass);
00281 if (*obj!=NULL)
00282 {
00283 freezer *my = OBJECTDATA(*obj,freezer);;
00284 gl_set_parent(*obj,parent);
00285 my->create();
00286 return 1;
00287 }
00288 return 0;
00289 }
00290
00291 EXPORT TIMESTAMP sync_freezer(OBJECT *obj, TIMESTAMP t0, PASSCONFIG pass)
00292 {
00293 freezer *my = OBJECTDATA(obj,freezer);
00294 TIMESTAMP t1 = TS_NEVER;
00295
00296
00297
00298 try {
00299 switch (pass)
00300 {
00301 case PC_PRETOPDOWN:
00302 t1 = my->presync(obj->clock, t0);
00303 break;
00304
00305 case PC_BOTTOMUP:
00306 t1 = my->sync(obj->clock, t0);
00307 obj->clock = t0;
00308 break;
00309
00310 case PC_POSTTOPDOWN:
00311 t1 = my->postsync(obj->clock, t0);
00312 break;
00313
00314 default:
00315 gl_error("freezer::sync- invalid pass configuration");
00316 t1 = TS_INVALID;
00317 }
00318 }
00319 catch (char *msg)
00320 {
00321 gl_error("freezer::sync exception caught: %s", msg);
00322 t1 = TS_INVALID;
00323 }
00324 catch (...)
00325 {
00326 gl_error("freezer::sync exception caught: no info");
00327 t1 = TS_INVALID;
00328 }
00329 return t1;
00330 }
00331
00332 EXPORT int init_freezer(OBJECT *obj)
00333 {
00334 freezer *my = OBJECTDATA(obj,freezer);
00335 return my->init(obj->parent);
00336 }
00337
00338 EXPORT int isa_freezer(OBJECT *obj, char *classname)
00339 {
00340 if(obj != 0 && classname != 0){
00341 return OBJECTDATA(obj,freezer)->isa(classname);
00342 } else {
00343 return 0;
00344 }
00345 }
00346
00347
00348 EXPORT TIMESTAMP plc_freezer(OBJECT *obj, TIMESTAMP t0)
00349 {
00350
00351
00352 freezer *my = OBJECTDATA(obj,freezer);
00353 my->thermostat(obj->clock, t0);
00354
00355 return TS_NEVER;
00356 }
00357