From 5e842d5ee4d2510a1233d3739b28474c75105b48 Mon Sep 17 00:00:00 2001 From: Bla Bla Date: Tue, 30 Jul 2024 09:22:55 +0200 Subject: [PATCH] =?UTF-8?q?Strompreis=20entkoppelt,=20kann=20jetzt=20als?= =?UTF-8?q?=20Array=20=C3=BCbergeben=20werden.?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- flask_server.py | 65 +++-- modules/class_akku.py | 2 +- modules/class_battery_soc_predictor.py | 368 +++++++++++++++++-------- modules/class_ems.py | 2 +- modules/class_inverter.py | 8 +- modules/class_optimize.py | 23 +- modules/class_strompreis.py | 2 +- 7 files changed, 314 insertions(+), 156 deletions(-) diff --git a/flask_server.py b/flask_server.py index ddd40da..d01de68 100644 --- a/flask_server.py +++ b/flask_server.py @@ -8,6 +8,7 @@ from modules.class_strompreis import * from modules.class_heatpump import * from modules.class_load_container import * from modules.class_sommerzeit import * +from modules.class_soc_calc import * from modules.visualize import * from modules.class_battery_soc_predictor import * import os @@ -23,38 +24,56 @@ from modules.class_optimize import * import numpy as np import random import os +from config import * app = Flask(__name__) - opt_class = optimization_problem(prediction_hours=48, strafe=10) -soc_predictor = BatterySocPredictor.load_model('battery_model.pkl') + + @app.route('/soc', methods=['GET']) def flask_soc(): - if request.method == 'GET': - # URL-Parameter lesen - voltage = request.args.get('voltage') - current = request.args.get('current') - - # Erforderliche Parameter prüfen - if voltage is None or current is None: - missing_params = [] - if voltage is None: - missing_params.append('voltage') - if current is None: - missing_params.append('current') - return jsonify({"error": f"Fehlende Parameter: {', '.join(missing_params)}"}), 400 - # Werte in ein numpy Array umwandeln - x = np.array( [[float(voltage), float(current)]] ) + # MariaDB Verbindungsdetails + config = db_config + + # Parameter festlegen + voltage_high_threshold = 55.4 # 100% SoC + voltage_low_threshold = 46.5 # 0% SoC + current_low_threshold = 2 # Niedriger Strom für beide Zustände + gap = 30 # Zeitlücke in Minuten zum Gruppieren von Maxima/Minima + bat_capacity = 33 * 1000 / 48 + + # Zeitpunkt X definieren + zeitpunkt_x = (datetime.now() - timedelta(weeks=3)).strftime('%Y-%m-%d %H:%M:%S') + + + # BatteryDataProcessor instanziieren und verwenden + processor = BatteryDataProcessor(config, voltage_high_threshold, voltage_low_threshold, current_low_threshold, gap,bat_capacity) + processor.connect_db() + processor.fetch_data(zeitpunkt_x) + processor.process_data() + last_points_100_df, last_points_0_df = processor.find_soc_points() + soc_df, integration_results = processor.calculate_resetting_soc(last_points_100_df, last_points_0_df) + #soh_df = processor.calculate_soh(integration_results) + processor.update_database_with_soc(soc_df) + #processor.plot_data(last_points_100_df, last_points_0_df, soc_df) + processor.disconnect_db() - # Simulation durchführen - ergebnis = soc_predictor.predict(x) - print(ergebnis) - - return jsonify(ergebnis) + return jsonify("Done") + + +@app.route('/strompreis', methods=['GET']) +def flask_strompreis(): + date_now,date = get_start_enddate(prediction_hours,startdate=datetime.now().date()) + filepath = os.path.join (r'test_data', r'strompreise_akkudokAPI.json') # Pfad zur JSON-Datei anpassen + #price_forecast = HourlyElectricityPriceForecast(source=filepath) + price_forecast = HourlyElectricityPriceForecast(source="https://api.akkudoktor.net/prices?start="+date_now+"&end="+date+"", prediction_hours=prediction_hours) + specific_date_prices = price_forecast.get_price_for_daterange(date_now,date) + #print(specific_date_prices) + return jsonify(specific_date_prices.tolist()) @app.route('/optimize', methods=['POST']) @@ -63,7 +82,7 @@ def flask_optimize(): parameter = request.json # Erforderliche Parameter prüfen - erforderliche_parameter = [ 'pv_akku_cap', 'year_energy',"einspeiseverguetung_euro_pro_wh", 'max_heizleistung', 'pv_forecast_url', 'eauto_min_soc', "eauto_cap","eauto_charge_efficiency","eauto_charge_power","eauto_soc","pv_soc","start_solution","pvpowernow","haushaltsgeraet_dauer","haushaltsgeraet_wh"] + erforderliche_parameter = [ 'strompreis_euro_pro_wh','pv_akku_cap', 'year_energy',"einspeiseverguetung_euro_pro_wh", 'max_heizleistung', 'pv_forecast_url', 'eauto_min_soc', "eauto_cap","eauto_charge_efficiency","eauto_charge_power","eauto_soc","pv_soc","start_solution","pvpowernow","haushaltsgeraet_dauer","haushaltsgeraet_wh"] for p in erforderliche_parameter: if p not in parameter: return jsonify({"error": f"Fehlender Parameter: {p}"}), 400 diff --git a/modules/class_akku.py b/modules/class_akku.py index 98590bb..8baf15f 100644 --- a/modules/class_akku.py +++ b/modules/class_akku.py @@ -1,6 +1,6 @@ import numpy as np class PVAkku: - def __init__(self, kapazitaet_wh=None, hours=None, lade_effizienz=0.8, entlade_effizienz=1.0,max_ladeleistung_w=None,start_soc_prozent=0,min_soc_prozent=0,max_soc_prozent=100): + def __init__(self, kapazitaet_wh=None, hours=None, lade_effizienz=0.88, entlade_effizienz=0.88,max_ladeleistung_w=None,start_soc_prozent=0,min_soc_prozent=0,max_soc_prozent=100): # Kapazität des Akkus in Wh self.kapazitaet_wh = kapazitaet_wh # Initialer Ladezustand des Akkus in Wh diff --git a/modules/class_battery_soc_predictor.py b/modules/class_battery_soc_predictor.py index adde43e..702a05c 100644 --- a/modules/class_battery_soc_predictor.py +++ b/modules/class_battery_soc_predictor.py @@ -1,20 +1,37 @@ import numpy as np import pandas as pd -import joblib +import joblib, json from sklearn.preprocessing import StandardScaler from sklearn.gaussian_process import GaussianProcessRegressor -from sklearn.gaussian_process.kernels import RBF, ConstantKernel, WhiteKernel +from sklearn.gaussian_process.kernels import RBF, ConstantKernel, WhiteKernel, Matern,DotProduct from sklearn.model_selection import train_test_split - +from tensorflow.keras.models import Sequential, load_model +from tensorflow.keras.layers import LSTM, Dense,Dropout +from sklearn.preprocessing import MinMaxScaler +import matplotlib.pyplot as plt +from tensorflow.keras.optimizers import Adam +from tensorflow.keras.regularizers import l1, l2, l1_l2 +from scipy.signal import savgol_filter import numpy as np import matplotlib.pyplot as plt +import numpy as np +import pandas as pd +from tensorflow.keras.models import Sequential +from tensorflow.keras.layers import LSTM, Dense, Dropout, RepeatVector, TimeDistributed +from sklearn.preprocessing import MinMaxScaler +from tensorflow.keras.optimizers import Adam +from tensorflow.keras.regularizers import l2 +import matplotlib.pyplot as plt +from sklearn.metrics import mean_absolute_error, mean_squared_error -class BatterySocPredictor: + + +class BatterySocPredictorGauss: def __init__(self): # Initialisierung von Scaler und Gaußschem Prozessmodell self.scaler = StandardScaler() - kernel = WhiteKernel(1.0, (1e-7, 1e3)) + RBF(length_scale=(0.1,0.1), length_scale_bounds=((1e-7, 1e3),(1e-7, 1e3))) - self.gp = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=10, alpha=1e-2, normalize_y=True) + kernel = WhiteKernel(1.0, (1e-7, 1e3)) + Matern(length_scale=(0.1,0.1,0.1), length_scale_bounds=((1e-7, 1e3),(1e-7, 1e3),(1e-7, 1e3))) + DotProduct() + self.gp = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=10, alpha=1e-3, normalize_y=True) def fit(self, X, y): # Transformiere die Zielvariable @@ -34,7 +51,7 @@ class BatterySocPredictor: # Rücktransformieren der Unsicherheiten sigmoid_y_pred = 1 / (1 + np.exp(-y_pred_transformed)) sigma = sigma_transformed * 101 * sigmoid_y_pred * (1 - sigmoid_y_pred) - return float(y_pred), float(sigma) + return y_pred def save_model(self, file_path): # Speichere das gesamte Modell-Objekt @@ -44,132 +61,243 @@ class BatterySocPredictor: def load_model(file_path): # Lade das Modell-Objekt return joblib.load(file_path) + + +class BatterySoCPredictorLSTM: + def __init__(self, model_path=None, scaler_path=None, gauss=None): + self.scaler = MinMaxScaler(feature_range=(0, 1)) + self.target_scaler = MinMaxScaler(feature_range=(0, 1)) + self.seq_length = 5 # Anzahl der Zeitschritte in der Eingabesequenz + self.n_future_steps = 1 # Anzahl der zukünftigen Schritte, die vorhergesagt werden sollen + self.gauss_model = BatterySocPredictorGauss.load_model(gauss) + + if model_path: + self.model = load_model(model_path) + else: + self.model = self._build_model() + + if scaler_path: + self.load_scalers(scaler_path) + + def _build_model(self): + regu = 0.00 # Regularisierungsrate + model = Sequential() + model.add(LSTM(20, activation='relu', return_sequences=True, input_shape=(self.seq_length, 4), kernel_regularizer=l2(regu))) + model.add(LSTM(20, activation='relu', return_sequences=False, kernel_regularizer=l2(regu))) + model.add(RepeatVector(self.n_future_steps)) + model.add(LSTM(20, activation='relu', return_sequences=True, kernel_regularizer=l2(regu))) + model.add(TimeDistributed(Dense(1, kernel_regularizer=l2(regu)))) # TimeDistributed Layer für Multi-Step Output + + optimizer = Adam(learning_rate=0.0005) + model.compile(optimizer=optimizer, loss='mae') + return model + def fit(self, data_path, epochs=100, batch_size=50, validation_split=0.1): + data = pd.read_csv(data_path) + data['Time'] = pd.to_datetime(data['Time'], unit='ms') + data.set_index('Time', inplace=True) + + data.dropna(inplace=True) + + # Gauss + #data["temperature_mean"] = data[["data","data.1"]].mean(axis=1) + #data[['battery_voltage', 'battery_current', 'data']] + data["battery_soc_gauss"] = self.gauss_model.predict(data[['battery_voltage', 'battery_current', 'data']].values) + # print(data) + # sys.exit() + scaled_data = self.scaler.fit_transform(data[['battery_voltage', 'battery_current', 'data', 'battery_soc_gauss']].values) + data['scaled_soc'] = self.target_scaler.fit_transform(data[['battery_soc']]) + + X, y = self._create_sequences(scaled_data, self.seq_length, self.n_future_steps) + + print(y.shape) + + self.model.fit(X, y, epochs=epochs, batch_size=batch_size, validation_split=validation_split) + + def _create_sequences(self, data, seq_length, n_future_steps): + xs, ys = [], [] + for i in range(len(data) - seq_length - n_future_steps): + x = data[i:(i + seq_length)] + y = data[(i + seq_length):(i + seq_length + n_future_steps), -1] # Multi-Step Output + xs.append(x) + ys.append(y) + return np.array(xs), np.array(ys) + + # def predict(self, test_data_path): + # test_data = pd.read_csv(test_data_path) + # test_data['Time'] = pd.to_datetime(test_data['Time'], unit='ms') + # test_data.set_index('Time', inplace=True) + # test_data.replace('undefined', np.nan, inplace=True) + # test_data.dropna(inplace=True) + + # test_data['battery_voltage'] = pd.to_numeric(test_data['battery_voltage'], errors='coerce') + # test_data['battery_current'] = pd.to_numeric(test_data['battery_current'], errors='coerce') + # test_data['battery_soc'] = pd.to_numeric(test_data['battery_soc'], errors='coerce') + # test_data['data.1'] = pd.to_numeric(test_data['data.1'], errors='coerce') + # test_data.dropna(inplace=True) + + # scaled_test_data = self.scaler.transform(test_data[['battery_voltage', 'battery_current', 'data.1', 'battery_soc']]) + # test_data['scaled_soc'] = self.target_scaler.transform(test_data[['battery_soc']]) + # test_data.dropna(inplace=True) + + # X_test, _ = self._create_sequences(scaled_test_data, self.seq_length, self.n_future_steps) + # predictions = self.model.predict(X_test) + # predictions = self.target_scaler.inverse_transform(predictions.reshape(-1, 1)).reshape(-1, self.n_future_steps) + # return predictions + + def predict_single(self, voltage_current_temp_soc_sequence): + + if len(voltage_current_temp_soc_sequence) != self.seq_length or len(voltage_current_temp_soc_sequence[0]) != 3: + raise ValueError("Die Eingabesequenz muss die Form (seq_length, 3) haben.") + + + + soc_gauss = self.gauss_model.predict(voltage_current_temp_soc_sequence) + soc_gauss = soc_gauss.reshape(-1,1) + #print(voltage_current_temp_soc_sequence.shape) + #print(soc_gauss.shape) + voltage_current_sequence = np.hstack([voltage_current_temp_soc_sequence, soc_gauss]) + #print(voltage_current_sequence.shape) + print(voltage_current_sequence) + scaled_sequence = self.scaler.transform(voltage_current_sequence) + X = np.array([scaled_sequence]) + + prediction = self.model.predict(X) + prediction = self.target_scaler.inverse_transform(prediction.reshape(-1, 1)).reshape(-1, self.n_future_steps) + return prediction # Return the sequence of future SoC predictions + + def save_model(self, model_path=None, scaler_path=None): + self.model.save(model_path) + + scaler_params = { + 'scaler_min_': self.scaler.min_.tolist(), + 'scaler_scale_': self.scaler.scale_.tolist(), + 'target_scaler_min_': self.target_scaler.min_.tolist(), + 'target_scaler_scale_': self.target_scaler.scale_.tolist() + } + with open(scaler_path, 'w') as f: + json.dump(scaler_params, f) + + def load_scalers(self, scaler_path): + with open(scaler_path, 'r') as f: + scaler_params = json.load(f) + self.scaler.min_ = np.array(scaler_params['scaler_min_']) + self.scaler.scale_ = np.array(scaler_params['scaler_scale_']) + self.target_scaler.min_ = np.array(scaler_params['target_scaler_min_']) + self.target_scaler.scale_ = np.array(scaler_params['target_scaler_scale_']) + +if __name__ == '__main__': + train_data_path = 'lstm_train/raw_data_clean.csv' + test_data_path = 'Test_Data.csv' + model_path = 'battery_soc_predictor_lstm_model.keras' + scaler_path = 'battery_soc_predictor_scaler_model' -# # Daten laden und Modell verwenden -# data_path = 'train.csv' -# data = pd.read_csv(data_path) -# X = data[['battery_voltage', 'battery_current']] -# y = data['battery_soc'] + #################### + # GAUSS + K-Means + #################### + # Daten laden und vorbereiten + data_path = 'k_means.csv' + data = pd.read_csv(data_path, decimal='.') + data.dropna(inplace=True) # Entfernen von Zeilen mit NaN-Werten, die durch das Rolling entstehen + #print(data[["data","data.1"]].mean(axis=1)) + data["temperature_mean"] = data[["data","data.1"]].mean(axis=1) + # Features und Zielvariable definieren + X = data[['battery_voltage', 'battery_current',"temperature_mean"]] # + y = data['battery_soc'] -# # Aufteilen der Daten in Trainings- und Testdatensätze -# X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=42) + # Aufteilen der Daten in Trainings- und Testdatensätze + X_train, X_test, y_train, y_test = train_test_split(X, y, test_size=0.1, random_state=42) -# # Modell instanziieren und trainieren -# battery_model = BatteryModel() -# battery_model.fit(X_train, y_train) - -# # Modell speichern -# battery_model.save_model('battery_model.pkl') - -# # Modell für Vorhersagen laden -# loaded_model = BatteryModel.load_model('battery_model.pkl') - -# # Vorhersagen machen -# current_values = np.linspace(-100, 100, 5) -# voltage_range = np.linspace(48, 58, 50) -# for current in current_values: - # X_pred = np.column_stack([voltage_range, np.full(voltage_range.shape, current)]) - # y_pred, sigma = loaded_model.predict(X_pred) - # # Plotten der mittleren Vorhersage und des Konfidenzintervalls - # plt.plot(voltage_range, y_pred, label=f'Strom = {current:.1f} A') - # plt.fill_between(voltage_range, y_pred - 1.96 * sigma, y_pred + 1.96 * sigma, alpha=0.2) - -# # Hinzufügen von Titel und Legende zum Plot -# plt.title('Vorhergesagter SoC als Funktion der Batteriespannung bei verschiedenen Strömen') -# plt.xlabel('Batteriespannung (V)') -# plt.ylabel('State of Charge (SoC %)') -# plt.legend() -# plt.show() - - - -# sys.exit() - - - - - -# # Daten laden -# data_path = 'train.csv' -# data = pd.read_csv(data_path) - -# # Spalten auswählen -# X = data[['battery_voltage', 'battery_current']] # Merkmale -# y = data['battery_soc'] # Zielvariable - -# # Aufteilung der Daten in Trainings- und Testset - -# # Transformiere die Zielvariable -# y_transformed = np.log(y / (101 - y)) - - -# # X Normalisierung -# scaler = StandardScaler() -# X_scaled = scaler.fit_transform(X) - - -# # Aufteilen der Daten in Trainings- und Testdatensätze -# X_train, X_test, y_train, y_test = train_test_split(X_scaled, y_transformed, test_size=0.5, random_state=42) - -# # Kernel und Modell definieren -# kernel = WhiteKernel(1.0, (1e-7, 1e3)) + RBF(length_scale=(0.1,0.1), length_scale_bounds=((1e-7, 1e3),(1e-7, 1e3))) #* ConstantKernel(constant_value=1.0, constant_value_bounds=(1e-05, 100000.0)) - -# gp = GaussianProcessRegressor(kernel=kernel, n_restarts_optimizer=10, alpha=1e-2, normalize_y=True) - -# # Modell trainieren -# gp.fit(X_train, y_train) - -# # Vorhersagen und Rücktransformieren -# #y_pred_transformed, sigma = gp.predict(X_test, return_std=True) -# #y_pred = 100 / (1 + np.exp(-y_pred_transformed)) - - -# # Ergebnisse anzeigen -# #print("Vorhersagen:", y_pred) -# #print("Unsicherheit der Vorhersagen:", sigma) - - -# # Angenommen, 'gp' ist dein trainiertes Gaußsches Prozessmodell -# joblib.dump(gp, 'gaussian_process_model.pkl') - - - -# # Festlegen der Ströme und Spannungsrange für die Vorhersagen -# current_values = np.linspace(-100, 100, 5) -# voltage_range = np.linspace(48, 58, 50) - -# # Erstellen einer Figur für die Plots -# plt.figure(figsize=(12, 8)) - -# # Für jeden Stromwert einen Plot erstellen -# for current in current_values: - # # Erstellen von Vorhersagedatenpunkten - # X_pred = np.column_stack([voltage_range, np.full(voltage_range.shape, current)]) - # X_pred_scaled = scaler.transform(X_pred) # Standardisierung + # # # Modell instanziieren und trainieren + #battery_model = BatterySocPredictorGauss() + #battery_model.fit(X_train, y_train) + #battery_model.save_model('battery_model.pkl') - # # Vorhersage des SoC und der Unsicherheit - # y_pred_transformed, sigma_transformed = gp.predict(X_pred_scaled, return_std=True) - # y_pred = 101 / (1 + np.exp(-y_pred_transformed)) # Rücktransformation + battery_model = BatterySocPredictorGauss.load_model('battery_model.pkl') - # sigmoid_y_pred = 1 / (1 + np.exp(-y_pred_transformed)) - # sigma = sigma_transformed * 101 * sigmoid_y_pred * (1 - sigmoid_y_pred) + # Vorhersagen auf den Testdaten + y_pred_test = battery_model.predict(X_test) + print(y_pred_test.shape, " ", y_test.shape) + # Berechnung des MAE und RMSE + mae = mean_absolute_error(y_test, y_pred_test) + rmse = mean_squared_error(y_test, y_pred_test, squared=False) + + print(f'Mean Absolute Error (MAE): {mae}') + print(f'Root Mean Squared Error (RMSE): {rmse}') + + # Plotten der tatsächlichen Werte vs. Vorhersagen + # plt.figure(figsize=(12, 6)) + # plt.plot(y_test.values, label='Actual SoC') + # plt.plot(y_pred_test, label='Predicted SoC') + # plt.xlabel('Samples') + # plt.ylabel('State of Charge (SoC)') + # plt.title('Actual vs Predicted SoC') + # plt.legend() + # plt.show() + - # # Plotten der mittleren Vorhersage und des Konfidenzintervalls - # plt.plot(voltage_range, y_pred, label=f'Strom = {current:.1f} A') - # plt.fill_between(voltage_range, y_pred - 1.96 * sigma, y_pred + 1.96 * sigma, alpha=0.2) + # # # Modell speichern + #battery_model.save_model('battery_model.pkl') -# # Hinzufügen von Titel und Legende zum Plot -# plt.title('Vorhergesagter SoC als Funktion der Batteriespannung bei verschiedenen Strömen') -# plt.xlabel('Batteriespannung (V)') -# plt.ylabel('State of Charge (SoC %)') -# plt.legend() -# plt.show() + # Modell für Vorhersagen laden + #loaded_model = BatterySocPredictorGauss.load_model('battery_model.pkl') + + #################### + # LSTM + #################### + + + predictor = BatterySoCPredictorLSTM(gauss='battery_model.pkl') + + # # Training mit rekursiver Vorhersage + predictor.fit(train_data_path, epochs=50, batch_size=50, validation_split=0.1) + + # # # Speichern des Modells und der Scaler + predictor.save_model(model_path=model_path, scaler_path=scaler_path) + + # # # Laden des Modells und der Scaler + loaded_predictor = BatterySoCPredictorLSTM(model_path=model_path, scaler_path=scaler_path,gauss='battery_model.pkl') + + test_data = pd.read_csv(test_data_path) + test_data['Time'] = pd.to_datetime(test_data['Time'], unit='ms') + test_data.set_index('Time', inplace=True) + test_data.replace('undefined', np.nan, inplace=True) + test_data.dropna(inplace=True) + test_data['battery_voltage'] = pd.to_numeric(test_data['battery_voltage'], errors='coerce') + test_data['battery_current'] = pd.to_numeric(test_data['battery_current'], errors='coerce') + test_data['battery_soc'] = pd.to_numeric(test_data['battery_soc'], errors='coerce') + test_data['data'] = pd.to_numeric(test_data['data.1'], errors='coerce') + test_data.dropna(inplace=True) + + scaled_test_data = loaded_predictor.scaler.transform(test_data[['battery_voltage', 'battery_current', 'data', 'battery_soc']]) + test_data['scaled_soc'] = loaded_predictor.target_scaler.transform(test_data[['battery_soc']]) + test_data.dropna(inplace=True) + + X_test, y_test = loaded_predictor._create_sequences(scaled_test_data, loaded_predictor.seq_length, loaded_predictor.n_future_steps) + predictions = loaded_predictor.model.predict(X_test) + predictions = loaded_predictor.target_scaler.inverse_transform(predictions.reshape(-1, 1)).reshape(-1, loaded_predictor.n_future_steps) + # print(test_data['battery_soc'].values[5:-5,...].shape) + # print(predictions[:,0].shape) + test_data_y = test_data['battery_soc'].values[5:-1,...] + mae = mean_absolute_error(test_data_y, predictions[:,0]) + rmse = mean_squared_error(test_data_y, predictions[:,0], squared=False) + + print(f'Mean Absolute Error (MAE): {mae}') + print(f'Root Mean Squared Error (RMSE): {rmse}') + + plt.figure(figsize=(12, 6)) + plt.plot(test_data_y, label='Actual SoC') + plt.plot(predictions[:,0].flatten(), label='Predicted SoC') + plt.xlabel('Samples') + plt.ylabel('State of Charge (SoC)') + plt.title('Actual vs Predicted SoC using LSTM') + plt.legend() + plt.show() diff --git a/modules/class_ems.py b/modules/class_ems.py index 8b9d29d..1037d68 100644 --- a/modules/class_ems.py +++ b/modules/class_ems.py @@ -60,7 +60,6 @@ class EnergieManagementSystem: # Berechnet das Ende basierend auf der Länge der Lastkurve for stunde in range(start_stunde, ende): - # Anpassung, um sicherzustellen, dass Indizes korrekt sind verbrauch = lastkurve_wh[stunde] if self.haushaltsgeraet != None: @@ -104,6 +103,7 @@ class EnergieManagementSystem: eauto_soc_pro_stunde.append(eauto_soc) akku_soc_pro_stunde.append(self.akku.ladezustand_in_prozent()) + kosten_euro_pro_stunde.append(stündliche_kosten_euro) einnahmen_euro_pro_stunde.append(stündliche_einnahmen_euro) diff --git a/modules/class_inverter.py b/modules/class_inverter.py index 202efe4..a7ba9f0 100644 --- a/modules/class_inverter.py +++ b/modules/class_inverter.py @@ -10,7 +10,7 @@ class Wechselrichter: eigenverbrauch = 0.0 #eigenverbrauch = min(erzeugung, verbrauch) # Direkt verbrauchte Energie - if erzeugung > verbrauch: + if erzeugung >= verbrauch: if verbrauch > self.max_leistung_wh: verluste += erzeugung - self.max_leistung_wh @@ -29,7 +29,7 @@ class Wechselrichter: restleistung_nach_verbrauch = erzeugung-verbrauch #min(self.max_leistung_wh - verbrauch, erzeugung-verbrauch) # Akku geladene_energie, verluste_laden_akku = self.akku.energie_laden(restleistung_nach_verbrauch, hour) - rest_überschuss = restleistung_nach_verbrauch - geladene_energie + rest_überschuss = restleistung_nach_verbrauch - (geladene_energie+verluste_laden_akku) # if hour == 12: # print("Erzeugung:",erzeugung) # print("Last:",verbrauch) @@ -38,12 +38,14 @@ class Wechselrichter: # print("RestÜberschuss"," - ",rest_überschuss) # print("RestLesitung WR:",self.max_leistung_wh - verbrauch) # Einspeisung, restliche WR Kapazität + if rest_überschuss > self.max_leistung_wh - verbrauch: netzeinspeisung = self.max_leistung_wh - verbrauch verluste += rest_überschuss - netzeinspeisung else: netzeinspeisung = rest_überschuss - + #if hour ==10: + # print(rest_überschuss," ",restleistung_nach_verbrauch, " Gela:",geladene_energie," Ver:",verluste_laden_akku) verluste += verluste_laden_akku diff --git a/modules/class_optimize.py b/modules/class_optimize.py index dd875bf..4502e7d 100644 --- a/modules/class_optimize.py +++ b/modules/class_optimize.py @@ -4,7 +4,6 @@ from modules.class_load import * from modules.class_ems import * from modules.class_pv_forecast import * from modules.class_akku import * -from modules.class_strompreis import * from modules.class_heatpump import * from modules.class_load_container import * from modules.class_inverter import * @@ -237,11 +236,7 @@ class optimization_problem: ############### # Strompreise ############### - filepath = os.path.join (r'test_data', r'strompreise_akkudokAPI.json') # Pfad zur JSON-Datei anpassen - #price_forecast = HourlyElectricityPriceForecast(source=filepath) - price_forecast = HourlyElectricityPriceForecast(source="https://api.akkudoktor.net/prices?start="+date_now+"&end="+date+"", prediction_hours=self.prediction_hours) - specific_date_prices = price_forecast.get_price_for_daterange(date_now,date) - #print(price_forecast) + specific_date_prices = parameter["strompreis_euro_pro_wh"] print(specific_date_prices) #print("https://api.akkudoktor.net/prices?start="+date_now+"&end="+date) @@ -289,8 +284,22 @@ class optimization_problem: visualisiere_ergebnisse(gesamtlast, pv_forecast, specific_date_prices, o,best_solution[0::2],best_solution[1::2] , temperature_forecast, start_hour, self.prediction_hours,einspeiseverguetung_euro_pro_wh,extra_data=extra_data) os.system("cp visualisierungsergebnisse.pdf ~/") + # 'Eigenverbrauch_Wh_pro_Stunde': eigenverbrauch_wh_pro_stunde, + # 'Netzeinspeisung_Wh_pro_Stunde': netzeinspeisung_wh_pro_stunde, + # 'Netzbezug_Wh_pro_Stunde': netzbezug_wh_pro_stunde, + # 'Kosten_Euro_pro_Stunde': kosten_euro_pro_stunde, + # 'akku_soc_pro_stunde': akku_soc_pro_stunde, + # 'Einnahmen_Euro_pro_Stunde': einnahmen_euro_pro_stunde, + # 'Gesamtbilanz_Euro': gesamtkosten_euro, + # 'E-Auto_SoC_pro_Stunde':eauto_soc_pro_stunde, + # 'Gesamteinnahmen_Euro': sum(einnahmen_euro_pro_stunde), + # 'Gesamtkosten_Euro': sum(kosten_euro_pro_stunde), + # "Verluste_Pro_Stunde":verluste_wh_pro_stunde, + # "Gesamt_Verluste":sum(verluste_wh_pro_stunde), + # "Haushaltsgeraet_wh_pro_stunde":haushaltsgeraet_wh_pro_stunde + #print(eauto) - return {"discharge_hours_bin":discharge_hours_bin, "eautocharge_hours_float":eautocharge_hours_float ,"result":o ,"eauto_obj":eauto,"start_solution":best_solution,"spuelstart":spuelstart_int} + return {"discharge_hours_bin":discharge_hours_bin, "eautocharge_hours_float":eautocharge_hours_float ,"result":o ,"eauto_obj":eauto,"start_solution":best_solution,"spuelstart":spuelstart_int,"simulation_data":o} diff --git a/modules/class_strompreis.py b/modules/class_strompreis.py index c5e8d2d..85c24ab 100644 --- a/modules/class_strompreis.py +++ b/modules/class_strompreis.py @@ -29,7 +29,7 @@ def repeat_to_shape(array, target_shape): class HourlyElectricityPriceForecast: - def __init__(self, source, cache_dir='cache', abgaben=0.000, prediction_hours=24): #228 + def __init__(self, source, cache_dir='cache', abgaben=0.000228, prediction_hours=24): #228 self.cache_dir = cache_dir if not os.path.exists(self.cache_dir): os.makedirs(self.cache_dir)