1 /***************************************************************************
2 
3     file                 : susp.cpp
4     created              : Sun Mar 19 00:08:41 CET 2000
5     copyright            : (C) 2000-2016 by Eric Espie, Bernhard Wymann
6     email                : torcs@free.fr
7     version              : $Id: susp.cpp,v 1.10.2.10 2016/03/19 14:47:05 berniw Exp $
8 
9  ***************************************************************************/
10 
11 /***************************************************************************
12  *                                                                         *
13  *   This program is free software; you can redistribute it and/or modify  *
14  *   it under the terms of the GNU General Public License as published by  *
15  *   the Free Software Foundation; either version 2 of the License, or     *
16  *   (at your option) any later version.                                   *
17  *                                                                         *
18  ***************************************************************************/
19 
20 #include <stdio.h>
21 #include "sim.h"
22 
23 /*
24  * b2 and b3 calculus
25  */
initDamper(tSuspension * susp)26 static void initDamper(tSuspension *susp)
27 {
28 	tDamper *damp;
29 
30 	damp = &(susp->damper);
31 	damp->bump.b2 = (damp->bump.C1 - damp->bump.C2) * damp->bump.v1;
32 	damp->rebound.b2 = (damp->rebound.C1 - damp->rebound.C2) * damp->rebound.v1;
33 }
34 
35 
36 
37 
38 /*
39  * get damper force
40  */
damperForce(tSuspension * susp)41 static tdble damperForce(tSuspension *susp)
42 {
43 	tDamperDef *dampdef;
44 	tdble     f;
45 	tdble     av;
46 	tdble     v;
47 
48 	v = susp->v;
49 
50 	if (fabs(v) > 10.0f) {
51 		v = SIGN(v) * 10.0f;
52 	}
53 
54 	if (v < 0.0f) {
55 		/* rebound */
56 		dampdef = &(susp->damper.rebound);
57 	} else {
58 		/* bump */
59 		dampdef = &(susp->damper.bump);
60 	}
61 
62 	av = fabs(v);
63 	if (av < dampdef->v1) {
64 		f = (dampdef->C1 * av);
65 	} else {
66 		f = (dampdef->C2 * av + dampdef->b2);
67 	}
68 
69 	f *= SIGN(v);
70 
71 	return f;
72 }
73 
74 
75 
76 
77 /*
78  * get spring force
79  */
springForce(tSuspension * susp)80 static tdble springForce(tSuspension *susp)
81 {
82 	tSpring *spring = &(susp->spring);
83 	tdble f;
84 
85 	/* K is < 0 */
86 	f = spring->K * (susp->x - spring->x0) + spring->F0;
87 	if (f < 0.0f) {
88 		// Compression spring, so the force can never change the sign.
89 		f = 0.0f;
90 	}
91 
92 	return f;
93 }
94 
95 
96 
97 
SimSuspCheckIn(tSuspension * susp)98 void SimSuspCheckIn(tSuspension *susp)
99 {
100 	susp->state = 0;
101 	if (susp->x < susp->spring.packers) {
102 		// Packers are not scaled with susp->spring.bellcrank, because they are a hard
103 		// rubber element or plate spring packs directly mounted on the piston of the
104 		// damper.
105 		susp->x = susp->spring.packers;
106 		susp->state = SIM_SUSP_COMP;
107 	}
108 
109 	susp->x *= susp->spring.bellcrank;
110 	if (susp->x > susp->spring.xMax) {
111 		susp->x = susp->spring.xMax;
112 		susp->state = SIM_SUSP_EXT;
113 	}
114 }
115 
116 
117 
118 
SimSuspUpdate(tSuspension * susp)119 void SimSuspUpdate(tSuspension *susp)
120 {
121 	tdble internalForce = springForce(susp) + damperForce(susp);
122 	if (internalForce <= 0.0f) {
123 		// The damping can at its best cancel out the spring force. Requred because
124 		// of numerical integration artefacts with (if the velocity is 0 there is no
125 		// damping, so the spring accelarates the system for one time step; if the
126 		// damping is set very high this can result in a counterforce larger than the
127 		// spring force in the next timestep)
128 		susp->force = 0.0f;
129 	} else {
130 		susp->force = internalForce * susp->spring.bellcrank;
131 	}
132 }
133 
134 
135 
136 
SimSuspConfig(void * hdle,const char * section,tSuspension * susp,tdble F0,tdble X0)137 void SimSuspConfig(void *hdle, const char *section, tSuspension *susp, tdble F0, tdble X0)
138 {
139 	susp->spring.K          = GfParmGetNum(hdle, section, PRM_SPR, (char*)NULL, 175000.0f);
140 	susp->spring.xMax       = GfParmGetNum(hdle, section, PRM_SUSPCOURSE, (char*)NULL, 0.5f);
141 	susp->spring.bellcrank  = GfParmGetNum(hdle, section, PRM_BELLCRANK, (char*)NULL, 1.0f);
142 	susp->spring.packers    = GfParmGetNum(hdle, section, PRM_PACKERS, (char*)NULL, 0.0f);
143 	susp->damper.bump.C1    = GfParmGetNum(hdle, section, PRM_SLOWBUMP, (char*)NULL, 0.0f);
144 	susp->damper.rebound.C1 = GfParmGetNum(hdle, section, PRM_SLOWREBOUND, (char*)NULL, 0.0f);
145 	susp->damper.bump.C2    = GfParmGetNum(hdle, section, PRM_FASTBUMP, (char*)NULL, susp->damper.bump.C1);
146 	susp->damper.rebound.C2 = GfParmGetNum(hdle, section, PRM_FASTREBOUND, (char*)NULL, susp->damper.rebound.C1);
147 	susp->damper.bump.v1	= GfParmGetNum(hdle, section, PRM_BUMPTHRESHOLD, (char*)NULL, 0.5f);
148 	susp->damper.rebound.v1	= GfParmGetNum(hdle, section, PRM_REBOUNDTHRESHOLD, (char*)NULL, 0.5f);
149 
150 	susp->spring.x0 = susp->spring.bellcrank * X0;
151 	susp->spring.F0 = F0 / susp->spring.bellcrank;
152 	susp->spring.K = - susp->spring.K;
153 
154 	initDamper(susp);
155 }
156 
157 
SimSuspReConfig(tCar * car,int index,tSuspension * susp,tdble F0,tdble X0)158 void SimSuspReConfig(tCar* car, int index, tSuspension *susp, tdble F0, tdble X0)
159 {
160 	// Spring
161 	tCarPitSetupValue* v = &car->carElt->pitcmd.setup.suspspring[index];
162 	if (SimAdjustPitCarSetupParam(v)) {
163 		susp->spring.K = - v->value;
164 	}
165 
166 	// Packers
167 	v = &car->carElt->pitcmd.setup.susppackers[index];
168 	if (SimAdjustPitCarSetupParam(v)) {
169 		susp->spring.packers = v->value;
170 	}
171 
172 	// Slow bump
173 	v = &car->carElt->pitcmd.setup.suspslowbump[index];
174 	if (SimAdjustPitCarSetupParam(v)) {
175 		susp->damper.bump.C1 = v->value;
176 	}
177 
178 	// Slow rebound
179 	v = &car->carElt->pitcmd.setup.suspslowrebound[index];
180 	if (SimAdjustPitCarSetupParam(v)) {
181 		susp->damper.rebound.C1 = v->value;
182 	}
183 
184 	// Fast bump
185 	v = &car->carElt->pitcmd.setup.suspfastbump[index];
186 	if (SimAdjustPitCarSetupParam(v)) {
187 		susp->damper.bump.C2 = v->value;
188 	}
189 
190 	// Fast rebound
191 	v = &car->carElt->pitcmd.setup.suspfastrebound[index];
192 	if (SimAdjustPitCarSetupParam(v)) {
193 		susp->damper.rebound.C2 = v->value;
194 	}
195 
196 	susp->spring.x0 = susp->spring.bellcrank * X0;
197 	susp->spring.F0 = F0 / susp->spring.bellcrank;
198 
199 	initDamper(susp);
200 }
201 
202 
SimSuspThirdReConfig(tCar * car,int index,tSuspension * susp,tdble F0,tdble X0)203 void SimSuspThirdReConfig(tCar* car, int index, tSuspension *susp, tdble F0, tdble X0)
204 {
205 	// Spring
206 	tCarPitSetupValue* v = &car->carElt->pitcmd.setup.thirdspring[index];
207 	if (SimAdjustPitCarSetupParam(v)) {
208 		susp->spring.K = - v->value;
209 	}
210 
211 	// Bump
212 	v = &car->carElt->pitcmd.setup.thirdbump[index];
213 	if (SimAdjustPitCarSetupParam(v)) {
214 		susp->damper.bump.C1 = v->value;
215 		susp->damper.bump.C2 = v->value;
216 	}
217 
218 	// Rebound
219 	v = &car->carElt->pitcmd.setup.thirdrebound[index];
220 	if (SimAdjustPitCarSetupParam(v)) {
221 		susp->damper.rebound.C1 = v->value;
222 		susp->damper.rebound.C2 = v->value;
223 	}
224 
225 	susp->spring.xMax = X0;
226 
227 	susp->spring.x0 = susp->spring.bellcrank * X0;
228 	susp->spring.F0 = F0 / susp->spring.bellcrank;
229 
230 	initDamper(susp);
231 }
232