/** Water heater plc control code to set the water heater 'heat_needed' state The thermostat set point, deadband, tank state(height of hot water column) and current water temperature are used to determine 'heat_needed' state. **/ TIMESTAMP waterheater::presync(TIMESTAMP t0, TIMESTAMP t1){ /* time has passed ~ calculate internal gains, height change, temperature change */ double nHours = (gl_tohours(t1) - gl_tohours(t0))/TS_SECOND; OBJECT *my = OBJECTHDR(this); // update temperature and height update_T_and_or_h(nHours); if(Tw > 212.0){ //GL_THROW("the waterheater is boiling!"); gl_warning("waterheater:%i is boiling", my->id); /* TROUBLESHOOT The temperature model for the waterheater has broken, or the environment around the waterheater has burst into flames. Please post this with your model and dump files attached to the bug report. */ } /* determine loadshape effects */ switch(shape.type){ case MT_UNKNOWN: /* normal, undriven behavior. */ break; case MT_ANALOG: if(shape.params.analog.energy == 0.0){ GL_THROW("waterheater does not support fixed energy shaping"); /* TROUBLESHOOT Though it is possible to drive the water demand of a water heater, it is not possible to shape its power or energy draw. Its heater is either on or off, not in between. Change the load shape to not specify the power or energy and try again. */ } else if (shape.params.analog.power == 0){ /* power-driven ~ cheat with W/degF*gpm */ // double heat_per_gallon = RHOWATER * // lb/cf // CFPGAL * // lb/gal // CWATER * // BTU/degF / gal // KWBTUPH / // kW/gal // 1000.0; // W/gal water_demand = gl_get_loadshape_value(&shape) / 2.4449; } else { water_demand = gl_get_loadshape_value(&shape); /* unitless ~ drive gpm */ } break; case MT_PULSED: /* pulsed loadshapes "emit one or more pulses at random times s. t. the total energy is accumulated over the period of the loadshape". * pulsed loadshapes can either user time or kW values per pulse. */ if(shape.params.pulsed.pulsetype == MPT_TIME){ ; /* constant time pulse ~ consumes X gallons to drive heater for Y hours ~ but what's Vdot, what's t? */ } else if(shape.params.pulsed.pulsetype == MPT_POWER){ ; /* constant power pulse ~ draws water to consume X kW, limited by C + Q * h ~ Vdot proportional to power/time */ water_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; case MT_MODULATED: if(shape.params.modulated.pulsetype == MPT_TIME){ GL_THROW("Amplitude modulated water usage is nonsensical for residential water heaters"); /* TROUBLESHOOT Though it is possible to put a constant, low-level water draw on a water heater, it is thoroughly counterintuitive to the normal usage of the waterheater. */ } else if(shape.params.modulated.pulsetype == MPT_POWER){ /* frequency modulated */ /* fixed-amplitude, varying length pulses at regular intervals. */ water_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; case MT_QUEUED: if(shape.params.queued.pulsetype == MPT_TIME){ ; /* constant time pulse ~ consumes X gallons/minute to consume Y thermal energy */ } else if(shape.params.queued.pulsetype == MPT_POWER){ ; /* constant power pulse ~ draws water to consume X kW, limited by C + Q * h */ water_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; default: GL_THROW("waterheater load shape has an unknown state!"); break; } return TS_NEVER; //return residential_enduse::sync(t0,t1); }
/** oven plc control code to set the oven 'heat_needed' state The thermostat set point, deadband, oven state and current food temperature are used to determine 'heat_needed' state. **/ TIMESTAMP range::presync(TIMESTAMP t0, TIMESTAMP t1){ /* time has passed ~ calculate internal gains, height change, temperature change */ double nHours = (gl_tohours(t1) - gl_tohours(t0))/TS_SECOND; OBJECT *my = OBJECTHDR(this); // update temperature and height update_T_and_or_h(nHours); if(Tw > 212.0){ //GL_THROW("the range is boiling!"); gl_warning("range:%i is using an experimental model and should not be considered reliable", my->id); /* TROUBLESHOOT The range object has a number of VERY experimental features and development is incomplete. If you are receiving this error message, reccommend no longer using this particular feature without considerable overhaul. */ } /* determine loadshape effects */ switch(shape.type){ case MT_UNKNOWN: /* normal, undriven behavior. */ break; case MT_ANALOG: if(shape.params.analog.energy == 0.0){ GL_THROW("range does not support fixed energy shaping"); /* TROUBLESHOOT Though it is possible to drive the demand of a oven, it is not possible to shape its power or energy draw. Its heater is either on or off, not in between. Change the load shape to not specify the power or energy and try again. */ } else if (shape.params.analog.power == 0){ oven_demand = gl_get_loadshape_value(&shape) / 2.4449; } else { oven_demand = gl_get_loadshape_value(&shape); /* unitless ~ drive gpm */ } break; case MT_PULSED: /* pulsed loadshapes "emit one or more pulses at random times s. t. the total energy is accumulated over the period of the loadshape". * pulsed loadshapes can either user time or kW values per pulse. */ if(shape.params.pulsed.pulsetype == MPT_TIME){ ; /* constant time pulse ~ consumes X gallons to drive heater for Y hours ~ but what's Vdot, what's t? */ } else if(shape.params.pulsed.pulsetype == MPT_POWER){ ; /* constant power pulse ~ oven demand X kW, limited by C + Q * h ~ Vdot proportional to power/time */ oven_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; case MT_MODULATED: if(shape.params.modulated.pulsetype == MPT_TIME){ GL_THROW("Amplitude modulated oven usage is nonsensical for residential ovens"); /* TROUBLESHOOT Though it is possible to put a constant,it is thoroughly counterintuitive to the normal usage of the oven. */ } else if(shape.params.modulated.pulsetype == MPT_POWER){ /* frequency modulated */ /* fixed-amplitude, varying length pulses at regular intervals. */ oven_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; case MT_QUEUED: if(shape.params.queued.pulsetype == MPT_TIME){ ; /* constant time pulse ~ consumes X gallons/minute to consume Y thermal energy */ } else if(shape.params.queued.pulsetype == MPT_POWER){ ; /* constant power pulse ~ range demand X kW, limited by C + Q * h */ oven_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; default: GL_THROW("range load shape has an unknown state!"); break; } return TS_NEVER; //return residential_enduse::sync(t0,t1); }