pid_controller 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: ed3b92ab6f402ed7ca931150c9832a245c62a8fa
4
+ data.tar.gz: 02b6b58e47954514a8b89d79bc5a3b30bb99595c
5
+ SHA512:
6
+ metadata.gz: 28b63c397d384f6f06f077185c1b833a5330702286c4e5f0072cfea0dcd77c8f60adcec4b0ff8bcd92bd1e8bff251a32ab16a3852e2b89f78d7da9c55f6d1e86
7
+ data.tar.gz: 90bee02b13d177287108d51f869001061856a4b14bc4c2955dedc3fa97138c15ae8ca6f7df70df1c352f3923242f3ab76a61261ff2b959ae338d30dce3188780
@@ -0,0 +1,11 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /_yardoc/
4
+ /coverage/
5
+ /doc/
6
+ /pkg/
7
+ /spec/reports/
8
+ /tmp/
9
+
10
+ # rspec failure tracking
11
+ .rspec_status
data/.rspec ADDED
@@ -0,0 +1,3 @@
1
+ --format documentation
2
+ --color
3
+ --require spec_helper
@@ -0,0 +1,7 @@
1
+ AllCops:
2
+ DisplayCopNames: true
3
+
4
+ Metrics/BlockLength:
5
+ ExcludedMethods:
6
+ - context
7
+ - describe
@@ -0,0 +1,14 @@
1
+ sudo: false
2
+ language: ruby
3
+ rvm:
4
+ - 2.4.2
5
+ cache: bundler
6
+ before_install: gem install bundler -v 1.16.0
7
+ branches:
8
+ only: [master]
9
+ script: $TASK
10
+ env:
11
+ matrix:
12
+ - TASK="bundle exec rspec"
13
+ - TASK="bundle exec rubocop"
14
+
data/Gemfile ADDED
@@ -0,0 +1,6 @@
1
+ source 'https://rubygems.org'
2
+
3
+ git_source(:github) { |repo_name| "https://github.com/#{repo_name}" }
4
+
5
+ # Specify your gem's dependencies in pid_controller.gemspec
6
+ gemspec
@@ -0,0 +1,58 @@
1
+ PATH
2
+ remote: .
3
+ specs:
4
+ pid_controller (0.1.0)
5
+
6
+ GEM
7
+ remote: https://rubygems.org/
8
+ specs:
9
+ ast (2.3.0)
10
+ coderay (1.1.2)
11
+ diff-lcs (1.3)
12
+ method_source (0.9.0)
13
+ parallel (1.12.0)
14
+ parser (2.4.0.2)
15
+ ast (~> 2.3)
16
+ powerpack (0.1.1)
17
+ pry (0.11.3)
18
+ coderay (~> 1.1.0)
19
+ method_source (~> 0.9.0)
20
+ rainbow (2.2.2)
21
+ rake
22
+ rake (10.5.0)
23
+ rspec (3.7.0)
24
+ rspec-core (~> 3.7.0)
25
+ rspec-expectations (~> 3.7.0)
26
+ rspec-mocks (~> 3.7.0)
27
+ rspec-core (3.7.0)
28
+ rspec-support (~> 3.7.0)
29
+ rspec-expectations (3.7.0)
30
+ diff-lcs (>= 1.2.0, < 2.0)
31
+ rspec-support (~> 3.7.0)
32
+ rspec-mocks (3.7.0)
33
+ diff-lcs (>= 1.2.0, < 2.0)
34
+ rspec-support (~> 3.7.0)
35
+ rspec-support (3.7.0)
36
+ rubocop (0.51.0)
37
+ parallel (~> 1.10)
38
+ parser (>= 2.3.3.1, < 3.0)
39
+ powerpack (~> 0.1)
40
+ rainbow (>= 2.2.2, < 3.0)
41
+ ruby-progressbar (~> 1.7)
42
+ unicode-display_width (~> 1.0, >= 1.0.1)
43
+ ruby-progressbar (1.9.0)
44
+ unicode-display_width (1.3.0)
45
+
46
+ PLATFORMS
47
+ ruby
48
+
49
+ DEPENDENCIES
50
+ bundler (~> 1.16)
51
+ pid_controller!
52
+ pry
53
+ rake (~> 10.0)
54
+ rspec (~> 3.0)
55
+ rubocop (~> 0.51)
56
+
57
+ BUNDLED WITH
58
+ 1.16.0
@@ -0,0 +1,33 @@
1
+ # PidController
2
+
3
+ This is a Ruby implementation of a [PID Controller](https://en.wikipedia.org/wiki/PID_controller). A PID controller is a feedback system that is configured with a target setpoint, can read measurements of the system to see how close we are to the setpoint, and will omit an output. Every day examples include:
4
+
5
+ - Cruise control
6
+ - Thermostats
7
+ - Quadcopters (appearently, because they predominate search results)
8
+ - Database load (yay! This is why the purpose I'm actually writing this for).
9
+
10
+ ## Usage
11
+
12
+ I mentioned databases, so here's an example of how we can prevent a low priority task (e.g. bulk deletion) from contending with customer traffic:
13
+
14
+ ```ruby
15
+ sensor = MySQLSensor.new # Use your imagination
16
+ controller = PIDController.new(setpoint: 60.0, kp: 5.0, ki: 1.0, kd: 0.1)
17
+
18
+ Event.where(account_id: account_id).in_batches do |relation|
19
+ relation.delete_all
20
+ backoff = controller << sensor.cpu_utilization
21
+ sleep backoff if backoff > 0
22
+ end
23
+ ```
24
+
25
+ ## Development
26
+
27
+ After checking out the repo, run `bin/setup` to install dependencies. Then, run `rake spec` to run the tests. You can also run `bin/console` for an interactive prompt that will allow you to experiment.
28
+
29
+ To install this gem onto your local machine, run `bundle exec rake install`. To release a new version, update the version number in `version.rb`, and then run `bundle exec rake release`, which will create a git tag for the version, push git commits and tags, and push the `.gem` file to [rubygems.org](https://rubygems.org).
30
+
31
+ ## Contributing
32
+
33
+ Bug reports and pull requests are welcome on GitHub at https://github.com/gabetax/pid_controller.
@@ -0,0 +1,8 @@
1
+ require 'bundler/gem_tasks'
2
+ require 'rspec/core/rake_task'
3
+ require 'rubocop/rake_task'
4
+
5
+ RSpec::Core::RakeTask.new(:spec)
6
+ RuboCop::RakeTask.new(:rubocop)
7
+
8
+ task default: :spec
@@ -0,0 +1,7 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'bundler/setup'
4
+ require 'pid_controller'
5
+
6
+ require 'pry'
7
+ Pry.start
@@ -0,0 +1,8 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+ IFS=$'\n\t'
4
+ set -vx
5
+
6
+ bundle install
7
+
8
+ # Do any other automated setup that you need to do here
@@ -0,0 +1,63 @@
1
+ require 'pid_controller/version'
2
+
3
+ # https://en.wikipedia.org/wiki/PID_controller
4
+ class PidController
5
+ attr_accessor :setpoint, :kp, :ki, :kd
6
+
7
+ def initialize(setpoint:, kp: 1.0, ki: 1.0, kd: 1.0)
8
+ @setpoint = setpoint
9
+ @kp = kp
10
+ @ki = ki
11
+ @kd = kd
12
+ @integral = 0.0
13
+ @derivative = 0.0
14
+ @last_error = nil
15
+ @last_update = nil
16
+ end
17
+
18
+ def update(measurement)
19
+ now = clock_time
20
+ dt = if @last_update
21
+ now - @last_update
22
+ else
23
+ 0.0
24
+ end
25
+ @last_update = now
26
+ update_with_duration(measurement, dt)
27
+ end
28
+
29
+ alias << update
30
+
31
+ def update_with_duration(measurement, dt)
32
+ error = setpoint - measurement.to_f
33
+
34
+ if dt > 0.0
35
+ @integral += error * dt
36
+ @derivative = (error - @last_error) / dt
37
+ end
38
+
39
+ @last_error = error
40
+
41
+ output
42
+ end
43
+
44
+ def output
45
+ p_term + i_term + d_term
46
+ end
47
+
48
+ def p_term
49
+ kp * @last_error
50
+ end
51
+
52
+ def i_term
53
+ ki * @integral
54
+ end
55
+
56
+ def d_term
57
+ kd * @derivative
58
+ end
59
+
60
+ def clock_time
61
+ Process.clock_gettime(Process::CLOCK_MONOTONIC)
62
+ end
63
+ end
@@ -0,0 +1,3 @@
1
+ class PidController
2
+ VERSION = '0.1.0'.freeze
3
+ end
@@ -0,0 +1,27 @@
1
+
2
+ lib = File.expand_path('../lib', __FILE__)
3
+ $LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
4
+ require 'pid_controller/version'
5
+
6
+ Gem::Specification.new do |spec|
7
+ spec.name = 'pid_controller'
8
+ spec.version = PidController::VERSION
9
+ spec.authors = ['Gabe Martin-Dempesy']
10
+ spec.email = ['gabetax@gmail.com']
11
+
12
+ spec.summary = 'A Ruby PID controller implementation'
13
+ spec.homepage = 'https://github.com/gabetax/pid_controller'
14
+
15
+ spec.files = `git ls-files -z`.split("\x0").reject do |f|
16
+ f.match(%r{^(test|spec|features)/})
17
+ end
18
+ spec.bindir = 'exe'
19
+ spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
20
+ spec.require_paths = ['lib']
21
+
22
+ spec.add_development_dependency 'bundler', '~> 1.16'
23
+ spec.add_development_dependency 'pry'
24
+ spec.add_development_dependency 'rake', '~> 10.0'
25
+ spec.add_development_dependency 'rspec', '~> 3.0'
26
+ spec.add_development_dependency 'rubocop', '~> 0.51'
27
+ end
metadata ADDED
@@ -0,0 +1,126 @@
1
+ --- !ruby/object:Gem::Specification
2
+ name: pid_controller
3
+ version: !ruby/object:Gem::Version
4
+ version: 0.1.0
5
+ platform: ruby
6
+ authors:
7
+ - Gabe Martin-Dempesy
8
+ autorequire:
9
+ bindir: exe
10
+ cert_chain: []
11
+ date: 2017-11-29 00:00:00.000000000 Z
12
+ dependencies:
13
+ - !ruby/object:Gem::Dependency
14
+ name: bundler
15
+ requirement: !ruby/object:Gem::Requirement
16
+ requirements:
17
+ - - "~>"
18
+ - !ruby/object:Gem::Version
19
+ version: '1.16'
20
+ type: :development
21
+ prerelease: false
22
+ version_requirements: !ruby/object:Gem::Requirement
23
+ requirements:
24
+ - - "~>"
25
+ - !ruby/object:Gem::Version
26
+ version: '1.16'
27
+ - !ruby/object:Gem::Dependency
28
+ name: pry
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - ">="
32
+ - !ruby/object:Gem::Version
33
+ version: '0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - ">="
39
+ - !ruby/object:Gem::Version
40
+ version: '0'
41
+ - !ruby/object:Gem::Dependency
42
+ name: rake
43
+ requirement: !ruby/object:Gem::Requirement
44
+ requirements:
45
+ - - "~>"
46
+ - !ruby/object:Gem::Version
47
+ version: '10.0'
48
+ type: :development
49
+ prerelease: false
50
+ version_requirements: !ruby/object:Gem::Requirement
51
+ requirements:
52
+ - - "~>"
53
+ - !ruby/object:Gem::Version
54
+ version: '10.0'
55
+ - !ruby/object:Gem::Dependency
56
+ name: rspec
57
+ requirement: !ruby/object:Gem::Requirement
58
+ requirements:
59
+ - - "~>"
60
+ - !ruby/object:Gem::Version
61
+ version: '3.0'
62
+ type: :development
63
+ prerelease: false
64
+ version_requirements: !ruby/object:Gem::Requirement
65
+ requirements:
66
+ - - "~>"
67
+ - !ruby/object:Gem::Version
68
+ version: '3.0'
69
+ - !ruby/object:Gem::Dependency
70
+ name: rubocop
71
+ requirement: !ruby/object:Gem::Requirement
72
+ requirements:
73
+ - - "~>"
74
+ - !ruby/object:Gem::Version
75
+ version: '0.51'
76
+ type: :development
77
+ prerelease: false
78
+ version_requirements: !ruby/object:Gem::Requirement
79
+ requirements:
80
+ - - "~>"
81
+ - !ruby/object:Gem::Version
82
+ version: '0.51'
83
+ description:
84
+ email:
85
+ - gabetax@gmail.com
86
+ executables: []
87
+ extensions: []
88
+ extra_rdoc_files: []
89
+ files:
90
+ - ".gitignore"
91
+ - ".rspec"
92
+ - ".rubocop.yml"
93
+ - ".travis.yml"
94
+ - Gemfile
95
+ - Gemfile.lock
96
+ - README.md
97
+ - Rakefile
98
+ - bin/console
99
+ - bin/setup
100
+ - lib/pid_controller.rb
101
+ - lib/pid_controller/version.rb
102
+ - pid_controller.gemspec
103
+ homepage: https://github.com/gabetax/pid_controller
104
+ licenses: []
105
+ metadata: {}
106
+ post_install_message:
107
+ rdoc_options: []
108
+ require_paths:
109
+ - lib
110
+ required_ruby_version: !ruby/object:Gem::Requirement
111
+ requirements:
112
+ - - ">="
113
+ - !ruby/object:Gem::Version
114
+ version: '0'
115
+ required_rubygems_version: !ruby/object:Gem::Requirement
116
+ requirements:
117
+ - - ">="
118
+ - !ruby/object:Gem::Version
119
+ version: '0'
120
+ requirements: []
121
+ rubyforge_project:
122
+ rubygems_version: 2.6.13
123
+ signing_key:
124
+ specification_version: 4
125
+ summary: A Ruby PID controller implementation
126
+ test_files: []