diff --git a/wpilibcIntegrationTests/src/FRCUserProgram/cpp/FilterOutputTest.cpp b/wpilibcIntegrationTests/src/FRCUserProgram/cpp/FilterOutputTest.cpp index 49ceb3badd..9ca129b79c 100644 --- a/wpilibcIntegrationTests/src/FRCUserProgram/cpp/FilterOutputTest.cpp +++ b/wpilibcIntegrationTests/src/FRCUserProgram/cpp/FilterOutputTest.cpp @@ -19,7 +19,12 @@ using namespace frc; -enum FilterOutputTestType { TEST_SINGLE_POLE_IIR, TEST_HIGH_PASS, TEST_MOVAVG }; +enum FilterOutputTestType { + TEST_SINGLE_POLE_IIR, + TEST_HIGH_PASS, + TEST_MOVAVG, + TEST_PULSE +}; std::ostream& operator<<(std::ostream& os, const FilterOutputTestType& type) { switch (type) { @@ -32,6 +37,9 @@ std::ostream& operator<<(std::ostream& os, const FilterOutputTestType& type) { case TEST_MOVAVG: os << "LinearDigitalFilter MovingAverage"; break; + case TEST_PULSE: + os << "LinearDigitalFilter Pulse"; + break; } return os; @@ -70,11 +78,18 @@ class FilterOutputTest : public testing::TestWithParam { return 100.0 * std::sin(2.0 * M_PI * t) + 20.0 * std::cos(50.0 * M_PI * t); } - void SetUp() override { - m_data = std::make_shared(GetData); + static double GetPulseData(double t) { + if (std::abs(t - 1.0) < 0.001) { + return 1.0; + } else { + return 0.0; + } + } + void SetUp() override { switch (GetParam()) { case TEST_SINGLE_POLE_IIR: { + m_data = std::make_shared(GetData); m_filter = std::make_unique( LinearDigitalFilter::SinglePoleIIR( m_data, TestBench::kSinglePoleIIRTimeConstant, @@ -84,6 +99,7 @@ class FilterOutputTest : public testing::TestWithParam { } case TEST_HIGH_PASS: { + m_data = std::make_shared(GetData); m_filter = std::make_unique(LinearDigitalFilter::HighPass( m_data, TestBench::kHighPassTimeConstant, @@ -93,11 +109,20 @@ class FilterOutputTest : public testing::TestWithParam { } case TEST_MOVAVG: { + m_data = std::make_shared(GetData); m_filter = std::make_unique( LinearDigitalFilter::MovingAverage(m_data, TestBench::kMovAvgTaps)); m_expectedOutput = TestBench::kMovAvgExpectedOutput; break; } + + case TEST_PULSE: { + m_data = std::make_shared(GetPulseData); + m_filter = std::make_unique( + LinearDigitalFilter::MovingAverage(m_data, TestBench::kMovAvgTaps)); + m_expectedOutput = 0.0; + break; + } } } }; @@ -122,4 +147,4 @@ TEST_P(FilterOutputTest, FilterOutput) { INSTANTIATE_TEST_CASE_P(Test, FilterOutputTest, testing::Values(TEST_SINGLE_POLE_IIR, TEST_HIGH_PASS, - TEST_MOVAVG)); + TEST_MOVAVG, TEST_PULSE)); diff --git a/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/FilterOutputTest.java b/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/FilterOutputTest.java index 9b6f3a177b..911143586c 100644 --- a/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/FilterOutputTest.java +++ b/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/FilterOutputTest.java @@ -58,7 +58,8 @@ public class FilterOutputTest extends AbstractComsSetup { return Arrays.asList(new FilterOutputFixture[][]{ {TestBench.getInstance().getSinglePoleIIROutputFixture()}, {TestBench.getInstance().getHighPassOutputFixture()}, - {TestBench.getInstance().getMovAvgOutputFixture()}}); + {TestBench.getInstance().getMovAvgOutputFixture()}, + {TestBench.getInstance().getPulseFixture()}}); } @Before diff --git a/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/fixtures/FilterOutputFixture.java b/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/fixtures/FilterOutputFixture.java index 39c650219a..d91850bfef 100644 --- a/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/fixtures/FilterOutputFixture.java +++ b/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/fixtures/FilterOutputFixture.java @@ -8,6 +8,7 @@ package edu.wpi.first.wpilibj.fixtures; import java.lang.reflect.ParameterizedType; +import java.util.function.DoubleFunction; import java.util.logging.Logger; import edu.wpi.first.wpilibj.PIDSource; @@ -15,11 +16,10 @@ import edu.wpi.first.wpilibj.PIDSourceType; import edu.wpi.first.wpilibj.test.TestBench; /** - * Represents a filterphysically connected Motor and Encoder to allow for unit tests on these - * different pairs
Designed to allow the user to easily setup and tear down the fixture to allow - * for reuse. This class should be explicitly instantiated in the TestBed class to allow any test to - * access this fixture. This allows tests to be mailable so that you can easily reconfigure the - * physical testbed without breaking the tests. + * Represents a filter to allow for unit tests on them
Designed to allow the user to easily + * setup and tear down the fixture to allow for reuse. This class should be explicitly instantiated + * in the TestBed class to allow any test to access this fixture. This allows tests to be mailable + * so that you can easily reconfigure the physical testbed without breaking the tests. */ public abstract class FilterOutputFixture implements ITestFixture { private static final Logger logger = Logger.getLogger(FilterOutputFixture.class.getName()); @@ -40,24 +40,37 @@ public abstract class FilterOutputFixture implements ITestF return m_expectedOutput; } + public static DoubleFunction getData = new DoubleFunction() { + @Override + @SuppressWarnings("ParameterName") + public Double apply(double t) { + return 100.0 * Math.sin(2.0 * Math.PI * t) + 20.0 * Math.cos(50.0 * Math.PI * t); + } + }; + + public static DoubleFunction getPulseData = new DoubleFunction() { + @Override + @SuppressWarnings("ParameterName") + public Double apply(double t) { + if (Math.abs(t - 1.0) < 0.001) { + return 1.0; + } else { + return 0.0; + } + } + }; + /** * Where the implementer of this class should pass the filter constructor. */ - protected abstract T giveFilter(PIDSource source); + protected abstract T giveFilter(); private void initialize() { synchronized (this) { if (!m_initialized) { m_initialized = true; // This ensures it is only initialized once - m_data = new DataWrapper() { - @Override - @SuppressWarnings("ParameterName") - public double getData(double t) { - return 100.0 * Math.sin(2.0 * Math.PI * t) + 20.0 * Math.cos(50.0 * Math.PI * t); - } - }; - m_filter = giveFilter(m_data); + m_filter = giveFilter(); } } } @@ -78,16 +91,6 @@ public abstract class FilterOutputFixture implements ITestF return m_filter; } - /** - * Gets the data wrapper for this object. - * - * @return the data wrapper that this object refers too - */ - public DataWrapper getDataWrapper() { - initialize(); - return m_data; - } - /** * Retrieves the name of the filter that this object refers to. * @@ -122,13 +125,15 @@ public abstract class FilterOutputFixture implements ITestF return string.toString(); } - public abstract class DataWrapper implements PIDSource { + public class DataWrapper implements PIDSource { // Make sure first call to pidGet() uses count == 0 private double m_count = -TestBench.kFilterStep; - @SuppressWarnings("ParameterName") - public abstract double getData(double t); + private DoubleFunction m_func; + public DataWrapper(DoubleFunction func) { + m_func = func; + } @Override public void setPIDSourceType(PIDSourceType pidSource) { @@ -144,7 +149,7 @@ public abstract class FilterOutputFixture implements ITestF @Override public double pidGet() { m_count += TestBench.kFilterStep; - return getData(m_count); + return m_func.apply(m_count); } public void reset() { diff --git a/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/test/TestBench.java b/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/test/TestBench.java index 247792783a..d1148502c1 100644 --- a/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/test/TestBench.java +++ b/wpilibjIntegrationTests/src/main/java/edu/wpi/first/wpilibj/test/TestBench.java @@ -387,8 +387,9 @@ public final class TestBench { public FilterOutputFixture getSinglePoleIIROutputFixture() { return new FilterOutputFixture(kSinglePoleIIRExpectedOutput) { @Override - protected LinearDigitalFilter giveFilter(PIDSource source) { - return LinearDigitalFilter.singlePoleIIR(source, + protected LinearDigitalFilter giveFilter() { + DataWrapper data = new DataWrapper(getData); + return LinearDigitalFilter.singlePoleIIR(data, kSinglePoleIIRTimeConstant, kFilterStep); } @@ -403,8 +404,9 @@ public final class TestBench { public FilterOutputFixture getHighPassOutputFixture() { return new FilterOutputFixture(kHighPassExpectedOutput) { @Override - protected LinearDigitalFilter giveFilter(PIDSource source) { - return LinearDigitalFilter.highPass(source, kHighPassTimeConstant, + protected LinearDigitalFilter giveFilter() { + DataWrapper data = new DataWrapper(getData); + return LinearDigitalFilter.highPass(data, kHighPassTimeConstant, kFilterStep); } }; @@ -419,8 +421,25 @@ public final class TestBench { public FilterOutputFixture getMovAvgOutputFixture() { return new FilterOutputFixture(kMovAvgExpectedOutput) { @Override - protected LinearDigitalFilter giveFilter(PIDSource source) { - return LinearDigitalFilter.movingAverage(source, kMovAvgTaps); + protected LinearDigitalFilter giveFilter() { + DataWrapper data = new DataWrapper(getData); + return LinearDigitalFilter.movingAverage(data, kMovAvgTaps); + } + }; + } + + /** + * Constructs a new set of objects representing a moving average filter with a repeatable data + * source using a linear digital filter. + * + * @return a moving average filter with a repeatable data source + */ + public FilterOutputFixture getPulseFixture() { + return new FilterOutputFixture(0.0) { + @Override + protected LinearDigitalFilter giveFilter() { + DataWrapper data = new DataWrapper(getPulseData); + return LinearDigitalFilter.movingAverage(data, kMovAvgTaps); } }; }