fixed functions

This commit is contained in:
IrynaMatveieva 2025-02-26 15:22:42 +02:00
parent a52c578ecd
commit 72f26d9fe2
2 changed files with 100 additions and 36 deletions

View File

@ -25,7 +25,6 @@ import org.thingsboard.script.api.tbel.TbelCfTsDoubleVal;
import org.thingsboard.script.api.tbel.TbelCfTsRollingArg; import org.thingsboard.script.api.tbel.TbelCfTsRollingArg;
import org.thingsboard.server.common.data.kv.KvEntry; import org.thingsboard.server.common.data.kv.KvEntry;
import org.thingsboard.server.common.data.kv.TsKvEntry; import org.thingsboard.server.common.data.kv.TsKvEntry;
import org.thingsboard.server.exception.CalculatedFieldStateException;
import java.util.ArrayList; import java.util.ArrayList;
import java.util.List; import java.util.List;
@ -116,10 +115,11 @@ public class TsRollingArgumentEntry implements ArgumentEntry {
case STRING -> value.getStrValue().ifPresent(aString -> tsRecords.put(ts, Double.parseDouble(aString))); case STRING -> value.getStrValue().ifPresent(aString -> tsRecords.put(ts, Double.parseDouble(aString)));
case JSON -> value.getJsonValue().ifPresent(aString -> tsRecords.put(ts, Double.parseDouble(aString))); case JSON -> value.getJsonValue().ifPresent(aString -> tsRecords.put(ts, Double.parseDouble(aString)));
} }
cleanupExpiredRecords();
} catch (Exception e) { } catch (Exception e) {
tsRecords.put(ts, Double.NaN); tsRecords.put(ts, Double.NaN);
log.debug("Invalid value '{}' for time series rolling arguments. Only numeric values are supported.", value.getValue()); log.debug("Invalid value '{}' for time series rolling arguments. Only numeric values are supported.", value.getValue());
} finally {
cleanupExpiredRecords();
} }
} }

View File

@ -61,14 +61,18 @@ public class TbelCfTsRollingArg implements TbelCfArg, Iterable<TbelCfTsDoubleVal
} }
public double max() { public double max() {
return max(true);
}
public double max(boolean ignoreNaN) {
if (values.isEmpty()) { if (values.isEmpty()) {
return 0; throw new IllegalArgumentException("Rolling argument values are empty.");
} }
double max = Double.MIN_VALUE; double max = Double.MIN_VALUE;
for (TbelCfTsDoubleVal value : values) { for (TbelCfTsDoubleVal value : values) {
double val = value.getValue(); double val = value.getValue();
if (Double.isNaN(val)) { if (!ignoreNaN && Double.isNaN(val)) {
return val; return val;
} }
if (max < val) { if (max < val) {
@ -79,14 +83,18 @@ public class TbelCfTsRollingArg implements TbelCfArg, Iterable<TbelCfTsDoubleVal
} }
public double min() { public double min() {
return min(true);
}
public double min(boolean ignoreNaN) {
if (values.isEmpty()) { if (values.isEmpty()) {
return 0; throw new IllegalArgumentException("Rolling argument values are empty.");
} }
double min = Double.MAX_VALUE; double min = Double.MAX_VALUE;
for (TbelCfTsDoubleVal value : values) { for (TbelCfTsDoubleVal value : values) {
double val = value.getValue(); double val = value.getValue();
if (Double.isNaN(val)) { if (!ignoreNaN && Double.isNaN(val)) {
return Double.NaN; return Double.NaN;
} }
if (min > val) { if (min > val) {
@ -97,21 +105,28 @@ public class TbelCfTsRollingArg implements TbelCfArg, Iterable<TbelCfTsDoubleVal
} }
public double mean() { public double mean() {
return mean(true);
}
public double mean(boolean ignoreNaN) {
if (values.isEmpty()) { if (values.isEmpty()) {
return 0; throw new IllegalArgumentException("Rolling argument values are empty.");
} }
double sum = sum(); return sum(ignoreNaN) / count(ignoreNaN);
return Double.isNaN(sum) ? Double.NaN : sum / values.size();
} }
public double std() { public double std() {
return std(true);
}
public double std(boolean ignoreNaN) {
if (values.isEmpty()) { if (values.isEmpty()) {
return 0; throw new IllegalArgumentException("Rolling argument values are empty.");
} }
double mean = mean(); double mean = mean(ignoreNaN);
if (Double.isNaN(mean)) { if (!ignoreNaN && Double.isNaN(mean)) {
return Double.NaN; return Double.NaN;
} }
@ -119,25 +134,35 @@ public class TbelCfTsRollingArg implements TbelCfArg, Iterable<TbelCfTsDoubleVal
for (TbelCfTsDoubleVal value : values) { for (TbelCfTsDoubleVal value : values) {
double val = value.getValue(); double val = value.getValue();
if (Double.isNaN(val)) { if (Double.isNaN(val)) {
return Double.NaN; if (!ignoreNaN) {
return Double.NaN;
}
} else {
sum += Math.pow(val - mean, 2);
} }
sum += Math.pow(val - mean, 2);
} }
return Math.sqrt(sum / values.size()); return Math.sqrt(sum / count(ignoreNaN));
} }
public double median() { public double median() {
return median(true);
}
public double median(boolean ignoreNaN) {
if (values.isEmpty()) { if (values.isEmpty()) {
return 0; throw new IllegalArgumentException("Rolling argument values are empty.");
} }
List<Double> sortedValues = new ArrayList<>(); List<Double> sortedValues = new ArrayList<>();
for (TbelCfTsDoubleVal value : values) { for (TbelCfTsDoubleVal value : values) {
double val = value.getValue(); double val = value.getValue();
if (Double.isNaN(val)) { if (Double.isNaN(val)) {
return Double.NaN; if (!ignoreNaN) {
return Double.NaN;
}
} else {
sortedValues.add(val);
} }
sortedValues.add(val);
} }
Collections.sort(sortedValues); Collections.sort(sortedValues);
@ -147,51 +172,90 @@ public class TbelCfTsRollingArg implements TbelCfArg, Iterable<TbelCfTsDoubleVal
: (sortedValues.get(size / 2 - 1) + sortedValues.get(size / 2)) / 2.0; : (sortedValues.get(size / 2 - 1) + sortedValues.get(size / 2)) / 2.0;
} }
public double count() { public int count() {
return hasNaN() ? Double.NaN : values.size(); return count(true);
}
public int count(boolean ignoreNaN) {
int count = 0;
if (ignoreNaN) {
for (TbelCfTsDoubleVal value : values) {
if (!Double.isNaN(value.getValue())) {
count++;
}
}
return count;
}
return values.size();
} }
public double last() { public double last() {
return last(true);
}
public double last(boolean ignoreNaN) {
if (values.isEmpty()) { if (values.isEmpty()) {
return 0; throw new IllegalArgumentException("Rolling argument values are empty.");
} }
return hasNaN() ? Double.NaN : values.get(values.size() - 1).getValue(); double value = values.get(values.size() - 1).getValue();
if (!Double.isNaN(value) || !ignoreNaN) {
return value;
}
for (int i = values.size() - 2; i >= 0; i--) {
double prevValue = values.get(i).getValue();
if (!Double.isNaN(prevValue)) {
return prevValue;
}
}
throw new IllegalArgumentException("Rolling argument values are empty.");
} }
public double first() { public double first() {
return first(true);
}
public double first(boolean ignoreNaN) {
if (values.isEmpty()) { if (values.isEmpty()) {
return 0; throw new IllegalArgumentException("Rolling argument values are empty.");
} }
return hasNaN() ? Double.NaN : values.get(0).getValue(); double firstValue = values.get(0).getValue();
if (!Double.isNaN(firstValue) || !ignoreNaN) {
return firstValue;
}
for (int i = 1; i < values.size(); i++) {
double nextValue = values.get(i).getValue();
if (!Double.isNaN(nextValue)) {
return nextValue;
}
}
throw new IllegalArgumentException("Rolling argument values are empty.");
} }
public double sum() { public double sum() {
return sum(true);
}
public double sum(boolean ignoreNaN) {
if (values.isEmpty()) { if (values.isEmpty()) {
return 0; throw new IllegalArgumentException("Rolling argument values are empty.");
} }
double sum = 0; double sum = 0;
for (TbelCfTsDoubleVal value : values) { for (TbelCfTsDoubleVal value : values) {
double val = value.getValue(); double val = value.getValue();
if (Double.isNaN(val)) { if (Double.isNaN(val)) {
return Double.NaN; if (!ignoreNaN) {
return Double.NaN;
}
} else {
sum += val;
} }
sum += val;
} }
return sum; return sum;
} }
private boolean hasNaN() {
for (TbelCfTsDoubleVal value : values) {
if (Double.isNaN(value.getValue())) {
return true;
}
}
return false;
}
@JsonIgnore @JsonIgnore
public int getSize() { public int getSize() {
return values.size(); return values.size();