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