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

Pid improvements #94

Open
wants to merge 6 commits into
base: florida
Choose a base branch
from
Open
Show file tree
Hide file tree
Changes from all commits
Commits
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
68 changes: 46 additions & 22 deletions src/com/nutrons/framework/util/FlowOperators.java
Original file line number Diff line number Diff line change
Expand Up @@ -20,10 +20,10 @@ public class FlowOperators {
* Generate a Flowable from a periodic call to a Supplier. Drops on backpressure.
*
* @param ignored the number of time units to wait before calling the supplier again
* @param <T> the type of the Flowable and Supplier
* @param <T> the type of the Flowable and Supplier
*/
public static <T> Flowable<T> toFlow(Supplier<T> supplier,
long ignored, TimeUnit unit) {
long ignored, TimeUnit unit) {
return Flowable.interval(ignored, unit).subscribeOn(Schedulers.io())
.map(x -> supplier.get()).onBackpressureDrop().observeOn(Schedulers.computation())
.onBackpressureDrop().share();
Expand Down Expand Up @@ -57,7 +57,7 @@ public static Flowable<Double> deadband(Flowable<Double> input) {
* specified by minimum and maximum. If so, the value will be changed to remap.
*/
public static Function<Double, Double> deadbandMap(double minimum, double maximum,
double remap) {
double remap) {
return bandMap(minimum, maximum, x -> remap);
}

Expand All @@ -66,7 +66,7 @@ public static Function<Double, Double> deadbandMap(double minimum, double maximu
* specified by minimum and maximum. If so, the value will be passed through the remap function.
*/
public static Function<Double, Double> bandMap(double minimum, double maximum,
Function<Double, Double> remap) {
Function<Double, Double> remap) {
return x -> x < maximum && x > minimum ? remap.apply(x) : x;
}

Expand All @@ -76,33 +76,57 @@ public static <T> T getLastValue(Flowable<T> input) {

/**
* Creates a PID Loop Function.
* DON'T USE EVER
*/
public static FlowableTransformer<Double, Double> pidLoop(double proportional,
int integralBuffer,
double integral,
double derivative) {
return error -> {
Flowable<Double> errorP = error.map(x -> x * proportional);
Flowable<Double> errorI = error.buffer(integralBuffer, 1)
.map(list -> list.stream().reduce(0.0, (x, acc) -> x + acc))
.map(x -> x * integral);
Flowable<Double> errorD = error.buffer(2, 1)
.map(last -> last.stream().reduce(0.0, (x, y) -> x - y))
.map(x -> x * derivative);
Flowable<Double> output = Flowable.combineLatest(errorP, errorI, errorD,
(p, i, d) -> p + i + d);
return output;
};
@Deprecated
public static FlowableTransformer<Double, Double> veryBadDontUseEverPidLoop(double proportional,
int integralBuffer,
double integral,
double derivative) {
return controlLoop(proportional, derivative, integral,
(error) -> error.buffer(integralBuffer, 1)
.map(list -> list.stream().reduce(0.0, (x, acc) -> x + acc))
.map(x -> x * integral / integralBuffer));
}

/**
* Exponential average version of PID Loop.
*/
public static FlowableTransformer<Double, Double> exponentialPidLoop(double proportinal,
double integralBuffer,
double integral,
double derivative) {
return controlLoop(proportinal, integral, derivative, error -> error.scan(
(newVal, lastAvg) -> lastAvg * (integralBuffer - 1) / integralBuffer + newVal / integralBuffer));
}

/**
* RegularPD loop with the 0.0 integral stream.
*/
public static FlowableTransformer<Double, Double> pdLoop(double proportional,
double derivative) {
double derivative) {
return controlLoop(proportional, derivative, 0.0, error -> Flowable.just(0.0));
}

/**
* Control Loop for PID which
*/
private static FlowableTransformer<Double, Double> controlLoop(double proportional,
double derivative,
double integral,
Function<Flowable<Double>, Flowable<Double>> errorI) {
return error -> {
Flowable<Double> errorP = error.map(x -> x * proportional);
Flowable<Double> errorD = error.buffer(2, 1)
.map(last -> last.stream().reduce(0.0, (x, y) -> x - y))
.map(x -> x * derivative);
return Flowable.combineLatest(errorP, errorD, (p, d) -> p + d).share();
try {
return Flowable.combineLatest(errorP, errorI.apply(error).map(x -> x * integral), errorD,
(p, i, d) -> p + i + d);
} catch (Exception e) {
e.printStackTrace();
throw new RuntimeException(e);
}
};
}

Expand Down
18 changes: 18 additions & 0 deletions test/com/nutrons/framework/test/TestPD.java
Original file line number Diff line number Diff line change
@@ -0,0 +1,18 @@
package com.nutrons.framework.test;

import static com.nutrons.framework.util.FlowOperators.pdLoop;
import static com.nutrons.framework.util.FlowOperators.toFlow;

import io.reactivex.Flowable;
import org.junit.Test;

public class TestPD {

@Test
public void testPDConcurrency (){
Flowable<Double> input = toFlow(() -> 1.0);
Flowable<Double> output = input.compose(pdLoop(1.0, 1.0));
output.subscribe(x -> {
}); //tests
}
}
4 changes: 2 additions & 2 deletions test/com/nutrons/framework/test/TestPID.java
Original file line number Diff line number Diff line change
@@ -1,7 +1,7 @@
package com.nutrons.framework.test;

import static com.nutrons.framework.util.FlowOperators.pidLoop;
import static com.nutrons.framework.util.FlowOperators.toFlow;
import static com.nutrons.framework.util.FlowOperators.veryBadDontUseEverPidLoop;

import io.reactivex.Flowable;
import org.junit.Test;
Expand All @@ -11,7 +11,7 @@ public class TestPID {
@Test
public void testPIDConcurrency() {
Flowable<Double> input = toFlow(() -> 1.0);
Flowable<Double> output = input.compose(pidLoop(1, 1, 0, 0));
Flowable<Double> output = input.compose(veryBadDontUseEverPidLoop(1, 1, 0, 0));
output.subscribe(x -> {
}); // tests that this is done on an io scheduler
}
Expand Down