driving_physics 0.0.1.2 → 0.0.3.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.
@@ -0,0 +1,34 @@
1
+ module DrivingPhysics
2
+ module Timer
3
+ # don't use `defined?` with mruby
4
+ if (Process::CLOCK_MONOTONIC rescue false)
5
+ def self.now
6
+ Process.clock_gettime Process::CLOCK_MONOTONIC
7
+ end
8
+ else
9
+ def self.now
10
+ Time.now
11
+ end
12
+ end
13
+
14
+ def self.since(t)
15
+ self.now - t
16
+ end
17
+
18
+ def self.elapsed(&work)
19
+ t = self.now
20
+ return yield, self.since(t)
21
+ end
22
+
23
+ # HH:MM:SS.mmm
24
+ def self.display(seconds: 0, ms: 0)
25
+ ms += (seconds * 1000).round if seconds > 0
26
+ DrivingPhysics.elapsed_display(ms)
27
+ end
28
+
29
+ def self.summary(start, num_ticks, paused = 0)
30
+ elapsed = self.since(start) - paused
31
+ format("%.3f s (%d ticks/s)", elapsed, num_ticks.to_f / elapsed)
32
+ end
33
+ end
34
+ end
@@ -26,14 +26,14 @@ module DrivingPhysics
26
26
 
27
27
  def initialize(env)
28
28
  @env = env
29
- @radius = 350/1000r # m
30
- @width = 200/1000r # m
29
+ @radius = 0.35
30
+ @width = 0.2
31
31
  @density = DENSITY
32
32
  @temp = @env.air_temp
33
- @mu_s = 11/10r # static friction
34
- @mu_k = 7/10r # kinetic friction
35
- @base_friction = 5/10_000r
36
- @omega_friction = 5/100_000r # scales with speed
33
+ @mu_s = 1.1 # static friction
34
+ @mu_k = 0.7 # kinetic friction
35
+ @base_friction = 5.0/10_000
36
+ @omega_friction = 5.0/100_000
37
37
  @roll_cof = DrivingPhysics::ROLL_COF
38
38
 
39
39
  yield self if block_given?
@@ -64,6 +64,29 @@ module DrivingPhysics
64
64
  dir
65
65
  end
66
66
 
67
+ def self.torque_vector(force, radius)
68
+ if !force.is_a?(Vector) or force.size != 2
69
+ raise(ArgumentError, "force must be a 2D vector")
70
+ end
71
+ if !radius.is_a?(Vector) or radius.size != 2
72
+ raise(ArgumentError, "radius must be a 2D vector")
73
+ end
74
+ force = Vector[force[0], force[1], 0]
75
+ radius = Vector[radius[0], radius[1], 0]
76
+ force.cross(radius)
77
+ end
78
+
79
+ def self.force_vector(torque, radius)
80
+ if !torque.is_a?(Vector) or torque.size != 3
81
+ raise(ArgumentError, "torque must be a 3D vector")
82
+ end
83
+ if !radius.is_a?(Vector) or radius.size != 2
84
+ raise(ArgumentError, "radius must be a 2D vector")
85
+ end
86
+ radius = Vector[radius[0], radius[1], 0]
87
+ radius.cross(torque) / radius.dot(radius)
88
+ end
89
+
67
90
  module VectorForce
68
91
  #
69
92
  # Resistance Forces
@@ -1,37 +1,36 @@
1
+ #
2
+ # Units: metric
3
+ #
4
+ # distance: meter
5
+ # velocity: meter / sec
6
+ # acceleration: meter / sec^2
7
+ # volume: Liter
8
+ # temperature: Celsius
9
+ #
1
10
  module DrivingPhysics
2
- #
3
- # Units: metric
4
- #
5
- # distance: meter
6
- # velocity: meter / sec
7
- # acceleration: meter / sec^2
8
- # volume: Liter
9
- # temperature: Celsius
10
- #
11
+ # runtime check; this returns false by default
12
+ # Vector is not currently/easily available in mruby
13
+ def self.has_vector?
14
+ Vector rescue false
15
+ end
11
16
 
12
- #
13
17
  # environmental defaults
14
- #
15
18
  HZ = 1000
16
19
  TICK = Rational(1) / HZ
17
20
  G = 9.8 # m/s^2
18
21
  AIR_TEMP = 25 # deg c
19
22
  AIR_DENSITY = 1.29 # kg / m^3
20
- PETROL_DENSITY = 0.71 # kg / L TODO: move to car.rb
23
+ PETROL_DENSITY = 0.71 # kg / L
21
24
 
22
- #
23
25
  # defaults for resistance forces
24
- #
25
- FRONTAL_AREA = 2.2 # m^2, based roughly on 2000s-era Chevrolet Corvette
26
- DRAG_COF = 0.3 # based roughly on 2000s-era Chevrolet Corvette
27
- DRAG = 0.4257 # air_resistance at 1 m/s given above numbers
28
- ROT_COF = 12.771 # if rotating resistance matches air resistance at 30 m/s
29
- ROT_CONST = 0.05 # N opposing drive force / torque
30
- ROLL_COF = 0.01 # roughly: street tires on concrete
26
+ FRONTAL_AREA = 2.2 # m^2, based roughly on 2000s-era Chevrolet Corvette
27
+ DRAG_COF = 0.3 # based roughly on 2000s-era Chevrolet Corvette
28
+ DRAG = 0.4257 # air_resistance at 1 m/s given above numbers
29
+ ROT_COF = 12.771 # if rot matches air at 30 m/s
30
+ ROT_CONST = 0.05 # N opposing drive force / torque
31
+ ROLL_COF = 0.01 # roughly: street tires on concrete
31
32
 
32
- #
33
33
  # constants
34
- #
35
34
  SECS_PER_MIN = 60
36
35
  MINS_PER_HOUR = 60
37
36
  SECS_PER_HOUR = SECS_PER_MIN * MINS_PER_HOUR
@@ -70,4 +69,11 @@ module DrivingPhysics
70
69
  alias_method(:omega, :accum)
71
70
  alias_method(:theta, :accum)
72
71
  end
72
+
73
+ def self.unit_interval!(val)
74
+ if val < 0.0 or val > 1.0
75
+ raise(ArgumentError, "val #{val.inspect} should be between 0 and 1")
76
+ end
77
+ val
78
+ end
73
79
  end
data/test/disk.rb CHANGED
@@ -1,113 +1,78 @@
1
1
  require 'minitest/autorun'
2
2
  require 'driving_physics/disk'
3
+ require 'matrix'
3
4
 
4
- D = DrivingPhysics::Disk
5
+ include DrivingPhysics
5
6
 
6
- describe D do
7
+ describe Disk do
7
8
  describe "Disk.volume" do
8
9
  it "calculates the volume (m^3) of disk given radius and width" do
9
- cubic_m = D.volume(1.0, 1.0)
10
+ cubic_m = Disk.volume(1.0, 1.0)
10
11
  expect(cubic_m).must_equal Math::PI
11
12
 
12
- cubic_m = D.volume(0.35, 0.2)
13
+ cubic_m = Disk.volume(0.35, 0.2)
13
14
  expect(cubic_m).must_be_within_epsilon 0.076969
14
15
  end
15
16
  end
16
17
 
17
18
  describe "Disk.volume_l" do
18
19
  it "calculates the volume (L) of a disk given radius and width" do
19
- liters = D.volume_l(1.0, 1.0)
20
+ liters = Disk.volume_l(1.0, 1.0)
20
21
  expect(liters).must_equal Math::PI * 1000
21
22
 
22
- liters = D.volume_l(0.35, 0.2)
23
+ liters = Disk.volume_l(0.35, 0.2)
23
24
  expect(liters).must_be_within_epsilon 76.96902
24
25
  end
25
26
  end
26
27
 
27
28
  describe "Disk.density" do
28
29
  it "calculates the density (kg/L) given mass and volume" do
29
- expect(D.density(25.0, 25.0)).must_equal 1.0
30
- expect(D.density(50.0, 25.0)).must_equal 2.0
30
+ expect(Disk.density(25.0, 25.0)).must_equal 1.0
31
+ expect(Disk.density(50.0, 25.0)).must_equal 2.0
31
32
  end
32
33
  end
33
34
 
34
35
  describe "Disk.mass" do
35
36
  it "calculates the mass (kg) of a disk given radius, width, and density" do
36
- skip
37
- expect(D.mass(0.35, 0.2, D::DENSITY)).must_be_within_epsilon 25.015
37
+ expect(Disk.mass(0.35, 0.2, Disk::DENSITY)).must_be_within_epsilon 76.969
38
38
  end
39
39
  end
40
40
 
41
41
  describe "Disk.rotational_inertia" do
42
42
  it "calculates rotational inertia for a disk given radius and mass" do
43
- expect(D.rotational_inertia(0.35, 25.0)).must_be_within_epsilon 1.53125
43
+ expect(Disk.rotational_inertia(0.35, 25.0)).must_be_within_epsilon 1.53125
44
44
  end
45
45
  end
46
46
 
47
47
  describe "Disk.alpha" do
48
48
  it "calculates angular acceleration from torque and inertia" do
49
49
  scalar_torque = 1000
50
- inertia = D.rotational_inertia(0.35, 25.0)
51
- expect(D.alpha scalar_torque, inertia).must_be_within_epsilon 653.061
50
+ inertia = Disk.rotational_inertia(0.35, 25.0)
51
+ expect(Disk.alpha scalar_torque, inertia).must_be_within_epsilon 653.061
52
52
 
53
+ skip unless DrivingPhysics.has_vector?
53
54
  vector_torque = Vector[0, 0, 1000]
54
- vector_alpha = D.alpha vector_torque, inertia
55
+ vector_alpha = Disk.alpha vector_torque, inertia
55
56
  expect(vector_alpha).must_be_instance_of Vector
56
57
  expect(vector_alpha.size).must_equal 3
57
58
  expect(vector_alpha[2]).must_be_within_epsilon 653.06
58
59
  end
59
60
  end
60
61
 
61
- describe "Disk.torque_vector" do
62
- it "calculates a torque in the 3rd dimension given 2D force and radius" do
63
- force = Vector[1000, 0]
64
- radius = Vector[0, 5]
65
- torque = D.torque_vector(force, radius)
66
- expect(torque).must_be_instance_of Vector
67
- expect(torque.size).must_equal 3
68
- expect(torque[2]).must_be_within_epsilon 5000.0
69
- end
70
- end
71
-
72
- describe "Disk.force_vector" do
73
- it "calculates a (3D) force given 3D torque and 2D radius" do
74
- # let's invert the Disk.torque_vector case from above:
75
- torque = Vector[0, 0, 5000]
76
- radius = Vector[0, 5]
77
- force = D.force_vector(torque, radius)
78
- expect(force).must_be_instance_of Vector
79
- expect(force.size).must_equal 3
80
- expect(force[0]).must_be_within_epsilon 1000.0
81
-
82
- # now let's rotate the radius into the x-dimension
83
- # right hand rule, positive torque means thumb into screen, clockwise
84
- # negative-x radius means positive-y force
85
- torque = Vector[0, 0, 500]
86
- radius = Vector[-5, 0]
87
- force = D.force_vector(torque, radius)
88
- expect(force).must_be_instance_of Vector
89
- expect(force.size).must_equal 3
90
- expect(force[1]).must_be_within_epsilon 100.0
91
- end
92
- end
93
-
94
62
  describe "instance methods" do
95
63
  before do
96
64
  @env = DrivingPhysics::Environment.new
97
- @disk = D.new(@env)
65
+ @disk = Disk.new(@env)
98
66
  end
99
67
 
100
68
  it "initializes" do
101
- skip
102
- expect(@disk).must_be_instance_of D
103
- expect(@disk.density).must_equal D::DENSITY # sanity check
104
- expect(@disk.mass).must_be_within_epsilon 25.01
105
-
106
- with_mass = D.new(@env) { |w|
107
- w.mass = 99.01
108
- }
69
+ expect(@disk).must_be_instance_of Disk
70
+ expect(@disk.density).must_equal Disk::DENSITY # sanity check
71
+ expect(@disk.mass).must_be_within_epsilon 76.969
72
+
73
+ with_mass = Disk.new(@env) { |w| w.mass = 99.01 }
109
74
  expect(with_mass.mass).must_equal 99.01
110
- expect(with_mass.density).wont_equal D::DENSITY
75
+ expect(with_mass.density).wont_equal Disk::DENSITY
111
76
  end
112
77
 
113
78
  it "has a string representation" do
@@ -122,8 +87,7 @@ describe D do
122
87
  end
123
88
 
124
89
  it "has inertia" do
125
- skip
126
- expect(@disk.rotational_inertia).must_be_within_epsilon 1.5321
90
+ expect(@disk.rotational_inertia).must_be_within_epsilon 4.714
127
91
  end
128
92
  end
129
93
  end
data/test/gearbox.rb ADDED
@@ -0,0 +1,36 @@
1
+ require 'minitest/autorun'
2
+ require 'driving_physics/gearbox'
3
+
4
+ include DrivingPhysics
5
+
6
+ describe Gearbox do
7
+ it "has gear ratios" do
8
+ end
9
+
10
+ it "has a final drive" do
11
+ end
12
+
13
+ it "has a neutral gear" do
14
+ end
15
+
16
+ it "has a clutch with state" do
17
+ end
18
+
19
+ it "has mass" do
20
+ end
21
+
22
+ it "has rotating mass" do
23
+ end
24
+
25
+ it "converts crank torque to axle torque" do
26
+ end
27
+
28
+ it "has losses due to inertia and friction" do
29
+ end
30
+
31
+ it "converts crank omega to axle omega (and vice versa)" do
32
+ end
33
+
34
+ it "varies torque delivery based on gear ratio and clutch" do
35
+ end
36
+ end
data/test/motor.rb ADDED
@@ -0,0 +1,236 @@
1
+ require 'minitest/autorun'
2
+ require 'driving_physics/motor'
3
+
4
+ include DrivingPhysics
5
+
6
+ describe "interpolate" do
7
+ it "validates xs and ys match in size" do
8
+ xs = [0, 5, 10, 15, 20]
9
+ ys = [10, 10, 10, 10, 5]
10
+ expect(DrivingPhysics.interpolate(1, xs: xs, ys: ys)).must_equal 10
11
+ expect { DrivingPhysics.interpolate(1, xs: xs + [10], ys: ys) }.must_raise
12
+ expect { DrivingPhysics.interpolate(1, xs: xs, ys: ys + [10]) }.must_raise
13
+ end
14
+
15
+ it "validates x is within the range of xs" do
16
+ xs = [0, 5, 10, 15, 20]
17
+ ys = [10, 10, 10, 10, 5]
18
+ expect(DrivingPhysics.interpolate(1, xs: xs, ys: ys)).must_equal 10
19
+ expect { DrivingPhysics.interpolate(-1, xs: xs, ys: ys) }.must_raise
20
+ expect { DrivingPhysics.interpolate(25, xs: xs, ys: ys) }.must_raise
21
+ end
22
+
23
+ it "validates the xs are in ascending order" do
24
+ xs = [0, 5, 10, 15, 20]
25
+ ys = [10, 10, 10, 10, 5]
26
+ expect(DrivingPhysics.interpolate(1, xs: xs, ys: ys)).must_equal 10
27
+ xs[1] = 15
28
+ expect {
29
+ DrivingPhysics.interpolate(16, xs: xs, ys: ys)
30
+ }.must_raise
31
+ end
32
+
33
+ it "performs linear interpolation to yield a y value for a valid x" do
34
+ xs = [0, 5, 10, 15, 20]
35
+ ys = [5, 5, 10, 10, 15]
36
+
37
+ expect(DrivingPhysics.interpolate(0, xs: xs, ys: ys)).must_equal 5
38
+ expect(DrivingPhysics.interpolate(1, xs: xs, ys: ys)).must_equal 5
39
+ expect(DrivingPhysics.interpolate(4, xs: xs, ys: ys)).must_equal 5
40
+ expect(DrivingPhysics.interpolate(5, xs: xs, ys: ys)).must_equal 5
41
+ expect(DrivingPhysics.interpolate(6, xs: xs, ys: ys)).must_equal 6
42
+ expect(DrivingPhysics.interpolate(7, xs: xs, ys: ys)).must_equal 7
43
+ expect(DrivingPhysics.interpolate(8, xs: xs, ys: ys)).must_equal 8
44
+ expect(DrivingPhysics.interpolate(9, xs: xs, ys: ys)).must_equal 9
45
+ expect(DrivingPhysics.interpolate(10, xs: xs, ys: ys)).must_equal 10
46
+ expect(DrivingPhysics.interpolate(11, xs: xs, ys: ys)).must_equal 10
47
+ expect(DrivingPhysics.interpolate(12, xs: xs, ys: ys)).must_equal 10
48
+ expect(DrivingPhysics.interpolate(14, xs: xs, ys: ys)).must_equal 10
49
+ expect(DrivingPhysics.interpolate(15, xs: xs, ys: ys)).must_equal 10
50
+ expect(DrivingPhysics.interpolate(16, xs: xs, ys: ys)).must_equal 11
51
+ expect(DrivingPhysics.interpolate(17, xs: xs, ys: ys)).must_equal 12
52
+ expect(DrivingPhysics.interpolate(18, xs: xs, ys: ys)).must_equal 13
53
+ expect(DrivingPhysics.interpolate(19, xs: xs, ys: ys)).must_equal 14
54
+ expect(DrivingPhysics.interpolate(20, xs: xs, ys: ys)).must_equal 15
55
+ end
56
+ end
57
+
58
+ # shorthand
59
+ def tc(rpms, torques)
60
+ TorqueCurve.new(rpms: rpms, torques: torques)
61
+ end
62
+
63
+ describe TorqueCurve do
64
+ before do
65
+ @default = TorqueCurve.new
66
+ @rpms = [500, 1000, 3500, 6000, 7000, 7100]
67
+ @torques = [ 0, 100, 300, 300, 250, 0]
68
+ @minr = [0, 1]
69
+ @mint = [0, 0]
70
+ end
71
+
72
+ it "maps rpm values to torque values" do
73
+ expect(@default.torque(3500)).must_be(:>, 100)
74
+ end
75
+
76
+ describe "initialize" do
77
+ it "accepts two arrays: rpms, and the corresponding torques" do
78
+ expect(tc(@rpms, @torques)).must_be_kind_of(TorqueCurve)
79
+ end
80
+
81
+ it "has defaults for rpms and torques" do
82
+ expect(@default).must_be_kind_of(TorqueCurve)
83
+ end
84
+
85
+ it "validates size match for rpms and torques" do
86
+ expect( tc( @minr, @mint) ).must_be_kind_of TorqueCurve
87
+ expect { tc( [0], @mint) }.must_raise
88
+ expect { tc([0,1,2], @mint) }.must_raise
89
+ expect { tc(@minr, [0]) }.must_raise
90
+ expect { tc(@minr, [0,1,0]) }.must_raise
91
+
92
+ rpms = [100, 2000, 30_000]
93
+ torques = [0, 500, 0]
94
+
95
+ expect( tc( rpms, torques) ).must_be_kind_of TorqueCurve
96
+ expect { tc( rpms, [0, 0]) }.must_raise
97
+ expect { tc([1,2], torques) }.must_raise
98
+ expect { tc([1,2,3,4], torques) }.must_raise
99
+ end
100
+
101
+
102
+ describe "rpms" do
103
+ it "validates rpms are positive" do
104
+ expect( tc( @minr, @mint) ).must_be_kind_of TorqueCurve
105
+ expect { tc([-10, 10], @mint) }.must_raise
106
+ end
107
+
108
+ it "validates rpms are in ascending order" do
109
+ expect( tc( @minr, @mint) ).must_be_kind_of TorqueCurve
110
+ expect { tc([0, 0], @mint) }.must_raise
111
+ expect( tc([99, 100], @mint) ).must_be_kind_of TorqueCurve
112
+ expect { tc([100, 99], @mint) }.must_raise
113
+ end
114
+ end
115
+
116
+ describe "torques" do
117
+ it "validates that torques start and end at zero" do
118
+ expect( tc(@minr, @mint) ).must_be_kind_of TorqueCurve
119
+ expect { tc(@minr, [1,0]) }.must_raise
120
+ expect { tc(@minr, [0,1]) }.must_raise
121
+ expect { tc(@minr, [1,1]) }.must_raise
122
+
123
+ expect( tc([1,2,3], [0,500,0]) ).must_be_kind_of TorqueCurve
124
+ expect { tc([1,2,3], [1,500,0]) }.must_raise
125
+ expect { tc([1,2,3], [0,500,1]) }.must_raise
126
+ end
127
+
128
+ it "validates that torques are positive" do
129
+ expect( tc([1,2,3], [0, 5,0]) ).must_be_kind_of TorqueCurve
130
+ expect { tc([1,2,3], [0,-5,0]) }.must_raise
131
+ end
132
+ end
133
+ end
134
+
135
+ it "finds the peak torque and corresponding RPM" do
136
+ rpm, torque = *@default.peak
137
+ expect(rpm).must_be(:>, 1000)
138
+ expect(rpm).must_be(:<, 10_000)
139
+ expect(torque).must_be(:>, 0)
140
+ expect(torque).must_be(:<, 10_000)
141
+ end
142
+
143
+ it "interpolates to find the torque for a valid RPM" do
144
+ tc = tc(@rpms, @torques)
145
+ r1 = @rpms[1]
146
+ r2 = @rpms[2]
147
+
148
+ expect(tc.torque(r1)).must_equal @torques[1]
149
+ expect(tc.torque(r2)).must_equal @torques[2]
150
+
151
+ r3 = (r1 + r2) / 2
152
+ t3 = tc.torque(r3)
153
+ t3_expect = (@torques[1] + @torques[2]) / 2.0
154
+
155
+ expect(t3).must_be :>, @torques[1]
156
+ expect(t3).must_be :<, @torques[2]
157
+ expect(t3).must_be :>=, t3_expect.floor
158
+ expect(t3).must_be :<=, t3_expect.ceil
159
+ end
160
+
161
+ it "tracks min, idle, redline, and max rpms" do
162
+ expect(@default.min).must_be :>, 0
163
+ expect(@default.min).must_be :<, 1000
164
+ expect(@default.idle).must_be :>, @default.min
165
+ expect(@default.idle).must_be :<, 3000
166
+ expect(@default.redline).must_be :>, @default.idle
167
+ expect(@default.redline).must_be :<, 20_000
168
+ expect(@default.max).must_be :>, @default.redline
169
+ expect(@default.max).must_be :<, 20_000
170
+ end
171
+ end
172
+
173
+ describe Motor do
174
+ before do
175
+ @default = Motor.new(Environment.new)
176
+ end
177
+
178
+ it "has a throttle with state" do
179
+ expect(@default.throttle).must_equal 0.0
180
+ @default.throttle = 0.5
181
+ expect(@default.throttle).must_equal 0.5
182
+ expect(@default.throttle_pct).must_equal "50.0%"
183
+
184
+ expect { @default.throttle = 1.5 }.must_raise
185
+ end
186
+
187
+ it "has mass" do
188
+ expect(@default.mass).must_be :>, 0
189
+ expect(@default.fixed_mass).must_be :>, 0
190
+ expect(@default.rotating_mass).must_be :>, 0
191
+ end
192
+
193
+ it "has a torque curve" do
194
+ expect(@default.torque_curve).must_be_kind_of TorqueCurve
195
+ end
196
+
197
+ it "has idle RPM and redline RPM" do
198
+ expect(@default.idle).must_be :>, 500
199
+ expect(@default.idle).must_be :<, 1500
200
+
201
+ expect(@default.redline).must_be :>, @default.idle
202
+ expect(@default.redline).must_be :<, 10_000
203
+ end
204
+
205
+ it "has inertia and energy" do
206
+ expect(@default.inertia).must_be :>, 0
207
+ expect(@default.energy(99)).must_be :>, 0
208
+ end
209
+
210
+ it "determines crank alpha from torque" do
211
+ expect(@default.alpha(50)).must_be :>, 0
212
+ end
213
+
214
+ it "determines torque from crank alpha" do
215
+ a = @default.alpha(50, omega: 20)
216
+ t = @default.implied_torque(a)
217
+ # frictional losses
218
+ expect(t).must_be :>, 40
219
+ expect(t).must_be :<, 50
220
+ end
221
+
222
+ it "determines torque based on torque curve, RPM and throttle" do
223
+ @default.throttle = 1.0
224
+ expect(@default.torque(1000)).must_be :>, 0
225
+ expect(@default.torque(3500)).must_be :>, @default.torque(1000)
226
+ end
227
+
228
+ it "has an engine braking effect when the throttle is closed" do
229
+ @default.throttle = 0
230
+ expect(@default.torque(3500)).must_be :<, 0
231
+ end
232
+
233
+ it "has a starter motor to get running" do
234
+ expect(@default.starter_torque).must_be :>, 0
235
+ end
236
+ end
@@ -0,0 +1,21 @@
1
+ require 'minitest/autorun'
2
+ require 'driving_physics/powertrain'
3
+
4
+ include DrivingPhysics
5
+
6
+ describe Powertrain do
7
+ it "has a motor and a gearbox" do
8
+ end
9
+
10
+ it "has mass" do
11
+ end
12
+
13
+ it "coverts rpm to axle torque" do
14
+ end
15
+
16
+ it "converts rpm to axle omega" do
17
+ end
18
+
19
+ it "determines crank rpm from axle_omega" do
20
+ end
21
+ end
data/test/scalar_force.rb CHANGED
@@ -12,8 +12,7 @@ describe ScalarForce do
12
12
  # ROT_COF's value is from observing that rotational resistance
13
13
  # matches air resistance at roughly 30 m/s in street cars
14
14
  it "approximates a reasonable rotational resistance constant" do
15
- expect(30 * ScalarForce.air_resistance(1)).
16
- must_be_within_epsilon(-1 * ROT_COF)
15
+ _(30 * ScalarForce.air_resistance(1)).must_be_within_epsilon(-1 * ROT_COF)
17
16
  end
18
17
 
19
18
  it "approximates a positive drag force" do
@@ -21,12 +20,10 @@ describe ScalarForce do
21
20
  end
22
21
 
23
22
  it "approximates a positive rotational resistance force" do
24
- expect(ScalarForce.rotational_resistance 30).
25
- must_be_within_epsilon(-383.13)
23
+ _(ScalarForce.rotational_resistance 30).must_be_within_epsilon(-383.13)
26
24
  end
27
25
 
28
26
  it "approximates a positive rolling resistance force" do
29
- nf = 1000 * G
30
- expect(ScalarForce.rolling_resistance nf).must_be_within_epsilon(-98.0)
27
+ _(ScalarForce.rolling_resistance(1000 * G)).must_be_within_epsilon(-98.0)
31
28
  end
32
29
  end