MicroHTR (Part 5)

Part 1, 2, 3, 4, 5, 6, 7, 8

Few more lines of code are required to build a fully operational PID. In the case of a PWM control, we need to get an output value ranging from 0 to 100% (Duty cycle). But other applications may require different ranges. That is the reason why we shall set extra global parameters and use them in the following way:

	/* Compute output */
	double outputValue = (_Kp * error) + (_Ki * _integralError) + (_Kd * dError); 
	outputValue *= (_limitUpp - _limitLow);
	outputValue += _limitLow;
	/* Constrain output signal to predefined values */
	if (outputValue < _limitLow) { outputValue = _limitLow; } else if (outputValue > _limitUpp) {
		outputValue = _limitUpp;
	}

In this way, the PID function output shall be constrained within the _limitLow and _limitUpp bounds. Finally with get a fully operating PID which will work fine for controlling heating systems.

double PlainPID::PIDOutput(double processVariable)
/* Compute output signal */
{
	_actualPointValue = processVariable;
	/* Timing stuff */
	uint32_t now = millis();
	double timeInterval = (now - _lastTime) / 1000.0;
	/* Auto adjust set point in order to prevent windup and spikes */
	if (_firstPass == 0x01) {
		_computedSetpoint = processVariable;
		_firstPass = 0x00;
	}
	if (_computedSetpoint != _setpoint) {
		/* Reset integral of errors */
		_integralError = 0;
		if (_computedSetpoint < _setpoint) { _computedSetpoint = (processVariable + 1); if (_computedSetpoint > _setpoint)  {
				_computedSetpoint = _setpoint;
			}
		} else if (_computedSetpoint > _setpoint)  {
			_computedSetpoint = (processVariable - 1);
			if (_computedSetpoint < _setpoint)  {
				_computedSetpoint = _setpoint;
			}
		}
	}
	/* Compute error */
	double error = (_computedSetpoint - processVariable); 
	/* Compute error derivative */
	double dError = (error - _lastError) / timeInterval;
	/* Compute error integral */
	_integralError += ((error + _lastError ) * timeInterval) / 2.0;
	/* Compute output */
	double outputValue = (_Kp * error) + (_Ki * _integralError) + (_Kd * dError); 
	outputValue *= (_limitUpp - _limitLow);
	outputValue += _limitLow;
	/* Constrain output signal to predefined values */
	if (outputValue < _limitLow) { outputValue = _limitLow; } else if (outputValue > _limitUpp) {
		outputValue = _limitUpp;
	}
	/* Save last values in volatile variables */
	_lastTime = now;
	_lastError = error; 
	return(outputValue);
};

Next post on same subject

Leave a Reply

You must be logged in to post a comment.