*2.4. Implementation*

The model was implemented in Python [28] as it is one of the popular languages with many well-implemented libraries. The libraries used were: pandas (which contains the very useful DataFrame structure that allows for database-like operation on data), numpy [29] (a package that contains a wide number of data structures and functions for data analysis and scientific methods), scipy [30] (which is equipped with a set of well-known optimization methods and also methods for interpolation and statistical analysis) and datetime (library for advanced operations on date–time formats).

The scheme of the software developed by the authors to run the technical and economic models, to calculate the optimization algorithm and to analyze and plot the results is illustrated in Figure 5. The model was designed to analyze the long-term (yearly) operation of the installation, and for that purpose a 15 min time-step was chosen, as it is a standard resolution of energy meters in Poland. This strictly binds the model to the data gathered in real systems.

**Figure 5.** The general scheme of the operation of the optimization method.

The input data for the program were:


for selling energy to the grid (or other) in PLN per kWh. It can represent dynamic tariffs [31] related to market or fixed peak hours tariffs. We assumed that changes can occur after a 15 min interval.

The data flow of the implemented model is schematically presented in Figure 5. The first stage is the initialization of a single DataFrame type structure with all the data indexed by a timestamp. Thanks to this, it is possible to make fast operations on columns and rows without the danger of missing the time alignment of the data. The program calculates initial balances of the energy *pgrid* that result from local load *pload* and generation *pPV* profiles and initializes structures for energy storage operation. The output data are the input to the optimization algorithm, which sequentially calculates the battery levels.

The program divides the data into 1-day-long chunks (starting from midnight) as daily patterns in usage are very often present and the production from PV modules has, by default, strong daily patterns.

Many different solvers were tested, the COBYLA [32] solver was the fastest in execution, but there were small fluctuations in the result that were not explainable in context of the test case. We chose SLSQP [33] as it is based on verified methods; for the considered problem, it should be effective in finding an optimal solution—if there is one—in reasonable time, without the need for extensive adjustments of the solver's parameters. The SLSQP optimizer is a sequential least squares programming algorithm, it applies the Han–Powell quasi-Newton method with a Broyden–Fletcher–Goldfarb–Shanno algorithm update of the B-matrix and an L1-test function in the step-length algorithm. Its implementation contains a modified version of Lawson and Hanson's nonlinear least-squares solver. The original source code was provided by Dieter Kraft in 1991, based on his work presented in [34]. The SLSQP was used in many publications in the domain of energy, e.g., [35,36]. The convergence and properties of the SLSQP are described in [37] and [38]. The parameters of the solver in this implementation were: maximum 500 iterations and the precision goal for the value of the goal function in the stopping criterion equals 0.1.

The optimization algorithm was called for each 24 h time window independently; only the final state of charge of each battery within HESS was passed to the next iteration. The outcome of the optimization was a time-series of the HESS operation—its discharge and charging power, change in the state of charge and amount of losses. Losses of the battery were defined as impacting the energy while charging—the program subtracts part of the energy that was equivalent to the *1–RTE*.

The order of calculating the energy storage was defined by the durability of the battery, which was the nominal number of cycles *NoC*. The storage was ranked with this parameter, and the one with the highest value was considered first. This approach was chosen as a method to maximize overall durability of the HESS. When the first energy storage was calculated, the program recalculated the balances to include the energy storage impact on the installation. Then, the optimizer started with the next battery in line. Due to the nature of applied batteries it was assumed that priority would go to VRFB because of its high cycle life, low power and large capacity. The LFP battery was calculated in the second step to supplement operation of energy storage when higher power was needed. After each round, the details on the operation of each battery were saved and were also aggregated to the operation of the whole hybrid storage, which consisted of the sum of charging power, discharging power and losses.

The last step was calculating the economic balance of the costs and revenues from the installation. This was calculated for two cases: (a) with HESS and (b) without HESS. On the side of the revenues was the energy that was sold to the grid, which was solely overproduction from the local energy sources. On the cost side was the energy that had to be bought from the grid, as well as the cost of the degradation of the batteries, which was calculated proportionally to the battery throughput.

The analysis of the complexity was performed. We used the O-notation, as defined in [39], as it is a known standard in the defining of algorithm's complexity. In the balancing algorithm, the complexity depended only on the number of considered batteries (*Nb*) and number of days the calculation was performed for (*n*), the complexity is *O(Nb*×*n)* as the time of calculation of the operation plan for a battery was constant. The optimization method was different—it used a solver and the number of iterations varied depending on the shape of the goal function. The worst case scenario was when there was no convergence and solver reached the maximum number of iterations, which was set to 500. Given that the maximum number of iterations was limited, this can be treated as a constant factor, and according to the O-notation this means the complexity of the operation was also *O(Nb*×*n)*.

To estimate the mean time of calculation, we checked the distribution of the number of iterations—the histogram is presented in Figure 6. The number of iterations in time for both batteries is presented in Figure 7. On average, the simulation takes 186 iterations for each 24h window, per battery.

**Figure 6.** The histogram of the number of iterations for the cost optimization method.

**Figure 7.** The number of iterations for each day of calculation for the cost optimization method.

### **3. Results**

The annual energy balance without an energy storage system is presented in Figure 3. In the following sections, a series of the graphs to visualize the performance of the behavior of the HESS operating for a full year are presented. The performance of HESS governed by different algorithms is analyzed in daily and seasonal horizons. Annual results for each algorithm are summarized and discussed in Section 4.

To describe the context, the situation of energy flows and costs without any battery system is presented in Figure 8. It is clearly visible that in winter, the purchase of energy in different tariff zones is comparable to the duration of those zones in a day. In the summer months, the photovoltaic installation is producing enough energy to cover the morning peaks almost completely. However, the production cannot cover the evening peak tariffs. The overall cost balance for the year is PLN 295,000, which includes the purchase of energy and the selling of surpluses from PV production.

**Figure 8.** Monthly economic indicators for the setup without HESS or any other energy storage: (**a**) purchase cost classified by tariff zones (tariff prices), (**b**) costs, profits and financial balance.
