Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

WIP : Long short term memory prediction models for Time series Data #2721

Open
wants to merge 50 commits into
base: develop
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
Show all changes
50 commits
Select commit Hold shift + click to select a range
f3775eb
Initial push of the Lstm project
Jul 22, 2024
5515129
Included changes from another branch.
Jul 22, 2024
395287b
refactoring, adding the missing and methods, removing un used imports
pooran-c Jul 22, 2024
2c4493b
async sesonlaity and trend prediction
pooran-c Jul 22, 2024
18fa30a
no message
pooran-c Jul 22, 2024
27e0cc4
code refactor
pooran-c Jul 22, 2024
167eee8
more refactor
pooran-c Jul 22, 2024
76a2aca
renaming method
pooran-c Jul 22, 2024
67b65cf
no message
pooran-c Jul 22, 2024
ef32315
no message
pooran-c Jul 22, 2024
ffffa5c
no message
pooran-c Jul 22, 2024
673c6c3
no message
pooran-c Jul 22, 2024
f93aa79
no message
pooran-c Jul 22, 2024
b9591ab
no message
pooran-c Jul 22, 2024
74b3d09
code refactor
pooran-c Jul 23, 2024
3faceb9
code refactor 2
pooran-c Jul 23, 2024
58790cc
code refactor 3
pooran-c Jul 23, 2024
cd3b286
refactor code 4
pooran-c Jul 24, 2024
19f7eb5
refactor code 5
pooran-c Jul 24, 2024
0e5ffd5
refactor code 6
pooran-c Jul 24, 2024
08816af
added in the edge app
pooran-c Jul 24, 2024
b0822fa
Refactored hyperparameters and Cubical Interpolation
Jul 24, 2024
1067f65
Added no training conditions and refactoring.
Jul 25, 2024
6fdc072
refactor code 7
pooran-c Jul 25, 2024
c0be349
Multiparameter implemented in unit test case
Jul 25, 2024
6efa3cf
Merge branch 'feature/LstmModel' of https://github.com/OpenEMS/openem…
Jul 25, 2024
d9efdbb
refactor code 8
pooran-c Jul 26, 2024
d590c51
refactor 9
pooran-c Jul 31, 2024
f4ee6e0
Merge remote-tracking branch 'origin/develop' into feature/LstmModel
sfeilmeier Aug 1, 2024
83f2d33
Merge branch 'develop' into feature/LstmModel
sfeilmeier Aug 1, 2024
1aff505
Fix Checkstyle - add Javadoc
sfeilmeier Aug 1, 2024
5c8555b
Disable tests
sfeilmeier Aug 1, 2024
a30a409
Merge branch 'feature/LstmModel' of https://github.com/OpenEMS/openem…
sfeilmeier Aug 1, 2024
8c866c3
Apply prepare-commit.sh
sfeilmeier Aug 1, 2024
b571932
Merge branch 'develop' into feature/LstmModel
pooran-c Sep 23, 2024
86e2578
added read me
pooran-c Sep 23, 2024
3f6bc7b
Merge branch 'develop' into feature/LstmModel
pooran-c Sep 30, 2024
2c7397c
Add missing JUnit test for DateUtils duodecimus
sfeilmeier Sep 30, 2024
3eade01
Clearly name singular ChannelAddress; private final vars
sfeilmeier Sep 30, 2024
1883875
Change int the batch size
pooran-c Oct 7, 2024
9dbf4d1
json rpc changes
pooran-c Oct 7, 2024
4eb1132
few more json rpc changes
pooran-c Oct 7, 2024
616725e
Merge branch 'develop' into feature/LstmModel
pooran-c Oct 7, 2024
cb1dd44
refactor and removed the duo decimus
pooran-c Oct 29, 2024
9881037
Merge branch 'develop' into feature/LstmModel
pooran-c Oct 29, 2024
cb2393f
remove enum
pooran-c Oct 29, 2024
75fc720
remove test utils
pooran-c Oct 29, 2024
9827f52
remove duplicate test
pooran-c Oct 29, 2024
b007e15
remove line
pooran-c Oct 29, 2024
ec82ec4
Gradient Descent changed to Stochastic gradient descent.
Bishalghimire1997 Nov 10, 2024
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 2 additions & 0 deletions io.openems.edge.application/EdgeApp.bndrun
Original file line number Diff line number Diff line change
Expand Up @@ -167,6 +167,7 @@
bnd.identity;id='io.openems.edge.meter.weidmueller',\
bnd.identity;id='io.openems.edge.meter.ziehl',\
bnd.identity;id='io.openems.edge.onewire.thermometer',\
bnd.identity;id='io.openems.edge.predictor.lstmmodel',\
bnd.identity;id='io.openems.edge.predictor.persistencemodel',\
bnd.identity;id='io.openems.edge.predictor.similardaymodel',\
bnd.identity;id='io.openems.edge.pvinverter.cluster',\
Expand Down Expand Up @@ -345,6 +346,7 @@
io.openems.edge.meter.ziehl;version=snapshot,\
io.openems.edge.onewire.thermometer;version=snapshot,\
io.openems.edge.predictor.api;version=snapshot,\
io.openems.edge.predictor.lstmmodel;version=snapshot,\
io.openems.edge.predictor.persistencemodel;version=snapshot,\
io.openems.edge.predictor.similardaymodel;version=snapshot,\
io.openems.edge.pvinverter.api;version=snapshot,\
Expand Down
12 changes: 12 additions & 0 deletions io.openems.edge.predictor.lstmmodel/.classpath
Original file line number Diff line number Diff line change
@@ -0,0 +1,12 @@
<?xml version="1.0" encoding="UTF-8"?>
<classpath>
<classpathentry kind="con" path="aQute.bnd.classpath.container"/>
<classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER/org.eclipse.jdt.internal.debug.ui.launcher.StandardVMType/JavaSE-17"/>
<classpathentry kind="src" output="bin" path="src"/>
<classpathentry kind="src" output="bin_test" path="test">
<attributes>
<attribute name="test" value="true"/>
</attributes>
</classpathentry>
<classpathentry kind="output" path="bin"/>
</classpath>
2 changes: 2 additions & 0 deletions io.openems.edge.predictor.lstmmodel/.gitignore
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
/bin_test/
/generated/
23 changes: 23 additions & 0 deletions io.openems.edge.predictor.lstmmodel/.project
Original file line number Diff line number Diff line change
@@ -0,0 +1,23 @@
<?xml version="1.0" encoding="UTF-8"?>
<projectDescription>
<name>io.openems.edge.predictor.lstmmodel</name>
<comment></comment>
<projects>
</projects>
<buildSpec>
<buildCommand>
<name>org.eclipse.jdt.core.javabuilder</name>
<arguments>
</arguments>
</buildCommand>
<buildCommand>
<name>bndtools.core.bndbuilder</name>
<arguments>
</arguments>
</buildCommand>
</buildSpec>
<natures>
<nature>org.eclipse.jdt.core.javanature</nature>
<nature>bndtools.core.bndnature</nature>
</natures>
</projectDescription>
Original file line number Diff line number Diff line change
@@ -0,0 +1,2 @@
eclipse.preferences.version=1
encoding/<project>=UTF-8
16 changes: 16 additions & 0 deletions io.openems.edge.predictor.lstmmodel/bnd.bnd
Original file line number Diff line number Diff line change
@@ -0,0 +1,16 @@
Bundle-Name: OpenEMS Edge Predictor Lstm-Model
Bundle-Vendor: OpenEMS Association e.V.
Bundle-License: https://opensource.org/licenses/EPL-2.0
Bundle-Version: 1.0.0.${tstamp}

-buildpath: \
${buildpath},\
io.openems.common,\
io.openems.edge.common,\
io.openems.edge.controller.api,\
io.openems.edge.predictor.api,\
io.openems.edge.timedata.api,\
org.apache.commons.math3,\

-testpath: \
${testpath}
28 changes: 28 additions & 0 deletions io.openems.edge.predictor.lstmmodel/readme.adoc
Original file line number Diff line number Diff line change
@@ -0,0 +1,28 @@
= Long short term model predictor

The Long Short-Term Memory (LSTM) model is a type of recurrent neural network (RNN) that is particularly well-suited for time series prediction tasks, including consumption and production power predictions, due to its ability to capture dependencies and patterns over time. https://en.wikipedia.org/wiki/Long_short-term_memory[More details of LSTM]

This application is used for predicting power (consumption and production) values.
Here, For power prediction, LSTM models can analyze historical power data to learn patterns and trends that occur over time, such as:

* Daily and Seasonal Variations: example, Consumption power often follows cyclic patterns (e.g., higher usage during the day, lower at night). Production power often higher during the day and none during the nights.
* External Factors: LSTM can incorporate external factors like weather, day of the week, or holidays to improve prediction accuracy.

== Training LSTM for Power Predictions:

* Input Data (Channels address "_sum/ConsumptionActivePower"): Time series data of past consumption levels.
* Pre-processing: Data needs to be scaled and sometimes transformed to remove seasonality or noise.
* Training: The LSTM is trained on historical data using techniques like backpropagation through time (BPTT), where it learns to minimize the error between predicted and actual consumption.
* Prediction: Once trained, the model can predict future power consumption for various time steps ahead (e.g., hours, days, or even weeks).

In practice, LSTMs are favored for their ability to learn complex time-related patterns, making them effective in forecasting energy demand patterns that can inform Energy management system (EMS), energy distribution, and cost optimization strategies.

== Note for activating the predictor

To run this predictor, please create a folder named "models" in the OpenEMS data directory (openems/data/).

Initially, a generic model will be used for predictions, which may not yield optimal results. However, a training process is scheduled to occur every 45 days, during which the models in this directory will be updated. The 45-day interval consists of 30 days for training and 15 days for validation.

As a result of this process, a new model will be trained and will automatically replace the previous one.

https://github.com/OpenEMS/openems/tree/develop/io.openems.edge.predictor.lstmmodel[Source Code icon:github[]]
Original file line number Diff line number Diff line change
@@ -0,0 +1,31 @@
package io.openems.edge.predictor.lstmmodel;

import org.osgi.service.metatype.annotations.AttributeDefinition;
import org.osgi.service.metatype.annotations.ObjectClassDefinition;

import io.openems.edge.predictor.api.prediction.LogVerbosity;

@ObjectClassDefinition(//
name = "Predictor Lstm-Model", //
description = "Implements Long Short-Term Memory (LSTM) model, which is a type of recurrent neural network (RNN) designed to capture long-range dependencies in sequential data, such as time series. "
+ "This makes LSTMs particularly effective for time series prediction, "
+ "as they can learn patterns and trends over time, handling long-term dependencies while filtering out irrelevant information.")
@interface Config {

@AttributeDefinition(name = "Component-ID", description = "Unique ID of this Component")
String id() default "predictor0";

@AttributeDefinition(name = "Alias", description = "Human-readable name of this Component; defaults to Component-ID")
String alias() default "";

@AttributeDefinition(name = "Is enabled?", description = "Is this Component enabled?")
boolean enabled() default true;

@AttributeDefinition(name = "Channel-Address", description = "Channel-Address this Predictor is used for, e.g. '_sum/UnmanagedConsumptionActivePower'")
String channelAddress();

@AttributeDefinition(name = "Log-Verbosity", description = "The log verbosity.")
LogVerbosity logVerbosity() default LogVerbosity.NONE;

String webconsole_configurationFactory_nameHint() default "Predictor Lstm-Model [{id}]";
}
Original file line number Diff line number Diff line change
@@ -0,0 +1,129 @@
package io.openems.edge.predictor.lstmmodel;

import io.openems.common.types.OpenemsType;
import io.openems.edge.common.channel.BooleanReadChannel;
import io.openems.edge.common.channel.Doc;
import io.openems.edge.common.channel.DoubleReadChannel;
import io.openems.edge.common.channel.StringReadChannel;
import io.openems.edge.common.channel.value.Value;
import io.openems.edge.common.component.OpenemsComponent;

public interface LstmModel extends OpenemsComponent {

public enum ChannelId implements io.openems.edge.common.channel.ChannelId {
LAST_TRAINED_TIME(Doc.of(OpenemsType.STRING) //
.text("Last trained time in Unixstimestamp")), //
MODEL_ERROR(Doc.of(OpenemsType.DOUBLE) //
.text("Error in the Model")), //
CANNOT_TRAIN_CONDITON(Doc.of(OpenemsType.BOOLEAN) //
.text("When the data set is empty, entirely null, or contains 50% null values."));

private final Doc doc;

private ChannelId(Doc doc) {
this.doc = doc;
}

@Override
public Doc doc() {
return this.doc;
}
}

/**
* Gets the Channel for {@link ChannelId#CANNOT_TRAIN_CONDITON}.
*
* @return the Channel
*/
public default BooleanReadChannel getCannotTrainConditionChannel() {
return this.channel(ChannelId.CANNOT_TRAIN_CONDITON);
}

/**
* Gets the Cannot train condition in boolean. See
* {@link ChannelId#CANNOT_TRAIN_CONDITON}.
*
* @return the Channel {@link Value}
*/
public default Value<Boolean> getCannotTrainCondition() {
return this.getCannotTrainConditionChannel().value();
}

/**
* Internal method to set the 'nextValue' on
* {@link ChannelId#CANNOT_TRAIN_CONDITON} Channel.
*
* @param value the next value
*/
public default void _setCannotTrainCondition(boolean value) {
this.getCannotTrainConditionChannel().setNextValue(value);
}

/**
* Internal method to set the 'nextValue' on
* {@link ChannelId#CANNOT_TRAIN_CONDITON} Channel.
*
* @param value the next value
*/
public default void _setCannotTrainCondition(Boolean value) {
this.getCannotTrainConditionChannel().setNextValue(value);
}

/**
* Gets the Channel for {@link ChannelId#LAST_TRAINED_TIME}.
*
* @return the Channel
*/
public default StringReadChannel getLastTrainedTimeChannel() {
return this.channel(ChannelId.LAST_TRAINED_TIME);
}

/**
* Gets the Last time trained time in Unix time stamp. See
* {@link ChannelId#LAST_TRAINED_TIME}.
*
* @return the Channel {@link Value}
*/
public default Value<String> getLastTrainedTime() {
return this.getLastTrainedTimeChannel().value();
}

/**
* Internal method to set the 'nextValue' on {@link ChannelId#LAST_TRAINED_TIME}
* Channel.
*
* @param value the next value
*/
public default void _setLastTrainedTime(String value) {
this.getLastTrainedTimeChannel().setNextValue(value);
}

/**
* Gets the Channel for {@link ChannelId#MODEL_ERROR}.
*
* @return the Channel
*/
public default DoubleReadChannel getModelErrorChannel() {
return this.channel(ChannelId.MODEL_ERROR);
}

/**
* Gets the Model error. See {@link ChannelId#MODEL_ERROR}.
*
* @return the Channel {@link Value}
*/
public default Value<Double> getModelError() {
return this.getModelErrorChannel().value();
}

/**
* Internal method to set the 'nextValue' on {@link ChannelId#LAST_TRAINED_TIME}
* Channel.
*
* @param value the next value
*/
public default void _setModelError(Double value) {
this.getModelErrorChannel().setNextValue(value);
}

}
Loading
Loading