void substation::fetch_double(double **prop, char *name, OBJECT *parent){ OBJECT *hdr = OBJECTHDR(this); *prop = gl_get_double_by_name(parent, name); if(*prop == NULL){ char tname[32]; char *namestr = (hdr->name ? hdr->name : tname); char msg[256]; sprintf(tname, "substation:%i", hdr->id); if(*name == NULL) sprintf(msg, "%s: substation unable to find property: name is NULL", namestr); else sprintf(msg, "%s: substation unable to find %s", namestr, name); throw(msg); } }
/** 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); }
TIMESTAMP ZIPload::sync(TIMESTAMP t0, TIMESTAMP t1) { TIMESTAMP t2 = TS_NEVER; double real_power = 0.0; double imag_power = 0.0; double angleval; double test = multiplier; if(first_time==0) { first_time=t1; } if(gl_todays(t1)-gl_todays(first_time)==1) { first_time=2; } if(soil_sensor!=NULL){ double *humidity2=gl_get_double_by_name(soil_sensor,"humidity"); humidity=*humidity2; } if(first_time==2) { if( irrigation_contr_object!=NULL) { if(actual_power>0) { //mpila mia fora gl_set_value_by_name(irrigation_contr_object,"insync","2"); actual_power_non_zero=actual_power.Re(); //system("pause"); } insync=gl_get_int16_by_name(irrigation_contr_object,"insync"); test3=gl_get_int16_by_name(irrigation_contr_object,"test"); if(*test3==1) { // printf("ewdw"); // system("pause"); base_power=prev_base_power; } clear_price=gl_get_double_by_name(auction_object,"current_market.clearing_price"); clear_quantity=gl_get_double_by_name(auction_object,"current_market.seller_total_quantity"); bid_price=gl_get_double_by_name(irrigation_contr_object,"bid_price"); bid_q=gl_get_double_by_name(irrigation_contr_object,"bid_quantity"); /* if(*bid_price>=*clear_price && (*bid_q)*3>=*clear_quantity)// && last_q<market->past_frame.clearing_quantity) { ///printf(" den "); base_power=prev_base_power; //printf("%f ----------------------------------",base_power); /// base_power=0; } else { base_power=0; }*/ } } /////////////////////////////////////////////////////////////////////////////////// if(choose_load==0) { // printf("den anrebazw nero \n"); //system("pause"); // actual_power=0; } if(choose_load==1) { if (demand_response_mode == true && next_time <= t1) { double dNon,dNoff; double hold_off; N_on = N_off = 0; for (int jj=0; jj<L; jj++) { //previous_drm.on[jj] = drm.on[jj]; //previous_drm.off[jj] = drm.off[jj]; if (eta > 0) { if (jj != (L-1)) dNon = -ron * drm.on[jj] + eta * drm.off[jj] + ron * drm.on[jj+1]; else dNon = -ron * drm.on[jj] + (1 - eta) * drm.off[jj] * roff + eta * drm.off[jj]; if (jj != 0) dNoff = -(1 - eta) * drm.off[jj] * roff - eta * drm.off[jj] + (1 - eta) * hold_off * roff; else dNoff = -(1 - eta) * drm.off[jj] * roff - eta * drm.off[jj] + ron * drm.on[jj]; } else { if (jj != (L-1)) dNon = -ron * (1 + eta) * drm.on[jj] + eta * drm.on[jj] + ron * (1 + eta) * drm.on[jj+1]; else dNon = -ron * (1 + eta) * drm.on[jj] + eta * drm.on[jj] + roff * drm.off[jj]; if (jj != 0) dNoff = -roff * drm.off[jj] - eta * drm.on[jj] + hold_off * roff; else dNoff = -roff * drm.off[jj] - eta * drm.on[jj] + ron * (1 + eta) * drm.on[jj]; } hold_off = drm.off[jj]; drm.on[jj] = drm.on[jj] + dNon; N_on += drm.on[jj]; drm.off[jj] = drm.off[jj] + dNoff; } N_off = N - N_on; phi = roff / (ron + roff); nominal_power = base_power * N_on / N; double R = ron; int dt = 0; if (ron < roff) R = roff; dt = int(1/R * 3600); next_time = t1 + dt; } // We're in duty cycle mode if (duty_cycle != -1) { double phase_shift = 0; if (first_pass == 0) // after first time step { phase_shift = (t1 - last_time) / (period * 3600); phase = phase + phase_shift; last_time = t1; } else first_pass = 0; last_time = t1; if (this->re_override == OV_NORMAL) // Normal operation { if (phase >= 1) phase = 0; // Track the time of 2 transistions if (t1 >= next_time || last_duty_cycle != duty_cycle) { if (duty_cycle > phase) // OFF->ON { multiplier = 1; next_time = t1 + (period * 3600) * (duty_cycle - phase) + 1; // +1 a bit of an offset for rounding } else // ON->OFF { multiplier = 0; next_time = t1 + (period * 3600) * (1 - phase) + 1; } } last_duty_cycle = duty_cycle; } else if (this->re_override == OV_OFF) // After release or recovery time { if (phase <= 1 && t1>=next_time) { this->re_override = OV_NORMAL; next_time = t1; } else if (t1 >= next_time || next_time == TS_NEVER) // we just came from override ON { if (recovery_duty_cycle > fmod(phase,1)) // OFF->ON { multiplier = 1; next_time = t1 + (period * 3600) * (recovery_duty_cycle - fmod(phase,1)) + 1; // +1 a bit of an offset for rounding if (duty_cycle != 0.0) phase -= 1 * recovery_duty_cycle / duty_cycle * (1 - fmod(phase,1)); // Track everything by the original duty cycle else phase = 0; //Start over /*if (phase < 0) { next_time = t1 + (period * 3600) * (recovery_duty_cycle - 0) + 1; phase = 0; }*/ } else // ON->OFF { //if (multiplier == 1) // we just transitioned //{ //if (phase >= 1 * recovery_duty_cycle / duty_cycle) // phase -= 1 * recovery_duty_cycle / duty_cycle; // Track everything by the original duty cycle //else if (phase < 1) // this->re_override = OV_NORMAL; //} multiplier = 0; next_time = t1 + (period * 3600) * (1 - fmod(phase,1)) + 1; } } last_duty_cycle = duty_cycle; } else // override is ON, so no power { if (multiplier == 1 && duty_cycle > phase) { // do nothing last_duty_cycle = duty_cycle; } else { multiplier = 0; next_time = TS_NEVER; if (recovery_duty_cycle > 0) // in TOU/CPP mode last_duty_cycle = duty_cycle; else // DLC mode { if (phase >= 1) phase -= 1; last_duty_cycle = 0; } } } // last_duty_cycle = duty_cycle; } if (pCircuit!=NULL){ if (is_240) { load.voltage_factor = pCircuit->pV->Mag() / 240; // update voltage factor - not really used for anything } else //120 { load.voltage_factor = pCircuit->pV->Mag() / 120; // update voltage factor - not really used for anything } } t2 = residential_enduse::sync(t0,t1); if (pCircuit->status==BRK_CLOSED) { //All values placed as kW/kVAr values - to be consistent with other loads double demand_power = multiplier * base_power; if (demand_response_mode == true) demand_power = nominal_power; if (heatgain_only == false) { //Calculate power portion real_power = demand_power * load.power_fraction; imag_power = (power_pf == 0.0) ? 0.0 : real_power * sqrt(1.0/(power_pf * power_pf) - 1.0); if (power_pf < 0) { imag_power *= -1.0; //Adjust imaginary portion for negative PF } load.power.SetRect(real_power,imag_power); //Calculate current portion real_power = demand_power * load.current_fraction; imag_power = (current_pf == 0.0) ? 0.0 : real_power * sqrt(1.0/(current_pf * current_pf) - 1.0); if (current_pf < 0) { imag_power *= -1.0; //Adjust imaginary portion for negative PF } load.current.SetRect(real_power,imag_power); //Calculate impedance portion real_power = demand_power * load.impedance_fraction; imag_power = (impedance_pf == 0.0) ? 0.0 : real_power * sqrt(1.0/(impedance_pf * impedance_pf) - 1.0); if (impedance_pf < 0) { imag_power *= -1.0; //Adjust imaginary portion for negative PF } load.admittance.SetRect(real_power,imag_power); //Put impedance in admittance. From a power point of view, they are the same //Compute total power - not sure if needed, but will use below load.total = load.power + load.current + load.admittance; if(first_time==2) { if(*test3==2) { actual_power.Re()=actual_power_non_zero; } } actual_power = load.power + load.current * load.voltage_factor + load.admittance * load.voltage_factor * load.voltage_factor; //Update power factor, just in case angleval = load.total.Arg(); load.power_factor = (angleval < 0) ? -1.0 * cos(angleval) : cos(angleval); //Determine the heat contributions - percentage of real power load.heatgain = load.total.Re() * load.heatgain_fraction * BTUPHPKW; } else { load.power = load.current = load.admittance = actual_power = load.total = 0.0; load.heatgain = demand_power * BTUPHPKW; return TS_NEVER; } } else //Breaker's open - nothing happens { load.total = 0.0; load.power = 0.0; load.current = 0.0; load.admittance = 0.0; load.heatgain = 0.0; load.power_factor = 0.0; } } if (next_time < t2 && next_time > 0) t2 = next_time; ///////////////////estimate if i satisfied from market///////////////////////////// if( irrigation_contr_object!=NULL) { int16 *insync=gl_get_int16_by_name(irrigation_contr_object,"insync"); if(*insync==2&&only_once==1) { actual_power_non_zero=actual_power.Re(); only_once=2; gl_set_value_by_name(irrigation_contr_object,"insync","2"); } } return t2; }
/** initialization process **/ int irrigation_controller::init(OBJECT *parent){ OBJECT *hdr = OBJECTHDR(this); char tname[32]; parent2=parent; insync=0; initial_zipload_power=gl_get_double_by_name(parent,"base_power"); char *namestr = (hdr->name ? hdr->name : tname); sprintf(tname, "irrigation_controller:%i", hdr->id); first=0; cheat(); if(parent == NULL){ gl_error("%s: irrigation_controller has no parent, therefore nothing to control", namestr); return 0; } if(pMarket == NULL){ gl_error("%s: irrigation_controller has no market, therefore no price signals", namestr); return 0; } if(gl_object_isa(pMarket, "auction")){ gl_set_dependent(hdr, pMarket); market = OBJECTDATA(pMarket, auction); } else { gl_error("irrigation_controllers only work when attached to an 'auction' object"); return 0; } if(dPeriod == 0.0){ if((pMarket->flags & OF_INIT) != OF_INIT){ char objname[256]; gl_verbose("irrigation_controller::init(): deferring initialization on %s", gl_name(pMarket, objname, 255)); return 2; // defer } period = market->period; } else { period = (TIMESTAMP)floor(dPeriod + 0.5); } if(bid_delay < 0){ bid_delay = -bid_delay; } if(bid_delay > period){ gl_warning("Bid delay is greater than the irrigation_controller period. Resetting bid delay to 0."); bid_delay = 0; } if(target[0] == 0){ GL_THROW("irrigation_controller: %i, target property not specified", hdr->id); } if(setpoint[0] == 0 && control_mode == CN_RAMP){ GL_THROW("irrigation_controller: %i, setpoint property not specified", hdr->id);; } if(demand[0] == 0 && control_mode == CN_RAMP){ GL_THROW("irrigation_controller: %i, demand property not specified", hdr->id); } if(deadband[0] == 0 && use_predictive_bidding == TRUE && control_mode == CN_RAMP){ GL_THROW("irrigation_controller: %i, deadband property not specified", hdr->id); } if(total[0] == 0){ GL_THROW("irrigation_controller: %i, total property not specified", hdr->id); } if(load[0] == 0){ GL_THROW("irrigation_controller: %i, load property not specified", hdr->id); } fetch(&pMonitor, target, parent); // auto tha einai to soil hmidit tha to pairnei apo to soil_SENSOR if(control_mode == CN_RAMP){ fetch(&pSetpoint, setpoint, parent); fetch(&pDemand, demand, parent); fetch(&pTotal, total, parent); fetch(&pLoad, load, parent); if(use_predictive_bidding == TRUE){ fetch(&pDeadband, deadband.get_string(), parent); } } fetch(&pAvg, avg_target.get_string(), pMarket); fetch(&pStd, std_target.get_string(), pMarket); if(dir == 0){ double high = ramp_high * range_high; double low = ramp_low * range_low; //printf("high:%f, low:%f, rh:%f, rl:%f,gh:%f,gl:%f\n\n\n\n",high,low,ramp_high,ramp_low,range_high,range_low); if(high > low){ dir = 1; } else if(high < low){ dir = -1; } else if((high == low) && (fabs(ramp_high) > 0.001 || fabs(ramp_low) > 0.001)){ dir = 0; if(ramp_high > 0){ direction = 1; } else { direction = -1; } gl_warning("%s: irrigation_controller has no price ramp", namestr); /* occurs given no price variation, or no control width (use a normal thermostat?) */ } if(ramp_low * ramp_high < 0){ gl_warning("%s: irrigation_controller price curve is not injective and may behave strangely"); /* TROUBLESHOOT The price curve 'changes directions' at the setpoint, which may create odd conditions in a number of circumstances. */ } } if(setpoint0==0) setpoint0 = -1; // key to check first thing // double period = market->period; // next_run = gl_globalclock + (TIMESTAMP)(period - fmod(gl_globalclock+period,period)); next_run = gl_globalclock;// + (market->period - gl_globalclock%market->period); init_time = gl_globalclock; time_off = TS_NEVER; if(sliding_time_delay < 0 ) dtime_delay = 21600; // default sliding_time_delay of 6 hours else dtime_delay = (int64)sliding_time_delay; if(state[0] != 0){ // grab state pointer pState = gl_get_enum_by_name(parent, state); last_pState = 0; if(pState == 0){ gl_error("state property name \'%s\' is not published by parent class", state); return 0; } } // get override, if set if(re_override[0] != 0){ pOverride = gl_get_enum_by_name(parent, re_override); } if((pOverride == 0) && (use_override == OU_ON)){ gl_error("use_override is ON but no valid override property name is given"); return 0; } if(control_mode == CN_RAMP){ if(slider_setting < -0.001){ gl_warning("slider_setting is negative, reseting to 0.0"); slider_setting = 0.0; } if(slider_setting > 1.0){ gl_warning("slider_setting is greater than 1.0, reseting to 1.0"); slider_setting = 1.0; } } last_p = market->init_price; /////////////////search for virtual_battery/////////////////////// /* static FINDLIST *xt1=NULL; xt1=gl_find_objects(FL_NEW,FT_CLASS,SAME,"virtual_battery",FT_END); OBJECT *firstt1= gl_find_next(xt1,NULL); OBJECT *it1; for(it1=firstt1;it1!=NULL;it1=it1->next) { if(gl_object_isa(it1,"virtual_battery")) { virtual_battery_object=it1; } else { // virtual_battery_object=NULL; } } */ ////////////////////////////////////////////////////////////////// return 1; }
TIMESTAMP irrigation_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; double deadband_shift = 0.0; double shift_direction = 0.0; double shift_setpoint = 0.0; double prediction_ramp = 0.0; double prediction_range = 0.0; double midpoint = 0.0; OBJECT *hdr = OBJECTHDR(this); if(insync==0) { insync=2; } else if(insync==2) { x=gl_get_double_by_name(parent2,"actual_power_non_zero"); // printf("%d %f ",parent2->id,*x); //system("pause"); insync=1; pDemand=x; initial_zipload_power=x; } if(first_period==0) //for two diffrent periods { //OBJECT *p=gl_get_object("sensor"); // double *humidity=gl_get_double_by_name(p,"humidity"); double *humidity=gl_get_double_by_name(soil_sensor,"humidity"); *pMonitor =*humidity; //printf("irrigaiton:%d %f \n",soil_sensor->id,*pMonitor); // system("pause"); //printf("%f %f",*pMonitor,setpoint0); //system("pause"); /* 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){ if(use_predictive_bidding == TRUE && ((control_mode == CN_RAMP && last_setpoint != setpoint0) || (control_mode == CN_DOUBLE_RAMP && (last_heating_setpoint != heating_setpoint0 || last_cooling_setpoint != cooling_setpoint0)))) { ; } else {// check to see if we have changed states if(pState == 0){ return next_run; } else if(*pState == last_pState){ return next_run; } } } else { return next_run; } } if(use_predictive_bidding == TRUE){ deadband_shift = *pDeadband * 0.5; } 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)){ //printf("EDWWWWWWWWWWWWWWWWWWW\n"); //system("pause"); 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(use_predictive_bidding == TRUE){ if((dir > 0 && clear_price < last_p) || (dir < 0 && clear_price > last_p)){ shift_direction = -1; } else if((dir > 0 && clear_price >= last_p) || (dir < 0 && clear_price <= last_p)){ shift_direction = 1; } else { shift_direction = 0; } } 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) + deadband_shift*shift_direction; } else if(clear_price > *pAvg && range_high != 0){ set_temp = setpoint0 + (clear_price - *pAvg) * fabs(range_high) / (ramp_high * *pStd) + deadband_shift*shift_direction; } else { set_temp = setpoint0 + deadband_shift*shift_direction; } 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("irrigation_controller::postsync(): temp %f given p %f vs avg %f",set_temp, market->next.price, market->avg24); } if(dir > 0){ //edw mpainei if(use_predictive_bidding == TRUE){ if(*pState == 0 && *pMonitor > (max - deadband_shift)){ bid = market->pricecap; } else if(*pState != 0 && *pMonitor < (min + deadband_shift)){ bid = 0.0; no_bid = 1; } else if(*pState != 0 && *pMonitor > max){ bid = market->pricecap; } else if(*pState == 0 && *pMonitor < min){ bid = 0.0; no_bid = 1; } } else { if(*pMonitor > max){ // printf("sto max"); bid = market->pricecap; } else if (*pMonitor < min){ // printf("sto min"); bid = -1.0; no_bid = 0; } } } else if(dir < 0){ if(use_predictive_bidding == TRUE){ if(*pState == 0 && *pMonitor < (min + deadband_shift)){ bid = market->pricecap; } else if(*pState != 0 && *pMonitor > (max - deadband_shift)){ bid = 0.0; no_bid = 1; } else if(*pState != 0 && *pMonitor < min){ bid = market->pricecap; } else if(*pState == 0 && *pMonitor > max){ bid = 0.0; no_bid = 1; } } else { if(*pMonitor < min){ bid = market->pricecap; } else if (*pMonitor > max){ bid = 0.0; no_bid = 0; } } } else if(dir == 0){ if(use_predictive_bidding == TRUE){ if(direction == 0.0) { gl_error("the variable direction did not get set correctly."); } else if((*pMonitor > max + deadband_shift || (*pState != 0 && *pMonitor > min - deadband_shift)) && direction > 0){ bid = market->pricecap; } else if((*pMonitor < min - deadband_shift || (*pState != 0 && *pMonitor < max + deadband_shift)) && direction < 0){ bid = market->pricecap; } else { bid = 0.0; no_bid = 0; } } else { if(*pMonitor < min){ bid = market->pricecap; } else if(*pMonitor > max){ bid = 0.0; no_bid = 0; } else { bid = *pAvg; } } } // calculate bid price //printf("%f,monitor:%f,min:%f max:%f, setpoint:%f\n",*humidity,*pMonitor,min,max,setpoint0); if(*pMonitor > setpoint0){ k_T = ramp_low; T_lim = range_low; bid=0; // printf("values : %f %f %f \n",bid,k_T, T_lim ); } else if(*pMonitor < setpoint0) { //printf("right_side "); k_T = ramp_low; T_lim = range_low; //printf("values : %f %f %f \n",bid,k_T, T_lim ); ///////////////////close all the controllers//////////////////////////// static FINDLIST *xt1=NULL; xt1=gl_find_objects(FL_NEW,FT_CLASS,SAME,"controller",FT_END); OBJECT *firstt1= gl_find_next(xt1,NULL); OBJECT *it1; for(it1=firstt1;it1!=NULL;it1=it1->next) { if(gl_object_isa(it1,"controller")) { gl_set_value_by_name(it1,"second_period_for_market","1") ; } } ////////////////////////////////////////////////////////////////////////////////// } else { k_T = 0.0; T_lim = 0.0; } if(bid < 0.0 && *pMonitor != setpoint0) { gl_set_value_by_name(soil_sensor,"irrigate_flag","1"); last_q = *initial_zipload_power; *pDemand =*initial_zipload_power; bid = *pAvg + ( (fabs(*pStd) < bid_offset) ? 0.0 : (*pMonitor - setpoint0) * (k_T * *pStd) / fabs(T_lim) ); //printf("price:%f %f %f %f\n",bid,(*pMonitor - setpoint0) ,(k_T * *pStd) , fabs(T_lim)); ////////////////////////////////////// char x_position_string[1024]; double *prev=gl_get_double_by_name(parent2,"prev_base_power"); double pos_x = *prev; sprintf(x_position_string, "%f", pos_x); gl_set_value_by_name(parent2,"base_power",x_position_string); ///////////////////////////////////// } else if(*pMonitor == setpoint0) { bid = *pAvg; } else { last_q=0; gl_set_value_by_name(parent2,"base_power","0"); } // 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(last_q > 0 && no_bid != 1){ last_p = bid; last_q= *initial_zipload_power; //if(last_p < 0) //{ //last_p=clear_price; //} 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.get_string()); 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("irrigation_controller:%d: residual unresponsive load is negative! (%.1f kW)", hdr->id, residual); } if (pState != 0) last_pState = *pState; char timebuf[128]; gl_printtime(t1,timebuf,127); return TS_NEVER; //} } //end of first_period==0 }
//EXPORT for object-level call (as opposed to module-level) EXPORT SIMULATIONMODE update_double_assert(OBJECT *obj, TIMESTAMP t0, unsigned int64 delta_time, unsigned long dt, unsigned int iteration_count_val) { char buff[64]; char dateformat[8]=""; char error_output_buff[1024]; char datebuff[64]; double_assert *da = OBJECTDATA(obj,double_assert); DATETIME delta_dt_val; double del_clock; TIMESTAMP del_clock_int; int del_microseconds; double *x; if(da->get_once() == da->ONCE_TRUE){ da->set_once_value(da->get_value()); da->set_once(da->ONCE_DONE); } else if (da->get_once() == da->ONCE_DONE){ if(da->get_once_value() == da->get_value()){ gl_verbose("Assert skipped with ONCE logic"); return SM_EVENT; } else { da->set_once_value(da->get_value()); } } // get the within range double range = 0.0; if ( da->get_within_mode() == da->IN_RATIO ) { range = da->get_value() * da->get_within(); //if ( range<0.001 ) //minimum bounds removed since many deltamode items are small //{ // minimum bounds // range = 0.001; //} } else if ( da->get_within_mode()== da->IN_ABS ) { range = da->get_within(); } //Iteration checker - assert only valid on the first timestep if (iteration_count_val == 0) { //Skip first timestep of any delta iteration -- nature of delta means it really isn't checking the right one if (delta_time>=dt) { //Get value x = (double*)gl_get_double_by_name(obj->parent,da->get_target()); if (x==NULL) { gl_error("Specified target %s for %s is not valid.",da->get_target(),gl_name(obj->parent,buff,64)); /* TROUBLESHOOT Check to make sure the target you are specifying is a published variable for the object that you are pointing to. Refer to the documentation of the command flag --modhelp, or check the wiki page to determine which variables can be published within the object you are pointing to with the assert function. */ return SM_ERROR; } else if (da->get_status() == da->ASSERT_TRUE) { double m = fabs(*x-da->get_value()); if (_isnan(m) || m>range) { //Calculate time if (delta_time>=dt) //After first iteration del_clock = (double)t0 + (double)(delta_time-dt)/(double)DT_SECOND; else //First second different, don't back out del_clock = (double)t0 + (double)(delta_time)/(double)DT_SECOND; del_clock_int = (TIMESTAMP)del_clock; /* Whole seconds - update from global clock because we could be in delta for over 1 second */ del_microseconds = (int)((del_clock-(int)(del_clock))*1000000+0.5); /* microseconds roll-over - biased upward (by 0.5) */ //Convert out gl_localtime(del_clock_int,&delta_dt_val); //Determine output format gl_global_getvar("dateformat",dateformat,sizeof(dateformat)); //Output date appropriately if ( strcmp(dateformat,"ISO")==0) sprintf(datebuff,"ERROR [%04d-%02d-%02d %02d:%02d:%02d.%.06d %s] : ",delta_dt_val.year,delta_dt_val.month,delta_dt_val.day,delta_dt_val.hour,delta_dt_val.minute,delta_dt_val.second,del_microseconds,delta_dt_val.tz); else if ( strcmp(dateformat,"US")==0) sprintf(datebuff,"ERROR [%02d-%02d-%04d %02d:%02d:%02d.%.06d %s] : ",delta_dt_val.month,delta_dt_val.day,delta_dt_val.year,delta_dt_val.hour,delta_dt_val.minute,delta_dt_val.second,del_microseconds,delta_dt_val.tz); else if ( strcmp(dateformat,"EURO")==0) sprintf(datebuff,"ERROR [%02d-%02d-%04d %02d:%02d:%02d.%.06d %s] : ",delta_dt_val.day,delta_dt_val.month,delta_dt_val.year,delta_dt_val.hour,delta_dt_val.minute,delta_dt_val.second,del_microseconds,delta_dt_val.tz); else sprintf(datebuff,"ERROR .09f : ",del_clock); //Actual error part sprintf(error_output_buff,"Assert failed on %s - %s (%g) not within %f of given value %g",gl_name(obj->parent, buff, 64),da->get_target(), *x, da->get_within(), da->get_value()); //Send it out gl_output("%s%s",datebuff,error_output_buff); return SM_ERROR; } gl_verbose("Assert passed on %s", gl_name(obj->parent, buff, 64)); return SM_EVENT; } else if (da->get_status() == da->ASSERT_FALSE) { double m = fabs(*x-da->get_value()); if (_isnan(m) || m<range) { //Calculate time if (delta_time>=dt) //After first iteration del_clock = (double)t0 + (double)(delta_time-dt)/(double)DT_SECOND; else //First second different, don't back out del_clock = (double)t0 + (double)(delta_time)/(double)DT_SECOND; del_clock_int = (TIMESTAMP)del_clock; /* Whole seconds - update from global clock because we could be in delta for over 1 second */ del_microseconds = (int)((del_clock-(int)(del_clock))*1000000+0.5); /* microseconds roll-over - biased upward (by 0.5) */ //Convert out gl_localtime(del_clock_int,&delta_dt_val); //Determine output format gl_global_getvar("dateformat",dateformat,sizeof(dateformat)); //Output date appropriately if ( strcmp(dateformat,"ISO")==0) sprintf(datebuff,"ERROR [%04d-%02d-%02d %02d:%02d:%02d.%.06d %s] : ",delta_dt_val.year,delta_dt_val.month,delta_dt_val.day,delta_dt_val.hour,delta_dt_val.minute,delta_dt_val.second,del_microseconds,delta_dt_val.tz); else if ( strcmp(dateformat,"US")==0) sprintf(datebuff,"ERROR [%02d-%02d-%04d %02d:%02d:%02d.%.06d %s] : ",delta_dt_val.month,delta_dt_val.day,delta_dt_val.year,delta_dt_val.hour,delta_dt_val.minute,delta_dt_val.second,del_microseconds,delta_dt_val.tz); else if ( strcmp(dateformat,"EURO")==0) sprintf(datebuff,"ERROR [%02d-%02d-%04d %02d:%02d:%02d.%.06d %s] : ",delta_dt_val.day,delta_dt_val.month,delta_dt_val.year,delta_dt_val.hour,delta_dt_val.minute,delta_dt_val.second,del_microseconds,delta_dt_val.tz); else sprintf(datebuff,"ERROR .09f : ",del_clock); //Actual error part sprintf(error_output_buff,"Assert failed on %s - %s (%g) not within %f of given value %g",gl_name(obj->parent, buff, 64),da->get_target(), *x, da->get_within(), da->get_value()); //Send it out gl_output("%s%s",datebuff,error_output_buff); return SM_ERROR; } gl_verbose("Assert passed on %s", gl_name(obj->parent, buff, 64)); return SM_EVENT; } else { gl_verbose("Assert test is not being run on %s", gl_name(obj->parent, buff, 64)); return SM_EVENT; } } else //First pass, just proceed return SM_EVENT; } else //Iteration, so don't care return SM_EVENT; }
int load_tracker::init(OBJECT *parent) { // Make sure we have a target object if (target==NULL) { GL_THROW("Target object not set"); /* TROUBLESHOOT Please specify the name of the target object to be monitored. */ } // Make sure we have a target property PROPERTY* target_property = gl_get_property(target,target_prop.get_string()); if (target_property==NULL) { GL_THROW("Unable to find property \"%s\" in object %s", target_prop.get_string(), target->name); /* TROUBLESHOOT Please specify an existing property of the target object to be monitored. */ } // Make sure it is a supported type switch (target_property->ptype) { case PT_double: case PT_complex: case PT_int16: case PT_int32: case PT_int64: break; default: GL_THROW("Unsupported property type. Supported types are complex, double and integer"); /* TROUBLESHOOT Please specify a property whose type is either a double, complex, int16, int32, or an int64. */ } type = target_property->ptype; // Get a pointer to the target property value switch (type) { case PT_double: pointer.d = gl_get_double_by_name(target, target_prop.get_string()); break; case PT_complex: pointer.c = gl_get_complex_by_name(target, target_prop.get_string()); break; case PT_int16: pointer.i16 = gl_get_int16_by_name(target, target_prop.get_string()); break; case PT_int32: pointer.i32 = gl_get_int32_by_name(target, target_prop.get_string()); break; case PT_int64: pointer.i64 = gl_get_int64_by_name(target, target_prop.get_string()); break; } // The VALUEPOINTER is a union of pointers so we only need to check one of them.... if (pointer.d == NULL) { GL_THROW("Unable to bind to property \"%s\" in object %s", target_prop.get_string(), target->name); /* TROUBLESHOOT The property given does not exist for the given property object. Please specify an existing property of the target object. */ } // Make sure we have a full_scale value if (full_scale == 0.0) { GL_THROW("The full_scale property must be non-zero"); /* TROUBLESHOOT Please specify full_scale as a non-zero value. */ } // Check deadbank is OK if (deadband < 1.0 || deadband > 50.0) { GL_THROW("Deadband must be in the range 1% to 50%"); /* TROUBLESHOOT Please specify deadband as a value between 1 and 50. */ } // Check damping is OK if (damping < 0.0) { GL_THROW("Damping must greater than or equal to 0.0"); /* TROUBLESHOOT Please specify damping as a value of 0 or greater. */ } // Set the default output value based on feed-forward control output = setpoint / full_scale; return 1; }
/** Water heater plc control code to set the water heater 'heat_needed' state The thermostat set point, deadband, tank state(height of hot water column) and current water temperature are used to determine 'heat_needed' state. **/ TIMESTAMP virtual_battery::presync(TIMESTAMP t0, TIMESTAMP t1){ power= gl_get_double_by_name(parent2,"TotalRealPow"); if(first_time==0) { first_time=t1; } if(gl_todays(t1)-gl_todays(first_time)==1) { first_time=2; } if(gl_todays(t1)-gl_todays(first_time)==2) { first_time2=2; } if(first_time==2 && first_time2==0) { if(change_capacity==1) { char timebuf[128]; gl_printtime(t1,timebuf,127); printf("%s \n",timebuf); //system("pause"); double *clear_quantity=gl_get_double_by_name(auction_object,"current_market.clearing_quantity"); double *clear_price=gl_get_double_by_name(auction_object,"current_market.clearing_price"); if(*clear_quantity > capacity/1000) { // printf("1 glfdlhdljhdljkkjlhjlhlddfgdfg\n\n\n\n"); capacity=0; // system("pause"); charge=1; } else if(*clear_price >= price) { //printf("2 "); capacity=0; // printf("post: %f ",capacity); // system("pause"); charge=1; } else if(*clear_price < price) { // printf("3 "); capacity=capacity; // system("pause"); charge=1; } change_capacity=0; } //printf("%f\n\n", capacity); } return TS_NEVER; }
/** 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 histogram::feed_bins(OBJECT *obj){ double value = 0.0; complex cval = 0.0; //gl_get_complex(obj, ; int64 ival = 0; int i = 0; switch(prop_ptr->ptype){ case PT_complex: cval = (prop_ptr ? *gl_get_complex(obj, prop_ptr) : *gl_get_complex_by_name(obj, property) ); switch(this->comp_part){ case REAL: value = cval.Re(); break; case IMAG: value = cval.Im(); break; case MAG: value = cval.Mag(); break; case ANG: value = cval.Arg(); break; default: gl_error("Complex property with no part defined in %s", (obj->name ? obj->name : "(unnamed)")); } ival = 1; /* fall through */ case PT_double: if(ival == 0) value = (prop_ptr ? *gl_get_double(obj, prop_ptr) : *gl_get_double_by_name(obj, property.get_string()) ); for(i = 0; i < bin_count; ++i){ if(value > bin_list[i].low_val && value < bin_list[i].high_val){ ++binctr[i]; } else if(bin_list[i].low_inc && bin_list[i].low_val == value){ ++binctr[i]; } else if(bin_list[i].high_inc && bin_list[i].high_val == value){ ++binctr[i]; } } break; case PT_int16: ival = (prop_ptr ? *gl_get_int16(obj, prop_ptr) : *gl_get_int16_by_name(obj, property.get_string()) ); value = 1.0; case PT_int32: if(value == 0.0){ ival = (prop_ptr ? *gl_get_int32(obj, prop_ptr) : *gl_get_int32_by_name(obj, property.get_string()) ); value = 1.0; } case PT_int64: if(value == 0.0){ ival = (prop_ptr ? *gl_get_int64(obj, prop_ptr) : *gl_get_int64_by_name(obj, property.get_string()) ); value = 1.0; } case PT_enumeration: if(value == 0.0){ ival = (prop_ptr ? *gl_get_enum(obj, prop_ptr) : *gl_get_enum_by_name(obj, property.get_string()) ); value = 1.0; } case PT_set: if(value == 0.0){ ival = (prop_ptr ? *gl_get_set(obj, prop_ptr) : *gl_get_set_by_name(obj, property.get_string()) ); value = 1.0; } /* may be prone to fractional errors */ for(i = 0; i < bin_count; ++i){ if(ival > bin_list[i].low_val && ival < bin_list[i].high_val){ ++binctr[i]; } else if(bin_list[i].low_inc && bin_list[i].low_val == ival){ ++binctr[i]; } else if(bin_list[i].high_inc && bin_list[i].high_val == ival){ ++binctr[i]; } } break; } return 0; }