engine-tune 0.4.1
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.
- data/.document +5 -0
- data/.gitignore +21 -0
- data/LICENSE +20 -0
- data/README.rdoc +81 -0
- data/Rakefile +51 -0
- data/VERSION +1 -0
- data/engine-tune.gemspec +59 -0
- data/lib/engine-tune/calculations.rb +103 -0
- data/lib/engine-tune/calculator.rb +131 -0
- data/lib/engine-tune.rb +20 -0
- data/test/helper.rb +34 -0
- data/test/test_calculations.rb +42 -0
- data/test/test_calculator.rb +95 -0
- data/test/test_engine_tune.rb +9 -0
- data/test/test_suite.rb +5 -0
- metadata +86 -0
data/.document
ADDED
data/.gitignore
ADDED
data/LICENSE
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
Copyright (c) 2009 Guts & Bolts LLC
|
2
|
+
|
3
|
+
Permission is hereby granted, free of charge, to any person obtaining
|
4
|
+
a copy of this software and associated documentation files (the
|
5
|
+
"Software"), to deal in the Software without restriction, including
|
6
|
+
without limitation the rights to use, copy, modify, merge, publish,
|
7
|
+
distribute, sublicense, and/or sell copies of the Software, and to
|
8
|
+
permit persons to whom the Software is furnished to do so, subject to
|
9
|
+
the following conditions:
|
10
|
+
|
11
|
+
The above copyright notice and this permission notice shall be
|
12
|
+
included in all copies or substantial portions of the Software.
|
13
|
+
|
14
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
|
15
|
+
EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
|
16
|
+
MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
|
17
|
+
NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS BE
|
18
|
+
LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN ACTION
|
19
|
+
OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN CONNECTION
|
20
|
+
WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE SOFTWARE.
|
data/README.rdoc
ADDED
@@ -0,0 +1,81 @@
|
|
1
|
+
= EngineTune
|
2
|
+
|
3
|
+
Interested in determining how well your engine will run under certain meteorological and geological conditions?
|
4
|
+
|
5
|
+
This is the gem for you! (And I am sure there are a lot of you out there.)
|
6
|
+
|
7
|
+
EngineTune returns the following calculations when supplied with altitude, altimeter (barometric pressure), temperature and dew point:
|
8
|
+
|
9
|
+
* AE Relative Horsepower
|
10
|
+
* Dyno Correction Factor
|
11
|
+
* Air Density
|
12
|
+
* Density Altitude
|
13
|
+
* ICAO Relative Air Density
|
14
|
+
* Virtual Temperature
|
15
|
+
* Absolute Air Pressure
|
16
|
+
* Vapor Pressure
|
17
|
+
* Relative Humidity
|
18
|
+
|
19
|
+
The calculations in this gem are modeled after Richard Shelquist's Engine Tuner's Calculator, but have been re-factored to be more ruby-like. I urge you to read his technical articles on Density Altitude and Corrected Horsepower for detailed explanations of these concepts.
|
20
|
+
|
21
|
+
http://wahiduddin.net/calc/calc_hp_dp.htm
|
22
|
+
|
23
|
+
== Standard Usage
|
24
|
+
|
25
|
+
<i>Note that all observations must be supplied using the metric system of measurement.</i>
|
26
|
+
|
27
|
+
observations = Hash.new
|
28
|
+
observations[:temperature] = 32.0 # Celsius
|
29
|
+
observations[:dew_point] = 22.0 # Celsius
|
30
|
+
observations[:altitude] = 149.0 # Meters
|
31
|
+
observations[:altimeter] = 1013.4 # Millibars
|
32
|
+
|
33
|
+
calculations = EngineTune.calculate(observations)
|
34
|
+
|
35
|
+
calculations.relative_horsepower
|
36
|
+
#=> 96.2 (as percentage)
|
37
|
+
|
38
|
+
calculations.density_altitude
|
39
|
+
#=> 876 (as meters)
|
40
|
+
|
41
|
+
|
42
|
+
Calculations are returned in metric units, but if you prefer your calculations using the English system of measurement, do this:
|
43
|
+
|
44
|
+
calculations.metric = false
|
45
|
+
|
46
|
+
calculations.density_altitude
|
47
|
+
#=> 2874 (as feet)
|
48
|
+
|
49
|
+
And if you forget what system of measurement your calculations object is using, just ask it:
|
50
|
+
|
51
|
+
calculations.metric = false
|
52
|
+
|
53
|
+
calculations.metric?
|
54
|
+
#=> false
|
55
|
+
|
56
|
+
calculations.english?
|
57
|
+
#=> true
|
58
|
+
|
59
|
+
== The Calculator
|
60
|
+
|
61
|
+
You can also bypass the calculations object and directly use the calculator:
|
62
|
+
|
63
|
+
temperature = 32.0 # Celsius
|
64
|
+
dew_point = 22.0 # Celsius
|
65
|
+
altitude = 149.0 # Meters
|
66
|
+
altimeter = 1013.4 # Millibars
|
67
|
+
|
68
|
+
EngineTune::Calculator.relative_horsepower(altimeter, altitude, dew_point, temperature)
|
69
|
+
#=> 96.2 (as percentage)
|
70
|
+
|
71
|
+
Convenience methods to convert between metric and English units are provided as well:
|
72
|
+
|
73
|
+
EngineTune::Calculator.meters_to_feet 1054
|
74
|
+
#=> 3458.0052546
|
75
|
+
|
76
|
+
EngineTune::Calculator.inches_to_millibars 1223
|
77
|
+
#=> 41415.3694298
|
78
|
+
|
79
|
+
== Copyright
|
80
|
+
|
81
|
+
Copyright (c) 2010 Guts & Bolts LLC. See LICENSE for details.
|
data/Rakefile
ADDED
@@ -0,0 +1,51 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'rake'
|
3
|
+
|
4
|
+
begin
|
5
|
+
require 'jeweler'
|
6
|
+
Jeweler::Tasks.new do |gem|
|
7
|
+
gem.name = "engine-tune"
|
8
|
+
gem.summary = "Determine how well your engine will run under certain meteorological and geological conditions."
|
9
|
+
gem.description = "Determine how well your engine will run under certain meteorological and geological conditions."
|
10
|
+
gem.email = "theo@gutsbolts.com"
|
11
|
+
gem.homepage = "http://github.com/gutsbolts/engine-tune"
|
12
|
+
gem.authors = ["Theodore Mills"]
|
13
|
+
end
|
14
|
+
Jeweler::GemcutterTasks.new
|
15
|
+
rescue LoadError
|
16
|
+
puts "Jeweler (or a dependency) not available. Install it with: gem install jeweler"
|
17
|
+
end
|
18
|
+
|
19
|
+
require 'rake/testtask'
|
20
|
+
Rake::TestTask.new(:test) do |test|
|
21
|
+
test.libs << 'lib' << 'test'
|
22
|
+
test.pattern = 'test/**/test_*.rb'
|
23
|
+
test.verbose = true
|
24
|
+
end
|
25
|
+
|
26
|
+
begin
|
27
|
+
require 'rcov/rcovtask'
|
28
|
+
Rcov::RcovTask.new do |test|
|
29
|
+
test.libs << 'test'
|
30
|
+
test.pattern = 'test/**/test_*.rb'
|
31
|
+
test.verbose = true
|
32
|
+
end
|
33
|
+
rescue LoadError
|
34
|
+
task :rcov do
|
35
|
+
abort "RCov is not available. In order to run rcov, you must: sudo gem install spicycode-rcov"
|
36
|
+
end
|
37
|
+
end
|
38
|
+
|
39
|
+
task :test => :check_dependencies
|
40
|
+
|
41
|
+
task :default => :test
|
42
|
+
|
43
|
+
require 'rake/rdoctask'
|
44
|
+
Rake::RDocTask.new do |rdoc|
|
45
|
+
version = File.exist?('VERSION') ? File.read('VERSION') : ""
|
46
|
+
|
47
|
+
rdoc.rdoc_dir = 'rdoc'
|
48
|
+
rdoc.title = "engine-tune #{version}"
|
49
|
+
rdoc.rdoc_files.include('README*')
|
50
|
+
rdoc.rdoc_files.include('lib/**/*.rb')
|
51
|
+
end
|
data/VERSION
ADDED
@@ -0,0 +1 @@
|
|
1
|
+
0.4.1
|
data/engine-tune.gemspec
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
# Generated by jeweler
|
2
|
+
# DO NOT EDIT THIS FILE DIRECTLY
|
3
|
+
# Instead, edit Jeweler::Tasks in Rakefile, and run the gemspec command
|
4
|
+
# -*- encoding: utf-8 -*-
|
5
|
+
|
6
|
+
Gem::Specification.new do |s|
|
7
|
+
s.name = %q{engine-tune}
|
8
|
+
s.version = "0.4.1"
|
9
|
+
|
10
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
11
|
+
s.authors = ["Theodore Mills"]
|
12
|
+
s.date = %q{2010-07-07}
|
13
|
+
s.description = %q{Determine how well your engine will run under certain meteorological and geological conditions.}
|
14
|
+
s.email = %q{theo@gutsbolts.com}
|
15
|
+
s.extra_rdoc_files = [
|
16
|
+
"LICENSE",
|
17
|
+
"README.rdoc"
|
18
|
+
]
|
19
|
+
s.files = [
|
20
|
+
".document",
|
21
|
+
".gitignore",
|
22
|
+
"LICENSE",
|
23
|
+
"README.rdoc",
|
24
|
+
"Rakefile",
|
25
|
+
"VERSION",
|
26
|
+
"engine-tune.gemspec",
|
27
|
+
"lib/engine-tune.rb",
|
28
|
+
"lib/engine-tune/calculations.rb",
|
29
|
+
"lib/engine-tune/calculator.rb",
|
30
|
+
"test/helper.rb",
|
31
|
+
"test/test_calculations.rb",
|
32
|
+
"test/test_calculator.rb",
|
33
|
+
"test/test_engine_tune.rb",
|
34
|
+
"test/test_suite.rb"
|
35
|
+
]
|
36
|
+
s.homepage = %q{http://github.com/gutsbolts/engine-tune}
|
37
|
+
s.rdoc_options = ["--charset=UTF-8"]
|
38
|
+
s.require_paths = ["lib"]
|
39
|
+
s.rubygems_version = %q{1.3.7}
|
40
|
+
s.summary = %q{Determine how well your engine will run under certain meteorological and geological conditions.}
|
41
|
+
s.test_files = [
|
42
|
+
"test/helper.rb",
|
43
|
+
"test/test_calculations.rb",
|
44
|
+
"test/test_calculator.rb",
|
45
|
+
"test/test_engine_tune.rb",
|
46
|
+
"test/test_suite.rb"
|
47
|
+
]
|
48
|
+
|
49
|
+
if s.respond_to? :specification_version then
|
50
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
51
|
+
s.specification_version = 3
|
52
|
+
|
53
|
+
if Gem::Version.new(Gem::VERSION) >= Gem::Version.new('1.2.0') then
|
54
|
+
else
|
55
|
+
end
|
56
|
+
else
|
57
|
+
end
|
58
|
+
end
|
59
|
+
|
@@ -0,0 +1,103 @@
|
|
1
|
+
module EngineTune
|
2
|
+
|
3
|
+
#
|
4
|
+
# After getting instantiated with a set of meterological and geological observations,
|
5
|
+
# a Calculations object can determine a number of calculations related to engine
|
6
|
+
# efficiency.
|
7
|
+
#
|
8
|
+
class Calculations
|
9
|
+
|
10
|
+
# Names of observations required for calculations to compute
|
11
|
+
OBSERVATION_ATTRS = [:temperature, :dew_point, :altitude, :altimeter]
|
12
|
+
OBSERVATION_ATTRS.each { |a| attr_accessor a }
|
13
|
+
|
14
|
+
attr_writer :metric
|
15
|
+
|
16
|
+
#
|
17
|
+
# Instantiates a new instance with a hash of observations including temperature,
|
18
|
+
# dew_point, altimeter and altitude. These observations are the only required data
|
19
|
+
# to calculate all the engine tuning metrics exposed in this object.
|
20
|
+
#
|
21
|
+
def initialize(observations)
|
22
|
+
observations.each { |method, value| send("#{method}=", value) }
|
23
|
+
@metric = true
|
24
|
+
end
|
25
|
+
|
26
|
+
#
|
27
|
+
# Objects are equal if their observations are identical
|
28
|
+
#
|
29
|
+
def ==(object)
|
30
|
+
self.observations == object.observations
|
31
|
+
end
|
32
|
+
|
33
|
+
#
|
34
|
+
# Returns a hash of observations for this set of calculations
|
35
|
+
#
|
36
|
+
def observations
|
37
|
+
OBSERVATION_ATTRS.inject({}) do |result, o|
|
38
|
+
result[o] = send(o)
|
39
|
+
result
|
40
|
+
end
|
41
|
+
end
|
42
|
+
|
43
|
+
#
|
44
|
+
# Returns true if calculations should be returned using the metric system
|
45
|
+
#
|
46
|
+
def metric?
|
47
|
+
@metric
|
48
|
+
end
|
49
|
+
|
50
|
+
#
|
51
|
+
# Returns true if calculations should be returned using the English system
|
52
|
+
#
|
53
|
+
def english?
|
54
|
+
!@metric
|
55
|
+
end
|
56
|
+
|
57
|
+
def vapor_pressure
|
58
|
+
@vapor_pressure ||= EngineTune::Calculator.vapor_pressure(dew_point)
|
59
|
+
@vapor_pressure_inches ||= EngineTune::Calculator.millibars_to_inches(@vapor_pressure)
|
60
|
+
metric? ? @vapor_pressure : @vapor_pressure_inches
|
61
|
+
end
|
62
|
+
|
63
|
+
def relative_humidity
|
64
|
+
@relative_humidity ||= EngineTune::Calculator.relative_humidity(temperature, dew_point)
|
65
|
+
end
|
66
|
+
|
67
|
+
def absolute_pressure
|
68
|
+
@absolute_air_pressure ||= EngineTune::Calculator.absolute_pressure(altimeter, altitude)
|
69
|
+
@absolute_air_pressure_inches ||= EngineTune::Calculator.millibars_to_inches(@absolute_air_pressure)
|
70
|
+
metric? ? @absolute_air_pressure : @absolute_air_pressure_inches
|
71
|
+
end
|
72
|
+
|
73
|
+
def density
|
74
|
+
@density ||= EngineTune::Calculator.density(altimeter, altitude, dew_point, temperature)
|
75
|
+
end
|
76
|
+
|
77
|
+
def relative_density
|
78
|
+
@relative_density ||= EngineTune::Calculator.relative_density(altimeter, altitude, dew_point, temperature)
|
79
|
+
end
|
80
|
+
|
81
|
+
def dyno_correction_factor
|
82
|
+
@dyno_correction_factor ||= EngineTune::Calculator.dyno_correction_factor(altimeter, altitude, dew_point, temperature)
|
83
|
+
end
|
84
|
+
|
85
|
+
def virtual_temperature
|
86
|
+
@virtual_temperature ||= EngineTune::Calculator.virtual_temperature(altimeter, altitude, dew_point, temperature)
|
87
|
+
@virtual_temperature_f ||= EngineTune::Calculator.celsius_to_fahrenheit(@virtual_temperature)
|
88
|
+
metric? ? @virtual_temperature : @virtual_temperature_f
|
89
|
+
end
|
90
|
+
|
91
|
+
def density_altitude
|
92
|
+
@density_altitude ||= EngineTune::Calculator.density_altitude(altimeter, altitude, dew_point, temperature)
|
93
|
+
@density_altitude_feet ||= EngineTune::Calculator.meters_to_feet(@density_altitude)
|
94
|
+
metric? ? @density_altitude : @density_altitude_feet
|
95
|
+
end
|
96
|
+
|
97
|
+
def relative_horsepower
|
98
|
+
@relative_horsepower ||= EngineTune::Calculator.relative_horsepower(altimeter, altitude, dew_point, temperature)
|
99
|
+
end
|
100
|
+
|
101
|
+
end
|
102
|
+
|
103
|
+
end
|
@@ -0,0 +1,131 @@
|
|
1
|
+
module EngineTune
|
2
|
+
|
3
|
+
#
|
4
|
+
# A collection of formulas and calculations used to determine, among other things,
|
5
|
+
# the relative horsepower of an engine given different environmental conditions.
|
6
|
+
#
|
7
|
+
# These calculations are modeled after Richard Shelquist's Engine Tuner's Calculator,
|
8
|
+
# but have been re-factored to be more ruby-like. I urge you to read his technical
|
9
|
+
# articles on Density Altitude and Corrected Horsepower for detailed explanations of
|
10
|
+
# these concepts.
|
11
|
+
#
|
12
|
+
# In some cases I took a guess at what a method should be named based on the calculation
|
13
|
+
# it is returning, so any better suggestions are welcomed.
|
14
|
+
#
|
15
|
+
module Calculator
|
16
|
+
class << self
|
17
|
+
|
18
|
+
def density_altitude(altimeter, altitude, dew_point, temperature)
|
19
|
+
# Calculate geometric altitude Z (m) from geopotential altitude (m) H
|
20
|
+
densaltzm = self.altitude_z(altimeter, altitude, dew_point, temperature)
|
21
|
+
unless (-5000..11000).include?(densaltzm)
|
22
|
+
raise "Out of range for Troposhere Algorithm: Altitude =" + densaltzm.round + " meters"
|
23
|
+
end
|
24
|
+
densaltzm.round
|
25
|
+
end
|
26
|
+
|
27
|
+
def dyno_correction_factor(altimeter, altitude, dew_point, temperature)
|
28
|
+
vapor_pressure_mb = self.vapor_pressure(dew_point)
|
29
|
+
absolute_pressure_mb = self.absolute_pressure(altimeter, altitude)
|
30
|
+
absolute_pressure_in = millibars_to_inches(absolute_pressure_mb)
|
31
|
+
vapor_pressure_in = millibars_to_inches(vapor_pressure_mb)
|
32
|
+
p1 = 29.235 / (absolute_pressure_in - vapor_pressure_in)
|
33
|
+
p2 = ((temperature + 273) / 298)**0.5
|
34
|
+
(1.18 * (p1 * p2) - 0.18)
|
35
|
+
end
|
36
|
+
|
37
|
+
|
38
|
+
def virtual_temperature(altimeter, altitude, dew_point, temperature)
|
39
|
+
absolute_pressure = self.absolute_pressure(altimeter, altitude)
|
40
|
+
vapor_pressure = self.vapor_pressure(dew_point)
|
41
|
+
((temperature + 273.15) / (1- (0.377995 * vapor_pressure / absolute_pressure)))-273.15
|
42
|
+
end
|
43
|
+
|
44
|
+
#
|
45
|
+
# Polynomial from Herman Wobus
|
46
|
+
#
|
47
|
+
def vapor_pressure(temperature_c)
|
48
|
+
values = [ 1.1112018e-17, -1.7892321e-15, 2.1874425e-13, -2.9883885e-11, 4.3884187e-09, -6.1117958e-07, 7.8736169e-05, -0.0090826951, 0.99999683 ]
|
49
|
+
pol = values.inject(-0.30994571E-19) { |result, v| result = v + temperature_c * result }
|
50
|
+
6.1078 / (pol**8)
|
51
|
+
end
|
52
|
+
|
53
|
+
def geopotential_altitude(elevation_in_meters)
|
54
|
+
r = 6369E3;
|
55
|
+
((r * elevation_in_meters) / (r + elevation_in_meters))
|
56
|
+
end
|
57
|
+
|
58
|
+
def density(altimeter, altitude, dew_point, temperature)
|
59
|
+
vapor_pressure = self.vapor_pressure(dew_point)
|
60
|
+
absolute_pressure = self.absolute_pressure(altimeter, altitude)
|
61
|
+
|
62
|
+
rv, rd = 461.4964, 287.0531
|
63
|
+
temperature_k = temperature + 273.15
|
64
|
+
pv = vapor_pressure * 100
|
65
|
+
pd = (absolute_pressure - vapor_pressure) * 100
|
66
|
+
(pv / (rv * temperature_k)) + (pd / (rd * temperature_k))
|
67
|
+
end
|
68
|
+
|
69
|
+
def altitude(altimeter, elevation, dew_point, temperature)
|
70
|
+
density = self.density(altimeter, elevation, dew_point, temperature)
|
71
|
+
g, po, to, l, r, m = 9.80665, 101325, 288.15, 6.5, 8.314320, 28.9644
|
72
|
+
density = density * 1000
|
73
|
+
p2 = ( (l * r)/(g* m - l * r) ) * Math.log( (r * to * density) / (m * po) )
|
74
|
+
h = -(to / l)*( Math.exp(p2) -1 )
|
75
|
+
h * 1000
|
76
|
+
end
|
77
|
+
|
78
|
+
def altitude_z(altimeter, elevation, dew_point, temperature)
|
79
|
+
altitude = self.altitude(altimeter, elevation, dew_point, temperature)
|
80
|
+
r = 6369E3
|
81
|
+
((r * altitude) / (r - altitude))
|
82
|
+
end
|
83
|
+
|
84
|
+
|
85
|
+
def absolute_pressure(altimeter, altitude)
|
86
|
+
k1, k2 = 0.190263, 8.417286E-5
|
87
|
+
((altimeter**k1)-(k2 * self.geopotential_altitude(altitude)))**(1/k1)
|
88
|
+
end
|
89
|
+
|
90
|
+
def relative_density(altimeter, altitude, dew_point, temperature)
|
91
|
+
density = self.density(altimeter, altitude, dew_point, temperature)
|
92
|
+
100 * (density / 1.225)
|
93
|
+
end
|
94
|
+
|
95
|
+
def relative_humidity(temperature, dew_point)
|
96
|
+
(vapor_pressure(dew_point) / vapor_pressure(temperature)) * 100
|
97
|
+
end
|
98
|
+
|
99
|
+
def relative_horsepower(altimeter, altitude, dew_point, temperature)
|
100
|
+
dyno_correction_factor = self.dyno_correction_factor(altimeter, altitude, dew_point, temperature)
|
101
|
+
round((100 / dyno_correction_factor), 1)
|
102
|
+
end
|
103
|
+
|
104
|
+
#
|
105
|
+
# Systems of measurement conversion methods
|
106
|
+
#
|
107
|
+
|
108
|
+
def millibars_to_inches(mb)
|
109
|
+
mb * (1/33.86389)
|
110
|
+
end
|
111
|
+
|
112
|
+
def inches_to_millibars(inches)
|
113
|
+
inches * 33.8637526
|
114
|
+
end
|
115
|
+
|
116
|
+
def meters_to_feet(meters)
|
117
|
+
meters * 3.2808399
|
118
|
+
end
|
119
|
+
|
120
|
+
def round(f, d)
|
121
|
+
(f * 10**d).round.to_f / 10**d
|
122
|
+
end
|
123
|
+
|
124
|
+
def celsius_to_fahrenheit(temp)
|
125
|
+
((temp * 9.0) / 5.0) + 32.0
|
126
|
+
end
|
127
|
+
|
128
|
+
end
|
129
|
+
|
130
|
+
end
|
131
|
+
end
|
data/lib/engine-tune.rb
ADDED
@@ -0,0 +1,20 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
|
3
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
4
|
+
|
5
|
+
require "engine-tune/calculations"
|
6
|
+
require "engine-tune/calculator"
|
7
|
+
|
8
|
+
#
|
9
|
+
# An engine's efficiency can be impacted by environmental factors such as
|
10
|
+
# altitude and temperature. EngineForecast first collects environmental data
|
11
|
+
# based on the supplied latitude and longitude and then returns a set of calculations
|
12
|
+
# to determine how great that impact is.
|
13
|
+
#
|
14
|
+
module EngineTune
|
15
|
+
|
16
|
+
def self.calculate(observations)
|
17
|
+
EngineTune::Calculations.new(observations)
|
18
|
+
end
|
19
|
+
|
20
|
+
end
|
data/test/helper.rb
ADDED
@@ -0,0 +1,34 @@
|
|
1
|
+
require 'rubygems'
|
2
|
+
require 'test/unit'
|
3
|
+
require 'shoulda'
|
4
|
+
|
5
|
+
$LOAD_PATH.unshift(File.join(File.dirname(__FILE__), '..', 'lib'))
|
6
|
+
$LOAD_PATH.unshift(File.dirname(__FILE__))
|
7
|
+
require 'engine-tune'
|
8
|
+
|
9
|
+
class Test::Unit::TestCase
|
10
|
+
def observations
|
11
|
+
{ :altitude => 149.0, :temperature => 32.0, :dew_point=>22.0, :altimeter=>1013.4 }
|
12
|
+
end
|
13
|
+
|
14
|
+
def round(f, d)
|
15
|
+
(f * 10**d).round.to_f / 10**d
|
16
|
+
end
|
17
|
+
|
18
|
+
def self.correct_answers
|
19
|
+
{
|
20
|
+
:vapor_pressure => 26.4295210976309,
|
21
|
+
:density_altitude => 876,
|
22
|
+
:dyno_correction_factor => 1.0394157966139073,
|
23
|
+
:relative_horsepower => 96.2,
|
24
|
+
:virtual_temperature => 35.09294483203081,
|
25
|
+
:geopotential_altitude => 148.99651429099868,
|
26
|
+
:density => 1.1252290472090851,
|
27
|
+
:relative_density => 91.85543242523143,
|
28
|
+
:altitude => 876.1337602041878,
|
29
|
+
:altitude_z => 876.2542996883268,
|
30
|
+
:absolute_pressure => 995.6262086849655,
|
31
|
+
:relative_humidity => 55.58171762613951
|
32
|
+
}
|
33
|
+
end
|
34
|
+
end
|
@@ -0,0 +1,42 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class EngineTune::TestCalculations < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
@calculations = EngineTune::Calculations.new(observations)
|
7
|
+
end
|
8
|
+
|
9
|
+
self.correct_answers.each do |method, answer|
|
10
|
+
|
11
|
+
# List of methods inside correct answers hash that are not exposed
|
12
|
+
# on the Calculations object so don't create a test for them
|
13
|
+
exceptions = [:geopotential_altitude, :altitude, :altitude_z]
|
14
|
+
|
15
|
+
unless exceptions.include?(method)
|
16
|
+
define_method "test_calculations_#{method}" do
|
17
|
+
assert_equal round(answer, 13), round(@calculations.send(method), 13)
|
18
|
+
end
|
19
|
+
end
|
20
|
+
end
|
21
|
+
|
22
|
+
def test_vapor_pressure_inches
|
23
|
+
@calculations.metric = false
|
24
|
+
assert_equal 0.780463233775887, round(@calculations.vapor_pressure, 15)
|
25
|
+
end
|
26
|
+
|
27
|
+
def test_absolute_pressure_inches
|
28
|
+
@calculations.metric = false
|
29
|
+
assert_equal 29.4008221939348, round(@calculations.absolute_pressure, 13)
|
30
|
+
end
|
31
|
+
|
32
|
+
def test_virtual_temperature_fahrenheit
|
33
|
+
@calculations.metric = false
|
34
|
+
assert_equal 95.1673006976555, round(@calculations.virtual_temperature, 13)
|
35
|
+
end
|
36
|
+
|
37
|
+
def test_density_altitude_feet
|
38
|
+
@calculations.metric = false
|
39
|
+
assert_equal 2874.0157524, round(@calculations.density_altitude, 7)
|
40
|
+
end
|
41
|
+
|
42
|
+
end
|
@@ -0,0 +1,95 @@
|
|
1
|
+
require 'helper'
|
2
|
+
|
3
|
+
class EngineTune::TestCalculator < Test::Unit::TestCase
|
4
|
+
|
5
|
+
def setup
|
6
|
+
observations.each { |k, v| instance_variable_set("@#{k}", v)}
|
7
|
+
end
|
8
|
+
|
9
|
+
def correct_answers
|
10
|
+
Test::Unit::TestCase.correct_answers
|
11
|
+
end
|
12
|
+
|
13
|
+
def test_vapor_pressure
|
14
|
+
value = EngineTune::Calculator.vapor_pressure(@dew_point)
|
15
|
+
assert_equal correct_answers[:vapor_pressure] , round(value, 13)
|
16
|
+
end
|
17
|
+
|
18
|
+
def test_density_altitude
|
19
|
+
value = EngineTune::Calculator.density_altitude(@altimeter, @altitude, @dew_point, @temperature)
|
20
|
+
assert_equal correct_answers[:density_altitude], value
|
21
|
+
end
|
22
|
+
|
23
|
+
def test_dyno_correction_factor
|
24
|
+
value = EngineTune::Calculator.dyno_correction_factor(@altimeter, @altitude, @dew_point, @temperature)
|
25
|
+
assert_equal correct_answers[:dyno_correction_factor], value
|
26
|
+
end
|
27
|
+
|
28
|
+
def test_relative_horsepower
|
29
|
+
value = EngineTune::Calculator.relative_horsepower(@altimeter, @altitude, @dew_point, @temperature)
|
30
|
+
assert_equal correct_answers[:relative_horsepower], value
|
31
|
+
end
|
32
|
+
|
33
|
+
def test_virtual_temperature
|
34
|
+
value = EngineTune::Calculator.virtual_temperature(@altimeter, @altitude, @dew_point, @temperature)
|
35
|
+
assert_equal correct_answers[:virtual_temperature], value
|
36
|
+
end
|
37
|
+
|
38
|
+
def test_geopotential_altitude
|
39
|
+
assert_equal correct_answers[:geopotential_altitude], EngineTune::Calculator.geopotential_altitude(@altitude)
|
40
|
+
end
|
41
|
+
|
42
|
+
def test_density
|
43
|
+
value = EngineTune::Calculator.density(@altimeter, @altitude, @dew_point, @temperature)
|
44
|
+
assert_equal correct_answers[:density], value
|
45
|
+
end
|
46
|
+
|
47
|
+
def relative_density
|
48
|
+
value = EngineTune::Calculator.relative_density(@altimeter, @altitude, @dew_point, @temperature)
|
49
|
+
assert_equal correct_answers[:relative_density], value
|
50
|
+
end
|
51
|
+
|
52
|
+
def test_altitude
|
53
|
+
value = EngineTune::Calculator.altitude(@altimeter, @altitude, @dew_point, @temperature)
|
54
|
+
assert_equal correct_answers[:altitude], value
|
55
|
+
end
|
56
|
+
|
57
|
+
def test_altitude_z
|
58
|
+
value = EngineTune::Calculator.altitude_z(@altimeter, @altitude, @dew_point, @temperature)
|
59
|
+
assert_equal correct_answers[:altitude_z], value
|
60
|
+
end
|
61
|
+
|
62
|
+
def test_absolute_pressure
|
63
|
+
value = EngineTune::Calculator.absolute_pressure(@altimeter, @altitude)
|
64
|
+
assert_equal correct_answers[:absolute_pressure], value
|
65
|
+
end
|
66
|
+
|
67
|
+
def test_relative_humidity
|
68
|
+
z = EngineTune::Calculator.relative_humidity(@temperature, @dew_point)
|
69
|
+
assert_equal round(correct_answers[:relative_humidity], 13), round(z, 13)
|
70
|
+
end
|
71
|
+
|
72
|
+
# Measurement conversion tests
|
73
|
+
|
74
|
+
def test_inches_to_millibars
|
75
|
+
assert_equal 997.96, round(EngineTune::Calculator.inches_to_millibars(29.47), 2)
|
76
|
+
end
|
77
|
+
|
78
|
+
def test_millibars_to_inches
|
79
|
+
assert_equal 29.47, round(EngineTune::Calculator.millibars_to_inches(998), 2)
|
80
|
+
end
|
81
|
+
|
82
|
+
def test_meters_to_feet
|
83
|
+
assert_equal 3458.0052546, EngineTune::Calculator.meters_to_feet(1054)
|
84
|
+
end
|
85
|
+
|
86
|
+
def test_round
|
87
|
+
number = 21345.56789999
|
88
|
+
assert_equal 21345.57, EngineTune::Calculator.round(number, 2)
|
89
|
+
end
|
90
|
+
|
91
|
+
def test_celsius_to_fahrenheit
|
92
|
+
assert_equal 80.6, EngineTune::Calculator.celsius_to_fahrenheit(27)
|
93
|
+
end
|
94
|
+
|
95
|
+
end
|
data/test/test_suite.rb
ADDED
metadata
ADDED
@@ -0,0 +1,86 @@
|
|
1
|
+
--- !ruby/object:Gem::Specification
|
2
|
+
name: engine-tune
|
3
|
+
version: !ruby/object:Gem::Version
|
4
|
+
hash: 13
|
5
|
+
prerelease: false
|
6
|
+
segments:
|
7
|
+
- 0
|
8
|
+
- 4
|
9
|
+
- 1
|
10
|
+
version: 0.4.1
|
11
|
+
platform: ruby
|
12
|
+
authors:
|
13
|
+
- Theodore Mills
|
14
|
+
autorequire:
|
15
|
+
bindir: bin
|
16
|
+
cert_chain: []
|
17
|
+
|
18
|
+
date: 2010-07-07 00:00:00 -05:00
|
19
|
+
default_executable:
|
20
|
+
dependencies: []
|
21
|
+
|
22
|
+
description: Determine how well your engine will run under certain meteorological and geological conditions.
|
23
|
+
email: theo@gutsbolts.com
|
24
|
+
executables: []
|
25
|
+
|
26
|
+
extensions: []
|
27
|
+
|
28
|
+
extra_rdoc_files:
|
29
|
+
- LICENSE
|
30
|
+
- README.rdoc
|
31
|
+
files:
|
32
|
+
- .document
|
33
|
+
- .gitignore
|
34
|
+
- LICENSE
|
35
|
+
- README.rdoc
|
36
|
+
- Rakefile
|
37
|
+
- VERSION
|
38
|
+
- engine-tune.gemspec
|
39
|
+
- lib/engine-tune.rb
|
40
|
+
- lib/engine-tune/calculations.rb
|
41
|
+
- lib/engine-tune/calculator.rb
|
42
|
+
- test/helper.rb
|
43
|
+
- test/test_calculations.rb
|
44
|
+
- test/test_calculator.rb
|
45
|
+
- test/test_engine_tune.rb
|
46
|
+
- test/test_suite.rb
|
47
|
+
has_rdoc: true
|
48
|
+
homepage: http://github.com/gutsbolts/engine-tune
|
49
|
+
licenses: []
|
50
|
+
|
51
|
+
post_install_message:
|
52
|
+
rdoc_options:
|
53
|
+
- --charset=UTF-8
|
54
|
+
require_paths:
|
55
|
+
- lib
|
56
|
+
required_ruby_version: !ruby/object:Gem::Requirement
|
57
|
+
none: false
|
58
|
+
requirements:
|
59
|
+
- - ">="
|
60
|
+
- !ruby/object:Gem::Version
|
61
|
+
hash: 3
|
62
|
+
segments:
|
63
|
+
- 0
|
64
|
+
version: "0"
|
65
|
+
required_rubygems_version: !ruby/object:Gem::Requirement
|
66
|
+
none: false
|
67
|
+
requirements:
|
68
|
+
- - ">="
|
69
|
+
- !ruby/object:Gem::Version
|
70
|
+
hash: 3
|
71
|
+
segments:
|
72
|
+
- 0
|
73
|
+
version: "0"
|
74
|
+
requirements: []
|
75
|
+
|
76
|
+
rubyforge_project:
|
77
|
+
rubygems_version: 1.3.7
|
78
|
+
signing_key:
|
79
|
+
specification_version: 3
|
80
|
+
summary: Determine how well your engine will run under certain meteorological and geological conditions.
|
81
|
+
test_files:
|
82
|
+
- test/helper.rb
|
83
|
+
- test/test_calculations.rb
|
84
|
+
- test/test_calculator.rb
|
85
|
+
- test/test_engine_tune.rb
|
86
|
+
- test/test_suite.rb
|