dPID: The code
- status:
RC-1.0
The code of the test-examples and the (empty) dpid.dPID class are shown here. They are
exactly as the python-files; but for the highlighting.
Some (py)test examples
1# Copyright (C) 2017: ALbert Mietus, SoftwareBeterMaken
2# Part of my MESS project
3# Dropjes licencie: Beloon me met dropjes naar nuttigheid
4
5import pytest
6
7from logging import getLogger
8logger = getLogger(__name__)
9
10from dpid import dPID
11
12def test_P():
13 MARGIN = 0.5
14
15 c = dPID(1,0,0)
16
17 c.setpoint(10.0)
18 c.measured(10.0)
19 out = c.result()
20
21 assert (-1*MARGIN) < out < MARGIN, "result (%s) should be close to zero (MARGIN=%s)" % (out, MARGIN)
22
23def test_clip():
24 c = dPID(1,2,3)
25
26 c.set_min_max(min_result=10)
27 c.set_min_max(max_result=10)
28
29 for sp in range(-100,100,10):
30 c.setpoint(sp)
31 c.measured(0)
32
33 got = c.result()
34 assert got == 10, "Both min and max are clipped to 10; so result should be 10!. But it is: %s" % c.result()
The class (empty)
1# Copyright (C) 2017, 2025: ALbert Mietus, SoftwareBeterMaken
2# Part of my MESS project
3# Dropjes licencie: Beloon me met dropjes naar nuttigheid
4
5from numbers import Real
6from typing import Optional
7
8from logging import getLogger
9logger = getLogger(__name__)
10
11class dPID:
12 """A simple discrete-PID controller, as an exercise.
13
14 This PID-controller can be initialised with constantes for ``P``, ``I`` and ``D``;
15 which can't be changed afterwards. Optional, a minimum and maximum
16 output value can be given; both during initialisation, and later.
17
18 The controller has two **inputs**: :meth:`.setpoint` and
19 :meth:`.measured`, and one **output**: :meth:`.result`. Those inputs can
20 be set/updated independently. Similarly, the :meth:`.result` can be read
21 at any-moment. As the controller will *remember* the timestamp a values
22 changes (and knows when the result is read), it will always give the
23 correct output. Thus, that output value does depend on the timestamp it
24 is requested!
25
26 The :meth:`.setpoint` is considered as a step-function: between two
27 changes, it will remain the last value. The :meth:`.measured` value
28 however should be considered as a continuously linear-changing value. So,
29 between two updates of this value, the dPID-controller will interpolate
30 linearly.
31
32 When a :meth:`.result` is read during such a period; the PID-controller can't
33 predict the next-measured-value, however. Therefor, it will (for that
34 single read) assume the measured-value is the same as last-time.
35
36 When a maximum and/or minimum value is set, the :meth:`.result` will be
37 clipped to that value when needed. Without a min/max, the :meth:`.result` is
38 unlimited.
39
40
41 .. hint:: As this class is part of an exercise; no implementation is given.
42
43 During the training one should update this file to implement the class
44 **without** changing the interface.
45
46 All (numeric) input & output values are either integers or floats.
47
48 """
49
50 def __init__(self, P:Real, I:Real, D:Real, min_result:Optional[Real]=None, max_result:Optional[Real]=None):
51 assert NotImplementedError("This class is part of an exercise; please implement it yourself")
52
53 def setpoint(self, sp:Real):
54 """Set the setpoint: a numeric value."""
55
56 def measured(self, value:Real):
57 """Give the controller an update on the actual *measured* (or simulated) process-value.
58
59 The controller will assume a linear progression between the last update and the current one."""
60
61 def result(self) -> Real:
62 """Return the actual result value"""
63
64 def set_min_max(self, min_result :Optional[Real]=None, max_result :Optional[Real]=None):
65 """Change the minimum and/or maximal result value. Used to clip the :meth:`.result`"""
Downloads
You can download these files directly from bitbucket
Comments
comments powered by Disqus