Skip to content

Commit

Permalink
Faster temperature sampling and moving average
Browse files Browse the repository at this point in the history
There is a large noise in the temperature readings. That makes the projected temperatures unreliable.

Here we add a moving average of 100 samples on top of the temperature readings. The value of 100 was found by looking at the data from previous runs. The temperature readings are done every 10 ms. Assuming the noise is high-frequency, this should produce smooth temperature readings. The added latency is no more than 1 second, which is negligible.

The heatings controls are updated every 2 seconds. The logic is not changed.

We add an element to the serial output to log which heater has been chosen.
  • Loading branch information
tlecomte committed Oct 14, 2019
1 parent 53b2224 commit 5591b3d
Show file tree
Hide file tree
Showing 2 changed files with 104 additions and 37 deletions.
128 changes: 94 additions & 34 deletions crepemaker.ino
Original file line number Diff line number Diff line change
Expand Up @@ -6,19 +6,26 @@
// libraries to be installed from the library manager
#include "max6675.h"

// other compile directives
#define LOOPTIME 500 // cycle time, in ms

// global variables and objects
MAX6675 thermocouple1(CLKPIN, CS1PIN, DOPIN);
MAX6675 thermocouple2(CLKPIN, CS2PIN, DOPIN);

// variables for the heating control
float previoustemp1 = 0;
float previoustemp2 = 0;
unsigned long timestamp = 0;
int counter = 0;

void seriallogger(float temp1, float temp2, float ror1, float ror2, float projectedtemp1, float projectedtemp2) {
unsigned long lastControlUpdate = 0; // last time controls were updated

// variables for the moving averages on temperature readings
float tempReadings1[NUMREADINGS]; // the temperature readings from the analog input
float tempReadings2[NUMREADINGS];
int readIndex = 0; // the index of the current reading
unsigned long lastRead = 0; // last time readings were updated
float tempReadingsTotal1 = 0; // the running total
float tempReadingsTotal2 = 0;
float temp1; // the average
float temp2;

void seriallogger(float temp1, float temp2, float ror1, float ror2, float projectedtemp1, float projectedtemp2, byte control) {
Serial.print(temp1);
Serial.print(",");
Serial.print(temp2);
Expand All @@ -29,42 +36,92 @@ void seriallogger(float temp1, float temp2, float ror1, float ror2, float projec
Serial.print(",");
Serial.print(projectedtemp1);
Serial.print(",");
Serial.println(projectedtemp2);
Serial.print(projectedtemp2);
Serial.print(",");
Serial.println(control);
}

void setup() {
pinMode(SSR1PIN, OUTPUT);
pinMode(SSR2PIN, OUTPUT);

Serial.begin(BAUD);

// wait for MAX chips to stabilize
delay(500);

// initialize the readings array to zero
for (int i = 0; i < NUMREADINGS; i++) {
tempReadings1[i] = 0;
tempReadings2[i] = 0;
}

// initialize the temperature readings and averages with actual values
while (readIndex < NUMREADINGS - 1) {
updateTemperatureReadings();
delay(LOOP_PERIOD_MS);
}
}

void loop() {
updateTemperatureReadings();
updateControls();
delay(LOOP_PERIOD_MS);
}

void updateTemperatureReadings() {
if (millis() - lastRead < READING_PERIOD_MS) {
return;
}

lastRead += READING_PERIOD_MS;

// subtract the last reading
tempReadingsTotal1 = tempReadingsTotal1 - tempReadings1[readIndex];
tempReadingsTotal2 = tempReadingsTotal2 - tempReadings2[readIndex];

// read from the sensor
tempReadings1[readIndex] = thermocouple1.readCelsius();
tempReadings2[readIndex] = thermocouple2.readCelsius();

// add the reading to the total
tempReadingsTotal1 = tempReadingsTotal1 + tempReadings1[readIndex];
tempReadingsTotal2 = tempReadingsTotal2 + tempReadings2[readIndex];

// advance to the next position in the array
readIndex = readIndex + 1;

// if we are at the end of the array...
if (readIndex >= NUMREADINGS) {
// ...wrap around to the beginning
readIndex = 0;
}

// calculate the average
temp1 = tempReadingsTotal1 / NUMREADINGS;
temp2 = tempReadingsTotal2 / NUMREADINGS;
}

void loop() {
void updateControls()
{
unsigned long timeelapsed = 0;
float temp1;
float temp2;
float ror1;
float ror2;
float projectedtemp1;
float projectedtemp2;

temp1 = thermocouple1.readCelsius();
temp2 = thermocouple2.readCelsius();

if (counter >= SAMPLING) {
timeelapsed = (millis() - timestamp);
ror1 = (((temp1 - previoustemp1) / timeelapsed) * 1000 * 60); //Raise of rise in C/min
ror2 = (((temp2 - previoustemp2) / timeelapsed) * 1000 * 60); //Raise of rise in C/min
timestamp = millis();
counter = 0;
previoustemp1 = temp1; // We should really calculate an average rather...
previoustemp2 = temp2;
timeelapsed = (millis() - lastControlUpdate);

if (timeelapsed < CONTROL_UPDATE_PERIOD_MS) {
return;
}

counter++;

lastControlUpdate += CONTROL_UPDATE_PERIOD_MS; // do not use timeelapsed here to avoid drift

ror1 = (((temp1 - previoustemp1) / timeelapsed) * 1000 * 60); //Raise of rise in C/min
ror2 = (((temp2 - previoustemp2) / timeelapsed) * 1000 * 60); //Raise of rise in C/min
previoustemp1 = temp1;
previoustemp2 = temp2;

if (ror1 >= 0) {
projectedtemp1 = (temp1 + (ror1 * RISEINERTIA));
Expand All @@ -80,21 +137,24 @@ void loop() {
projectedtemp2 = (temp2 + (ror2 * FALLINERTIA));
}

seriallogger(temp1,temp2,ror1,ror2,projectedtemp1,projectedtemp2);
byte control = 0;

if (projectedtemp1 <= SV1) {
digitalWrite(SSR2PIN, LOW);
digitalWrite(SSR1PIN, HIGH);
}
if (projectedtemp1 <= SV1) {
digitalWrite(SSR2PIN, LOW);
digitalWrite(SSR1PIN, HIGH);
control = 1;
}
else {
digitalWrite(SSR1PIN, LOW);
digitalWrite(SSR1PIN, LOW);

if (projectedtemp2 <= SV2) {
digitalWrite(SSR2PIN, HIGH);
digitalWrite(SSR2PIN, HIGH);
control = 2;
}
else {
digitalWrite(SSR2PIN, LOW);
digitalWrite(SSR2PIN, LOW);
}
}
delay(LOOPTIME);

seriallogger(temp1, temp2, ror1, ror2, projectedtemp1, projectedtemp2, control);
}
13 changes: 10 additions & 3 deletions user.h
Original file line number Diff line number Diff line change
Expand Up @@ -14,14 +14,21 @@
#define RISEINERTIA 3 //how long it takes the system to stop rising (in min)
#define FALLINERTIA 1 //how long it takes the system to stop falling (in min)

#define SAMPLING 5 //loops to calculate ror
// cycle time, in ms
#define LOOP_PERIOD_MS 1

// Delay time between temperature readings
// from the temperature sensor (ms).
#define DELAY_TIME 20
// (must be larger than LOOP_PERIOD_MS)
#define READING_PERIOD_MS 10

// How many readings are taken to determine a mean temperature.
#define READINGS 10
// accounts for the thermocouple noise
#define NUMREADINGS 100

// delay between 2 control updates
// (must be larger than LOOP_PERIOD_MS)
#define CONTROL_UPDATE_PERIOD_MS 2000

// Pin mapping
// Common SPI pins
Expand Down

0 comments on commit 5591b3d

Please sign in to comment.