Question-and-Answer Resource for the Building Energy Modeling Community
Get started with the Help page
Ask Your Question

Revision history [back]

click to hide/show revision 1
initial version

modeling coefficient of performance curves for ASHP

Hi,

I am a university student working on the electrification of heating systems. I want to model the coefficient of performance curves for ASHPs, and I was looking at how ResStock does it. Each of the air source heat pumps uses the corresponding performance curve for EIR based on how many stages it has. Then it is scaled based on some data on COP values.

Here is an excerpt from the code. Could anyone help me understand how to use these coefficients--what would be the variables associated with them or point me towards relevant documentation that might aid my understanding? I could not find their source:

require_relative "constants" require_relative "geometry" require_relative "util" require_relative "unit_conversions" require_relative "psychrometrics" require_relative "schedules"

class HVAC def self.apply_central_ac_1speed(model, unit, runner, seer, eers, shrs, fan_power_rated, fan_power_installed, crankcase_capacity, crankcase_temp, eer_capacity_derates, capacity, dse, frac_cool_load_served)

return true if frac_cool_load_served <= 0

num_speeds = 1

# Performance curves
# NOTE: These coefficients are in IP UNITS
curves_in_ip = true
cOOL_CAP_FT_SPEC = [[3.670270705, -0.098652414, 0.000955906, 0.006552414, -0.0000156, -0.000131877]]
cOOL_EIR_FT_SPEC = [[-3.302695861, 0.137871531, -0.001056996, -0.012573945, 0.000214638, -0.000145054]]
cOOL_CAP_FFLOW_SPEC = [[0.718605468, 0.410099989, -0.128705457]]
cOOL_EIR_FFLOW_SPEC = [[1.32299905, -0.477711207, 0.154712157]]

capacity_ratios = [1.0]
fan_speed_ratios = [1.0]

# Cooling Coil
rated_airflow_rate = 386.1 # cfm
cfms_ton_rated = calc_cfms_ton_rated(rated_airflow_rate, fan_speed_ratios, capacity_ratios)
cooling_eirs = calc_cooling_eirs(num_speeds, eers, fan_power_rated)
shrs_rated_gross = calc_shrs_rated_gross(num_speeds, shrs, fan_power_rated, cfms_ton_rated)
cOOL_CLOSS_FPLR_SPEC = [calc_plr_coefficients_cooling(num_speeds, seer)]

obj_name = Constants.ObjectNameCentralAirConditioner(unit.name.to_s)

thermal_zones = Geometry.get_thermal_zones_from_spaces(unit.spaces)

control_slave_zones_hash = get_control_and_slave_zones(thermal_zones)
control_slave_zones_hash.each do |control_zone, slave_zones|
  # _processCurvesDXCooling

  clg_coil_stage_data = calc_coil_stage_data_cooling(model, capacity, (0...num_speeds).to_a, cooling_eirs, shrs_rated_gross, cOOL_CAP_FT_SPEC, cOOL_EIR_FT_SPEC, cOOL_CLOSS_FPLR_SPEC, cOOL_CAP_FFLOW_SPEC, cOOL_EIR_FFLOW_SPEC, curves_in_ip, dse)


  # _processSystemFan

  fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule)
  fan_eff = 0.75 # Overall Efficiency of the Fan, Motor and Drive
  fan.setName(obj_name + " clg supply fan")
  fan.setEndUseSubcategory(obj_name + " clg supply fan")
  fan.setFanEfficiency(fan_eff)
  fan.setPressureRise(calculate_fan_pressure_rise(fan_eff, fan_power_installed / dse))
  fan.setMotorEfficiency(1.0)
  fan.setMotorInAirstreamFraction(1.0)

  # _processSystemAir

  air_loop_unitary = OpenStudio::Model::AirLoopHVACUnitarySystem.new(model)
  air_loop_unitary.setName(obj_name + " unitary system")
  air_loop_unitary.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
  air_loop_unitary.setCoolingCoil(clg_coil)
  air_loop_unitary.setSupplyAirFlowRateDuringHeatingOperation(0.0)
  air_loop_unitary.setSupplyFan(fan)
  air_loop_unitary.setFanPlacement("BlowThrough")
  air_loop_unitary.setSupplyAirFanOperatingModeSchedule(model.alwaysOffDiscreteSchedule)
  air_loop_unitary.setMaximumSupplyAirTemperature(UnitConversions.convert(120.0, "F", "C"))
  air_loop_unitary.setSupplyAirFlowRateWhenNoCoolingorHeatingisRequired(0)

  air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
  air_loop.setName(obj_name + " asys")
  air_supply_inlet_node = air_loop.supplyInletNode
  air_supply_outlet_node = air_loop.supplyOutletNode
  air_demand_inlet_node = air_loop.demandInletNode
  air_demand_outlet_node = air_loop.demandOutletNode

  air_loop_unitary.addToNode(air_supply_inlet_node)

  runner.registerInfo("Added '#{fan.name}' to '#{air_loop_unitary.name}' of '#{air_loop.name}'")
  runner.registerInfo("Added '#{clg_coil.name}' to '#{air_loop_unitary.name}' of '#{air_loop.name}'")

  air_loop_unitary.setControllingZoneorThermostatLocation(control_zone)

  # _processSystemDemandSideAir
  # Demand Side

  # Supply Air
  zone_splitter = air_loop.zoneSplitter
  zone_splitter.setName(obj_name + " zone splitter")

  zone_mixer = air_loop.zoneMixer
  zone_mixer.setName(obj_name + " zone mixer")

  diffuser_living = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule)
  diffuser_living.setName(obj_name + " #{control_zone.name} direct air")
  air_loop.multiAddBranchForZone(control_zone, diffuser_living)

  air_loop.multiAddBranchForZone(control_zone)
  runner.registerInfo("Added '#{air_loop.name}' to '#{control_zone.name}' of #{unit.name}")

  prioritize_zone_hvac(model, runner, control_zone)

  slave_zones.each do |slave_zone|
    diffuser_fbsmt = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule)
    diffuser_fbsmt.setName(obj_name + " #{slave_zone.name} direct air")
    air_loop.multiAddBranchForZone(slave_zone, diffuser_fbsmt)

    air_loop.multiAddBranchForZone(slave_zone)
    runner.registerInfo("Added '#{air_loop.name}' to '#{slave_zone.name}' of #{unit.name}")

    prioritize_zone_hvac(model, runner, slave_zone)
  end # slave_zone

  # Store info for HVAC Sizing measure
  air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACCapacityDerateFactorEER, eer_capacity_derates.join(","))
  air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACRatedCFMperTonCooling, cfms_ton_rated.join(","))
  air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACFracCoolLoadServed, frac_cool_load_served)
end # control_zone

return true

end

def self.apply_central_ac_2speed(model, unit, runner, seer, eers, shrs, capacity_ratios, fan_speed_ratios, fan_power_rated, fan_power_installed, crankcase_capacity, crankcase_temp, eer_capacity_derates, capacity, dse, frac_cool_load_served)

return true if frac_cool_load_served <= 0

num_speeds = 2

# Performance curves
# NOTE: These coefficients are in IP UNITS
curves_in_ip = true
cOOL_CAP_FT_SPEC = [[3.940185508, -0.104723455, 0.001019298, 0.006471171, -0.00000953, -0.000161658],
                    [3.109456535, -0.085520461, 0.000863238, 0.00863049, -0.0000210, -0.000140186]]
cOOL_EIR_FT_SPEC = [[-3.877526888, 0.164566276, -0.001272755, -0.019956043, 0.000256512, -0.000133539],
                    [-1.990708931, 0.093969249, -0.00073335, -0.009062553, 0.000165099, -0.0000997]]
cOOL_CAP_FFLOW_SPEC = [[0.65673024, 0.516470835, -0.172887149],
                       [0.690334551, 0.464383753, -0.154507638]]
cOOL_EIR_FFLOW_SPEC = [[1.562945114, -0.791859997, 0.230030877],
                       [1.31565404, -0.482467162, 0.166239001]]

# Cooling Coil
rated_airflow_rate = 355.2 # cfm
cfms_ton_rated = calc_cfms_ton_rated(rated_airflow_rate, fan_speed_ratios, capacity_ratios)
cooling_eirs = calc_cooling_eirs(num_speeds, eers, fan_power_rated)
shrs_rated_gross = calc_shrs_rated_gross(num_speeds, shrs, fan_power_rated, cfms_ton_rated)
cOOL_CLOSS_FPLR_SPEC = [calc_plr_coefficients_cooling(num_speeds, seer)] * num_speeds

obj_name = Constants.ObjectNameCentralAirConditioner(unit.name.to_s)

thermal_zones = Geometry.get_thermal_zones_from_spaces(unit.spaces)

control_slave_zones_hash = get_control_and_slave_zones(thermal_zones)
control_slave_zones_hash.each do |control_zone, slave_zones|

I looked at this study for some information: https://www.nrel.gov/docs/fy13osti/56354.pdf and this paper: https://www.sciencedirect.com/science/article/pii/S0306261921005559

I would appreciate it if anyone could guide me to gain a better understanding of how to model COP curves using this information.

modeling coefficient of performance curves for ASHP

Hi,

I am a university student working on the electrification of heating systems. I want to model the coefficient of performance curves for ASHPs, and I was looking at how ResStock does it. Each of the air source heat pumps uses the corresponding performance curve for EIR based on how many stages it has. Then it is scaled based on some data on COP values.

Here is an excerpt from the code. Could anyone help me understand how to use these coefficients--what would be the variables associated with them or point me towards relevant documentation that might aid my understanding? I could not find their source:

require_relative "constants" require_relative "geometry" require_relative "util" require_relative "unit_conversions" require_relative "psychrometrics" require_relative "schedules"

class HVAC def self.apply_central_ac_1speed(model, unit, runner, seer, eers, shrs, fan_power_rated, fan_power_installed, crankcase_capacity, crankcase_temp, eer_capacity_derates, capacity, dse, frac_cool_load_served)

return true if frac_cool_load_served <= 0

num_speeds = 1

# Performance curves
# NOTE: These coefficients are in IP UNITS
curves_in_ip = true
cOOL_CAP_FT_SPEC = [[3.670270705, -0.098652414, 0.000955906, 0.006552414, -0.0000156, -0.000131877]]
cOOL_EIR_FT_SPEC = [[-3.302695861, 0.137871531, -0.001056996, -0.012573945, 0.000214638, -0.000145054]]
cOOL_CAP_FFLOW_SPEC = [[0.718605468, 0.410099989, -0.128705457]]
cOOL_EIR_FFLOW_SPEC = [[1.32299905, -0.477711207, 0.154712157]]

capacity_ratios = [1.0]
fan_speed_ratios = [1.0]

# Cooling Coil
rated_airflow_rate = 386.1 # cfm
cfms_ton_rated = calc_cfms_ton_rated(rated_airflow_rate, fan_speed_ratios, capacity_ratios)
cooling_eirs = calc_cooling_eirs(num_speeds, eers, fan_power_rated)
shrs_rated_gross = calc_shrs_rated_gross(num_speeds, shrs, fan_power_rated, cfms_ton_rated)
cOOL_CLOSS_FPLR_SPEC = [calc_plr_coefficients_cooling(num_speeds, seer)]

obj_name = Constants.ObjectNameCentralAirConditioner(unit.name.to_s)

thermal_zones = Geometry.get_thermal_zones_from_spaces(unit.spaces)

control_slave_zones_hash = get_control_and_slave_zones(thermal_zones)
control_slave_zones_hash.each do |control_zone, slave_zones|
  # _processCurvesDXCooling

  clg_coil_stage_data = calc_coil_stage_data_cooling(model, capacity, (0...num_speeds).to_a, cooling_eirs, shrs_rated_gross, cOOL_CAP_FT_SPEC, cOOL_EIR_FT_SPEC, cOOL_CLOSS_FPLR_SPEC, cOOL_CAP_FFLOW_SPEC, cOOL_EIR_FFLOW_SPEC, curves_in_ip, dse)


  # _processSystemFan

  fan = OpenStudio::Model::FanOnOff.new(model, model.alwaysOnDiscreteSchedule)
  fan_eff = 0.75 # Overall Efficiency of the Fan, Motor and Drive
  fan.setName(obj_name + " clg supply fan")
  fan.setEndUseSubcategory(obj_name + " clg supply fan")
  fan.setFanEfficiency(fan_eff)
  fan.setPressureRise(calculate_fan_pressure_rise(fan_eff, fan_power_installed / dse))
  fan.setMotorEfficiency(1.0)
  fan.setMotorInAirstreamFraction(1.0)

  # _processSystemAir

  air_loop_unitary = OpenStudio::Model::AirLoopHVACUnitarySystem.new(model)
  air_loop_unitary.setName(obj_name + " unitary system")
  air_loop_unitary.setAvailabilitySchedule(model.alwaysOnDiscreteSchedule)
  air_loop_unitary.setCoolingCoil(clg_coil)
  air_loop_unitary.setSupplyAirFlowRateDuringHeatingOperation(0.0)
  air_loop_unitary.setSupplyFan(fan)
  air_loop_unitary.setFanPlacement("BlowThrough")
  air_loop_unitary.setSupplyAirFanOperatingModeSchedule(model.alwaysOffDiscreteSchedule)
  air_loop_unitary.setMaximumSupplyAirTemperature(UnitConversions.convert(120.0, "F", "C"))
  air_loop_unitary.setSupplyAirFlowRateWhenNoCoolingorHeatingisRequired(0)

  air_loop = OpenStudio::Model::AirLoopHVAC.new(model)
  air_loop.setName(obj_name + " asys")
  air_supply_inlet_node = air_loop.supplyInletNode
  air_supply_outlet_node = air_loop.supplyOutletNode
  air_demand_inlet_node = air_loop.demandInletNode
  air_demand_outlet_node = air_loop.demandOutletNode

  air_loop_unitary.addToNode(air_supply_inlet_node)

  runner.registerInfo("Added '#{fan.name}' to '#{air_loop_unitary.name}' of '#{air_loop.name}'")
  runner.registerInfo("Added '#{clg_coil.name}' to '#{air_loop_unitary.name}' of '#{air_loop.name}'")

  air_loop_unitary.setControllingZoneorThermostatLocation(control_zone)

  # _processSystemDemandSideAir
  # Demand Side

  # Supply Air
  zone_splitter = air_loop.zoneSplitter
  zone_splitter.setName(obj_name + " zone splitter")

  zone_mixer = air_loop.zoneMixer
  zone_mixer.setName(obj_name + " zone mixer")

  diffuser_living = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule)
  diffuser_living.setName(obj_name + " #{control_zone.name} direct air")
  air_loop.multiAddBranchForZone(control_zone, diffuser_living)

  air_loop.multiAddBranchForZone(control_zone)
  runner.registerInfo("Added '#{air_loop.name}' to '#{control_zone.name}' of #{unit.name}")

  prioritize_zone_hvac(model, runner, control_zone)

  slave_zones.each do |slave_zone|
    diffuser_fbsmt = OpenStudio::Model::AirTerminalSingleDuctUncontrolled.new(model, model.alwaysOnDiscreteSchedule)
    diffuser_fbsmt.setName(obj_name + " #{slave_zone.name} direct air")
    air_loop.multiAddBranchForZone(slave_zone, diffuser_fbsmt)

    air_loop.multiAddBranchForZone(slave_zone)
    runner.registerInfo("Added '#{air_loop.name}' to '#{slave_zone.name}' of #{unit.name}")

    prioritize_zone_hvac(model, runner, slave_zone)
  end # slave_zone

  # Store info for HVAC Sizing measure
  air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACCapacityDerateFactorEER, eer_capacity_derates.join(","))
  air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACRatedCFMperTonCooling, cfms_ton_rated.join(","))
  air_loop_unitary.additionalProperties.setFeature(Constants.SizingInfoHVACFracCoolLoadServed, frac_cool_load_served)
end # control_zone

return true

end

def self.apply_central_ac_2speed(model, unit, runner, seer, eers, shrs, capacity_ratios, fan_speed_ratios, fan_power_rated, fan_power_installed, crankcase_capacity, crankcase_temp, eer_capacity_derates, capacity, dse, frac_cool_load_served)

return true if frac_cool_load_served <= 0

num_speeds = 2

# Performance curves
# NOTE: These coefficients are in IP UNITS
curves_in_ip = true
cOOL_CAP_FT_SPEC = [[3.940185508, -0.104723455, 0.001019298, 0.006471171, -0.00000953, -0.000161658],
                    [3.109456535, -0.085520461, 0.000863238, 0.00863049, -0.0000210, -0.000140186]]
cOOL_EIR_FT_SPEC = [[-3.877526888, 0.164566276, -0.001272755, -0.019956043, 0.000256512, -0.000133539],
                    [-1.990708931, 0.093969249, -0.00073335, -0.009062553, 0.000165099, -0.0000997]]
cOOL_CAP_FFLOW_SPEC = [[0.65673024, 0.516470835, -0.172887149],
                       [0.690334551, 0.464383753, -0.154507638]]
cOOL_EIR_FFLOW_SPEC = [[1.562945114, -0.791859997, 0.230030877],
                       [1.31565404, -0.482467162, 0.166239001]]

# Cooling Coil
rated_airflow_rate = 355.2 # cfm
cfms_ton_rated = calc_cfms_ton_rated(rated_airflow_rate, fan_speed_ratios, capacity_ratios)
cooling_eirs = calc_cooling_eirs(num_speeds, eers, fan_power_rated)
shrs_rated_gross = calc_shrs_rated_gross(num_speeds, shrs, fan_power_rated, cfms_ton_rated)
cOOL_CLOSS_FPLR_SPEC = [calc_plr_coefficients_cooling(num_speeds, seer)] * num_speeds

obj_name = Constants.ObjectNameCentralAirConditioner(unit.name.to_s)

thermal_zones = Geometry.get_thermal_zones_from_spaces(unit.spaces)

control_slave_zones_hash = get_control_and_slave_zones(thermal_zones)
control_slave_zones_hash.each do |control_zone, slave_zones|

I looked at this study for some information: https://www.nrel.gov/docs/fy13osti/56354.pdf and this paper: https://www.sciencedirect.com/science/article/pii/S0306261921005559

I would appreciate it if anyone could guide me to gain a better understanding of how to model COP curves using this information.