void range::thermostat(TIMESTAMP t0, TIMESTAMP t1){ Ton = oven_setpoint - thermostat_deadband/2; Toff = oven_setpoint + thermostat_deadband/2; OBJECT *hdr = OBJECTHDR(this); switch(range_state()){ case FULL: if (enduse_queue_oven>1)// && dryer_on == true) { oven_run_prob = double(gl_random_uniform(&hdr->rng_state,queue_min,queue_max)); if(Tw-TSTAT_PRECISION < Ton && (oven_run_prob > enduse_queue_oven || oven_run_prob >1 ) && (time_oven_operation <time_oven_setting)) { heat_needed = TRUE; oven_check = true; remainon = true; if (time_oven_operation == 0) enduse_queue_oven --; } } if (Tw+TSTAT_PRECISION > Toff || (time_oven_operation >= time_oven_setting)) { heat_needed = FALSE; oven_check = false; } if (Tw-TSTAT_PRECISION < Ton && (time_oven_operation <time_oven_setting) && remainon == true) { heat_needed = TRUE; oven_check = true; } if (time_oven_operation >= time_oven_setting) { remainon = false; time_oven_operation = 0; } else { ; // no change } break; case PARTIAL: case EMPTY: heat_needed = TRUE; // if we aren't full, fill 'er up! break; default: GL_THROW("range thermostat() detected that the oven is in an unknown state"); } //return TS_NEVER; // this thermostat is purely reactive and will never drive the system }
int passive_controller::calc_proboff(TIMESTAMP t0, TIMESTAMP t1){ if(observation_addr == 0 || expectation_addr == 0 || observation_stdev_addr == 0){ GL_THROW("insufficient input for probabilistic shutoff control mode"); return -1; } double erf_in, erf_out; double cdf_out; double r; extern double bid_offset; switch(distribution_type){ case PDT_NORMAL: // N is the cumulative normal distribution // k_w is a comfort setting // r is compared to a uniformly random number on [0,1.0) // erf_in = (x-mean) / (var^2 * sqrt(2)) if(obs_stdev < bid_offset){ // short circuit if(observation > expectation){ output_state = -1; prob_off = 1.0; } else { output_state = 0; prob_off = 0.0; } return 0; } erf_in = (observation - expectation) / (obs_stdev*obs_stdev * sqrt(2.0)); erf_out = tc_erf(erf_in); cdf_out = 0.5 * (1 + erf_out); prob_off = comfort_level * (cdf_out-0.5); break; case PDT_EXPONENTIAL: prob_off = comfort_level * (1 - exp(-observation/expectation)); break; case PDT_UNIFORM: prob_off = comfort_level * (observation - expectation) / expectation; break; default: gl_error(""); } if(prob_off < 0 || !isfinite(prob_off)){ prob_off = 0.0; } r = gl_random_uniform(RNGSTATE,0.0,1.0); if(r < prob_off){ output_state = -1; // off? } else { output_state = 0; //Normal } return 0; }
TIMESTAMP refrigerator::presync(TIMESTAMP t0, TIMESTAMP t1){ OBJECT *hdr = OBJECTHDR(this); if(start_time==0) { start_time = int32(t0); DO_random_opening = int32(gl_random_uniform(&hdr->rng_state,0,1800)); } return TS_NEVER; }
int plugload::create() { int res = residential_enduse::create(); // name of enduse load.name = oclass->name; load.power = load.admittance = load.current = load.total = complex(0,0,J); load.power_fraction = load.current_fraction = load.impedance_fraction = 0; load.heatgain_fraction = 0.90; load.power_factor = 0.90; //load.power_fraction = 1.0; load.voltage_factor = 1.0; // assume 'even' voltage, initially shape.load = gl_random_uniform(RNGSTATE,0, 0.1); return res; }
int microwave::create() { int res = residential_enduse::create(); // name of enduse load.name = oclass->name; load.power = load.admittance = load.current = load.total = complex(0,0,J); load.heatgain_fraction = 0.25; load.power_factor = 0.95; standby_power = 0.01; shape.load = gl_random_uniform(RNGSTATE,0, 0.1); // assuming a default maximum 10% of the sync time gl_warning("explicit %s model is experimental", OBJECTHDR(this)->oclass->name); return res; }
// periodically activates for the tail demand % of a cycle_time period. Has a random offset to prevent // lock-step behavior across uniform devices // start ....... on .. off TIMESTAMP microwave::update_state_cycle(TIMESTAMP t0, TIMESTAMP t1){ double ti0 = (double)t0, ti1 = (double)t1; if(shape.load == 0){ state = OFF; cycle_start = 0; return TS_NEVER; } if(shape.load == 1){ state = ON; cycle_start = 0; return TS_NEVER; } if(cycle_start == 0){ double off = gl_random_uniform(RNGSTATE,0, this->cycle_time); cycle_start = (TIMESTAMP)(ti1 + off); cycle_on = (TIMESTAMP)((1 - shape.load) * cycle_time) + cycle_start; cycle_off = (TIMESTAMP)cycle_time + cycle_start; state = OFF; return (TIMESTAMP)cycle_on; } if(t0 == cycle_on){ state = ON; } if(t0 == cycle_off){ state = OFF; cycle_start = cycle_off; } if(t0 == cycle_start){ cycle_on = (TIMESTAMP)((1 - shape.load) * cycle_time) + cycle_start; state = OFF; cycle_off = (TIMESTAMP)cycle_time + cycle_start; } if(state == ON) return (TIMESTAMP)cycle_off; if(state == OFF) return (TIMESTAMP)cycle_on; return TS_NEVER; // from ambiguous state }
int refrigerator::init(OBJECT *parent) { OBJECT *hdr = OBJECTHDR(this); hdr->flags |= OF_SKIPSAFE; // defaults for unset values */ if (size==0) size = gl_random_uniform(RNGSTATE,20,40); // cf if (thermostat_deadband==0) thermostat_deadband = gl_random_uniform(RNGSTATE,2,3); if (Tset==0) Tset = gl_random_uniform(RNGSTATE,35,39); if (UA == 0) UA = 0.6; if (UAr==0) UAr = UA+size/40*gl_random_uniform(RNGSTATE,0.9,1.1); if (UAf==0) UAf = gl_random_uniform(RNGSTATE,0.9,1.1); if (COPcoef==0) COPcoef = gl_random_uniform(RNGSTATE,0.9,1.1); if (Tout==0) Tout = 59.0; if (load.power_factor==0) load.power_factor = 0.95; pTout = (double*)gl_get_addr(parent, "air_temperature"); if (pTout==NULL) { static double default_air_temperature = 72; gl_warning("%s (%s:%d) parent object lacks air temperature, using %0f degF instead", hdr->name, hdr->oclass->name, hdr->id, default_air_temperature); pTout = &default_air_temperature; } /* derived values */ Tair = gl_random_uniform(RNGSTATE,Tset-thermostat_deadband/2, Tset+thermostat_deadband/2); // size is used to couple Cw and Qrated Cf = size/10.0 * RHOWATER * CWATER; // cf * lb/cf * BTU/lb/degF = BTU / degF rated_capacity = BTUPHPW * size*10; // BTU/h ... 10 BTU.h / cf (34W/cf, so ~700 for a full-sized refrigerator) // duty cycle estimate for initial condition if (gl_random_bernoulli(RNGSTATE,0.1)){ Qr = rated_capacity; } else { Qr = 0; } // initial demand load.total = Qr * KWPBTUPH; return residential_enduse::init(parent); }
int dishwasher::init(OBJECT *parent) { // default properties if(shape.params.analog.power == 0){ shape.params.analog.power = gl_random_uniform(1000, 3000); // dishwasher size [W] } if(load.heatgain_fraction == 0){ load.heatgain_fraction = 0.50; //Assuming 50% of the power is transformed to internal heat } if(load.power_factor == 0){ load.power_factor = 0.95; } OBJECT *hdr = OBJECTHDR(this); hdr->flags |= OF_SKIPSAFE; /* handle schedules */ switch(shape.type){ case MT_UNKNOWN: break; case MT_ANALOG: break; case MT_PULSED: break; case MT_MODULATED: break; case MT_QUEUED: break; default: char name[64]; if(hdr->name == 0){ sprintf(name, "%s:%s", hdr->oclass->name, hdr->id); } gl_error("dishwasher %s schedule of an unrecognized type", hdr->name ? hdr->name : name); } return residential_enduse::init(parent); }
int clotheswasher::init(OBJECT *parent) { OBJECT *hdr = OBJECTHDR(this); if(parent != NULL){ if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("clotheswasher::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } } hdr->flags |= OF_SKIPSAFE; // default properties if (shape.params.analog.power==0) shape.params.analog.power = gl_random_uniform(&hdr->rng_state,0.100,0.750); // clotheswasher size [W] if (load.heatgain_fraction==0) load.heatgain_fraction = 0.5; if (load.power_factor==0) load.power_factor = 0.95; if(shape.params.analog.power < 0.1){ gl_error("clotheswasher motor is undersized, using 500W motor"); shape.params.analog.power = 0.5; } int res = residential_enduse::init(parent); Is_on = 0; if(NORMAL_PREWASH_ENERGY == 0) NORMAL_PREWASH_ENERGY = 12*20*60; if(NORMAL_WASH_ENERGY == 0) NORMAL_WASH_ENERGY = 4*40*60; if(NORMAL_SMALLWASH_ENERGY == 0) NORMAL_SMALLWASH_ENERGY = 2*25*60; if(NORMAL_SPIN_LOW_ENERGY == 0) NORMAL_SPIN_LOW_ENERGY = 2*60*60; if(NORMAL_SPIN_MEDIUM_ENERGY == 0) NORMAL_SPIN_MEDIUM_ENERGY = 2*150*60; if(NORMAL_SPIN_HIGH_ENERGY == 0) NORMAL_SPIN_HIGH_ENERGY = 2*220*60; if(NORMAL_PREWASH_POWER == 0) NORMAL_PREWASH_POWER = 20; if(NORMAL_WASH_POWER == 0) NORMAL_WASH_POWER = 40; if(NORMAL_SMALLWASH_POWER == 0) NORMAL_SMALLWASH_POWER = 25; if(NORMAL_SPIN_LOW_POWER == 0) NORMAL_SPIN_LOW_POWER = 60; if(NORMAL_SPIN_MEDIUM_POWER == 0) NORMAL_SPIN_MEDIUM_POWER = 150; if(NORMAL_SPIN_HIGH_POWER == 0) NORMAL_SPIN_HIGH_POWER = 220; if(PERMPRESS_PREWASH_ENERGY == 0) PERMPRESS_PREWASH_ENERGY = 12*20*60; if(PERMPRESS_WASH_ENERGY == 0) PERMPRESS_WASH_ENERGY = 4*40*60; if(PERMPRESS_SMALLWASH_ENERGY == 0) PERMPRESS_SMALLWASH_ENERGY = 2*25*60; if(PERMPRESS_SPIN_LOW_ENERGY == 0) PERMPRESS_SPIN_LOW_ENERGY = 2*60*60; if(PERMPRESS_SPIN_MEDIUM_ENERGY == 0) PERMPRESS_SPIN_MEDIUM_ENERGY = 2*150*60; if(PERMPRESS_SPIN_HIGH_ENERGY == 0) PERMPRESS_SPIN_HIGH_ENERGY = 2*220*60; if(PERMPRESS_PREWASH_POWER == 0) PERMPRESS_PREWASH_POWER = 20; if(PERMPRESS_WASH_POWER == 0) PERMPRESS_WASH_POWER = 40; if(PERMPRESS_SMALLWASH_POWER == 0) PERMPRESS_SMALLWASH_POWER = 25; if(PERMPRESS_SPIN_LOW_POWER == 0) PERMPRESS_SPIN_LOW_POWER = 60; if(PERMPRESS_SPIN_MEDIUM_POWER == 0) PERMPRESS_SPIN_MEDIUM_POWER = 150; if(PERMPRESS_SPIN_HIGH_POWER == 0) PERMPRESS_SPIN_HIGH_POWER = 220; if(GENTLE_PREWASH_ENERGY == 0) GENTLE_PREWASH_ENERGY = 12*20*60; if(GENTLE_WASH_ENERGY == 0) GENTLE_WASH_ENERGY = 4*40*60; if(GENTLE_SMALLWASH_ENERGY == 0) GENTLE_SMALLWASH_ENERGY = 2*25*60; if(GENTLE_SPIN_LOW_ENERGY == 0) GENTLE_SPIN_LOW_ENERGY = 2*60*60; if(GENTLE_SPIN_MEDIUM_ENERGY == 0) GENTLE_SPIN_MEDIUM_ENERGY = 2*150*60; if(GENTLE_SPIN_HIGH_ENERGY == 0) GENTLE_SPIN_HIGH_ENERGY = 2*220*60; if(GENTLE_PREWASH_POWER == 0) GENTLE_PREWASH_POWER = 20; if(GENTLE_WASH_POWER == 0) GENTLE_WASH_POWER = 40; if(GENTLE_SMALLWASH_POWER == 0) GENTLE_SMALLWASH_POWER = 25; if(GENTLE_SPIN_LOW_POWER == 0) GENTLE_SPIN_LOW_POWER = 60; if(GENTLE_SPIN_MEDIUM_POWER == 0) GENTLE_SPIN_MEDIUM_POWER = 150; if(GENTLE_SPIN_HIGH_POWER == 0) GENTLE_SPIN_HIGH_POWER = 220; if(normal_perc == 0) normal_perc = 0.5; if(perm_press_perc == 0) perm_press_perc = 0.8; return res; }
/** Initialize water heater model properties - randomized defaults for all published variables **/ int waterheater::init(OBJECT *parent) { OBJECT *hdr = OBJECTHDR(this); if(parent != NULL){ if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("waterheater::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } } hdr->flags |= OF_SKIPSAFE; static double sTair = 74; static double sTout = 68; if(parent){ pTair = gl_get_double_by_name(parent, "air_temperature"); pTout = gl_get_double_by_name(parent, "outdoor_temperature"); } if(pTair == 0){ pTair = &sTair; gl_warning("waterheater parent lacks \'air_temperature\' property, using default"); } if(pTout == 0){ pTout = &sTout; gl_warning("waterheater parent lacks \'outside_temperature\' property, using default"); } /* sanity checks */ /* initialize water tank volume */ if(tank_volume <= 0.0){ // tank_volume = 5*floor((1.0/5.0)*gl_random_uniform(0.90, 1.10) * 50.0 * (pHouse->get_floor_area() /2000.0)); // [gal] if (tank_volume > 100.0) tank_volume = 100.0; else if (tank_volume < 20.0) tank_volume = 20.0; } else { if (tank_volume > 100.0 || tank_volume < 20.0){ gl_error("watertank volume of %f outside the volume bounds of 20 to 100 gallons.", tank_volume); /* TROUBLESHOOT All waterheaters must be set between 40 and 100 gallons. Most waterheaters are assumed to be 50 gallon tanks. */ } } if (tank_setpoint<90 || tank_setpoint>160) gl_error("watertank thermostat is set to %f and is outside the bounds of 90 to 160 degrees Fahrenheit (32.2 - 71.1 Celsius).", tank_setpoint); /* TROUBLESHOOT All waterheaters must be set between 90 degF and 160 degF. /* initialize water tank deadband */ if (thermostat_deadband>10 || thermostat_deadband < 0.0) GL_THROW("watertank deadband of %f is outside accepted bounds of 0 to 10 degrees (5.6 degC).", thermostat_deadband); // initial tank UA if (tank_UA <= 0.0) GL_THROW("Tank UA value is negative."); // Set heating element capacity if not provided by the user if (heating_element_capacity <= 0.0) { if (tank_volume >= 50) heating_element_capacity = 4.500; else { // Smaller tanks can be either 3200, 3500, or 4500... double randVal = gl_random_uniform(RNGSTATE,0,1); if (randVal < 0.33) heating_element_capacity = 3.200; else if (randVal < 0.67) heating_element_capacity = 3.500; else heating_element_capacity = 4.500; } } // set gas electric loads, if not provided by the user if(0 > gas_fan_power){ gas_fan_power = heating_element_capacity * 0.01; } if(0 > gas_standby_power){ gas_standby_power = 0.0; // some units consume 3-5W } // Other initial conditions if(Tw < Tinlet){ // uninit'ed temperature Tw = gl_random_uniform(RNGSTATE,tank_setpoint - thermostat_deadband, tank_setpoint + thermostat_deadband); } current_model = NONE; load_state = STABLE; // initial demand Tset_curtail = tank_setpoint - thermostat_deadband/2 - 10; // Allow T to drop only 10 degrees below lower cut-in T... // Setup derived characteristics... area = (pi * pow(tank_diameter,2))/4; height = tank_volume/GALPCF / area; Cw = tank_volume/GALPCF * RHOWATER * Cp; // [Btu/F] h = height; // initial water temperature if(h == 0){ // discharged Tlower = Tinlet; Tupper = Tinlet + TSTAT_PRECISION; } else { Tlower = Tinlet; } /* schedule checks */ 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 residential_enduse::init(parent); }
double refrigerator::update_refrigerator_state(double dt0,TIMESTAMP t1) { OBJECT *hdr = OBJECTHDR(this); // accumulate the energy energy_used += refrigerator_power*dt0; if(cycle_time>0) { cycle_time -= dt0; } if(defrostDelayed>0) { defrostDelayed -= dt0; } if(defrostDelayed<=0){ if(DC_TIMED==defrost_criterion){ run_defrost = true; } else if(DC_COMPRESSOR_TIME==defrost_criterion && total_compressor_time>=compressor_defrost_time){ run_defrost = true; total_compressor_time = 0; check_defrost = false; } else if(no_of_defrost>0 && DC_DOOR_OPENINGS==defrost_criterion){ run_defrost = true; FF_Door_Openings = 0; check_defrost = false; } } else{ if(DC_TIMED==defrost_criterion){ check_defrost = true; } else if(DC_COMPRESSOR_TIME==defrost_criterion && total_compressor_time>=compressor_defrost_time){ check_defrost = true; } else if(no_of_defrost>0 && DC_DOOR_OPENINGS==defrost_criterion){ check_defrost = true; } } if(long_compressor_cycle_time>0) { long_compressor_cycle_time -= dt0; } if (dr_mode_double == 0) dr_mode = DM_UNKNOWN; else if (dr_mode_double == 1) dr_mode = DM_LOW; else if (dr_mode_double == 2) dr_mode = DM_NORMAL; else if (dr_mode_double == 3) dr_mode = DM_HIGH; else if (dr_mode_double == 4) dr_mode = DM_CRITICAL; else dr_mode = DM_UNKNOWN; if(door_return_time > 0){ door_return_time = door_return_time - dt0; } if(door_next_open_time > 0){ door_next_open_time = door_next_open_time - dt0; } if(door_return_time<=0 && true==door_open){ door_return_time = 0; door_open = false; } if(door_next_open_time<=0 && hourly_door_opening>0){ door_next_open_time = 0; door_open = true; FF_Door_Openings++; door_return_time += ceil(gl_random_uniform(&hdr->rng_state,0, door_open_time)); door_energy_calc = true; hourly_door_opening--; if(hourly_door_opening > 0){ door_next_open_time = int(gl_random_uniform(&hdr->rng_state,0,(3600-(t1-start_time)%3600))); // next_door_openings[hourly_door_opening-1] - ((t1-start_time)%3600); door_to_open = true; } else{ door_to_open = false; } check_DO = FF_Door_Openings%DO_Thershold; if(check_DO==0){ no_of_defrost++; } } if(((t1-start_time)%3600)==0 && start_time>0) { double temp_hourly_door_opening = (door_opening_criterion*daily_door_opening) - floor(door_opening_criterion*daily_door_opening); if(temp_hourly_door_opening >= 0.5){ hourly_door_opening = ceil(door_opening_criterion*daily_door_opening); } else{ hourly_door_opening = floor(door_opening_criterion*daily_door_opening); } hourly_door_opening = floor(gl_random_normal(&hdr->rng_state,hourly_door_opening, ((hourly_door_opening)/3))); //Clip the hourly door openings if(hourly_door_opening<0){ hourly_door_opening = 0; } else if(hourly_door_opening>2*hourly_door_opening){ hourly_door_opening = 2*hourly_door_opening; } if(hourly_door_opening > long_compressor_cycle_threshold*daily_door_opening) { long_compressor_cycle_due = true; long_compressor_cycle_time = int(gl_random_uniform(&hdr->rng_state,0,(3600))); } if(hourly_door_opening>0){ door_to_open = true; door_next_open_time = int(gl_random_uniform(&hdr->rng_state,0,(3600))); } else{ door_to_open = false; } } double dt1 = 0; switch(state){ case RS_DEFROST: if ((energy_used >= energy_needed || cycle_time <= 0)) { state = RS_COMPRESSSOR_ON_LONG; refrigerator_power = long_compressor_cycle_power; energy_needed = long_compressor_cycle_energy; energy_used = 0; cycle_time = ceil((energy_needed - energy_used)/refrigerator_power); } else { refrigerator_power = defrost_power; } break; case RS_COMPRESSSOR_ON_NORMAL: if(run_defrost==true) { state = RS_DEFROST; refrigerator_power = defrost_power; energy_needed = defrost_energy; energy_used = 0; cycle_time = ceil((energy_needed - energy_used)/refrigerator_power); run_defrost=false; no_of_defrost--; defrostDelayed = delay_defrost_time; } else if ((energy_used >= energy_needed || cycle_time <= 0)) { state = RS_COMPRESSSOR_OFF_NORMAL; refrigerator_power = compressor_off_normal_power; energy_needed = compressor_off_normal_energy; energy_used = 0; cycle_time = ceil((energy_needed - energy_used)/refrigerator_power); //new_running_state = true; } else { refrigerator_power = compressor_on_normal_power; total_compressor_time += dt0; if(door_energy_calc==true){ door_energy_calc = false; energy_needed += door_return_time*refrigerator_power; cycle_time = ceil((energy_needed - energy_used)/refrigerator_power); } } break; case RS_COMPRESSSOR_ON_LONG: if(run_defrost==true) { state = RS_DEFROST; refrigerator_power = defrost_power; energy_needed = defrost_energy; energy_used = 0; cycle_time = ceil((energy_needed - energy_used)/refrigerator_power); run_defrost=false; no_of_defrost--; defrostDelayed = delay_defrost_time; } else if ((energy_used >= energy_needed || cycle_time <= 0)) { state = RS_COMPRESSSOR_OFF_NORMAL; refrigerator_power = compressor_off_normal_power; energy_needed = compressor_off_normal_energy; energy_used = 0; cycle_time = ceil((energy_needed - energy_used)/refrigerator_power); //new_running_state = true; } else { refrigerator_power = long_compressor_cycle_power; if(door_energy_calc==true){ door_energy_calc = false; energy_needed += door_return_time*refrigerator_power; cycle_time = ceil((energy_needed - energy_used)/refrigerator_power); } } break; case RS_COMPRESSSOR_OFF_NORMAL: if(run_defrost==true) { state = RS_DEFROST; refrigerator_power = defrost_power; energy_needed = defrost_energy; energy_used = 0; cycle_time = ceil((energy_needed - energy_used)/refrigerator_power); run_defrost=false; no_of_defrost--; defrostDelayed = delay_defrost_time; } else if ((energy_used >= energy_needed || cycle_time <= 0)) { if(long_compressor_cycle_due==true && long_compressor_cycle_time<=0) { state = RS_COMPRESSSOR_ON_LONG; refrigerator_power = long_compressor_cycle_power; energy_needed = long_compressor_cycle_energy; long_compressor_cycle_due=false; energy_used = 0; cycle_time = ceil((energy_needed - energy_used)/refrigerator_power); } else{ state = RS_COMPRESSSOR_ON_NORMAL; refrigerator_power = compressor_on_normal_power; energy_needed = compressor_on_normal_energy; energy_used = 0; cycle_time = ceil((energy_needed - energy_used)/refrigerator_power); } } else { refrigerator_power = compressor_off_normal_power; if(door_energy_calc==true){ door_energy_calc = false; energy_needed -= door_return_time*compressor_off_normal_power; cycle_time = ceil((energy_needed - energy_used)/refrigerator_power); if(cycle_time<0) cycle_time = 0; } } break; } double posted_power = refrigerator_power; //*************************** if(door_open==true) { posted_power += door_opening_power; } //*************************** if(check_icemaking == true) { posted_power += icemaking_power; icemaker_running = true; return_time = 60-dt0; if(0==((t1-start_time)%60) || return_time<=0){ ice_making_no--; if(ice_making_no == 0) { check_icemaking = false; } return_time = 60; } } else { if(((t1-start_time)%60)==0) { ice_making = double(gl_random_uniform(&hdr->rng_state,0,1)); if(ice_making <=ice_making_probability) { check_icemaking = true; icemaker_running = true; // ice_making_no = gl_random_sampled(3,ice_making_time); ice_making_no = 1; posted_power += icemaking_power; return_time = 60; ice_making_no--; if(ice_making_no == 0) { check_icemaking = false; } } else { icemaker_running = false; return_time = 60; } } else { icemaker_running = false; } } load.power.SetPowerFactor(posted_power/1000, load.power_factor); load.admittance = complex(0,0,J); load.current = complex(0,0,J); if(true==door_open && true==door_to_open) { door_time = door_return_time<door_next_open_time?door_return_time:door_next_open_time; } else if(true==door_to_open) { door_time = door_next_open_time; } else if(true==door_open){ door_time = door_return_time; } else if(start_time>0) { door_time = (3600 - ((t1-start_time)%3600)); } if(0.0==return_time) { dt1 = cycle_time>door_time?door_time:cycle_time; } else { if(cycle_time>return_time) if(return_time>door_time) if(door_time>long_compressor_cycle_time) dt1 = long_compressor_cycle_time; else dt1 = door_time; else if(return_time>long_compressor_cycle_time) dt1 = long_compressor_cycle_time; else dt1 = return_time; else if(cycle_time>door_time) if(door_time>long_compressor_cycle_time) dt1 = long_compressor_cycle_time; else dt1 = door_time; else if(cycle_time>long_compressor_cycle_time) dt1 = long_compressor_cycle_time; else dt1 = cycle_time; } if(check_defrost == true){ if(dt1 > defrostDelayed){ dt1 = defrostDelayed; } } load.total = load.power + load.current + load.admittance; total_power = (load.power.Re() + (load.current.Re() + load.admittance.Re()*load.voltage_factor)*load.voltage_factor); last_dr_mode = dr_mode; if ((dt1 > 0) && (dt1 < 1)){ dt1 = 1; } return dt1; }
/** Initialize oven model properties - randomized defaults for all published variables **/ int range::init(OBJECT *parent) { // @todo This class has serious problems and should be deleted and started from scratch. Fuller 9/27/2013. if(parent != NULL){ if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("range::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } } OBJECT *hdr = OBJECTHDR(this); hdr->flags |= OF_SKIPSAFE; static double sTair = 74; static double sTout = 68; if (heat_fraction==0) heat_fraction = 0.2; if(parent){ pTair = gl_get_double_by_name(parent, "air_temperature"); pTout = gl_get_double_by_name(parent, "outdoor_temperature"); } if(pTair == 0){ pTair = &sTair; gl_warning("range parent lacks \'air_temperature\' property, using default"); } if(pTout == 0){ pTout = &sTout; gl_warning("range parent lacks \'outside_temperature\' property, using default"); } /* sanity checks */ /* initialize oven volume */ if(oven_volume <= 0.0){ // oven_volume = 5*floor((1.0/5.0)*gl_random_uniform(0.90, 1.10) * 50.0 * (pHouse->get_floor_area() /2000.0)); // [gal] if (oven_volume > 100.0) oven_volume = 100.0; else if (oven_volume < 20.0) oven_volume = 20.0; } if (oven_setpoint<90 || oven_setpoint>160){ GL_THROW("This model is experimental and not validated: oven thermostat is set to %f and is outside the bounds of 90 to 160 degrees Fahrenheit (32.2 - 71.1 Celsius).", oven_setpoint); /* TROUBLESHOOT TODO. */ } /* initialize oven deadband */ if (thermostat_deadband>10 || thermostat_deadband < 0.0) GL_THROW("oven deadband of %f is outside accepted bounds of 0 to 10 degrees (5.6 degC).", thermostat_deadband); // initial range UA if (oven_UA <= 0.0) GL_THROW("Range UA value is negative."); // Set heating element capacity if not provided by the user if (heating_element_capacity <= 0.0) { if (oven_volume >= 50) heating_element_capacity = 4.500; else { double randVal = gl_random_uniform(&hdr->rng_state,0,1); if (randVal < 0.33) heating_element_capacity = 3.200; else if (randVal < 0.67) heating_element_capacity = 3.500; else heating_element_capacity = 4.500; } } // Other initial conditions if(Tw < Tinlet){ // uninit'ed temperature Tw = gl_random_uniform(&hdr->rng_state,oven_setpoint - thermostat_deadband, oven_setpoint + thermostat_deadband); } current_model = NONE; load_state = STABLE; // initial demand Tset_curtail = oven_setpoint - thermostat_deadband/2 - 10; // Allow T to drop only 10 degrees below lower cut-in T... // Setup derived characteristics... area = (pi * pow(oven_diameter,2))/4; height = oven_volume/GALPCF / area; Cw = oven_volume/GALPCF * food_density * specificheat_food; // [Btu/F] h = height; // initial food temperature if(h == 0){ // discharged Tlower = Tinlet; Tupper = Tinlet + TSTAT_PRECISION; } else { Tlower = Tinlet; } /* schedule checks */ switch(shape.type){ case MT_UNKNOWN: /* normal, undriven behavior. */ gl_warning("This device, %s, is considered very experimental and has not been validated.", get_name()); 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 range. */ } 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 ~ oven 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 residential_enduse::init(parent); }
int refrigerator::init(OBJECT *parent) { if(parent != NULL){ if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("refrigerator::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } } OBJECT *hdr = OBJECTHDR(this); hdr->flags |= OF_SKIPSAFE; // defaults for unset values */ if (size==0) size = gl_random_uniform(&hdr->rng_state,20,40); // cf if (thermostat_deadband==0) thermostat_deadband = gl_random_uniform(&hdr->rng_state,2,3); if (Tset==0) Tset = gl_random_uniform(&hdr->rng_state,35,39); if (UA == 0) UA = 0.6; if (UAr==0) UAr = UA+size/40*gl_random_uniform(&hdr->rng_state,0.9,1.1); if (UAf==0) UAf = gl_random_uniform(&hdr->rng_state,0.9,1.1); if (COPcoef==0) COPcoef = gl_random_uniform(&hdr->rng_state,0.9,1.1); if (Tout==0) Tout = 59.0; if (load.power_factor==0) load.power_factor = 0.95; pTout = (double*)gl_get_addr(parent, "air_temperature"); if (pTout==NULL) { static double default_air_temperature = 72; gl_warning("%s (%s:%d) parent object lacks air temperature, using %0f degF instead", hdr->name, hdr->oclass->name, hdr->id, default_air_temperature); pTout = &default_air_temperature; } /* derived values */ Tair = gl_random_uniform(&hdr->rng_state,Tset-thermostat_deadband/2, Tset+thermostat_deadband/2); // size is used to couple Cw and Qrated Cf = size/10.0 * RHOWATER * CWATER; // cf * lb/cf * BTU/lb/degF = BTU / degF rated_capacity = BTUPHPW * size*10; // BTU/h ... 10 BTU.h / cf (34W/cf, so ~700 for a full-sized refrigerator) start_time = 0; if(compressor_off_normal_energy==0) compressor_off_normal_energy=15*45*60; //watt-secs if(compressor_off_normal_power==0) compressor_off_normal_power=15; //watt if(long_compressor_cycle_energy==0) long_compressor_cycle_energy=120*100*60; //watt-secs if(long_compressor_cycle_power==0) long_compressor_cycle_power=120; //watt if(compressor_on_normal_energy==0) compressor_on_normal_energy=120*35*60; //watt-secs if(compressor_on_normal_power==0) compressor_on_normal_power=120; //watt if(defrost_energy==0) defrost_energy=40*550*60; //watt-secs if(defrost_power==0) defrost_power=550; //watt if(icemaking_energy==0) icemaking_energy=300*60; //watt-secs if(icemaking_power==0) icemaking_power=300; //watt if(ice_making_probability==0) ice_making_probability=0.02; //watt if(DO_Thershold==0) DO_Thershold=24; if(long_compressor_cycle_threshold==0) long_compressor_cycle_threshold=0.05; if(FF_Door_Openings==0) FF_Door_Openings=0; if(door_opening_power==0) door_opening_power=16; if(delay_defrost_time==0) delay_defrost_time=28800; if(defrost_criterion==0) defrost_criterion=DC_TIMED; refrigerator_power = 0; return_time = 0; no_of_defrost = 0; total_compressor_time = 0; if(door_open_time==0) door_open_time=7; long_compressor_cycle_due=false; door_energy_calc = false; ice_making_time = new double[1,2,3]; icemaker_running = false; check_defrost = false; switch(state){ case RS_DEFROST: if(energy_needed==0) energy_needed = defrost_energy; cycle_time = ceil((energy_needed - energy_used)/defrost_power); break; case RS_COMPRESSSOR_OFF_NORMAL: if(energy_needed==0) energy_needed = compressor_off_normal_energy; cycle_time = ceil((energy_needed - energy_used)/compressor_off_normal_power); break; case RS_COMPRESSSOR_ON_NORMAL: if(energy_needed==0) energy_needed = compressor_on_normal_energy; cycle_time = ceil((energy_needed - energy_used)/compressor_on_normal_power); break; } run_defrost = false; if (is_240) { load.config = EUC_IS220; } load.total = Qr * KWPBTUPH; return residential_enduse::init(parent); }
double dishwasher::update_state(double dt) //,TIMESTAMP t1) { // accumulate the energy OBJECT *hdr = OBJECTHDR(this); energy_used += total_power/1000 * dt/3600; switch(state) { case dishwasher_STOPPED: if (enduse_queue>1)// && dryer_on == true) dishwasher_run_prob = double(gl_random_uniform(&hdr->rng_state,queue_min,queue_max)); if (enduse_queue > 1 && (dishwasher_run_prob > enduse_queue)) { state = dishwasher_CONTROL_ONLY; if (Heateddry_option_check == true) energy_needed = energy_baseline; else energy_needed = 0.66*energy_baseline; cycle_duration = cycle_time = 1000 * (energy_needed - energy_used) / coil_power[0] * 60 * 60; cycle_time = pulse_interval[5]; enduse_queue--; new_running_state = true; } else if (pCircuit->pV->Mag()<stall_voltage) { state = dishwasher_STALLED; state_time = 0; } break; case dishwasher_CONTROL_ONLY: if (energy_used >= energy_needed || cycle_time <= 0) { if (energy_used >= energy_needed) { state = dishwasher_STOPPED; cycle_time = 0; energy_used = 0; control_check1 = false; control_check2 = false; control_check3 = false; control_check4 = false; control_check5 = false; control_check6 = false; control_check7 = false; control_check8 = false; control_check9 = false; control_check10 = false; control_check11 = false; control_check12 = false; motor_only_check1 = false; motor_only_check2 = false; motor_only_check3 = false; motor_only_check4 = false; motor_only_check5 = false; motor_only_check6 = false; motor_only_check7 = false; motor_only_check8 = false; motor_only_check9 = false; motor_coil_only_check1 = false; motor_coil_only_check2 = false; heateddry_check1 = false; heateddry_check2 = false; coil_only_check1 = false; coil_only_check2 = false; coil_only_check3 = false; new_running_state = true; } else if (cycle_time<=0) { if (cycle_time<=0 && (control_check1 == false || control_check_temp == true)) { state = dishwasher_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; double interval = pulse_interval[0]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; control_check1 = true; control_check2 = true; } if (cycle_time<=0 && control_check2 == true) { state = dishwasher_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; double interval = pulse_interval[7]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; control_check2 = false; control_check6 = true; } if (cycle_time<=0 && control_check3 == true) { state = dishwasher_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; double interval = pulse_interval[6]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; control_check3 = false; control_check7 = true; } if (cycle_time<=0 && control_check4 == true) { state = dishwasher_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; double interval = pulse_interval[9]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; control_check4 = false; control_check5 = true; } if (cycle_time<=0 && control_check5 == true) { state = dishwasher_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; double interval = pulse_interval[4]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; control_check5 = false; control_check8 = true; } if (cycle_time<=0 && control_check6 == true) { state = dishwasher_COIL_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / coil_power[1] * 60 * 60; double interval = pulse_interval[0]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; control_check6 = false; control_check3 = true; } if(cycle_time<=0 && (control_check7 == true)) { state = dishwasher_MOTOR_COIL_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / (motor_power + coil_power[3]) * 60 * 60; double interval = pulse_interval[10]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; control_check7 = false; control_check4 = true; } if (cycle_time<=0 && control_check8 == true && count_control_only<5) { state = dishwasher_COIL_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / coil_power[1] * 60 * 60; double interval = pulse_interval[0]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; count_control_only += 1; if (count_control_only == 4) { control_check8 = false; control_check9 = true; } } if (cycle_time<=0 && control_check9 == true && count_control_only1 < 7) { state = dishwasher_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; double interval = pulse_interval[0]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; count_control_only1 +=1; if (count_control_only1 ==6) { control_check9 = false; control_check10 = true; } } if(cycle_time<=0 && (control_check10 == true)) { state = dishwasher_MOTOR_COIL_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / (motor_power + coil_power[3]) * 60 * 60; double interval = pulse_interval[17]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; control_check10 = false; control_check11 = true; } if(cycle_time<=0 && control_check11 == true && Heateddry_option_check == true) { state = dishwasher_HEATEDDRY_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / (coil_power[2]) * 60 * 60; double interval = pulse_interval[16]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; control_check11 = false; control_check12 = true; } if(cycle_time<=0 && control_check12 == true && Heateddry_option_check == true) { state = dishwasher_HEATEDDRY_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / (coil_power[2]) * 60 * 60; double interval = pulse_interval[15]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; control_check12 = false; } new_running_state = true; } else if (pCircuit->pV->Mag()<stall_voltage) { state = dishwasher_STALLED; state_time = 0; } } break; case dishwasher_MOTOR_ONLY: if (energy_used >= energy_needed || cycle_time<=0) { if (energy_used >= energy_needed) { state = dishwasher_STOPPED; cycle_time = 0; energy_used = 0; control_check1 = false; control_check2 = false; control_check3 = false; control_check4 = false; control_check5 = false; control_check6 = false; control_check7 = false; control_check8 = false; control_check9 = false; control_check10 = false; control_check11 = false; control_check12 = false; motor_only_check1 = false; motor_only_check2 = false; motor_only_check3 = false; motor_only_check4 = false; motor_only_check5 = false; motor_only_check6 = false; motor_only_check7 = false; motor_only_check8 = false; motor_only_check9 = false; motor_coil_only_check1 = false; motor_coil_only_check2 = false; heateddry_check1 = false; heateddry_check2 = false; coil_only_check1 = false; coil_only_check2 = false; coil_only_check3 = false; new_running_state = true; } else if (cycle_time<=0) { state = dishwasher_CONTROL_ONLY; if(cycle_time<=0 && (motor_only_check1 == false)) { double cycle_t = 1000 * (energy_needed - energy_used) / coil_power[0] * 60 * 60; double interval = pulse_interval[5]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; motor_only_check1 = true; motor_only_check2 = true; } if(cycle_time<=0 && motor_only_check2 == true) { double cycle_t = 1000 * (energy_needed - energy_used) / coil_power[0] * 60 * 60; double interval = pulse_interval[3]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; motor_only_check2 = false; motor_only_check3 = true; } if(cycle_time<=0 && motor_only_check3 == true && count_motor_only_68 < 3) { double cycle_t = 1000 * (energy_needed - energy_used) / coil_power[0] * 60 * 60; double interval = pulse_interval[5]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; count_motor_only_68 +=1; if (count_motor_only_68 ==2) { motor_only_check3 = false; motor_only_check4 = true; } } if(cycle_time<=0 && motor_only_check4 == true) { double cycle_t = 1000 * (energy_needed - energy_used) / coil_power[0] * 60 * 60; double interval = pulse_interval[2]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; motor_only_check4 = false; motor_only_check5 = true; } if(cycle_time<=0 && motor_only_check5 == true && count_motor_only_25 <6) { double cycle_t = 1000 * (energy_needed - energy_used) / coil_power[0] * 60 * 60; double interval = pulse_interval[1]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; count_motor_only_25 +=1; if (count_motor_only_25 == 5) { motor_only_check5 = false; motor_only_check6 = true; } } if(cycle_time<=0 && motor_only_check6 == true) { double cycle_t = 1000 * (energy_needed - energy_used) / coil_power[0] * 60 * 60; double interval = pulse_interval[7]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; motor_only_check6 = false; motor_only_check7 = true; } if(cycle_time<=0 && motor_only_check7 == true && count_motor_only <6) { double cycle_t = 1000 * (energy_needed - energy_used) / coil_power[0] * 60 * 60; double interval = pulse_interval[4]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; count_motor_only +=1; if (count_motor_only ==5) { motor_only_check7 = false; motor_only_check8 = true; } } if(cycle_time<=0 && motor_only_check8 == true) { double cycle_t = 1000 * (energy_needed - energy_used) / coil_power[0] * 60 * 60; double interval = pulse_interval[8]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; motor_only_check8 = false; motor_only_check9 = true; } if(cycle_time<=0 && motor_only_check9 == true) { double cycle_t = 1000 * (energy_needed - energy_used) / coil_power[0] * 60 * 60; double interval = pulse_interval[12]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; count_motor_only1 +=1; motor_only_check9 = false; } new_running_state = true; } else if (pCircuit->pV->Mag()<stall_voltage) { state = dishwasher_STALLED; state_time = 0; } } break; case dishwasher_MOTOR_COIL_ONLY: if (energy_used >= energy_needed || cycle_time <= 0) { if (energy_used >= energy_needed) { state = dishwasher_STOPPED; cycle_time = 0; energy_used = 0; control_check1 = false; control_check2 = false; control_check3 = false; control_check4 = false; control_check5 = false; control_check6 = false; control_check7 = false; control_check8 = false; control_check9 = false; control_check10 = false; control_check11 = false; control_check12 = false; motor_only_check1 = false; motor_only_check2 = false; motor_only_check3 = false; motor_only_check4 = false; motor_only_check5 = false; motor_only_check6 = false; motor_only_check7 = false; motor_only_check8 = false; motor_only_check9 = false; motor_coil_only_check1 = false; motor_coil_only_check2 = false; heateddry_check1 = false; heateddry_check2 = false; coil_only_check1 = false; coil_only_check2 = false; coil_only_check3 = false; new_running_state = true; } else if (cycle_time<=0) { state = dishwasher_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; if (cycle_time<=0 && motor_coil_only_check1 == false) { double interval = pulse_interval[11]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; motor_coil_only_check1 = true; motor_coil_only_check2 = true; } if(cycle_time<=0 && motor_coil_only_check2 == true) { double interval = pulse_interval[13]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; motor_coil_only_check2 = false; } new_running_state = true; } else if (pCircuit->pV->Mag()<stall_voltage) { state = dishwasher_STALLED; state_time = 0; } } break; case dishwasher_HEATEDDRY_ONLY: if (energy_used >= energy_needed || cycle_time <= 0 ) { if (energy_used >= energy_needed) { state = dishwasher_STOPPED; cycle_time = 0; energy_used = 0; control_check1 = false; control_check2 = false; control_check3 = false; control_check4 = false; control_check5 = false; control_check6 = false; control_check7 = false; control_check8 = false; control_check9 = false; control_check10 = false; control_check11 = false; control_check12 = false; motor_only_check1 = false; motor_only_check2 = false; motor_only_check3 = false; motor_only_check4 = false; motor_only_check5 = false; motor_only_check6 = false; motor_only_check7 = false; motor_only_check8 = false; motor_only_check9 = false; motor_coil_only_check1 = false; motor_coil_only_check2 = false; heateddry_check1 = false; heateddry_check2 = false; coil_only_check1 = false; coil_only_check2 = false; coil_only_check3 = false; new_running_state = true; } else if (cycle_time<=0 && heateddry_check1 == false) { state = dishwasher_CONTROL_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / coil_power[0] * 60 * 60; double interval = pulse_interval[7]; heateddry_check1 = true; heateddry_check2 = true; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; new_running_state = true; } else if (cycle_time<=0 && heateddry_check2 == true) { state = dishwasher_CONTROL_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / (coil_power[0]) * 60 * 60; double interval = pulse_interval[18]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; motor_only_check2 = false; new_running_state = true; } else if (pCircuit->pV->Mag()<stall_voltage) { state = dishwasher_STALLED; state_time = 0; } } break; case dishwasher_COIL_ONLY: if (energy_used >= energy_needed || cycle_time <= 0) { if (energy_used >= energy_needed) { state = dishwasher_STOPPED; cycle_time = 0; energy_used = 0; control_check1 = false; control_check2 = false; control_check3 = false; control_check4 = false; control_check5 = false; control_check6 = false; control_check7 = false; control_check8 = false; control_check9 = false; control_check10 = false; control_check11 = false; control_check12 = false; motor_only_check1 = false; motor_only_check2 = false; motor_only_check3 = false; motor_only_check4 = false; motor_only_check5 = false; motor_only_check6 = false; motor_only_check7 = false; motor_only_check8 = false; motor_only_check9 = false; motor_coil_only_check1 = false; motor_coil_only_check2 = false; heateddry_check1 = false; heateddry_check2 = false; coil_only_check1 = false; coil_only_check2 = false; coil_only_check3 = false; new_running_state = true; } else if (cycle_time<=0) { state = dishwasher_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; if (cycle_time<=0 && coil_only_check1 == false) { double interval = pulse_interval[8]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; coil_only_check1 = true; coil_only_check2 = true; } if(cycle_time<=0 && coil_only_check2 == true && count_coil_only <4) { double interval = pulse_interval[4]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; count_coil_only +=1; if (count_coil_only == 3) { coil_only_check2 = false; coil_only_check3 = true; } } if(cycle_time<=0 && coil_only_check3 == true) { double interval = pulse_interval[14]; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; coil_only_check3 = false; } new_running_state = true; } else if (pCircuit->pV->Mag()<stall_voltage) { state = dishwasher_STALLED; state_time = 0; } } break; case dishwasher_STALLED: if (pCircuit->pV->Mag()>start_voltage) { state = dishwasher_MOTOR_ONLY; state_time = cycle_time; } else if (state_time>trip_delay) { state = dishwasher_TRIPPED; state_time = 0; } break; case dishwasher_TRIPPED: if (state_time>reset_delay) { if (pCircuit->pV->Mag()>start_voltage) state = dishwasher_MOTOR_ONLY; else state = dishwasher_STALLED; state_time = 0; } break; } // accumulating units in the queue no matter what happens enduse_queue += daily_dishwasher_demand * dt/3600/24; //actual_dishwasher_demand = actual_dishwasher_demand + enduse_queue; // now implement current state switch(state) { case dishwasher_STOPPED: // nothing running load.power = load.current = load.admittance = complex(0,0,J); dt = ((enduse_queue>=1) || (enduse_queue==0)) ? 0 : ((1-enduse_queue)*3600)/(enduse_queue*24); break; case dishwasher_MOTOR_COIL_ONLY: cycle_time -= dt; load.power.SetPowerFactor(motor_power/1000, load.power_factor); load.admittance = complex((coil_power[3])/1000,0,J); //assume pure resistance load.current = complex(0,0,J); dt = cycle_time; break; case dishwasher_COIL_ONLY: cycle_time -= dt; load.power = load.current = complex(0,0,J); load.admittance = complex((coil_power[1])/1000,0,J); //assume pure resistance dt = cycle_time; break; case dishwasher_HEATEDDRY_ONLY: cycle_time -= dt; load.power = load.current = complex(0,0,J); load.admittance = complex((coil_power[2])/1000,0,J); //assume pure resistance dt = cycle_time; break; case dishwasher_CONTROL_ONLY: if(true==new_running_state){ new_running_state = false; } else{ cycle_time -= dt; } load.power = load.current = complex(0,0,J); load.admittance = complex(coil_power[0]/1000,0,J); dt = cycle_time; break; case dishwasher_STALLED: load.power = load.current = complex(0,0,J); load.admittance = complex(1)/stall_impedance; dt = trip_delay; break; case dishwasher_TRIPPED: load.power = load.current = load.admittance = complex(0,0,J); dt = reset_delay; break; case dishwasher_MOTOR_ONLY: motor_on_off = 1; motor_coil_on_off = both_coils_on_off = 0; cycle_time -= dt; load.power.SetPowerFactor(motor_power/1000, load.power_factor); load.admittance = complex(0,0,J); load.current = complex(0,0,J); dt = cycle_time; break; default: throw "unexpected motor state"; /* TROUBLESHOOT This is an error. Please submit a bug report along with at the dishwasher object & class sections from the relevant GLM file, and from the dump file. */ break; } // compute the total electrical load - first for the enduse structure and second for an internal variable load.total = load.power + load.current + load.admittance; total_power = (load.power.Re() + (load.current.Re() + load.admittance.Re()*load.voltage_factor)*load.voltage_factor) * 1000; // compute the total heat gain load.heatgain = load.total.Mag() * heat_fraction; if (dt > 0 && dt < 1) dt = 1; return dt; }
int dishwasher::init(OBJECT *parent) { // @todo This class has serious problems and should be deleted and started from scratch. Fuller 9/27/2013. OBJECT *hdr = OBJECTHDR(this); if(parent != NULL){ if((parent->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("dishwasher::init(): deferring initialization on %s", gl_name(parent, objname, 255)); return 2; // defer } } int rv = 0; // default properties if (motor_power==0) motor_power = gl_random_uniform(&hdr->rng_state,150,350); if (heat_fraction==0) heat_fraction = 0.2; if (is_240) { load.config = EUC_IS220; if (stall_voltage==0) stall_voltage = 0.6*240; } else if (stall_voltage==0) stall_voltage = 0.6*120; if (trip_delay==0) trip_delay = 10; if (reset_delay==0) reset_delay = 60; count_motor_only = 0; count_motor_only1 =0; count_motor_only_25 = 0; count_coil_only = 0; count_control_only =0; count_control_only1 =0; count_motor_only_68 =0; pulse_interval[0] = 8; pulse_interval[1] = 18; pulse_interval[2] = 21; pulse_interval[3] = 28; pulse_interval[4] = 38; pulse_interval[5] = 50; pulse_interval[6] = 65; pulse_interval[7] = 118; pulse_interval[8] = 150; pulse_interval[9] = 220; pulse_interval[10] = 320; pulse_interval[11] = 355; pulse_interval[12] = 460; pulse_interval[13] = 580; pulse_interval[14] = 615; pulse_interval[15] = 780; pulse_interval[16] = 800; pulse_interval[17] = 950; pulse_interval[18] = 1150; if (coil_power[0]==-1) coil_power[0] = 5800; coil_power[0] = 10; coil_power[1] = 580; coil_power[2] = 695; coil_power[3] = 950; motor_power = 250; enduse_queue = 1; queue_min = 0; queue_max = 2; control_check1 = false; control_check2 = false; control_check3 = false; control_check4 = false; control_check5 = false; control_check6 = false; control_check7 = false; control_check8 = false; control_check9 = false; control_check10 = false; control_check11 = false; control_check12 = false; motor_only_check1 = false; motor_only_check2 = false; motor_only_check3 = false; motor_only_check4 = false; motor_only_check5 = false; motor_only_check6 = false; motor_only_check7 = false; motor_only_check8 = false; motor_only_check9 = false; motor_coil_only_check1 = false; motor_coil_only_check2 = false; heateddry_check1 = false; heateddry_check2 = false; coil_only_check1 = false; coil_only_check2 = false; coil_only_check3 = false; //Heateddry_option_check = false; hdr->flags |= OF_SKIPSAFE; load.power_factor = 0.95; load.breaker_amps = 30; actual_dishwasher_demand = 0; energy_needed = 0; rv = residential_enduse::init(parent); if (rv==SUCCESS) update_state(0.0); /* schedule checks */ switch(shape.type){ case MT_UNKNOWN: gl_warning("This device, %s, is considered very experimental and has not been validated.", get_name()); break; case MT_ANALOG: if(shape.params.analog.energy == 0.0){ GL_THROW("dishwasher does not support fixed energy shaping"); } else if (shape.params.analog.power == 0){ daily_dishwasher_demand = gl_get_loadshape_value(&shape) / 2.4449; } else { daily_dishwasher_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 ~ dishwasher demand X kW, limited by C + Q * h ~ Vdot proportional to power/time */ daily_dishwasher_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; case MT_MODULATED: if(shape.params.modulated.pulsetype == MPT_TIME){ GL_THROW("Amplitude modulated dishwasher usage is nonsensical for residential dishwashers"); /* TROUBLESHOOT Though it is possible to put a constant, low-level dishwasher demand, it is thoroughly counterintuitive to the normal usage of the dishwasher. */ } else if(shape.params.modulated.pulsetype == MPT_POWER){ /* frequency modulated */ /* fixed-amplitude, varying length pulses at regular intervals. */ daily_dishwasher_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 ~ dishwasher demand X kW, limited by C + Q * h */ daily_dishwasher_demand = gl_get_loadshape_value(&shape) / 2.4449; } break; default: GL_THROW("dishwasher load shape has an unknown state!"); break; } return residential_enduse::init(parent); //} // must run before update_state() so that pCircuit can be set // return rv; }
int house::init(OBJECT *parent) { OBJECT *hdr = OBJECTHDR(this); hdr->flags |= OF_SKIPSAFE; // construct circuit variable map to meter struct { complex **var; char *varname; } map[] = { // local object name, meter object name {&pCircuit_V, "voltage_12"}, // assumes 1N and 2N follow immediately in memory {&pLine_I, "current_1"}, // assumes 2 and 3(N) follow immediately in memory {&pLine12, "current_12"}, // maps current load 1-2 onto triplex load /// @todo use triplex property mapping instead of assuming memory order for meter variables (residential, low priority) (ticket #139) }; extern complex default_line_voltage[3], default_line_current[3]; static complex default_line_current_12; int i; // find parent meter, if not defined, use a default meter (using static variable 'default_meter') OBJECT *obj = OBJECTHDR(this); if (parent!=NULL && gl_object_isa(parent,"triplex_meter")) { // attach meter variables to each circuit for (i=0; i<sizeof(map)/sizeof(map[0]); i++) { if ((*(map[i].var) = get_complex(parent,map[i].varname))==NULL) GL_THROW("%s (%s:%d) does not implement triplex_meter variable %s for %s (house:%d)", /* TROUBLESHOOT The House requires that the triplex_meter contains certain published properties in order to properly connect the house circuit panel to the meter. If the triplex_meter does not contain those properties, GridLAB-D may suffer fatal pointer errors. If you encounter this error, please report it to the developers, along with the version of GridLAB-D that raised this error. */ parent->name?parent->name:"unnamed object", parent->oclass->name, parent->id, map[i].varname, obj->name?obj->name:"unnamed", obj->id); } } else { gl_error("house:%d %s; using static voltages", obj->id, parent==NULL?"has no parent triplex_meter defined":"parent is not a triplex_meter"); /* TROUBLESHOOT The House model relies on a triplex_meter as a parent to calculate voltages based on events within the powerflow module. Create a triplex_meter object and set it as the parent of the house object. */ // attach meter variables to each circuit in the default_meter *(map[0].var) = &default_line_voltage[0]; *(map[1].var) = &default_line_current[0]; *(map[2].var) = &default_line_current_12; } // Set defaults for published variables nor provided by model definition while (floor_area <= 500) floor_area = gl_random_normal(RNGSTATE,2500,300); // house size (sf) by 100 ft incs; if (ceiling_height <= ROUNDOFF) ceiling_height = 8.0; if (envelope_UA <= ROUNDOFF) envelope_UA = gl_random_uniform(RNGSTATE,0.15,0.2)*floor_area; // UA of house envelope [BTU/h.F] if (aspect_ratio <= ROUNDOFF) aspect_ratio = 1.0; if (gross_wall_area <= ROUNDOFF) gross_wall_area = 4.0 * 2.0 * (aspect_ratio + 1.0) * ceiling_height * sqrt(floor_area/aspect_ratio); if (airchange_per_hour <= ROUNDOFF) airchange_per_hour = gl_random_uniform(RNGSTATE,4,6); // air changes per hour [cf/h] if (thermostat_deadband <= ROUNDOFF) thermostat_deadband = 2; // thermostat hysteresis [F] if (heating_setpoint <= ROUNDOFF) heating_setpoint = gl_random_uniform(RNGSTATE,68,72); // heating setpoint [F] if (cooling_setpoint <= ROUNDOFF) cooling_setpoint = gl_random_uniform(RNGSTATE,76,80); // cooling setpoint [F] if (window_wall_ratio <= ROUNDOFF) window_wall_ratio = 0.15; // assuming 15% window wall ratio if (glazing_shgc <= ROUNDOFF) glazing_shgc = 0.65; // assuming generic double glazing if (design_cooling_capacity <= ROUNDOFF) design_cooling_capacity = gl_random_uniform(RNGSTATE,18,24); // Btuh/sf if (design_heating_capacity <= ROUNDOFF) design_heating_capacity = gl_random_uniform(RNGSTATE,18,24); // Btuh/sf // initalize/set hvac model parameters if (COP_coeff <= ROUNDOFF) COP_coeff = gl_random_uniform(RNGSTATE,0.9,1.1); // coefficient of cops [scalar] if (Tair <= ROUNDOFF) Tair = gl_random_uniform(RNGSTATE,heating_setpoint+thermostat_deadband, cooling_setpoint-thermostat_deadband); // air temperature [F] if (over_sizing_factor <= ROUNDOFF) over_sizing_factor = gl_random_uniform(RNGSTATE,0.98,1.3); heat_cool_mode = house::OFF; // heating/cooling mode {HEAT, COOL, OFF} if (house_content_heat_transfer_coeff <= ROUNDOFF) house_content_heat_transfer_coeff = gl_random_uniform(RNGSTATE,0.5,1.0)*floor_area; // heat transfer coefficient of house contents [BTU/hr.F] //house properties for HVAC volume = 8*floor_area; // volume of air [cf] air_mass = air_density*volume; // mass of air [lb] air_thermal_mass = air_heat_capacity*air_mass; // thermal mass of air [BTU/F] Tmaterials = Tair; // material temperture [F] hvac_rated_power = 24*floor_area*over_sizing_factor; // rated heating/cooling output [BTU/h] if (set_Eigen_values() == FALSE) return 0; if (hdr->latitude < 24 || hdr->latitude > 48) { /* bind latitudes to [24N, 48N] */ hdr->latitude = hdr->latitude<24 ? 24 : 48; gl_error("Latitude beyond the currently supported range 24 - 48 N, Simulations will continue assuming latitude %.0fN",hdr->latitude); /* TROUBLESHOOT GridLAB-D currently only supports latitudes within a temperate band in the northern hemisphere for the building models. Latitudes outside 24N to 48N may not correctly calculate solar input. */ } // attach the house HVAC to the panel //attach(&load, 50, TRUE); hvac_circuit = attach_enduse_house_a(hdr, &load, 50, TRUE); return 1; }
double clotheswasher::update_state(double dt) { OBJECT *hdr = OBJECTHDR(this); // accumulating units in the queue no matter what happens enduse_queue += enduse_demand * dt/3600/24; switch(state) { case STOPPED: if (enduse_queue>1) clotheswasher_run_prob = double(gl_random_uniform(&hdr->rng_state,queue_min,queue_max)); if (enduse_queue > 1 && (clotheswasher_run_prob > enduse_queue)) { int temp_rand = gl_random_uniform(&hdr->rng_state,0,1); if(temp_rand <= normal_perc){ wash_mode = NORMAL; } else if(temp_rand <= perm_press_perc){ wash_mode = PERM_PRESS; } else{ wash_mode = GENTLE; } switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_PREWASH_ENERGY/NORMAL_PREWASH_POWER); clothesWasherPower = NORMAL_PREWASH_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_PREWASH_ENERGY/PERMPRESS_PREWASH_POWER); clothesWasherPower = PERMPRESS_PREWASH_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_PREWASH_ENERGY/GENTLE_PREWASH_POWER); clothesWasherPower = GENTLE_PREWASH_POWER; break; } state = PREWASH; enduse_queue--; Is_on = 1; new_running_state = true; } break; case PREWASH: if (cycle_time<=0) { state = WASH; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_WASH_ENERGY/NORMAL_WASH_POWER); clothesWasherPower = NORMAL_WASH_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_WASH_ENERGY/PERMPRESS_WASH_POWER); clothesWasherPower = PERMPRESS_WASH_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_WASH_ENERGY/GENTLE_WASH_POWER); clothesWasherPower = GENTLE_WASH_POWER; break; } new_running_state = true; } break; case WASH: if (cycle_time<=0) { state = SPIN1; spin_mode = SPIN_LOW; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_SPIN_LOW_ENERGY/NORMAL_SPIN_LOW_POWER); clothesWasherPower = NORMAL_SPIN_LOW_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_SPIN_LOW_ENERGY/PERMPRESS_SPIN_LOW_POWER); clothesWasherPower = PERMPRESS_SPIN_LOW_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_SPIN_LOW_ENERGY/GENTLE_SPIN_LOW_POWER); clothesWasherPower = GENTLE_SPIN_LOW_POWER; break; } new_running_state = true; } break; case SPIN1: if (cycle_time<=0) { switch(spin_mode){ case SPIN_LOW: spin_mode = SPIN_MEDIUM; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_SPIN_MEDIUM_ENERGY/NORMAL_SPIN_MEDIUM_POWER); clothesWasherPower = NORMAL_SPIN_MEDIUM_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_SPIN_MEDIUM_ENERGY/PERMPRESS_SPIN_MEDIUM_POWER); clothesWasherPower = PERMPRESS_SPIN_MEDIUM_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_SPIN_MEDIUM_ENERGY/GENTLE_SPIN_MEDIUM_POWER); clothesWasherPower = GENTLE_SPIN_MEDIUM_POWER; break; } break; case SPIN_MEDIUM: spin_mode = SPIN_HIGH; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_SPIN_HIGH_ENERGY/NORMAL_SPIN_HIGH_POWER); clothesWasherPower = NORMAL_SPIN_HIGH_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_SPIN_HIGH_ENERGY/PERMPRESS_SPIN_HIGH_POWER); clothesWasherPower = PERMPRESS_SPIN_HIGH_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_SPIN_HIGH_ENERGY/GENTLE_SPIN_HIGH_POWER); clothesWasherPower = GENTLE_SPIN_HIGH_POWER; break; } break; case SPIN_HIGH: spin_mode = SPIN_WASH; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_WASH_ENERGY/NORMAL_WASH_POWER); clothesWasherPower = NORMAL_WASH_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_WASH_ENERGY/PERMPRESS_WASH_POWER); clothesWasherPower = PERMPRESS_WASH_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_WASH_ENERGY/GENTLE_WASH_POWER); clothesWasherPower = GENTLE_WASH_POWER; break; } case SPIN_WASH: state = SPIN2; spin_mode = SPIN_LOW; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_SPIN_LOW_ENERGY/NORMAL_SPIN_LOW_POWER); clothesWasherPower = NORMAL_SPIN_LOW_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_SPIN_LOW_ENERGY/PERMPRESS_SPIN_LOW_POWER); clothesWasherPower = PERMPRESS_SPIN_LOW_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_SPIN_LOW_ENERGY/GENTLE_SPIN_LOW_POWER); clothesWasherPower = GENTLE_SPIN_LOW_POWER; break; } break; } new_running_state = true; } break; case SPIN2: if (cycle_time<=0) { switch(spin_mode){ case SPIN_LOW: spin_mode = SPIN_MEDIUM; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_SPIN_MEDIUM_ENERGY/NORMAL_SPIN_MEDIUM_POWER); clothesWasherPower = NORMAL_SPIN_MEDIUM_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_SPIN_MEDIUM_ENERGY/PERMPRESS_SPIN_MEDIUM_POWER); clothesWasherPower = PERMPRESS_SPIN_MEDIUM_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_SPIN_MEDIUM_ENERGY/GENTLE_SPIN_MEDIUM_POWER); clothesWasherPower = GENTLE_SPIN_MEDIUM_POWER; break; } break; case SPIN_MEDIUM: spin_mode = SPIN_HIGH; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_SPIN_HIGH_ENERGY/NORMAL_SPIN_HIGH_POWER); clothesWasherPower = NORMAL_SPIN_HIGH_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_SPIN_HIGH_ENERGY/PERMPRESS_SPIN_HIGH_POWER); clothesWasherPower = PERMPRESS_SPIN_HIGH_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_SPIN_HIGH_ENERGY/GENTLE_SPIN_HIGH_POWER); clothesWasherPower = GENTLE_SPIN_HIGH_POWER; break; } break; case SPIN_HIGH: spin_mode = SPIN_WASH; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_WASH_ENERGY/NORMAL_WASH_POWER); clothesWasherPower = NORMAL_WASH_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_WASH_ENERGY/PERMPRESS_WASH_POWER); clothesWasherPower = PERMPRESS_WASH_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_WASH_ENERGY/GENTLE_WASH_POWER); clothesWasherPower = GENTLE_WASH_POWER; break; } case SPIN_WASH: state = SPIN3; spin_mode = SPIN_LOW; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_SPIN_LOW_ENERGY/NORMAL_SPIN_LOW_POWER); clothesWasherPower = NORMAL_SPIN_LOW_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_SPIN_LOW_ENERGY/PERMPRESS_SPIN_LOW_POWER); clothesWasherPower = PERMPRESS_SPIN_LOW_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_SPIN_LOW_ENERGY/GENTLE_SPIN_LOW_POWER); clothesWasherPower = GENTLE_SPIN_LOW_POWER; break; } break; } new_running_state = true; } break; case SPIN3: if (cycle_time<=0) { switch(spin_mode){ case SPIN_LOW: spin_mode = SPIN_MEDIUM; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_SPIN_MEDIUM_ENERGY/NORMAL_SPIN_MEDIUM_POWER); clothesWasherPower = NORMAL_SPIN_MEDIUM_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_SPIN_MEDIUM_ENERGY/PERMPRESS_SPIN_MEDIUM_POWER); clothesWasherPower = PERMPRESS_SPIN_MEDIUM_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_SPIN_MEDIUM_ENERGY/GENTLE_SPIN_MEDIUM_POWER); clothesWasherPower = GENTLE_SPIN_MEDIUM_POWER; break; } break; case SPIN_MEDIUM: spin_mode = SMALLWASH; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_SMALLWASH_ENERGY/NORMAL_SMALLWASH_POWER); clothesWasherPower = NORMAL_SMALLWASH_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_SMALLWASH_ENERGY/PERMPRESS_SMALLWASH_POWER); clothesWasherPower = PERMPRESS_SMALLWASH_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_SMALLWASH_ENERGY/GENTLE_SMALLWASH_POWER); clothesWasherPower = GENTLE_SMALLWASH_POWER; break; } break; case SMALLWASH: state = SPIN4; spin_mode = SPIN_LOW; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_SPIN_LOW_ENERGY/NORMAL_SPIN_LOW_POWER); clothesWasherPower = NORMAL_SPIN_LOW_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_SPIN_LOW_ENERGY/PERMPRESS_SPIN_LOW_POWER); clothesWasherPower = PERMPRESS_SPIN_LOW_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_SPIN_LOW_ENERGY/GENTLE_SPIN_LOW_POWER); clothesWasherPower = GENTLE_SPIN_LOW_POWER; break; } break; } } break; case SPIN4: if (cycle_time<=0) { switch(spin_mode){ case SPIN_LOW: spin_mode = SPIN_MEDIUM; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_SPIN_MEDIUM_ENERGY/NORMAL_SPIN_MEDIUM_POWER); clothesWasherPower = NORMAL_SPIN_MEDIUM_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_SPIN_MEDIUM_ENERGY/PERMPRESS_SPIN_MEDIUM_POWER); clothesWasherPower = PERMPRESS_SPIN_MEDIUM_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_SPIN_MEDIUM_ENERGY/GENTLE_SPIN_MEDIUM_POWER); clothesWasherPower = GENTLE_SPIN_MEDIUM_POWER; break; } break; case SPIN_MEDIUM: spin_mode = SPIN_HIGH; //Longer high cycle, hence multiplication by 3 switch(wash_mode){ case NORMAL: cycle_time = ceil((NORMAL_SPIN_HIGH_ENERGY*3)/NORMAL_SPIN_HIGH_POWER); clothesWasherPower = NORMAL_SPIN_HIGH_POWER; break; case PERM_PRESS: cycle_time = ceil((PERMPRESS_SPIN_HIGH_ENERGY*3)/PERMPRESS_SPIN_HIGH_POWER); clothesWasherPower = PERMPRESS_SPIN_HIGH_POWER; break; case GENTLE: cycle_time = ceil((GENTLE_SPIN_HIGH_ENERGY*3)/GENTLE_SPIN_HIGH_POWER); clothesWasherPower = GENTLE_SPIN_HIGH_POWER; break; } break; case SPIN_HIGH: spin_mode = SMALLWASH; switch(wash_mode){ case NORMAL: cycle_time = ceil(NORMAL_SMALLWASH_ENERGY/NORMAL_SMALLWASH_POWER); clothesWasherPower = NORMAL_SMALLWASH_POWER; break; case PERM_PRESS: cycle_time = ceil(PERMPRESS_SMALLWASH_ENERGY/PERMPRESS_SMALLWASH_POWER); clothesWasherPower = PERMPRESS_SMALLWASH_POWER; break; case GENTLE: cycle_time = ceil(GENTLE_SMALLWASH_ENERGY/GENTLE_SMALLWASH_POWER); clothesWasherPower = GENTLE_SMALLWASH_POWER; break; } break; case SMALLWASH: state = STOPPED; cycle_time = 0; clothesWasherPower = 0; Is_on = 0; break; } new_running_state = true; } break; } if(state==STOPPED){ // nothing running load.power = load.current = load.admittance = complex(0,0,J); // time to next expected state change //dt = (enduse_demand<=0) ? -1 : dt = 3600/enduse_demand; if(0==enduse_demand){ if(true==starttime){ dt=0; } else{ dt = 3600; } } else{ dt = (enduse_queue>=1) ? 0 : ((1-enduse_queue)*3600)/(enduse_demand*24); } } else{ if(new_running_state == true){ new_running_state = false; cycle_time = cycle_time-1; } else{ cycle_time -=dt; } load.power = complex(clothesWasherPower/1000,0,J); load.current = 0; load.admittance =0; dt = cycle_time; } // compute the total electrical load load.total = load.power; if (dt > 0 && dt < 1) dt = 1; return dt; }
double range::update_state(double dt1,TIMESTAMP t1) { OBJECT *hdr = OBJECTHDR(this); cooktop_energy_used += total_power_cooktop* dt1/3600; switch(state_cooktop) { case CT_STOPPED: if (enduse_queue_cooktop>1) cooktop_run_prob = double(gl_random_uniform(&hdr->rng_state,queue_min,queue_max)); if (enduse_queue_cooktop > 1 && (cooktop_run_prob > enduse_queue_cooktop)) { state_cooktop = CT_STAGE_1_ONLY; cooktop_energy_needed = cooktop_energy_baseline; cycle_duration_cooktop = 1000 * (cooktop_energy_needed - cooktop_energy_used) /cooktop_coil_power[0] * 60 * 60; cycle_time_cooktop = cooktop_interval[0]; cooktop_check = true; enduse_queue_cooktop--; } else { state_cooktop = CT_STOPPED; state_time = 0; cycle_time_cooktop = 0; cooktop_energy_used = 0; cooktop_check = false; //enduse_queue_cooktop--; } break; case CT_STAGE_1_ONLY: if (cooktop_energy_used >= cooktop_energy_needed || time_cooktop_operation >= time_cooktop_setting || cycle_time_cooktop <= 0) { if (cooktop_energy_used >= cooktop_energy_needed || time_cooktop_operation >= time_cooktop_setting) { // The dishes are clean state_cooktop = CT_STOPPED; cycle_time_cooktop = 0; cooktop_energy_used = 0; cooktop_check = false; } else if (cycle_time_cooktop <= 0) { state_cooktop = CT_STAGE_2_ONLY; double cycle_t = 1000 * (cooktop_energy_needed - cooktop_energy_used) / cooktop_coil_power[2] * 60 * 60; double interval = cooktop_interval[1]; cooktop_check = true; if (cycle_t > interval) cycle_time_cooktop = interval; else cycle_time_cooktop = cycle_t; } else if (pCircuit->pV->Mag()<stall_voltage) { state_cooktop = CT_STALLED; state_time = 0; } } break; case CT_STAGE_2_ONLY: if (cooktop_energy_used >= cooktop_energy_needed || time_cooktop_operation >= time_cooktop_setting || cycle_time_cooktop <= 0) { if (cooktop_energy_used >= cooktop_energy_needed || time_cooktop_operation >= time_cooktop_setting) { state_cooktop = CT_STOPPED; cycle_time_cooktop = 0; cooktop_energy_used = 0; cooktop_check = false; } else if (cycle_time_cooktop <= 0) { state_cooktop = CT_STAGE_3_ONLY; cooktop_check = true; cycle_time_cooktop = time_cooktop_setting - cooktop_interval[0] - cooktop_interval[1]; } else if (pCircuit->pV->Mag()<stall_voltage) { state_cooktop = CT_STALLED; state_time = 0; } } break; case CT_STAGE_3_ONLY: if (cooktop_energy_used >= cooktop_energy_needed || cycle_time_cooktop <= 0) { // The dishes are clean state_cooktop = CT_STOPPED; cycle_time_cooktop = 0; cooktop_energy_used = 0; cooktop_check = false; } else if (pCircuit->pV->Mag()<stall_voltage) { state_cooktop = CT_STALLED; state_time = 0; } break; case CT_STALLED: if (pCircuit->pV->Mag()>start_voltage) { state_cooktop = CT_STAGE_1_ONLY; state_time = cycle_time_cooktop; cooktop_check = false; } break; case CT_TRIPPED: if (state_time>reset_delay) { if (pCircuit->pV->Mag()>start_voltage) state_cooktop = CT_STAGE_1_ONLY; else state_cooktop = CT_STALLED; state_time = 0; } break; } // advance the state_time state_time += dt1; // accumulating units in the queue no matter what happens // enduse_queue_oven += enduse_demand_oven * dt/3600/24; enduse_queue_cooktop += enduse_demand_cooktop * dt1/3600/24; if (cooktop_check == true) time_cooktop_operation += 1; else time_cooktop_operation = 0; // now implement current state switch(state_cooktop) { case CT_STOPPED: // nothing running load.power = load.current = load.admittance = complex(0,0,J); // time to next expected state_cooktop change //dt = (enduse_demand_cooktop<=0) ? -1 : dt = 3600/enduse_demand_cooktop; dt1 = (enduse_queue_cooktop>=1) ? 0 : ((1-enduse_queue_cooktop)*3600)/(enduse_queue_cooktop*24); break; case CT_STAGE_1_ONLY: //motor_on_off = motor_coil_on_off = both_coils_on_off = 1; cycle_time_cooktop -= dt1; load.power = load.current = complex(0,0,J); load.admittance = complex((cooktop_coil_power[0])/1000,0,J); dt1 = cycle_time_cooktop; break; case CT_STAGE_2_ONLY: //motor_on_off = motor_coil_on_off = both_coils_on_off = 1; cycle_time_cooktop -= dt1; load.power = load.current = complex(0,0,J); load.admittance = complex((cooktop_coil_power[1])/1000,0,J); dt1 = cycle_time_cooktop; break; case CT_STAGE_3_ONLY: //motor_on_off = motor_coil_on_off = both_coils_on_off = 1; cycle_time_cooktop -= dt1; load.power = load.current = complex(0,0,J); load.admittance = complex((cooktop_coil_power[2])/1000,0,J); dt1 = cycle_time_cooktop; break; case CT_STALLED: // running in constant impedance mode load.power = load.current = complex(0,0,J); load.admittance = complex(1)/stall_impedance; // time to trip dt1 = trip_delay; break; case CT_TRIPPED: // nothing running load.power = load.current = load.admittance = complex(0,0,J); // time to next expected state change dt1 = reset_delay; break; default: throw "unexpected motor state"; /* TROUBLESHOOT This is an error. Please submit a bug report along with at the range object & class sections from the relevant GLM file, and from the dump file. */ break; } load.total += load.power + load.current + load.admittance; total_power_cooktop = (load.power.Re() + (load.current.Re() + load.admittance.Re()*load.voltage_factor)*load.voltage_factor)*1000; //End of cook top //total_power_range = total_power_cooktop + total_power_oven; // compute the total heat gain load.heatgain = load.total.Mag() * heat_fraction; if (dt1 > 0 && dt1 < 1) dt1 = 1; return dt1; }
TIMESTAMP controller::sync(TIMESTAMP t0, TIMESTAMP t1){ double bid = -1.0; int64 no_bid = 0; // flag gets set when the current temperature drops in between the the heating setpoint and cooling setpoint curves double demand = 0.0; double rampify = 0.0; extern double bid_offset; OBJECT *hdr = OBJECTHDR(this); /* short circuit if the state variable doesn't change during the specified interval */ if((t1 < next_run) && (market->market_id == lastmkt_id)){ if(t1 == next_run - bid_delay){ ; // continue } else { if (pState == 0) return next_run; else if (*pState == last_pState) return next_run; } } if(control_mode == CN_RAMP){ // if market has updated, continue onwards if(market->market_id != lastmkt_id){// && (*pAvg == 0.0 || *pStd == 0.0 || setpoint0 == 0.0)){ double clear_price; lastmkt_id = market->market_id; lastbid_id = -1; // clear last bid id, refers to an old market // update using last price // T_set,a = T_set + (P_clear - P_avg) * | T_lim - T_set | / (k_T * stdev24) clear_price = market->current_frame.clearing_price; if(fabs(*pStd) < bid_offset){ set_temp = setpoint0; } else if(clear_price < *pAvg && range_low != 0){ set_temp = setpoint0 + (clear_price - *pAvg) * fabs(range_low) / (ramp_low * *pStd); } else if(clear_price > *pAvg && range_high != 0){ set_temp = setpoint0 + (clear_price - *pAvg) * fabs(range_high) / (ramp_high * *pStd); } else { set_temp = setpoint0; } if((use_override == OU_ON) && (pOverride != 0)){ if(clear_price <= last_p){ // if we're willing to pay as much as, or for more than the offered price, then run. *pOverride = 1; } else { *pOverride = -1; } } // clip if(set_temp > max){ set_temp = max; } else if(set_temp < min){ set_temp = min; } *pSetpoint = set_temp; //gl_verbose("controller::postsync(): temp %f given p %f vs avg %f",set_temp, market->next.price, market->avg24); } if(dir > 0){ if(*pMonitor > max){ bid = 9999.0; } else if (*pMonitor < min){ bid = 0.0; no_bid = 1; } } else if(dir < 0){ if(*pMonitor < min){ bid = 9999.0; } else if(*pMonitor > max){ bid = 0.0; no_bid = 1; } } else if(dir == 0){ if(*pMonitor < min){ bid = 9999.0; } else if(*pMonitor > max){ bid = 0.0; no_bid = 1; } else { bid = *pAvg; // override due to lack of "real" curve } } // calculate bid price if(*pMonitor > setpoint0){ k_T = ramp_high; T_lim = range_high; } else if(*pMonitor < setpoint0) { k_T = ramp_low; T_lim = range_low; } else { k_T = 0.0; T_lim = 0.0; } if(bid < 0.0 && *pMonitor != setpoint0) { bid = *pAvg + ( (fabs(*pStd) < bid_offset) ? 0.0 : (*pMonitor - setpoint0) * (k_T * *pStd) / fabs(T_lim) ); } else if(*pMonitor == setpoint0) { bid = *pAvg; } // bid the response part of the load double residual = *pTotal; /* WARNING ~ bid ID check will not work properly */ KEY bid_id = (KEY)(lastmkt_id == market->market_id ? lastbid_id : -1); // override //bid_id = -1; if(*pDemand > 0 && no_bid != 1){ last_p = bid; last_q = *pDemand; if(0 != strcmp(market->unit, "")){ if(0 == gl_convert("kW", market->unit, &(last_q))){ gl_error("unable to convert bid units from 'kW' to '%s'", market->unit); return TS_INVALID; } } //lastbid_id = market->submit(OBJECTHDR(this), -last_q, last_p, bid_id, (BIDDERSTATE)(pState != 0 ? *pState : 0)); if(pState != 0){ lastbid_id = submit_bid_state(pMarket, hdr, -last_q, last_p, (*pState > 0 ? 1 : 0), bid_id); } else { lastbid_id = submit_bid(pMarket, hdr, -last_q, last_p, bid_id); } residual -= *pLoad; } else { last_p = 0; last_q = 0; gl_verbose("%s's is not bidding", hdr->name); } if(residual < -0.001) gl_warning("controller:%d: residual unresponsive load is negative! (%.1f kW)", hdr->id, residual); } else if (control_mode == CN_DOUBLE_RAMP){ /* double heat_range_high; double heat_range_low; double heat_ramp_high; double heat_ramp_low; double cool_range_high; double cool_range_low; double cool_ramp_high; double cool_ramp_low; */ DATETIME t_next; gl_localtime(t1,&t_next); // find crossover double midpoint = 0.0; if(cool_min - heat_max < *pDeadband){ switch(resolve_mode){ case RM_DEADBAND: midpoint = (heat_max + cool_min) / 2; if(midpoint - *pDeadband/2 < heating_setpoint0 || midpoint + *pDeadband/2 > cooling_setpoint0) { gl_error("The midpoint between the max heating setpoint and the min cooling setpoint must be half a deadband away from each base setpoint"); return TS_INVALID; } else { heat_max = midpoint - *pDeadband/2; cool_min = midpoint + *pDeadband/2; } break; case RM_SLIDING: if(heat_max > cooling_setpoint0 - *pDeadband) { gl_error("the max heating setpoint must be a full deadband less than the cooling_base_setpoint"); return TS_INVALID; } if(cool_min < heating_setpoint0 + *pDeadband) { gl_error("The min cooling setpoint must be a full deadband greater than the heating_base_setpoint"); return TS_INVALID; } if(last_mode == TM_OFF || last_mode == TM_COOL){ heat_max = cool_min - *pDeadband; } else if (last_mode == TM_HEAT){ cool_min = heat_max + *pDeadband; } break; default: gl_error("unrecognized resolve_mode when double_ramp overlap resolution is needed"); break; } } // if the market has updated, if(lastmkt_id != market->market_id){ lastmkt_id = market->market_id; lastbid_id = -1; // retrieve cleared price double clear_price; clear_price = market->current_frame.clearing_price; if(clear_price == last_p){ // determine what to do at the marginal price switch(market->clearing_type){ case CT_SELLER: // may need to curtail break; case CT_PRICE: // should not occur case CT_NULL: // q zero or logic error ~ should not occur // occurs during the zero-eth market. //gl_warning("clearing price and bid price are equal with a market clearing type that involves inequal prices"); break; default: break; } } may_run = 1; // calculate setpoints if(fabs(*pStd) < bid_offset){ *pCoolingSetpoint = cooling_setpoint0; *pHeatingSetpoint = heating_setpoint0; } else { if(clear_price > *pAvg){ *pCoolingSetpoint = cooling_setpoint0 + (clear_price - *pAvg) * fabs(cool_range_high) / (cool_ramp_high * *pStd); //*pHeatingSetpoint = heating_setpoint0 + (clear_price - *pAvg) * fabs(heat_range_high) / (heat_ramp_high * *pStd); *pHeatingSetpoint = heating_setpoint0 + (clear_price - *pAvg) * fabs(heat_range_low) / (heat_ramp_low * *pStd); } else if(clear_price < *pAvg){ *pCoolingSetpoint = cooling_setpoint0 + (clear_price - *pAvg) * fabs(cool_range_low) / (cool_ramp_low * *pStd); //*pHeatingSetpoint = heating_setpoint0 + (clear_price - *pAvg) * fabs(heat_range_low) / (heat_ramp_low * *pStd); *pHeatingSetpoint = heating_setpoint0 + (clear_price - *pAvg) * fabs(heat_range_high) / (heat_ramp_high * *pStd); } else { *pCoolingSetpoint = cooling_setpoint0; *pHeatingSetpoint = heating_setpoint0; } } // apply overrides if((use_override == OU_ON)){ if(last_q != 0.0){ if(clear_price == last_p && clear_price != market->pricecap){ if(market->margin_mode == AM_DENY){ *pOverride = -1; } else if(market->margin_mode == AM_PROB){ double r = gl_random_uniform(0, 1.0); if(r < market->current_frame.marginal_frac){ *pOverride = 1; } else { *pOverride = -1; } } } else if(market->current_frame.clearing_price <= last_p){ *pOverride = 1; } else { *pOverride = -1; } } else { // equality *pOverride = 0; // 'normal operation' } } //clip if(*pCoolingSetpoint > cool_max) *pCoolingSetpoint = cool_max; if(*pCoolingSetpoint < cool_min) *pCoolingSetpoint = cool_min; if(*pHeatingSetpoint > heat_max) *pHeatingSetpoint = heat_max; if(*pHeatingSetpoint < heat_min) *pHeatingSetpoint = heat_min; lastmkt_id = market->market_id; } // submit bids double previous_q = last_q; //store the last value, in case we need it last_p = 0.0; last_q = 0.0; // We have to cool if(*pMonitor > cool_max){ last_p = market->pricecap; last_q = *pCoolingDemand; } // We have to heat else if(*pMonitor < heat_min){ last_p = market->pricecap; last_q = *pHeatingDemand; } // We're floating in between heating and cooling else if(*pMonitor > heat_max && *pMonitor < cool_min){ last_p = 0.0; last_q = 0.0; } // We might heat, if the price is right else if(*pMonitor <= heat_max && *pMonitor >= heat_min){ double ramp, range; ramp = (*pMonitor > heating_setpoint0 ? heat_ramp_high : heat_ramp_low); range = (*pMonitor > heating_setpoint0 ? heat_range_high : heat_range_low); if(*pMonitor != cooling_setpoint0){ last_p = *pAvg + ( (fabs(*pStd) < bid_offset) ? 0.0 : (*pMonitor - heating_setpoint0) * ramp * (*pStd) / fabs(range) ); } else { last_p = *pAvg; } last_q = *pHeatingDemand; } // We might cool, if the price is right else if(*pMonitor <= cool_max && *pMonitor >= cool_min){ double ramp, range; ramp = (*pMonitor > cooling_setpoint0 ? cool_ramp_high : cool_ramp_low); range = (*pMonitor > cooling_setpoint0 ? cool_range_high : cool_range_low); if(*pMonitor != cooling_setpoint0){ last_p = *pAvg + ( (fabs(*pStd) < bid_offset) ? 0 : (*pMonitor - cooling_setpoint0) * ramp * (*pStd) / fabs(range) ); } else { last_p = *pAvg; } last_q = *pCoolingDemand; } if(last_p > market->pricecap) last_p = market->pricecap; if(last_p < -market->pricecap) last_p = -market->pricecap; if(0 != strcmp(market->unit, "")){ if(0 == gl_convert("kW", market->unit, &(last_q))){ gl_error("unable to convert bid units from 'kW' to '%s'", market->unit); return TS_INVALID; } } if(last_q > 0.001){ if (pState != 0 ) { KEY bid = (KEY)(lastmkt_id == market->market_id ? lastbid_id : -1); lastbid_id = submit_bid_state(this->pMarket, OBJECTHDR(this), -last_q, last_p, (*pState > 0 ? 1 : 0), bid); } else { KEY bid = (KEY)(lastmkt_id == market->market_id ? lastbid_id : -1); lastbid_id = submit_bid(this->pMarket, OBJECTHDR(this), -last_q, last_p, bid); } } else { if (last_pState != *pState) { KEY bid = (KEY)(lastmkt_id == market->market_id ? lastbid_id : -1); double my_bid = -market->pricecap; if (*pState != 0) my_bid = last_p; lastbid_id = submit_bid_state(this->pMarket, OBJECTHDR(this), -last_q, my_bid, (*pState > 0 ? 1 : 0), bid); } } } if (pState != 0) last_pState = *pState; char timebuf[128]; gl_printtime(t1,timebuf,127); //gl_verbose("controller:%i::sync(): bid $%f for %f kW at %s",hdr->id,last_p,last_q,timebuf); //return postsync(t0, t1); return TS_NEVER; }
double dryer::update_state(double dt) //,TIMESTAMP t1) { OBJECT *hdr = OBJECTHDR(this); // accumulate the energy energy_used += total_power/1000 * dt/3600; switch(state) { case DRYER_STOPPED: if (enduse_queue>1)// && dryer_on == true) dryer_run_prob = double(gl_random_uniform(&hdr->rng_state,queue_min,queue_max)); if (enduse_queue > 1 && (dryer_run_prob > enduse_queue)) { state = DRYER_CONTROL_ONLY; energy_needed = energy_baseline; cycle_duration = cycle_time = 1000 * (energy_needed - energy_used) / controls_power * 60 * 60; cycle_time = pulse_interval[0]; //cycle_duration_dryer = pulse_interval[0]; enduse_queue--; new_running_state = true; } else if (pCircuit->pV->Mag()<stall_voltage) { state = DRYER_STALLED; state_time = 0; } break; case DRYER_CONTROL_ONLY: if (energy_used >= energy_needed && cycle_time <= 0) { // The clothes are dry state = DRYER_STOPPED; cycle_time = 0; energy_used = 0; control_check = false; motor_coil_only_check1 = false; motor_coil_only_check2 = false; motor_coil_only_check3 = false; motor_coil_only_check4 = false; motor_coil_only_check5 = false; motor_coil_only_check6 = false; motor_only_check1 = false; motor_only_check2 = false; motor_only_check3 = false; motor_only_check4 = false; motor_only_check5 = false; motor_only_check6 = false; new_running_state = true; } else if (cycle_time<=0 && control_check == false)//one-over { state = DRYER_MOTOR_COIL_ONLY;; double cycle_t = 1000 * (energy_needed - energy_used) / (motor_power + coil_power[0]) * 60 * 60; double interval = pulse_interval[1]; control_check = true; motor_coil_only_check1 = true; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; new_running_state = true; } else if (pCircuit->pV->Mag()<stall_voltage) { state = DRYER_STALLED; state_time = 0; } break; case DRYER_MOTOR_COIL_ONLY: if (energy_used >= energy_needed && cycle_time <= 0) { // The clothes are dry state = DRYER_STOPPED; cycle_time = 0; energy_used = 0; control_check = false; motor_coil_only_check1 = false; motor_coil_only_check2 = false; motor_coil_only_check3 = false; motor_coil_only_check4 = false; motor_coil_only_check5 = false; motor_coil_only_check6 = false; motor_only_check1 = false; motor_only_check2 = false; motor_only_check3 = false; motor_only_check4 = false; motor_only_check5 = false; motor_only_check6 = false; new_running_state = true; } else if (cycle_time<=0 && motor_coil_only_check1 == true)//one-over { state = DRYER_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; double interval = pulse_interval[0]; motor_coil_only_check1 = false; motor_coil_only_check2 = true; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; new_running_state = true; } else if (cycle_time<=0 && motor_coil_only_check2 == true)//two-over { state = DRYER_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; double interval = pulse_interval[3]; motor_coil_only_check2 = false; motor_coil_only_check3 = true; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; new_running_state = true; } else if (cycle_time<=0 && motor_coil_only_check3 == true)//three-over { state = DRYER_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; double interval = pulse_interval[3]; motor_coil_only_check3 = false; motor_coil_only_check4 = true; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; new_running_state = true; } else if (cycle_time<=0 && motor_coil_only_check4 == true)//four-over { state = DRYER_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; double interval = pulse_interval[3]; motor_coil_only_check4 = false; motor_coil_only_check5 = true; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; new_running_state = true; } else if (cycle_time<=0 && motor_coil_only_check5 == true)//five-over { state = DRYER_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; double interval = pulse_interval[5]; motor_coil_only_check5 = false; motor_coil_only_check6 = true; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; new_running_state = true; } else if (cycle_time<=0 && motor_coil_only_check6 == true)//five-over { state = DRYER_MOTOR_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / motor_power * 60 * 60; motor_only_check6 = false; new_running_state = true; /* if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; */ } else if (pCircuit->pV->Mag()<stall_voltage) { state = DRYER_STALLED; state_time = 0; } break; case DRYER_MOTOR_ONLY: if (energy_used >= energy_needed) { // The clothes are dry state = DRYER_STOPPED; cycle_time = 0; energy_used = 0; control_check = false; motor_coil_only_check1 = false; motor_coil_only_check2 = false; motor_coil_only_check3 = false; motor_coil_only_check4 = false; motor_coil_only_check5 = false; motor_coil_only_check6 = false; motor_only_check1 = false; motor_only_check2 = false; motor_only_check3 = false; motor_only_check4 = false; motor_only_check5 = false; motor_only_check6 = false; new_running_state = true; } else if (cycle_time<=0 && motor_only_check1 == false)//one-over { state = DRYER_MOTOR_COIL_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / (motor_power + coil_power[0]) * 60 * 60; double interval = pulse_interval[2]; motor_only_check1 = true; motor_only_check2 = true; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; new_running_state = true; } else if (cycle_time<=0 && motor_only_check2 == true)//two-over { state = DRYER_MOTOR_COIL_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / (motor_power + coil_power[0]) * 60 * 60; double interval = pulse_interval[4]; motor_only_check2 = false; motor_only_check3 = true; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; new_running_state = true; } else if (cycle_time<=0 && motor_only_check3 == true)//three-over { state = DRYER_MOTOR_COIL_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / (motor_power + coil_power[0]) * 60 * 60; double interval = pulse_interval[4]; motor_only_check3 = false; motor_only_check4 = true; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; new_running_state = true; } else if (cycle_time<=0 && motor_only_check4 == true)//four-over { state = DRYER_MOTOR_COIL_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / (motor_power + coil_power[0]) * 60 * 60; double interval = pulse_interval[4]; motor_only_check4 = false; motor_only_check5 = true; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; new_running_state = true; } else if (cycle_time<=0 && motor_only_check5 == true)//five-over { state = DRYER_MOTOR_COIL_ONLY; double cycle_t = 1000 * (energy_needed - energy_used) / (motor_power + coil_power[0]) * 60 * 60; double interval = pulse_interval[6]; motor_only_check5 = false; if (cycle_t > interval) cycle_time = interval; else cycle_time = cycle_t; new_running_state = true; } else if (pCircuit->pV->Mag()<stall_voltage) { state = DRYER_STALLED; state_time = 0; } break; case DRYER_STALLED: if (pCircuit->pV->Mag()>start_voltage) { state = DRYER_MOTOR_ONLY; state_time = cycle_time; } else if (state_time>trip_delay) { state = DRYER_TRIPPED; state_time = 0; } break; case DRYER_TRIPPED: if (state_time>reset_delay) { if (pCircuit->pV->Mag()>start_voltage) state = DRYER_MOTOR_ONLY; else state = DRYER_STALLED; state_time = 0; } break; } // accumulating units in the queue no matter what happens if (dryer_on == true) { enduse_queue += daily_dryer_demand * dt/24; } actual_dryer_demand = actual_dryer_demand + daily_dryer_demand; // now implement current state switch(state) { case DRYER_STOPPED: motor_on_off = motor_coil_on_off = 0; // nothing running load.power = load.current = load.admittance = complex(0,0,J); dt = ((enduse_queue>=1) || (enduse_queue==0)) ? 0 : ((1-enduse_queue)*3600)/(enduse_queue*24); break; case DRYER_MOTOR_COIL_ONLY: motor_on_off = motor_coil_on_off = 1; cycle_time -= dt; // running in constant power mode with intermittent coil load.power.SetPowerFactor(motor_power/1000, load.power_factor); load.admittance = complex((coil_power[0])/1000,0,J); //assume pure resistance load.current = complex(0,0,J); dt = cycle_time; break; case DRYER_CONTROL_ONLY: if(true==new_running_state){ new_running_state = false; } else{ cycle_time -= dt; } // running in constant power mode with intermittent coil load.power = load.current = complex(0,0,J); load.admittance = complex(controls_power/1000,0,J); dt = cycle_time; break; case DRYER_STALLED: // running in constant impedance mode load.power = load.current = complex(0,0,J); load.admittance = complex(1)/stall_impedance; // time to trip dt = trip_delay; break; case DRYER_TRIPPED: // nothing running load.power = load.current = load.admittance = complex(0,0,J); // time to next expected state change dt = reset_delay; break; case DRYER_MOTOR_ONLY: motor_on_off = 1; cycle_time -= dt; // running in constant power mode with intermittent coil load.power.SetPowerFactor(motor_power/1000, load.power_factor); load.admittance = complex(0,0,J); //assume pure resistance load.current = complex(0,0,J); dt = cycle_time; break; default: throw "unexpected motor state"; /* TROUBLESHOOT This is an error. Please submit a bug report along with at the dryer object & class sections from the relevant GLM file, and from the dump file. */ break; } // compute the total electrical load - first for the enduse structure and second for an internal variable load.total = load.power + load.current + load.admittance; total_power = (load.power.Re() + (load.current.Re() + load.admittance.Re()*load.voltage_factor)*load.voltage_factor) * 1000; // compute the total heat gain load.heatgain = load.total.Mag() * heat_fraction; if (dt > 0 && dt < 1) dt = 1; return dt; }