Spaces:
Sleeping
Sleeping
File size: 13,655 Bytes
60cca7c a1d7129 60cca7c a1d7129 60cca7c a1d7129 60cca7c a1d7129 60cca7c a1d7129 60cca7c a1d7129 60cca7c a1d7129 60cca7c a1d7129 60cca7c a1d7129 60cca7c a1d7129 60cca7c |
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256 257 258 259 260 261 262 263 264 265 266 267 268 269 270 271 272 273 274 275 276 277 278 279 280 281 282 283 284 285 286 287 288 289 290 291 292 293 294 295 296 297 298 299 300 301 302 303 304 305 306 307 308 309 310 311 312 313 314 315 316 317 318 319 320 321 322 323 324 325 326 327 328 329 330 331 332 333 334 335 336 337 338 339 340 341 342 343 344 345 346 347 348 |
"""
ASHRAE Heating Load Calculation Module
This module implements the ASHRAE method for calculating heating loads in residential buildings.
It calculates the heat loss from the building envelope and unwanted ventilation/infiltration.
"""
import numpy as np
import pandas as pd
class HeatingLoadCalculator:
"""
A class to calculate heating loads using the ASHRAE method.
"""
def __init__(self):
"""Initialize the heating load calculator with default values."""
# Specific heat capacity of air × density of air
self.air_heat_factor = 0.33
# Default values for internal heat gains (W)
self.heat_gain_per_person = 75
self.heat_gain_kitchen = 1000
def calculate_conduction_heat_loss(self, area, u_value, temp_diff):
"""
Calculate conduction heat loss through building components.
Args:
area (float): Area of the building component in m²
u_value (float): U-value of the component in W/m²°C
temp_diff (float): Temperature difference (inside - outside) in °C
Returns:
float: Heat loss in Watts
"""
return area * u_value * temp_diff
def calculate_wall_solar_heat_gain(self, area, u_value, orientation, daily_range='medium', latitude='medium'):
"""
Calculate solar heat gain through walls based on orientation.
Args:
area (float): Area of the wall in m²
u_value (float): U-value of the wall in W/m²°C
orientation (str): Wall orientation ('north', 'east', 'south', 'west')
daily_range (str): Daily temperature range ('low', 'medium', 'high')
latitude (str): Latitude category ('low', 'medium', 'high')
Returns:
float: Heat gain in Watts
"""
# Solar intensity factors based on orientation - for heating, south-facing walls (northern hemisphere)
# or north-facing walls (southern hemisphere) receive more solar gain in winter
# These are simplified factors for demonstration
orientation_factors = {
'north': 0.6, # Higher in southern hemisphere during winter
'east': 0.4,
'south': 0.2, # Lower in southern hemisphere during winter
'west': 0.4,
'horizontal': 0.3
}
# Adjustments for latitude
latitude_factors = {
'low': 0.9, # Closer to equator - less winter sun angle
'medium': 1.0, # Mid latitudes
'high': 1.1 # Closer to poles - more winter sun angle variation
}
# Adjustments for daily temperature range
range_factors = {
'low': 0.95, # Less than 8.5°C
'medium': 1.0, # Between 8.5°C and 14°C
'high': 1.05 # Over 14°C
}
# Base solar heat gain through walls (W/m²) - lower in winter
base_solar_gain = 10.0
# Get factors
orientation_factor = orientation_factors.get(orientation.lower(), 0.5) # Default to south if not found
latitude_factor = latitude_factors.get(latitude.lower(), 1.0)
range_factor = range_factors.get(daily_range.lower(), 1.0)
# Calculate solar heat gain
solar_gain = area * base_solar_gain * orientation_factor * latitude_factor * range_factor
# Factor in the U-value (walls with higher U-values transmit more solar heat)
u_value_factor = min(u_value / 0.5, 2.0) # Normalize against a typical U-value of 0.5
return solar_gain * u_value_factor
def calculate_infiltration_heat_loss(self, volume, air_changes, temp_diff):
"""
Calculate heat loss due to infiltration and ventilation.
Args:
volume (float): Volume of the space in m³
air_changes (float): Number of air changes per hour
temp_diff (float): Temperature difference (inside - outside) in °C
Returns:
float: Heat loss in Watts
"""
return self.air_heat_factor * volume * air_changes * temp_diff
def calculate_internal_heat_gain(self, num_people, has_kitchen=False, equipment_watts=0):
"""
Calculate internal heat gain from people, kitchen, and equipment.
Args:
num_people (int): Number of occupants
has_kitchen (bool): Whether the space includes a kitchen
equipment_watts (float): Additional equipment heat gain in Watts
Returns:
float: Heat gain in Watts
"""
people_gain = num_people * self.heat_gain_per_person
kitchen_gain = self.heat_gain_kitchen if has_kitchen else 0
return people_gain + kitchen_gain + equipment_watts
def calculate_annual_heating_energy(self, total_heat_loss, heating_degree_days, correction_factor=1.0):
"""
Calculate annual heating energy requirement using heating degree days.
Args:
total_heat_loss (float): Total heat loss in Watts
heating_degree_days (float): Number of heating degree days
correction_factor (float): Correction factor for occupancy
Returns:
float: Annual heating energy in kWh
"""
# Convert W to kW
heat_loss_kw = total_heat_loss / 1000
# Calculate annual heating energy (kWh)
# 24 hours in a day
annual_energy = heat_loss_kw * 24 * heating_degree_days * correction_factor
return annual_energy
def get_outdoor_design_temperature(self, location):
"""
Get the outdoor design temperature for a location.
Args:
location (str): Location name
Returns:
float: Outdoor design temperature in °C
"""
# This is a simplified version - in a real implementation, this would use lookup tables
# based on the AIRAH Design Data Manual
# Example data for Australian locations
temperatures = {
'sydney': 7.0,
'melbourne': 4.0,
'brisbane': 9.0,
'perth': 7.0,
'adelaide': 5.0,
'hobart': 2.0,
'darwin': 15.0,
'canberra': -1.0,
'mildura': 4.5
}
return temperatures.get(location.lower(), 5.0) # Default to 5°C if location not found
def get_heating_degree_days(self, location, base_temp=18):
"""
Get the heating degree days for a location.
Args:
location (str): Location name
base_temp (int): Base temperature for HDD calculation (default: 18°C)
Returns:
float: Heating degree days
"""
# This is a simplified version - in a real implementation, this would use lookup tables
# or API data from Bureau of Meteorology
# Example data for Australian locations with base temperature of 18°C
hdd_data = {
'sydney': 740,
'melbourne': 1400,
'brisbane': 320,
'perth': 760,
'adelaide': 1100,
'hobart': 1800,
'darwin': 0,
'canberra': 2000,
'mildura': 1200
}
return hdd_data.get(location.lower(), 1000) # Default to 1000 if location not found
def get_occupancy_correction_factor(self, occupancy_type):
"""
Get the correction factor for occupancy type.
Args:
occupancy_type (str): Type of occupancy
Returns:
float: Correction factor
"""
# Correction factors based on occupancy patterns
factors = {
'continuous': 1.0, # Continuously heated
'intermittent': 0.8, # Heated during occupied hours
'night_setback': 0.9, # Temperature setback at night
'weekend_off': 0.85, # Heating off during weekends
'vacation_home': 0.6 # Occasionally occupied
}
return factors.get(occupancy_type.lower(), 1.0) # Default to continuous if not found
def calculate_total_heating_load(self, building_components, infiltration, internal_gains=None):
"""
Calculate the total peak heating load.
Args:
building_components (list): List of dicts with 'area', 'u_value', 'temp_diff', and 'orientation' for each component
infiltration (dict): Dict with 'volume', 'air_changes', and 'temp_diff'
internal_gains (dict): Dict with 'num_people', 'has_kitchen', and 'equipment_watts'
Returns:
dict: Dictionary with component heat losses and total heating load in Watts
"""
# Calculate conduction heat loss through building components
component_losses = {}
total_conduction_loss = 0
wall_solar_gain = 0
for comp in building_components:
name = comp.get('name', f"Component {len(component_losses) + 1}")
loss = self.calculate_conduction_heat_loss(comp['area'], comp['u_value'], comp['temp_diff'])
component_losses[name] = loss
total_conduction_loss += loss
# Calculate solar gain for walls based on orientation
if 'orientation' in comp:
daily_range = comp.get('daily_range', 'medium')
latitude = comp.get('latitude', 'medium')
solar_gain = self.calculate_wall_solar_heat_gain(
comp['area'],
comp['u_value'],
comp['orientation'],
daily_range,
latitude
)
wall_solar_gain += solar_gain
# Calculate infiltration heat loss
infiltration_loss = self.calculate_infiltration_heat_loss(
infiltration['volume'], infiltration['air_changes'], infiltration['temp_diff']
)
# Calculate internal heat gain if provided
internal_gain = 0
if internal_gains:
internal_gain = self.calculate_internal_heat_gain(
internal_gains.get('num_people', 0),
internal_gains.get('has_kitchen', False),
internal_gains.get('equipment_watts', 0)
)
# Calculate total heating load (subtract solar gain and internal gains as they reduce heating load)
total_load = total_conduction_loss + infiltration_loss - wall_solar_gain - internal_gain
return {
'component_losses': component_losses,
'total_conduction_loss': total_conduction_loss,
'infiltration_loss': infiltration_loss,
'wall_solar_gain': wall_solar_gain,
'internal_gain': internal_gain,
'total_load': total_load
}
def calculate_annual_heating_requirement(self, total_load, location, occupancy_type='continuous', base_temp=18):
"""
Calculate the annual heating energy requirement.
Args:
total_load (float): Total heating load in Watts
location (str): Location name
occupancy_type (str): Type of occupancy
base_temp (int): Base temperature for HDD calculation
Returns:
dict: Dictionary with annual heating energy in kWh and related factors
"""
# Get heating degree days for the location
hdd = self.get_heating_degree_days(location, base_temp)
# Get correction factor for occupancy
correction_factor = self.get_occupancy_correction_factor(occupancy_type)
# Calculate annual heating energy
annual_energy = self.calculate_annual_heating_energy(total_load, hdd, correction_factor)
return {
'heating_degree_days': hdd,
'correction_factor': correction_factor,
'annual_energy_kwh': annual_energy,
'annual_energy_mj': annual_energy * 3.6 # Convert kWh to MJ
}
# Example usage
if __name__ == "__main__":
calculator = HeatingLoadCalculator()
# Example data for a simple room in Mildura
building_components = [
{'name': 'Floor', 'area': 50, 'u_value': 1.47, 'temp_diff': 16.5}, # Concrete slab
{'name': 'Walls', 'area': 80, 'u_value': 1.5, 'temp_diff': 16.5}, # External walls
{'name': 'Ceiling', 'area': 50, 'u_value': 0.9, 'temp_diff': 16.5}, # Ceiling
{'name': 'Windows', 'area': 8, 'u_value': 5.8, 'temp_diff': 16.5} # Windows
]
infiltration = {'volume': 125, 'air_changes': 0.5, 'temp_diff': 16.5}
# Calculate peak heating load
result = calculator.calculate_total_heating_load(building_components, infiltration)
print("Heating Load Calculation Results:")
for key, value in result.items():
if key == 'component_losses':
print("Component Losses:")
for comp, loss in value.items():
print(f" {comp}: {loss:.2f} W")
else:
print(f"{key}: {value:.2f} W")
# Calculate annual heating requirement
annual_result = calculator.calculate_annual_heating_requirement(result['total_load'], 'mildura')
print("\nAnnual Heating Requirement:")
for key, value in annual_result.items():
print(f"{key}: {value:.2f}")
|