-
Notifications
You must be signed in to change notification settings - Fork 0
/
pid.coffee
74 lines (64 loc) · 2.71 KB
/
pid.coffee
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
PID = class PID
###
the PID style of controller is intended to track a quantity from the real world as detected by some sensor.
The sensor is assumed to be reliable as possible, consistent and acccurate.
the output of the controller is a single quantity that controls a single output device.
The output device is related in some fashion to changes in the real world that affect the sensor.
A PID controller ses the input values to compte an output variable by looking at three internally
computed quantities.
1) the Proportial component, which simply is related to "How far away from our goal are we?"
2) the Integral component, which is related to "How far have we come to our goal?"
3) the Differential component, which asks "are we taking big steps, or tiny ones?"
###
constructor: (proportionalParm, integrationParm, derivativeParm, dt) ->
if (typeof proportionalParm == 'object')
options = proportionalParm
proportionalParm = options.proportionalParm
integrationParm = options.integrationParm
derivativeParm = options.derivativeParm
dt = options.dt || 0
integrationLimit = options.integrationLimit
# PID constants
@proportionalParm = if typeof proportionalParm == 'number' then proportionalParm else 1
@integrationParm = integrationParm || 0
@derivativeParm = derivativeParm || 0
# Interval of time between two updates
# If not set, it will be automatically calculated
@dt = dt || 0
# Maximum absolute value of sumDelta
@integrationLimit = integrationLimit || 0
@sumDelta = 0
@lastDelta = 0
@setTarget 0 # default value, can be modified with .setTarget
return
setTarget: (@target) ->
@lastTime = Date.now() # used only if dt is not explicit
return
update: (@currentValue) ->
# Calculate dt
dt = @dt
if !dt
currentTime = Date.now()
dt = (currentTime - @lastTime) / 1000 # in seconds
@lastTime = currentTime
if (typeof dt != 'number' || dt == 0)
dt = 1
delta = @target - @currentValue #used as the Proportional factor
@sumDelta = @sumDelta + delta*dt #used as the Integral factor
if 0< @integrationLimit < Math.abs(@sumDelta) #if there is an integration limit, check it
sumSign = if @sumDelta > 0 then 1 else -1
@sumDelta = sumSign * @integrationLimit # activate the caller's failsafe quantity
dDelta = (delta - @lastDelta)/dt # used as the Derivitive factor
@lastDelta = delta
return (@proportionalParm*delta) +
(@integrationParm * @sumDelta) +
(@derivativeParm * dDelta)
reset:() ->
@sumDelta = 0
@lastDelta = 0
@setTarget 0
return
if module?.exports
module.exports = PID
if window
window.PID=PID