# Documentation for the creation and usage of the heat pump library (hplib)¶

This documentation covers the database preperation, validation and usage for simulation. If you're only interested in using hplib for simulation purpose, you should have a look into chapter 4. How to simulate.

1. Definitions
2. Database preperation
3. Work with database
   1. Load database
   2. Load specific model
   3. Load generic model
4. How to simulate
   1. Simulate on time step
   2. Simulate a time series
5. Example heat pump
6. Validation
   1. Air/Water | on/off
   2. Brine/Water | on/off
   3. Water/Water | on/off
   4. Air/Water | regulated
      1. Heating
      2. Cooling
   5. Brine/Water | regulated
7. Conclusion

In [ ]:

    import hplib as hpl
    import hplib_database as db
    import pandas as pd
    import matplotlib.pyplot as plt
    import warnings
    import numpy
    warnings.filterwarnings("ignore")

In [ ]:

    %%html
    <style>
    table {float:left}
    </style>

## 1. Definitions ¶

Abbreviations

Abbreviation | Meaning
--- | ---
P_th | Thermal output power in W
P_el | Electical input Power in W
COP | Coefficient of performance
EER | Energy Efficiency Ratio
T_in | Input temperature in °C at primary side of the heat pump
T_out | Output temperature in °C at secondary side of the heat pump
T_amb | Ambient temperature in °C
P_th_h_ref | Thermal heating output power in W at T_in = -7 °C and T_out = 52 °C
P_el_h_ref | Elecrical input power (heating) in W at T_in = -7 °C and T_out = 52 °C
COP_ref | Coefficient of performance at T_in = -7 °C and T_out = 52 °C
P_th_c_ref | Thermal cooling output power in W at T_in = 35 °C and T_out = 7 °C
P_el_c_ref | Elecrical input power (cooling) in W at T_in = 35 °C and T_out = 7 °C
p1-p4 | Fit-Parameters for Fit-Function

Group IDs

Group ID | Type | Subtype
--- | --- | ---
1 | Outdoor Air / Water | Regulated
2 | Brine / Water | Regulated
3 | Water / Water | Regulated
4 | Outdoor Air / Water | On-Off
5 | Brine / Water | On-Off
6 | Water / Water | On-Off

## 2. Database preparation ¶

This section is only for documentation regarding the development of the final database. It's not neccesary to run this code again.

1. we downloaded all manufacturer data from https://keymark.eu/en/products/heatpumps/certified-products .
2. then we unzipped the files to the `input` folder and used the bash-skript `pdf2txt.sh` to convert pdf into txt.
3. afterwards we used the following functions to create and extent the heatpump keymark database.

In [ ]:

    # Import keymark data and save to csv database
    db.import_heating_data()
    # -> this creates /output/database_heating.csv
    db.import_cooling_data()
    # -> this creates /output/database_cooling.csv

In [ ]:

    # Reduce to climate measurement series with average climate, delete redundant entries and save to csv sub-database
    db.reduce_heating_data('database_heating.csv','average')
    # -> this creates /output/database_heating_average.csv

Process heating database

In [ ]:

    # Normalize electrical and thermal power from the keymark database to values from setpoint T_in = -7 °C and T_out = 52 °C
    db.normalize_heating_data('database_heating_average.csv')
    # -> this creates /output/database_heating_average_normalized.csv

In [ ]:

    # Identify subtypes like on-off or regulated heat pumps and assign group id depending on its type and subtype
    db.identify_subtypes('database_heating_average_normalized.csv')
    # -> this creates /output/database_heating_average_normalized_subtypes.csv

In [ ]:

    # Calculate parameters p1-p4 for P_th, P_el and COP with a least-square fit approach
    # based on  K. Schwamberger: „Modellbildung und Regelung von Gebäudeheizungsanlagen
    # mit Wärmepumpen“, VDI Verlag, Düsseldorf, Fortschrittsberichte VDI Reihe 6 Nr. 263, 1991.
    db.calculate_heating_parameters('database_heating_average_normalized_subtypes.csv')
    # -> this creates /output/hplib_database_heating.csv
    # -> this creates /src/hplib_database.csv

In [ ]:

    # Many heat pump models have redundant entries because of different controller or storage configurations.
    # Reduce to unique heat pump models.
    db.reduce_to_unique()
    # -> this overwrites the /output/hplib_database_heating.csv

In [ ]:

    # Calculate the relative error (RE) for each set point of every heat pump
    db.validation_relative_error_heating()
    # -> this creates /output/database_heating_average_normalized_subtypes_validation.csv

In [ ]:

    # Calculate the mean absolute percentage error (MAPE) for every heat pump
    db.validation_mape_heating()
    # -> this overwrites the /output/hplib_database_heating.csv

Process cooling database

Overall there are not so many unique Keymark heat pumps for cooling (34 models) in comparison to heating (505 models).

Out of the 34 models only 4 heat pumps had set points at different outflow temperature. With our fit method it is not possible to fit only over one outflow temperature. For that reason we added another set point at 18°C output temperature based on the heat pumps we had with this condition in Keymark. For that purpose, we identified multiplication factors for eletrical power and eer between 7°C and 18°C secondary output temperature. The mean value of that are used to calculate the electrical power and EER at 18°C for other heat pumps:

    P_el at 18°C = P_el at 7°C * multiplication factor
    EER at 18°C = EER at 7°C * multiplication factor

Outside Tempertature | Multiplication factor for P_el | Multiplication factor for EER
--- | --- | ---
35 | 0.85 | 1.21
30 | 0.82 | 1.21
25 | 0.77 | 1.20
20 | 0.63 | 0.95

In [ ]:

    #Only use heatpumps which are unique and also in the heating library
    db.reduce_cooling_data()
    #this generates /output/database_cooling_reduced.csv

In [ ]:

    # Normalize electrical and thermal power from the keymark database to values from setpoint T_outside = 35 °C and T_out = 7 °C
    db.normalize_and_add_cooling_data()
    #-> this creates /output/database_cooling_reduced_normalized.csv

In [ ]:

    # Used the same fit method like in heating
    # except: for P_el the point 20/7 is ignored
    db.calculate_cooling_parameters()
    # -> this overwrites /src/hplib_database.csv

In [ ]:

    # Calculate the relative error (RE) for each set point of every heat pump
    db.validation_relative_error_cooling()
    # this creates /output/database_cooling_reduced_normalized_subtypes_validation.csv

In [ ]:

    # Calculate the mean absolute percentage error (MAPE) for every heat pump
    db.validation_mape_cooling()
    # -> this overwrites the /src/hplib_database.csv

Create generic heat pump models

In [ ]:

    # Calculate generic heat pump models for each group id
    # for cooling: there is only a generic heat pump of type air/water | regulated available
    db.add_generic()
    # -> this overwrites the /src/hplib_database.csv

Hint: The csv files in the `output` folder are for documentation and validation purpose. The code `hplib.py` and database `hplib_database` files, which are meant to be used for simulations, are located in the `src` folder.

## 3. Work with database ¶

### 3.1 Load database ¶

Simply execute the command without arguments and you will get a DataFrame with the complete list of manufacturers and models. Now you are able to view, filter or sort the database.

In [ ]:

    database = hpl.load_database()
    database

Out[ ]:

| Manufacturer | Model | Date | Type | Subtype | Group | Refrigerant | Mass of Refrigerant [kg] | SPL indoor [dBA] | SPL outdoor [dBA] | ... | p2_P_el_c [1/°C] | p3_P_el_c [-] | p4_P_el_c [1/°C] | p1_EER [-] | p2_EER [-] | p3_EER [-] | p4_EER [-] | MAPE_P_el_cooling | MAPE_EER | MAPE_Pdc
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
0 | Advantix | i-SHWAK V4 06 | 2020-05-26 | Outdoor Air/Water | Regulated | 1.0 | R410a | 2.68 | 35.0 | 64.0 | ... | -0.010769 | -0.763316 | -70.588606 | 37.392760 | 0.046170 | 6.295339 | -37.488343 | 12.221419 | 6.840097 | 9.194424
1 | Advantix | i-SHWAK V4 08 | 2020-05-26 | Outdoor Air/Water | Regulated | 1.0 | R410a | 2.20 | 35.0 | 64.0 | ... | -0.010295 | -1.008835 | -70.584924 | 53.317794 | 0.045359 | 6.373991 | -53.417576 | 8.557697 | 5.543797 | 6.180972
2 | Advantix | i-SHWAK V4 10 | 2020-05-26 | Outdoor Air/Water | Regulated | 1.0 | R410a | 3.45 | 39.0 | 64.0 | ... | -0.009974 | -1.070117 | -71.138737 | -38.305956 | 0.055509 | 10.401025 | 38.096062 | 12.129224 | 4.233020 | 12.245195
3 | Advantix | i-SHWAK V4 12 | 2020-05-26 | Outdoor Air/Water | Regulated | 1.0 | R410a | 3.45 | 39.0 | 65.0 | ... | -0.009670 | -1.199827 | -79.730152 | -106.597525 | 0.055461 | 10.417088 | 106.386968 | 10.736620 | 4.251786 | 11.085364
4 | Advantix | i-SHWAK V4 14T | 2020-05-26 | Outdoor Air/Water | Regulated | 1.0 | R410a | 4.40 | 40.0 | 68.0 | ... | -0.009060 | -1.464498 | -70.578508 | -106.597525 | 0.055461 | 10.417088 | 106.386968 | 6.954977 | 4.251786 | 7.852487
... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ... | ...
506 | Generic | Generic | NaN | Brine/Water | Regulated | 2.0 | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN
507 | Generic | Generic | NaN | Water/Water | Regulated | 3.0 | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN
508 | Generic | Generic | NaN | Outdoor Air/Water | On-Off | 4.0 | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN
509 | Generic | Generic | NaN | Brine/Water | On-Off | 5.0 | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN
510 | Generic | Generic | NaN | Water/Water | On-Off | 6.0 | NaN | NaN | NaN | NaN | ... | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN | NaN

511 rows × 47 columns

### 3.2 Load specific model ¶

To get the parameters of a specific heat pump model, use the `get_parameters()` method with a specific Model name from the database. You will get a DataFrame with all parameters including the mean absolute percentage errors (MAPE) for this model.

In [ ]:

    parameters = hpl.get_parameters('i-SHWAK V4 06')
    parameters

Out[ ]:

| Manufacturer | Model | MAPE_COP | MAPE_P_el | MAPE_P_th | P_th_h_ref [W] | P_el_h_ref [W] | COP_ref | Group | p1_P_th [1/°C] | ... | p3_Pdc [-] | p4_Pdc [1/°C] | p1_P_el_c [1/°C] | p2_P_el_c [1/°C] | p3_P_el_c [-] | p4_P_el_c [1/°C] | p1_EER [-] | p2_EER [-] | p3_EER [-] | p4_EER [-]
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
0 | Advantix | i-SHWAK V4 06 | 9.244852 | 22.607658 | 24.897666 | 4500.0 | 2866.0 | 1.57 | 1.0 | 1.756924 | ... | 0.068769 | -70.599887 | 70.638879 | -0.010769 | -0.763316 | -70.588606 | 37.39276 | 0.04617 | 6.295339 | -37.488343

1 rows × 35 columns

### 3.3 Load generic model ¶

To get the parameters of a generic heat pump model, use the `get_parameters()` method with the following keyword arguments of a free choosen set point

- model='Generic'
- group_id: 1,2,4,5,6
- t_in: choose primary input temperature in °C
- t_out: choose secondary output temperature in °C
- p_th: choose thermal output power in W

You will get a DataFrame with all parameters for this generic model. For every group id the parameter set is based on the average parameters of all heat pumps of its group with an MAPE of less than 25%.

In [ ]:

    parameters = hpl.get_parameters(model='Generic', group_id=1, t_in=-7, t_out=52, p_th=10000)
    parameters

Out[ ]:

| Manufacturer | Model | MAPE_COP | MAPE_P_el | MAPE_P_th | P_th_h_ref [W] | P_el_h_ref [W] | COP_ref | Group | p1_P_th [1/°C] | ... | p4_Pdc [1/°C] | p1_P_el_c [1/°C] | p2_P_el_c [1/°C] | p3_P_el_c [-] | p4_P_el_c [1/°C] | p1_EER [-] | p2_EER [-] | p3_EER [-] | p4_EER [-] | EER_ref
--- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | --- | ---
0 | Generic | Generic | NaN | NaN | NaN | 10168.785754 | 7193.433182 | 1.413621 | 1.0 | 69.969927 | ... | -71.578974 | 69.044359 | -0.009208 | -1.368639 | -68.976493 | -11.722768 | 0.06484 | 11.52005 | 11.474317 | 3.278166

1 rows × 36 columns

## 4. How to simulate ¶

With the Fit-Parameters p1-p4 for P_th, P_el and COP it is possible to calculate the results with the following methods:

1. P_th and P_el with Fit-Functions and `COP = P_th / P_el` or
2. P_th and COP with Fit-Functions and `P_el = P_th / COP` or
3. P_el and COP with Fut-Functions and `P_th = P_el * COP`

While the model by Schwarmberger [1] uses the first method, our validation showed, that the third method leads to better results. Therefore we decided to implement this in the `simulate` definition.

### 4.1 Simulate one timestep ¶

Please define a primary input temperature (t_in_primary), secondary input temperature (t_in_secondary), ambient / outdoor temperature (t_amb) in °C and the parameters from the previous step. The t_in_secondary is supposed to be heated up by 5 K which then results in output temperature.

Important:

- for air / water heat pumps t_in_primary and t_amb are supposed to be the same values.
- for brine / water or water / water heat pumps t_in_primary and t_amb are independent values.

In [ ]:

    # Load parameters
    parameters = hpl.get_parameters(model='Generic', group_id=1, t_in=-7, t_out=52, p_th=10000)
    # Create heat pump object with parameters
    heatpump = hpl.HeatPump(parameters)
    # Simulate with values
    # whereas mode = 1 is for heating and mode = 2 is for cooling
    results = heatpump.simulate(t_in_primary=-7, t_in_secondary=47, t_amb=-7, mode=1)
    print(pd.DataFrame([results]))

       T_in  T_out  T_amb       COP  EER         P_el     P_th    m_dot
    0    -7     52     -7  1.413621    0  7074.033573  10000.0  0.47619

### 4.2 Simulate a timeseries ¶

The simulation approach could be to do a `for loop` around the method of simulating one timestep. But it will be faster to use the previous method with arrays as inputs. For usage you are allowed to define pandas.Series or arrays as input values. It is also possible to combine single values and pandas.Series / arrays.

The next example uses a measured timeseries for ambient / outdoor temperature and secondary input temperature of a real heating system to demonstrate the simulation approach. The data represents on year and has a temporal resolution of 1 minute

In [ ]:

    # Read input file with temperatures
    df = pd.read_csv('../input/TestYear.csv')
    df['T_amb'] = df['T_in_primary'] # air/water heat pump -> T_amb = T_in_primary
    # Simulate with values
    # Load parameters
    parameters = hpl.get_parameters(model='Generic', group_id=1, t_in=-7, t_out=52, p_th=10000)
    # Create heat pump object with parameters
    heatpump = hpl.HeatPump(parameters)
    # whereas mode = 1 is for heating and mode = 2 is for cooling
    results = heatpump.simulate(t_in_primary=df['T_in_primary'].values, t_in_secondary=df['T_in_secondary'].values, t_amb=df['T_amb'].values, mode=1)
    # Plot / Print some results
    # example for distribution of COPs
    results=pd.DataFrame.from_dict(results)
    results['COP'].plot.hist(bins=50, title='Distribution of COP values')
    # Calclulate seasonal performance factor (SPF)
    SPF = results['P_th'].mean() / results['P_el'].mean()
    print('The seasonal performance factor (SPF) for one year is = '+str(round(SPF,1)))

    The seasonal performance factor (SPF) for one year is = 3.9

## 5. Example heat pump ¶

To get a overview over the different operation conditions, this section plots the electrical and thermal power as well as the COP for all possible primary and secondary input temperatures

HEATING: Schematic plot of COP, P_el and P_th for an generic air/water heat pump: subtype = on/off

In [ ]:

    # Define Temperatures
    T_in_primary = range(-20,31)
    T_in_secondary = range(20,56)
    T_in = numpy.array([])
    T_out = numpy.array([])

    # Load parameters of generic air/water | regulated
    parameters = hpl.get_parameters('Generic', group_id=4, t_in=-7, t_out=52, p_th = 10000)
    heatpump=hpl.HeatPump(parameters)
    results=pd.DataFrame()
    # Create input series
    for t1 in T_in_primary:
        for t2 in T_in_secondary:
            T_in=numpy.append(T_in,t1)
            T_out=numpy.append(T_out,t2)
    results=heatpump.simulate(t_in_primary=T_in, t_in_secondary=T_out, t_amb=T_in, mode=1)
    results=pd.DataFrame.from_dict(results)

    # Plot COP
    fig1, ax1 = plt.subplots()
    plot = plt.tricontourf(results['T_in'], results['T_out'], results['COP'])
    ax1.tricontour(results['T_in'], results['T_out'], results['COP'], colors='k')
    fig1.colorbar(plot)
    ax1.set_title('COP')
    ax1.set_xlabel('Primary input temperature [°C]')
    ax1.set_ylabel('Secondary output temperature [°C]')
    fig1.show

    # Plot electrical input power
    fig1, ax1 = plt.subplots()
    plot = plt.tricontourf(results['T_in'], results['T_out'], results['P_el'])
    ax1.tricontour(results['T_in'], results['T_out'], results['P_el'], colors='k')
    fig1.colorbar(plot)
    ax1.set_title('Eletrical input power [W]')
    ax1.set_xlabel('Primary input temperature [°C]')
    ax1.set_ylabel('Secondary output temperature [°C]')
    fig1.show

    # Plot thermal output power
    fig1, ax1 = plt.subplots()
    plot = plt.tricontourf(results['T_in'], results['T_out'], results['P_th'])
    ax1.tricontour(results['T_in'], results['T_out'], results['P_th'], colors='k')
    fig1.colorbar(plot)
    ax1.set_title('Thermal output power [W]')
    ax1.set_xlabel('Primary input temperature [°C]')
    ax1.set_ylabel('Secondary output temperature [°C]')
    fig1.show

Out[ ]:

    <bound method Figure.show of <Figure size 432x288 with 2 Axes>>

COOLING: Schematic plot of EER, P_el and P_th for an generic air/water heat pump: subtype = regulated

In [ ]:

    # Define Temperatures
    T_in_primary = range(20,36)
    T_in_secondary = range(10,30)
    T_in = numpy.array([])
    T_out = numpy.array([])

    # Load parameters of generic air/water | regulated
    parameters = hpl.get_parameters('Generic', group_id=1, t_in=-7, t_out=52, p_th = 10000)
    heatpump=hpl.HeatPump(parameters)
    results=pd.DataFrame()
    # Create input series
    for t1 in T_in_primary:
        for t2 in T_in_secondary:
            T_in=numpy.append(T_in,t1)
            T_out=numpy.append(T_out,t2)
    results=heatpump.simulate(t_in_primary=T_in, t_in_secondary=T_out, t_amb=T_in, mode=2)
    results=pd.DataFrame.from_dict(results)
    # Plot EER
    fig1, ax1 = plt.subplots()
    plot = plt.tricontourf(results['T_in'], results['T_out'], results['EER'])
    ax1.tricontour(results['T_in'], results['T_out'], results['EER'], colors='k')
    fig1.colorbar(plot)
    ax1.set_title('EER')
    ax1.set_xlabel('Primary input temperature [°C]')
    ax1.set_ylabel('Secondary output temperature [°C]')
    fig1.show

    # Plot electrical input power
    fig1, ax1 = plt.subplots()
    plot = plt.tricontourf(results['T_in'], results['T_out'], results['P_el'])
    ax1.tricontour(results['T_in'], results['T_out'], results['P_el'], colors='k')
    fig1.colorbar(plot)
    ax1.set_title('Eletrical input power [W]')
    ax1.set_xlabel('Primary input temperature [°C]')
    ax1.set_ylabel('Secondary output temperature [°C]')
    fig1.show

    # Plot thermal output power
    fig1, ax1 = plt.subplots()
    plot = plt.tricontourf(results['T_in'], results['T_out'], results['P_th'])
    ax1.tricontour(results['T_in'], results['T_out'], results['P_th'], colors='k')
    fig1.colorbar(plot)
    ax1.set_title('Thermal output power [W]')
    ax1.set_xlabel('Primary input temperature [°C]')
    ax1.set_ylabel('Secondary output temperature [°C]')
    fig1.show

Out[ ]:

    <bound method Figure.show of <Figure size 432x288 with 2 Axes>>

## 6. Validation ¶

The following plots will give you a detailed view on the differences between simulation and measurement from heat pump keymark. Therefore, all set points for all heat pumps are loaded from the file `database_heating_average_normalized_subtypes_validation.csv`.

In [ ]:

    df = pd.read_csv('../output/database_heating_average_normalized_subtypes_validation.csv')

### 6.1 Air/Water | on/off ¶

- The mean absolute percentage error (MAPE) over all heat pumps is
  - 5.4 % for COP
  - 2.5 % for P_el
  - 5.8 % for P_th
- The errors come from deviation mostly at low ambient / outside temperatures

In [ ]:

    # Plot relative error for all heat pumps of type air/water | on-off
    Group = 4
    data = df.loc[(df['Group']==Group)]
    data = data[['T_amb [°C]','RE_COP', 'RE_P_el', 'RE_P_th']]
    ax = data.boxplot(by='T_amb [°C]', layout=(1,3), figsize=(10,5), showfliers=False)
    ax[0].set_ylim(-60,60)
    ax[0].set_ylabel('relative error in %')
    data.abs().mean()[1:4] # mean absolute percentage error (MAPE)

Out[ ]:

    RE_COP     5.404139
    RE_P_el    2.525073
    RE_P_th    5.806641
    dtype: float64

In [ ]:

    # Plot absolute values all heat pumps of type air/water | on-off as scatter plot
    Group = 4
    fig, ax = plt.subplots(1,3)
    data = df.loc[(df['Group']==Group)]
    data.plot.scatter(ax=ax[0], x='COP',y='COP_sim', alpha=0.3, figsize=(12,5), grid=True, title='Coefficient of performance')
    data.plot.scatter(ax=ax[1], x='P_el [W]',y='P_el_sim', alpha=0.3, figsize=(15,5), grid=True, title='Electrical input power [W]')
    data.plot.scatter(ax=ax[2], x='P_th [W]',y='P_th_sim', alpha=0.3, figsize=(15,5), grid=True, title='Thermal output power [W]')
    ax[0].set_xlim(0,10)
    ax[0].set_ylim(0,10)
    ax[1].set_xlim(0,20000)
    ax[1].set_ylim(0,20000)
    ax[2].set_xlim(0,50000)
    ax[2].set_ylim(0,50000)

Out[ ]:

    (0.0, 50000.0)

### 6.2 Brine/Water | on/off ¶

- The mean absolute percentage error (MAPE) over all heat pumps is
  - 3.9 % for COP
  - 1.7 % for P_el
  - 2.7 % for P_th
- Important: Validation data is only available at primary input temperature of 0 °C.

In [ ]:

    # Plot relative error for all heat pumps of type brine/water | on-off
    Group = 5
    data = df.loc[(df['Group']==Group)]
    data = data[['T_amb [°C]','RE_COP', 'RE_P_el', 'RE_P_th']]
    ax = data.boxplot(by='T_amb [°C]', layout=(1,3), figsize=(10,5), showfliers=False)
    ax[0].set_ylim(-60,60)
    ax[0].set_ylabel('relative error in %')
    data.abs().mean()[1:4] # mean absolute percentage error (MAPE)

Out[ ]:

    RE_COP     3.897897
    RE_P_el    1.678427
    RE_P_th    2.668440
    dtype: float64

In [ ]:

    # Plot absolute values all heat pumps of type brine/water | on-off as scatter plot
    Group = 5
    fig, ax = plt.subplots(1,3)
    data = df.loc[(df['Group']==Group)]
    data.plot.scatter(ax=ax[0], x='COP',y='COP_sim', alpha=0.3, figsize=(12,5), grid=True, title='Coefficient of performance')
    data.plot.scatter(ax=ax[1], x='P_el [W]',y='P_el_sim', alpha=0.3, figsize=(15,5), grid=True, title='Electrical input power [W]')
    data.plot.scatter(ax=ax[2], x='P_th [W]',y='P_th_sim', alpha=0.3, figsize=(15,5), grid=True, title='Thermal output power [W]')
    ax[0].set_xlim(0,10)
    ax[0].set_ylim(0,10)
    ax[1].set_xlim(0,20000)
    ax[1].set_ylim(0,20000)
    ax[2].set_xlim(0,50000)
    ax[2].set_ylim(0,50000)

Out[ ]:

    (0.0, 50000.0)

### 6.3 Water/Water | on/off ¶

- The mean absolute percentage error (MAPE) over all heat pumps is
  - 1.6 % for COP
  - 1.6 % for P_el
  - 2.4 % for P_th
- Important: Validation data is only available at primary input temperature of 10 °C.

In [ ]:

    # Plot relative error for all heat pumps of type water/water | on-off
    Group = 6
    data = df.loc[(df['Group']==Group)]
    data = data[['T_amb [°C]','RE_COP', 'RE_P_el', 'RE_P_th']]
    ax = data.boxplot(by='T_amb [°C]', layout=(1,3), figsize=(10,5), showfliers=False)
    ax[0].set_ylim(-60,60)
    ax[0].set_ylabel('relative error in %')
    data.abs().mean()[1:4] # mean absolute percentage error (MAPE)

Out[ ]:

    RE_COP     1.563460
    RE_P_el    1.582038
    RE_P_th    2.415430
    dtype: float64

In [ ]:

    # Plot absolute values all heat pumps of type water/water | on-off as scatter plot
    Group = 6
    fig, ax = plt.subplots(1,3)
    data = df.loc[(df['Group']==Group)]
    data.plot.scatter(ax=ax[0], x='COP',y='COP_sim', alpha=0.3, figsize=(12,5), grid=True, title='Coefficient of performance')
    data.plot.scatter(ax=ax[1], x='P_el [W]',y='P_el_sim', alpha=0.3, figsize=(15,5), grid=True, title='Electrical input power [W]')
    data.plot.scatter(ax=ax[2], x='P_th [W]',y='P_th_sim', alpha=0.3, figsize=(15,5), grid=True, title='Thermal output power [W]')
    ax[0].set_xlim(0,10)
    ax[0].set_ylim(0,10)
    ax[1].set_xlim(0,20000)
    ax[1].set_ylim(0,20000)
    ax[2].set_xlim(0,50000)
    ax[2].set_ylim(0,50000)

Out[ ]:

    (0.0, 50000.0)

### 6.4 Air/Water | regulated ¶

Heating

- The mean absolute percentage error (MAPE) over all heat pumps is
  - 12.1 % for COP
  - 19.5 % for P_el
  - 23.5 % for P_th

Cooling

- The mean absolute percentage error (MAPE) over all heat pumps is
  - 4.8 % for EER
  - 16.5 % for P_el
  - 17.0 % for P_th

Because of different control strategies, the deviation over different heat pump models is much higher compared to on/off types.

#### 6.4.1 Heating ¶

In [ ]:

    # Plot relative error for all heat pumps of type air/water | regulated
    Group = 1
    data = df.loc[(df['Group']==Group)]
    data = data[['T_amb [°C]','RE_COP', 'RE_P_el', 'RE_P_th']]
    ax = data.boxplot(by='T_amb [°C]', layout=(1,3), figsize=(10,5), showfliers=False)
    ax[0].set_ylim(-60,60)
    ax[0].set_ylabel('relative error in %')
    data.abs().mean()[1:4] # mean absolute percentage error (MAPE)

Out[ ]:

    RE_COP     12.076160
    RE_P_el    19.456473
    RE_P_th    23.522542
    dtype: float64

In [ ]:

    # Plot absolute values all heat pumps of type air/water | regulated as scatter plot
    Group = 1
    fig, ax = plt.subplots(1,3)
    data = df.loc[(df['Group']==Group)]
    data.plot.scatter(ax=ax[0], x='COP',y='COP_sim', alpha=0.3, figsize=(12,5), grid=True, title='Coefficient of performance')
    data.plot.scatter(ax=ax[1], x='P_el [W]',y='P_el_sim', alpha=0.1, figsize=(15,5), grid=True, title='Electrical input power [W]')
    data.plot.scatter(ax=ax[2], x='P_th [W]',y='P_th_sim', alpha=0.1, figsize=(15,5), grid=True, title='Thermal output power [W]')
    ax[0].set_xlim(0,10)
    ax[0].set_ylim(0,10)
    ax[1].set_xlim(0,20000)
    ax[1].set_ylim(0,20000)
    ax[2].set_xlim(0,50000)
    ax[2].set_ylim(0,50000)

Out[ ]:

    (0.0, 50000.0)

#### 6.4.2 Cooling ¶

In [ ]:

    data = pd.read_csv('../output/database_cooling_reduced_normalized_validation.csv')
    data = data[['T_outside [°C]','RE_Pdc', 'RE_P_el', 'RE_EER']]
    ax = data.boxplot(by='T_outside [°C]', layout=(1,3), figsize=(10,5), showfliers=False)
    ax[0].set_ylim(-60,60)
    ax[0].set_ylabel('relative error in %')
    data.abs().mean()[1:4] # mean absolute percentage error (MAPE)

Out[ ]:

    RE_Pdc     16.964163
    RE_P_el    16.476100
    RE_EER      4.843020
    dtype: float64

In [ ]:

    data = pd.read_csv('../output/database_cooling_reduced_normalized_validation.csv')
    fig, ax = plt.subplots(1,3)
    data.plot.scatter(ax=ax[0], x='EER',y='EER_sim', alpha=0.3, figsize=(12,5), grid=True, title='Coefficient of performance')
    data.plot.scatter(ax=ax[1], x='P_el [W]',y='P_el_sim', alpha=0.1, figsize=(15,5), grid=True, title='Electrical input power [W]')
    data.plot.scatter(ax=ax[2], x='Pdc [W]',y='Pdc_sim', alpha=0.1, figsize=(15,5), grid=True, title='Thermal output power [W]')
    ax[0].set_xlim(0,10)
    ax[0].set_ylim(0,10)
    ax[1].set_xlim(0,6000)
    ax[1].set_ylim(0,6000)
    ax[2].set_xlim(0,15000)
    ax[2].set_ylim(0,15000)

Out[ ]:

    (0.0, 15000.0)

### 6.5 Brine/Water | regulated ¶

- The mean absolute percentage error (MAPE) is over all heat pumps is
  - 4.2 % for COP
  - 17.7 % for P_el
  - 19.7 % for P_th
- Important: Validation data is only available at primary input temperature of 0 °C.

In [ ]:

    # Plot relative error for all heat pumps of type brine/water | regulated
    Group = 2
    data = df.loc[(df['Group']==Group)]
    data = data[['T_amb [°C]','RE_COP', 'RE_P_el', 'RE_P_th']]
    ax = data.boxplot(by='T_amb [°C]', layout=(1,3), figsize=(10,5), showfliers=False)
    ax[0].set_ylim(-60,60)
    ax[0].set_ylabel('relative error in %')
    data.abs().mean()[1:4] # mean absolute percentage error (MAPE)

Out[ ]:

    RE_COP      4.228648
    RE_P_el    17.650300
    RE_P_th    19.737515
    dtype: float64

In [ ]:

    # Plot absolute values all heat pumps of type brine/water | regulated as scatter plot
    Group = 2
    fig, ax = plt.subplots(1,3)
    data = df.loc[(df['Group']==Group)]
    data.plot.scatter(ax=ax[0], x='COP',y='COP_sim', alpha=0.3, figsize=(12,5), grid=True, title='Coefficient of performance')
    data.plot.scatter(ax=ax[1], x='P_el [W]',y='P_el_sim', alpha=0.1, figsize=(15,5), grid=True, title='Electrical input power [W]')
    data.plot.scatter(ax=ax[2], x='P_th [W]',y='P_th_sim', alpha=0.1, figsize=(15,5), grid=True, title='Thermal output power [W]')
    ax[0].set_xlim(0,10)
    ax[0].set_ylim(0,10)
    ax[1].set_xlim(0,20000)
    ax[1].set_ylim(0,20000)
    ax[2].set_xlim(0,50000)
    ax[2].set_ylim(0,50000)

Out[ ]:

    (0.0, 50000.0)

## 7. Conclusion ¶

- On/Off heat pumps can be simulated very well (mean relative error < 6 %)
- Regulated heat pumps show a good values in terms of COP and EER but relative mean errors about 15-20 % for electrical and thermal power, because of the non-linearity regarding different primary / secondary temperatures.
- Despite of that, generic heat pumps should work well, because the median shows only a small relative error