rusefi-1/unit_tests/test_pid_auto.cpp

229 lines
6.0 KiB
C++
Raw Normal View History

2017-09-14 04:58:58 -07:00
/*
* test_pid_auto.cpp
*
* Created on: Sep 14, 2017
2018-01-20 17:42:19 -08:00
* @author Andrey Belomutskiy, (c) 2012-2018
2017-09-14 04:58:58 -07:00
*/
2018-09-16 19:39:46 -07:00
#include "global.h"
2017-09-14 18:00:28 -07:00
#include "test_pid_auto.h"
2017-09-14 18:49:26 -07:00
#include "pid_auto_tune.h"
2018-03-04 20:08:32 -08:00
#include "unit_test_framework.h"
#include "cyclic_buffer.h"
2017-09-14 04:58:58 -07:00
efitimems_t mockTimeMs = 0;
efitimems_t currentTimeMillis(void) {
return mockTimeMs;
}
2017-09-14 18:49:26 -07:00
Logging logging;
2017-09-17 16:34:50 -07:00
static float zigZagOffset = 0;
2018-11-18 19:38:31 -08:00
2018-11-22 15:43:41 -08:00
#define CYCLE 20
2018-11-22 19:14:32 -08:00
// range of oscillation
static float oscRange;
2018-11-22 15:43:41 -08:00
/**
* output linearly goes from 0 to 100 and back within each 'CYCLE' steps
*/
static float zigZagValue(int index) {
int i = index % CYCLE;
if ( i <= CYCLE / 2) {
2018-11-22 19:14:32 -08:00
return i * (oscRange / 2 / CYCLE) + zigZagOffset;
2018-11-18 19:38:31 -08:00
} else {
2018-11-22 19:14:32 -08:00
return (CYCLE - i) * (oscRange / 2 / CYCLE) + zigZagOffset;
2018-11-18 19:38:31 -08:00
}
2017-09-14 18:49:26 -07:00
}
2018-11-22 19:14:32 -08:00
static void testPidAutoZigZagStable() {
printf("*************************************************** testPidAutoZigZagStable\r\n");
2018-11-18 19:38:31 -08:00
2018-11-22 19:14:32 -08:00
oscRange = 100;
2017-09-14 18:00:28 -07:00
mockTimeMs = 0;
2017-09-14 04:58:58 -07:00
2017-09-14 18:49:26 -07:00
PID_AutoTune at;
2018-11-22 15:43:41 -08:00
at.SetLookbackSec(5);
2018-11-22 20:06:06 -08:00
at.SetControlType(PID_AutoTune::ZIEGLER_NICHOLS_PI);
at.sampleTime = 0; // not used in math only used to filter values out
2018-11-22 15:43:41 -08:00
assertEqualsM("nLookBack", 20, at.nLookBack);
2017-09-14 18:49:26 -07:00
at.outputStart = 50;
at.input = zigZagValue(mockTimeMs);
at.Runtime(&logging);
mockTimeMs++;
at.input = zigZagValue(mockTimeMs);
at.Runtime(&logging);
// assertEqualsLM("min@1", 0, at.absMin);
// assertEqualsLM("max@1", 10, at.absMax);
2017-09-14 18:49:26 -07:00
assertEqualsM("peakCount", 0, at.peakCount);
2018-11-22 15:43:41 -08:00
int startMockMs = mockTimeMs;
2017-09-14 18:49:26 -07:00
2018-11-22 15:43:41 -08:00
for (; mockTimeMs <= 10 + startMockMs; mockTimeMs++) {
2017-09-14 18:49:26 -07:00
at.input = zigZagValue(mockTimeMs);
2018-11-22 19:14:32 -08:00
bool result = at.Runtime(&logging);
assertFalseM("should be false#1", result);
2017-09-14 18:49:26 -07:00
}
// assertEqualsLM("min@11", 0, at.absMin);
// assertEqualsLM("max@11", 100, at.absMax);
2017-09-14 18:49:26 -07:00
assertEqualsM("peakCount", 0, at.peakCount);
2017-09-17 16:34:50 -07:00
for (; mockTimeMs <= 21; mockTimeMs++) {
2017-09-14 18:49:26 -07:00
at.input = zigZagValue(mockTimeMs);
2018-11-22 19:14:32 -08:00
bool result = at.Runtime(&logging);
assertFalseM("should be false#2", result);
2017-09-14 18:49:26 -07:00
}
assertEqualsM("peakCount@21", 0, at.peakCount);
2017-09-14 18:49:26 -07:00
2017-09-17 16:34:50 -07:00
for (; mockTimeMs <= 41; mockTimeMs++) {
2017-09-14 18:49:26 -07:00
at.input = zigZagValue(mockTimeMs);
2018-11-22 19:14:32 -08:00
bool result = at.Runtime(&logging);
assertFalseM("should be false#2_2", result);
2017-09-14 18:49:26 -07:00
}
2018-11-22 15:43:41 -08:00
assertEqualsM("peakCount@41", 2, at.peakCount);
2018-11-18 20:40:39 -08:00
// assertEqualsM("Pu@41", 1, cisnan(at.Pu));
2017-09-14 18:49:26 -07:00
2017-09-17 16:34:50 -07:00
for (; mockTimeMs <= 60; mockTimeMs++) {
2017-09-14 19:07:26 -07:00
at.input = zigZagValue(mockTimeMs);
2018-11-22 19:14:32 -08:00
bool result = at.Runtime(&logging);
assertFalseM("should be false#4", result);
2017-09-14 19:07:26 -07:00
}
2018-11-22 15:43:41 -08:00
assertEqualsM("peakCount@60", 4, at.peakCount);
2018-11-18 20:40:39 -08:00
//assertEqualsM("Pu@60", 0.02, at.Pu);
2017-09-14 18:49:26 -07:00
2017-09-17 16:34:50 -07:00
// zigZagOffset = 10;
2018-11-22 19:14:32 -08:00
for (; mockTimeMs <= 69; mockTimeMs++) {
2017-09-17 16:34:50 -07:00
at.input = zigZagValue(mockTimeMs);
2018-11-22 19:14:32 -08:00
bool result = at.Runtime(&logging);
assertFalseM("should be false#4", result);
2017-09-17 16:34:50 -07:00
}
2018-11-22 19:14:32 -08:00
at.input = zigZagValue(mockTimeMs);
bool result = at.Runtime(&logging);
assertEqualsM("should be true", 1, result);
2018-11-22 20:06:06 -08:00
assertEqualsM("testPidAutoZigZagStable::output", 0.0, at.output);
2018-11-22 19:14:32 -08:00
assertEqualsM("peakCount@80", 5, at.peakCount);
2018-11-22 15:43:41 -08:00
assertEqualsM("ki", 27.7798, at.GetKi());
assertEqualsM("kd", 0.0, at.GetKd());
2017-09-17 16:34:50 -07:00
2017-10-08 15:18:07 -07:00
// todo: test the same code with noisy zig-zag function
2017-09-14 18:00:28 -07:00
}
2018-11-22 19:14:32 -08:00
static void testPidAutoZigZagGrowingOsc() {
printf("*************************************************** testPidAutoZigZagGrowingOsc\r\n");
oscRange = 100;
mockTimeMs = 0;
PID_AutoTune at;
at.SetLookbackSec(5);
at.sampleTime = 0; // not used in math only used to filter values out
int startMockMs;
for (int i =0;i<11;i++) {
startMockMs = mockTimeMs;
printf("loop=%d %d\r\n", i, startMockMs);
for (; mockTimeMs < CYCLE + startMockMs; mockTimeMs++) {
at.input = zigZagValue(mockTimeMs);
bool result = at.Runtime(&logging);
assertFalseM("should be false#4", result);
}
oscRange *= 1.5;
}
startMockMs = mockTimeMs;
// for (; mockTimeMs < CYCLE + startMockMs; mockTimeMs++) {
// printf("loop2=%d\r\n", mockTimeMs);
// at.input = zigZagValue(mockTimeMs);
// bool result = at.Runtime(&logging);
// assertFalseM("should be false#5", result);
// }
at.input = zigZagValue(mockTimeMs);
bool result = at.Runtime(&logging);
assertTrueM("should be true#2", result);
assertEqualsM("FAiled", FAILED, at.state);
assertEqualsM("output Growing", 0.0, at.output);
}
2018-12-01 08:36:05 -08:00
static void testPidZeroLine() {
2018-11-22 20:06:06 -08:00
printf("*************************************************** testPidAutoZigZagGrowingOsc\r\n");
mockTimeMs = 0;
PID_AutoTune at;
at.SetLookbackSec(5);
at.sampleTime = 0; // not used in math only used to filter values out
int startMockMs;
for (int i =0;i<110;i++) {
startMockMs = mockTimeMs;
printf("loop=%d %d\r\n", i, startMockMs);
for (; mockTimeMs < CYCLE + startMockMs; mockTimeMs++) {
2018-12-01 08:36:05 -08:00
at.input = 0;
2018-11-22 20:42:30 -08:00
bool result = at.Runtime(&logging);
assertFalseM("should be false#4", result);
2018-11-22 20:06:06 -08:00
}
}
2018-11-22 20:42:30 -08:00
// nothing happens in this test since we do not allow time play a role
2018-11-22 20:06:06 -08:00
}
static void testPidDelayLine(void) {
printf("*************************************************** testPidDelayLine\r\n");
static const int delayBufSize = 8;
// we use a small FIFO buf to imitate some "response delay" of our virtual PID-controlled "device"
cyclic_buffer<float, delayBufSize> delayBuf;
delayBuf.clear();
mockTimeMs = 0;
PID_AutoTune at;
at.SetLookbackSec(5);
at.sampleTime = 0; // not used in math only used to filter values out
int startMockMs;
bool result = false;
for (int i = 0; i < 110 && !result; i++) {
startMockMs = mockTimeMs;
//at.input = delayBuf.get(delayBuf.currentIndex - 1);
int numElems = minI(delayBuf.getSize(), delayBuf.getCount());
// our "device" is an averaging delay line
at.input = (numElems == 0) ? 0 : (delayBuf.sum(numElems) / delayBuf.getSize());
result = at.Runtime(&logging);
// this is how our "device" is controlled by auto-tuner
delayBuf.add(at.output);
printf("[%d] %d in=%f out=%f\r\n", i, startMockMs, at.input, at.output);
mockTimeMs++;
}
if (result)
printf("*** Converged! Got result: P=%f I=%f D=%f\r\n", at.GetKp(), at.GetKi(), at.GetKd());
assertTrueM("should be true#5", result);
}
2018-12-01 08:36:05 -08:00
void testPidAuto() {
printf("*************************************************** testPidAuto\r\n");
2018-11-22 19:14:32 -08:00
testPidDelayLine();
2018-12-01 08:36:05 -08:00
testPidZeroLine();
2018-11-22 19:14:32 -08:00
testPidAutoZigZagStable();
testPidAutoZigZagGrowingOsc();
}