TORCS  1.3.9
The Open Racing Car Simulator
engine.cpp
Go to the documentation of this file.
1 /***************************************************************************
2 
3  file : engine.cpp
4  created : Sun Mar 19 00:06:55 CET 2000
5  copyright : (C) 2000-2026 by Eric Espie, Bernhard Wymann
6  email : berniw@bluewin.ch
7 
8 ***************************************************************************/
9 
10 /***************************************************************************
11  * *
12  * This program is free software; you can redistribute it and/or modify *
13  * it under the terms of the GNU General Public License as published by *
14  * the Free Software Foundation; either version 2 of the License, or *
15  * (at your option) any later version. *
16  * *
17  ***************************************************************************/
18 
19 #include "sim.h"
20 #include <portability.h>
21 
22 void
24 {
25  void *hdle = car->params;
26  int i;
27  tdble maxTq;
28  tdble rpmMaxTq = 0;
29  const int IDXSIZE = 64;
30  char idx[IDXSIZE];
31  tEngineCurveElem *data;
32  struct tEdesc {
33  tdble rpm;
34  tdble tq;
35  } *edesc;
36 
37 
38  car->engine.revsLimiter = GfParmGetNum(hdle, SECT_ENGINE, PRM_REVSLIM, (char*)NULL, 800);
39  car->carElt->_enginerpmRedLine = car->engine.revsLimiter;
40  car->engine.revsMax = GfParmGetNum(hdle, SECT_ENGINE, PRM_REVSMAX, (char*)NULL, 1000);
41  car->carElt->_enginerpmMax = car->engine.revsMax;
42  car->engine.tickover = GfParmGetNum(hdle, SECT_ENGINE, PRM_TICKOVER, (char*)NULL, 150);
43  car->engine.I = GfParmGetNum(hdle, SECT_ENGINE, PRM_INERTIA, (char*)NULL, 0.2423f);
44  car->engine.fuelcons = GfParmGetNum(hdle, SECT_ENGINE, PRM_FUELCONS, (char*)NULL, 0.0622f);
45  car->engine.brakeCoeff = GfParmGetNum(hdle, SECT_ENGINE, PRM_ENGBRKCOEFF, (char*)NULL, 0.33f);
46  car->engine.exhaust_pressure = 0.0f;
47  car->engine.exhaust_refract = 0.1f;
49 
50  snprintf(idx, IDXSIZE, "%s/%s", SECT_ENGINE, ARR_DATAPTS);
51  car->engine.curve.nbPts = GfParmGetEltNb(hdle, idx);
52  edesc = (struct tEdesc*)malloc((car->engine.curve.nbPts + 1) * sizeof(struct tEdesc));
53 
54  for (i = 0; i < car->engine.curve.nbPts; i++) {
55  snprintf(idx, IDXSIZE, "%s/%s/%d", SECT_ENGINE, ARR_DATAPTS, i+1);
56  edesc[i].rpm = GfParmGetNum(hdle, idx, PRM_RPM, (char*)NULL, car->engine.revsMax);
57  edesc[i].tq = GfParmGetNum(hdle, idx, PRM_TQ, (char*)NULL, 0);
58  }
59  edesc[i].rpm = edesc[i - 1].rpm;
60  edesc[i].tq = edesc[i - 1].tq;
61 
62  maxTq = 0;
63  car->engine.curve.maxPw = 0;
64  car->engine.curve.data = (tEngineCurveElem *)malloc(car->engine.curve.nbPts * sizeof(tEngineCurveElem));
65  for(i = 0; i < car->engine.curve.nbPts; i++) {
66  data = &(car->engine.curve.data[i]);
67 
68  data->rads = edesc[i+1].rpm;
69  if ((data->rads >= car->engine.tickover)
70  && (edesc[i+1].tq > maxTq)
71  && (data->rads < car->engine.revsLimiter)) {
72  maxTq = edesc[i+1].tq;
73  rpmMaxTq = data->rads;
74  }
75  if ((data->rads >= car->engine.tickover)
76  && (data->rads * edesc[i+1].tq > car->engine.curve.maxPw)
77  && (data->rads < car->engine.revsLimiter)) {
78  car->engine.curve.TqAtMaxPw = edesc[i+1].tq;
79  car->engine.curve.maxPw = data->rads * edesc[i+1].tq;
80  car->engine.curve.rpmMaxPw = data->rads;
81  }
82 
83  /* Precompute the straight-line equation for the torque curve between the current map point and the next one.
84  * For the segment [rpm_i, rpm_(i+1)], torque is interpolated as:
85  *
86  * T(rpm) = a * rpm + b
87  *
88  * where:
89  * a = slope of the segment
90  * b = intercept chosen so that the line passes through point i
91  *
92  * This lets SimEngineUpdateTq() evaluate the maximum engine torque quickly
93  * at runtime without recomputing the interpolation formula in every timestep.
94  */
95  data->a = (edesc[i+1].tq - edesc[i].tq) / (edesc[i+1].rpm - edesc[i].rpm);
96  data->b = edesc[i].tq - data->a * edesc[i].rpm;
97  }
98 
99  car->engine.curve.maxTq = maxTq;
100  car->carElt->_engineMaxTq = maxTq;
101  car->carElt->_enginerpmMaxTq = rpmMaxTq;
102  car->carElt->_engineMaxPw = car->engine.curve.maxPw;
103  car->carElt->_enginerpmMaxPw = car->engine.curve.rpmMaxPw;
104 
105  car->engine.rads = car->engine.tickover;
106 
107  free(edesc);
108 }
109 
110 /* Update torque output with engine rpm and accelerator command */
111 void
113 {
114  int i;
115  tEngine *engine = &(car->engine);
116  tEngineCurve *curve = &(engine->curve);
117 
118  if ((car->fuel <= 0.0f) || (car->carElt->_state & (RM_CAR_STATE_BROKEN | RM_CAR_STATE_ELIMINATED))) {
119  engine->rads = 0;
120  engine->Tq = 0;
121  return;
122  }
123 
124  if (engine->rads > engine->revsLimiter) {
125  engine->rads = engine->revsLimiter;
126  engine->Tq = 0;
127  } else {
128  for (i = 0; i < car->engine.curve.nbPts; i++) {
129  if (engine->rads < curve->data[i].rads) {
130  tdble Tmax = engine->rads * curve->data[i].a + curve->data[i].b;
131  tdble EngBrkK = engine->brakeCoeff * (engine->rads - engine->tickover) / (engine->revsMax - engine->tickover);
132 
133  engine->Tq = Tmax * (car->ctrl->accelCmd * (1.0f + EngBrkK) - EngBrkK);
134  // Engines comsume always fuel (needed for keeping the process running, inner friction,
135  // braking, accelerating pistons, etc.
136  // TODO: Evaluate if it is worth implementing it.
137  car->fuel -= (tdble) fabs(engine->Tq) * engine->rads * engine->fuelcons * 0.0000001f * SimDeltaTime;
138  if (car->fuel <= 0.0) {
139  car->fuel = 0.0;
140  }
141  return;
142  }
143  }
144  }
145 }
146 
147 /*
148  * Function
149  * SimEngineUpdateRpm
150  *
151  * Description
152  * update engine RPM with wheels RPM
153  *
154  * Parameters
155  * car and axle RPM
156  *
157  * Return
158  * axle rpm for wheel update
159  * 0 if no wheel update
160  */
161 tdble
163 {
164  tTransmission *trans = &(car->transmission);
165  tClutch *clutch = &(trans->clutch);
166  tEngine *engine = &(car->engine);
167  float freerads;
168  float transfer;
169 
170 
171  if (car->fuel <= 0.0) {
172  engine->rads = 0;
173  clutch->state = CLUTCH_APPLIED;
174  clutch->transferValue = 0.0;
175  return 0.0;
176  }
177 
178  freerads = engine->rads;
179  freerads += engine->Tq / engine->I * SimDeltaTime;
180  {
181  tdble dp = engine->pressure;
182  engine->pressure = engine->pressure*0.9f + 0.1f*engine->Tq;
183  dp = (0.001f* (tdble) fabs(engine->pressure - dp));
184  dp = (tdble) fabs(dp);
185  tdble rth = urandom();
186  if (dp > rth) {
187  engine->exhaust_pressure += rth;
188  }
189  engine->exhaust_pressure *= 0.9f;
190  car->carElt->priv.smoke += 5.0f*engine->exhaust_pressure;
191  car->carElt->priv.smoke *= 0.99f;
192  }
193 
194  if ((clutch->transferValue > 0.01f) && (trans->gearbox.gear)) {
195  transfer = clutch->transferValue * clutch->transferValue * clutch->transferValue * clutch->transferValue;
196 
197  engine->rads = axleRpm * trans->curOverallRatio * transfer + freerads * (1.0f - transfer);
198 
199  if (engine->rads < engine->tickover) {
200  engine->rads = engine->tickover;
201  } else if (engine->rads > engine->revsMax) {
202  engine->rads = engine->revsMax;
203  return engine->revsMax / trans->curOverallRatio;
204  }
205  } else {
206  engine->rads = freerads;
207  }
208  return 0.0;
209 }
210 
211 void
213 {
214  free(car->engine.curve.data);
215 }
void SimEngineConfig(tCar *car)
Definition: engine.cpp:23
tdble fuel
Definition: carstruct.h:63
void * params
Definition: carstruct.h:39
tdble maxPw
Definition: engine.h:31
tdble rpmMaxPw
Definition: engine.h:32
#define RM_CAR_STATE_BROKEN
Engine no more working.
Definition: car.h:218
tdble brakeCoeff
Definition: engine.h:49
tdble I
Definition: engine.h:45
#define PRM_REVSLIM
Definition: car.h:586
tdble rulesFuelFactor
Definition: simu.cpp:39
Definition: carstruct.h:35
tdble fuelcons
Definition: engine.h:48
tCarCtrl * ctrl
Definition: carstruct.h:38
tdble SimDeltaTime
Definition: simu.cpp:35
float smoke
Definition: car.h:308
#define PRM_REVSMAX
Definition: car.h:587
#define CLUTCH_APPLIED
Definition: transmission.h:39
void SimEngineUpdateTq(tCar *car)
Definition: engine.cpp:112
tEngineCurve curve
Definition: engine.h:41
tdble tickover
Definition: engine.h:44
tdble maxTq
Definition: engine.h:30
#define PRM_ENGBRKCOEFF
Definition: car.h:593
tdble SimEngineUpdateRpm(tCar *car, tdble axleRpm)
Definition: engine.cpp:162
#define PRM_TICKOVER
Definition: car.h:588
tdble TqAtMaxPw
Definition: engine.h:33
float tdble
Floating point type used in TORCS.
Definition: tgf.h:48
tdble revsLimiter
Definition: engine.h:42
void SimEngineShutdown(tCar *car)
Definition: engine.cpp:212
tdble Tq
Definition: engine.h:47
tCarElt * carElt
Definition: carstruct.h:40
tdble transferValue
Definition: transmission.h:47
Definition: engine.h:39
tPrivCar priv
private
Definition: car.h:461
tdble exhaust_refract
Definition: engine.h:52
tdble exhaust_pressure
Definition: engine.h:51
#define SECT_ENGINE
Definition: car.h:500
#define ARR_DATAPTS
Definition: car.h:591
tdble accelCmd
Accelerator command [0.0, 1.0].
Definition: car.h:346
tdble GfParmGetNum(void *handle, const char *path, const char *key, const char *unit, tdble deflt)
Get a numerical parameter from the parameter set handle.
Definition: params.cpp:2392
#define RM_CAR_STATE_ELIMINATED
Eliminated due to rules infringement.
Definition: car.h:220
tdble revsMax
Definition: engine.h:43
int nbPts
Definition: engine.h:35
#define PRM_RPM
Definition: car.h:589
tClutch clutch
Definition: transmission.h:53
tTransmission transmission
Definition: carstruct.h:51
tdble rads
Definition: engine.h:24
int GfParmGetEltNb(void *handle, const char *path)
Count the number of subsections in a section in the parameter set handle.
Definition: params.cpp:2106
tEngine engine
Definition: carstruct.h:52
tdble pressure
Definition: engine.h:50
int state
Definition: transmission.h:38
tdble rads
Definition: engine.h:46
tEngineCurveElem * data
Definition: engine.h:36
real urandom()
#define PRM_INERTIA
Definition: car.h:525
tGearbox gearbox
Definition: transmission.h:52
#define PRM_TQ
Definition: car.h:590
#define PRM_FUELCONS
Definition: car.h:592
tdble curOverallRatio
Definition: transmission.h:62