inline double waterheater::new_temp_1node(double T0, double delta_t)
{
	// old because this happens in presync and needs previously used demand
	const double mdot_Cp = Cp * water_demand_old * 60 * RHOWATER / GALPCF;
	// Btu / degF.lb * gal/hr * lb/cf * cf/gal = Btu / degF.hr

    if (Cw <= ROUNDOFF || (tank_UA+mdot_Cp) <= ROUNDOFF)
        return T0;

	const double c1 = (tank_UA + mdot_Cp) / Cw;
	const double c2 = (actual_kW()*BTUPHPKW + mdot_Cp*Tinlet + tank_UA*get_Tambient(location)) / (tank_UA + mdot_Cp);

//	return  c2 - (c2 + T0) * exp(c1 * delta_t);	// [F]
	return  c2 - (c2 - T0) * exp(-c1 * delta_t);	// [F]
}
예제 #2
0
파일: range.cpp 프로젝트: brennane/gridpot
inline double range::new_temp_1node(double T0, double delta_t)
{
	// old because this happens in presync and needs previously used demand
	const double mdot_Cp = specificheat_food * oven_demand_old * 60 * food_density / GALPCF;
	// Btu / degF.lb * gal/hr * lb/cf * cf/gal = Btu / degF.hr

    if (Cw <= ROUNDOFF || (oven_UA+mdot_Cp) <= ROUNDOFF)
        return T0;

	const double c1 = (oven_UA + mdot_Cp) / Cw;
	const double c2 = (actual_kW()*BTUPHPKW + mdot_Cp*Tinlet + oven_UA*get_Tambient(location)) / (oven_UA + mdot_Cp);

//	return  c2 - (c2 + T0) * exp(c1 * delta_t);	// [F]
	return  c2 - (c2 - T0) * exp(-c1 * delta_t);	// [F]
}
inline double waterheater::new_time_1node(double T0, double T1)
{
	const double mdot_Cp = Cp * water_demand * 60 * RHOWATER / GALPCF;

    if (Cw <= ROUNDOFF)
        return -1.0;

	const double c1 = ((actual_kW()*BTUPHPKW + tank_UA * get_Tambient(location)) + mdot_Cp*Tinlet) / Cw;
	const double c2 = -(tank_UA + mdot_Cp) / Cw;

    if (fabs(c1 + c2*T1) <= ROUNDOFF || fabs(c1 + c2*T0) <= ROUNDOFF || fabs(c2) <= ROUNDOFF)
        return -1.0;

	const double new_time = (log(fabs(c1 + c2 * T1)) - log(fabs(c1 + c2 * T0))) / c2;	// [hr]
	return new_time;
}
예제 #4
0
파일: range.cpp 프로젝트: brennane/gridpot
inline double range::new_time_1node(double T0, double T1)
{
	const double mdot_Cp = specificheat_food * oven_demand * 60 * food_density / GALPCF;

    if (Cw <= ROUNDOFF)
        return -1.0;

	const double c1 = ((actual_kW()*BTUPHPKW + oven_UA * get_Tambient(location)) + mdot_Cp*Tinlet) / Cw;
	const double c2 = -(oven_UA + mdot_Cp) / Cw;

    if (fabs(c1 + c2*T1) <= ROUNDOFF || fabs(c1 + c2*T0) <= ROUNDOFF || fabs(c2) <= ROUNDOFF)
        return -1.0;

	const double new_time = (log(fabs(c1 + c2 * T1)) - log(fabs(c1 + c2 * T0))) / c2;	// [hr]
	return new_time;
}
/* the key to picking the equations apart is that the goal is to calculate the temperature differences relative to the
 *	temperature of the lower node (or inlet temp, if 1node).
 * cA is the volume change from water draw, heating element, and thermal jacket given a uniformly cold tank
 * cB is the volume change from the extra energy within the hot water node
 */
double waterheater::dhdt(double h)
{
	if (/*Tupper*/ Tw - Tlower < ROUNDOFF)
		return 0.0; // if /*Tupper*/ Tw and Tlower are same then dh/dt = 0.0;

	// Pre-set some algebra just for efficiency...
	const double mdot = water_demand * 60 * RHOWATER / GALPCF;		// lbm/hr...
    const double c1 = RHOWATER * Cp * area * (/*Tupper*/ Tw - Tlower);	// Btu/ft...
	
    // check c1 before dividing by it
    if (c1 <= ROUNDOFF)
        return 0.0; //Possible only when /*Tupper*/ Tw and Tlower are very close, and the difference is negligible

	const double cA = -mdot / (RHOWATER * area) + (actual_kW() * BTUPHPKW + tank_UA * (get_Tambient(location) - Tlower)) / c1;
	const double cb = (tank_UA / height) * (/*Tupper*/ Tw - Tlower) / c1;

	// Returns the rate of change of 'h'
	return cA - cb*h;
}
inline double waterheater::new_h_2zone(double h0, double delta_t)
{
	if (delta_t <= ROUNDOFF)
		return h0;

	// old because this happens in presync and needs previously used demand
	const double mdot = water_demand_old * 60 * RHOWATER / GALPCF;		// lbm/hr...
	const double c1 = RHOWATER * Cp * area * (/*Tupper*/ Tw - Tlower); // lb/ft^3 * ft^2 * degF * Btu/lb.degF = lb/lb * ft^2/ft^3 * degF/degF * Btu = Btu/ft

	// check c1 before division
	if (fabs(c1) <= ROUNDOFF)
        return height;      // if /*Tupper*/ Tw and Tlower are real close, then the new height is the same as tank height
//		throw MODEL_NOT_2ZONE;
		
//	#define CWATER		(0.9994)		// BTU/lb/F
	const double cA = -mdot / (RHOWATER * area) + (actual_kW()*BTUPHPKW + tank_UA * (get_Tambient(location) - Tlower)) / c1;
	// lbm/hr / lb/ft + kW * Btu.h/kW + 
	const double cb = (tank_UA / height) * (/*Tupper*/ Tw - Tlower) / c1;

    if (fabs(cb) <= ROUNDOFF)
        return height;

	return ((exp(cb * delta_t) * (cA + cb * h0)) - cA) / cb;	// [ft]
}
/** Water heater synchronization determines the time to next
	synchronization state and the power drawn since last synch
 **/
TIMESTAMP waterheater::sync(TIMESTAMP t0, TIMESTAMP t1) 
{
	double internal_gain = 0.0;
	double nHours = (gl_tohours(t1) - gl_tohours(t0))/TS_SECOND;
	double Tamb = get_Tambient(location);

	// use re_override to control heat_needed state
	// runs after thermostat() but before "the usual" calculations
	if(re_override == OV_ON){
		heat_needed = TRUE;
	} else if(re_override == OV_OFF){
		heat_needed = FALSE;
	}

	if(Tw > 212.0 - thermostat_deadband){ // if it's trying boil, turn it off!
		heat_needed = FALSE;
		is_waterheater_on = 0;
	}


	TIMESTAMP t2 = residential_enduse::sync(t0,t1);
	
	// Now find our current temperatures and boundary height...
	// And compute the time to the next transition...
	//Adjusted because shapers go on sync, not presync

	set_time_to_transition();

	// determine internal gains
	if (location == INSIDE){
		if(this->current_model == ONENODE){
			internal_gain = tank_UA * (Tw - get_Tambient(location));
		} else if(this->current_model == TWONODE){
			internal_gain = tank_UA * (Tw - Tamb) * h / height;
			internal_gain += tank_UA * (Tlower - Tamb) * (1 - h / height);
		}
	} else {
		internal_gain = 0;
	}

	// determine the power used
	if (heat_needed == TRUE){
		/* power_kw */ load.total = (heat_mode == GASHEAT ? gas_fan_power : heating_element_capacity);
		is_waterheater_on = 1;
	} else {
		/* power_kw */ load.total = (heat_mode == GASHEAT ? gas_standby_power : 0.0);
		is_waterheater_on = 0;
	}

	//load.total = load.power = /* power_kw */ load.power;
	load.power = load.total * load.power_fraction;
	load.admittance = load.total * load.impedance_fraction;
	load.current = load.total * load.current_fraction;
	load.heatgain = internal_gain;

	waterheater_actual_power = load.power + (load.current + load.admittance * load.voltage_factor )* load.voltage_factor;
	actual_load = waterheater_actual_power.Re();

	if (actual_load != 0.0)
	{
		prev_load = actual_load;
		power_state = PS_ON;
	}
	else
		power_state = PS_OFF;

//	gl_enduse_sync(&(residential_enduse::load),t1);

	if(re_override == OV_NORMAL){
		if (time_to_transition >= (1.0/3600.0))	// 0.0167 represents one second
		{
			TIMESTAMP t_to_trans = (TIMESTAMP)(t1+time_to_transition*3600.0/TS_SECOND);
			return -(t_to_trans); // negative means soft transition
		}
		// less than one second means never
		else
			return TS_NEVER; 
	} else {
		return TS_NEVER; // keep running until the forced state ends
	}
}
예제 #8
0
파일: range.cpp 프로젝트: brennane/gridpot
/** oven synchronization determines the time to next
	synchronization state and the power drawn since last synch
 **/
TIMESTAMP range::sync(TIMESTAMP t0, TIMESTAMP t1) 
{
	double internal_gain = 0.0;
	double nHours = (gl_tohours(t1) - gl_tohours(t0))/TS_SECOND;
	double Tamb = get_Tambient(location);
	double dt = gl_toseconds(t0>0?t1-t0:0);

	if (oven_check == true || remainon == true)	
	time_oven_operation +=dt;

	if (remainon == false) 
	time_oven_operation=0;

	enduse_queue_oven += enduse_demand_oven * dt/3600/24;
	

			if (t0>TS_ZERO && t1>t0)
		{
			// compute the total energy usage in this interval
			load.energy += load.total * dt/3600.0;
		}		

	if(re_override == OV_ON){
		heat_needed = TRUE;
	} else if(re_override == OV_OFF){
		heat_needed = FALSE;
	}

	if(Tw > 212.0 - thermostat_deadband){ // if it's trying boil, turn it off!
		heat_needed = FALSE;
		is_range_on = 0;
	}
	// determine the power used
	if (heat_needed == TRUE){
		/* power_kw */ load.total = heating_element_capacity * (heat_mode == GASHEAT ? 0.01 : 1.0);
		is_range_on = 1;
	} else {
		/* power_kw */ load.total = 0.0;
		is_range_on = 0;
	}

	TIMESTAMP t2 = residential_enduse::sync(t0,t1);
	
	set_time_to_transition();

	if (location == INSIDE){
		if(this->current_model == ONENODE){
			internal_gain = oven_UA * (Tw - get_Tambient(location));
		} 

	} else {
		internal_gain = 0;
	}

	dt = update_state(dt, t1);

	

	//load.total = load.power = /* power_kw */ load.power;
	load.power = load.total * load.power_fraction;
	load.admittance = load.total * load.impedance_fraction;
	load.current = load.total * load.current_fraction;
	load.heatgain = internal_gain;

	range_actual_power = load.power + (load.current + load.admittance * load.voltage_factor )* load.voltage_factor;
	actual_load = range_actual_power.Re();
	if (heat_needed == true)
	total_power_oven = actual_load;
	else
	total_power_oven =0;

	if (actual_load != 0.0)
	{
		prev_load = actual_load;
		power_state = PS_ON;
	}
	else
		power_state = PS_OFF;

//	gl_enduse_sync(&(residential_enduse::load),t1);

	if(re_override == OV_NORMAL){
		if (time_to_transition < dt)
		{
			if (time_to_transition >= (1.0/3600.0))	// 0.0167 represents one second
			{
				TIMESTAMP t_to_trans = (t1+time_to_transition*3600.0/TS_SECOND);
				return -(t_to_trans); // negative means soft transition
			}
			// less than one second means never
			else
				return TS_NEVER; 
		}
		else
			return (TIMESTAMP)(t1+dt);
	} else {
		return TS_NEVER; // keep running until the forced state ends
	}


}
예제 #9
0
파일: range.cpp 프로젝트: brennane/gridpot
/* the key to picking the equations apart is that the goal is to calculate the temperature differences relative to the
 *	temperature of the lower node (or inlet temp, if 1node).

 */
double range::dhdt(double h)
{
	if (/*Tupper*/ Tw - Tlower < ROUNDOFF)
		return 0.0; // if /*Tupper*/ Tw and Tlower are same then dh/dt = 0.0;

	// Pre-set some algebra just for efficiency...
	const double mdot = oven_demand * 60 * food_density / GALPCF;		// lbm/hr...
    const double c1 = food_density * specificheat_food * area * (/*Tupper*/ Tw - Tlower);	// Btu/ft...

	if (oven_demand > 0.0)
		double aaa=1;
	
    // check c1 before dividing by it
    if (c1 <= ROUNDOFF)
        return 0.0; //Possible only when /*Tupper*/ Tw and Tlower are very close, and the difference is negligible

	const double cA = -mdot / (food_density * area) + (actual_kW() * BTUPHPKW + oven_UA * (get_Tambient(location) - Tlower)) / c1;
	const double cb = (oven_UA / height) * (/*Tupper*/ Tw - Tlower) / c1;

	// Returns the rate of change of 'h'
	return cA - cb*h;
}