File size: 2,679 Bytes
ffa5234
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
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
# SOC is normalized so that minimal_depth_of_discharge = 0 and maximal_depth_of_discharge = 1.
# please set capacity_Ah = nominal_capacity_Ah * (max_dod - min_dod)
#
# TODO efficiency multiplier is not currently used, where best to put it?
class BatteryModel:
    def __init__(self, capacity_Ah, time_interval_h):
        self.capacity_Ah = capacity_Ah
        self.efficiency = 0.9 # [dimensionless]
        self.voltage_V = 600
        self.charge_kW = 50
        self.discharge_kW = 60
        self.time_interval_h = time_interval_h

        # the only non-constant member variable!
        # ratio of self.current_capacity_kWh and self.maximal_capacity_kWh
        self.soc = 0.0 

    @property
    def maximal_capacity_kWh(self):
        return self.capacity_Ah * self.voltage_V / 1000

    @property
    def current_capacity_kWh(self):
        return self.soc * self.maximal_capacity_kWh

    def satisfy_demand(self, demand_kW):
        assert 0 <= self.soc <= 1
        assert demand_kW >= 0
        # rate limited:
        possible_discharge_in_timestep_kWh = self.discharge_kW * self.time_interval_h
        # limited by current capacity:
        possible_discharge_in_timestep_kWh = min((possible_discharge_in_timestep_kWh, self.current_capacity_kWh))
        # limited by need:
        discharge_in_timestep_kWh = min((possible_discharge_in_timestep_kWh, demand_kW * self.time_interval_h))
        consumption_from_bess_kW = discharge_in_timestep_kWh / self.time_interval_h
        unsatisfied_demand_kW = demand_kW - consumption_from_bess_kW
        cap_of_battery_kWh = self.current_capacity_kWh - discharge_in_timestep_kWh
        soc = cap_of_battery_kWh / self.maximal_capacity_kWh
        assert 0 <= soc <= self.soc <= 1
        self.soc = soc
        return unsatisfied_demand_kW

    def charge(self, charge_kW):
        assert 0 <= self.soc <= 1
        assert charge_kW >= 0
        # rate limited:
        possible_charge_in_timestep_kWh = self.charge_kW * self.time_interval_h
        # limited by current capacity:
        possible_charge_in_timestep_kWh = min((possible_charge_in_timestep_kWh, self.maximal_capacity_kWh - self.current_capacity_kWh))
        # limited by supply:
        charge_in_timestep_kWh = min((possible_charge_in_timestep_kWh, charge_kW * self.time_interval_h))
        actual_charge_kW = charge_in_timestep_kWh / self.time_interval_h
        unused_charge_kW = charge_kW - actual_charge_kW
        cap_of_battery_kWh = self.current_capacity_kWh + charge_in_timestep_kWh
        soc = cap_of_battery_kWh / self.maximal_capacity_kWh
        assert 0 <= self.soc <= soc <= 1
        self.soc = soc
        return unused_charge_kW