// HARTWICH.DLL - implementiert ein Fahrzeugmodell nach Dr.-Ing. Erwin Hartwich, Darmstadt
// Quelle: ATZ Automobiltechnische Zeitschrift 74 (1972) 8
//
// This is meant to be compiled with Quick C for Windows version 1.0
// (the makefile will not work with other make utilities)
//
// Das Modell wird iterativ aufgerufen
// 1. void FAR PASCAL UpdateModel(double gasIn,double bremsIn) gasIn von 0 bis 100 Prozent, bremsIn von 0 bis 24 kp Trittkraft
// 2. double ModeledBlabla() liefert neuen Wert für Blabla
//
// Mit double SetModelQuiescence() kann das Modell reinitialisiert werden (alle Zustände 0)

#include <windows.h>
#include <float.h>
#include <math.h>
#include <errno.h>
#include "hartwich.h"

// Globale Lookup-Tabellen und Vektoren. Die Tabellen geben - wenn nichts anderes
// angegeben ist - die Funktionswerte für Argument von 0 bis 1 an. Die Werte
// liegen in Schritten von 0.01 vor. Sie wurden aus dem Originalartikel gewonnen,
// indem den Bildern mindstens 10 Stützpunkte entnommen wurden, Auf diesen Stützpunkten
// wurde eine AKIMA-Interpolation vorgenommen. Es wurden solange zusätzliche Stütz-
// punkte eingefügt, bis die interpolierten Kurven keine erkennbaren Unterschiede mehr
// zu den Diagrammen von Hartwich aufwiesen. Wo eine Kurvenanpassung vielversprechend
// erschien, wurde sie durchgeführt und eine Modellgleichung statt einer Tabelle verwendet.
// Terminologie:
// s   Gaspedalstellung
// nT  Turbinendrehzahl
// MT  Turbinendrehmoment

// Globale Modellvariablen für das Vollmodell
static double GasRelativ = 0;                 // von 0 bis 1
static double Fahrgeschwindigkeit = 0;
static double Turbinendrehmoment = 0;
static double Turbinendrehzahl = 0;
static double Antriebskraft = 0;
static double Bremskraft = 0;
static double Fahrwiderstand = 0;
static double Uebersetzung = 0;

// M0_nT wird zur Simulation des Turbinendrehmoments gebraucht

static const double M0_nT[101] = // Parameter: Turbinendrehzahl nT
{
    2.000000,
    1.691623,
    1.386215,
    1.083362,
    0.782646,
    0.483654,
    0.185969,
    -0.110823,
    -0.407138,
    -0.703392,
    -1.000000,
    -1.295907,
    -1.589483,
    -1.880276,
    -2.167835,
    -2.451709,
    -2.731446,
    -3.006595,
    -3.276705,
    -3.541323,
    -3.800000,
    -4.042766,
    -4.261832,
    -4.460022,
    -4.640161,
    -4.805070,
    -4.957573,
    -5.100495,
    -5.236658,
    -5.368885,
    -5.500000,
    -5.632602,
    -5.765519,
    -5.895917,
    -6.020959,
    -6.137812,
    -6.243639,
    -6.335607,
    -6.410879,
    -6.466622,
    -6.500000,
    -6.518302,
    -6.531520,
    -6.540867,
    -6.547560,
    -6.552813,
    -6.557840,
    -6.563857,
    -6.572080,
    -6.583722,
    -6.599999,
    -6.618890,
    -6.637653,
    -6.656430,
    -6.675360,
    -6.694583,
    -6.714240,
    -6.734469,
    -6.755413,
    -6.777210,
    -6.800000,
    -6.826399,
    -6.857866,
    -6.892799,
    -6.929599,
    -6.966665,
    -7.002398,
    -7.035199,
    -7.063466,
    -7.085599,
    -7.099999,
    -7.110000,
    -7.119999,
    -7.130000,
    -7.139999,
    -7.150000,
    -7.159999,
    -7.170000,
    -7.179999,
    -7.189999,
    -7.199999,
    -7.210000,
    -7.219999,
    -7.230000,
    -7.239999,
    -7.250000,
    -7.260000,
    -7.270000,
    -7.280000,
    -7.289999,
    -7.300000,
    -7.308550,
    -7.314400,
    -7.317850,
    -7.319200,
    -7.318750,
    -7.316801,
    -7.313651,
    -7.309600,
    -7.304951,
    -7.300001
};

// Mstr_nT wird zur Simulation des Turbinendrehmoments gebraucht

static const double Mstr_nT[101] = // Parameter: Turbinendrehzahl nT
{
    // Diese Kurve fällt nicht ganz so stark ab wei Hartwichs Original
    8.000000,
    7.935825,
    7.873600,
    7.813775,
    7.756800,
    7.703125,
    7.653200,
    7.607475,
    7.566400,
    7.530425,
    7.500000,
    7.473025,
    7.447200,
    7.422675,
    7.399600,
    7.378125,
    7.358400,
    7.340575,
    7.324800,
    7.311225,
    7.300000,
    7.290000,
    7.280000,
    7.270000,
    7.260000,
    7.250000,
    7.240000,
    7.230000,
    7.220000,
    7.210000,
    7.200000,
    7.190000,
    7.180000,
    7.170000,
    7.160000,
    7.150000,
    7.140000,
    7.130000,
    7.120000,
    7.110000,
    7.100000,
    7.090000,
    7.080000,
    7.070000,
    7.060000,
    7.050000,
    7.040000,
    7.030000,
    7.020000,
    7.010000,
    7.000000,
    6.990000,
    6.980000,
    6.970000,
    6.960000,
    6.950000,
    6.940001,
    6.930000,
    6.920001,
    6.910000,
    6.900001,
    6.890000,
    6.880001,
    6.870000,
    6.860001,
    6.850000,
    6.840001,
    6.830000,
    6.820001,
    6.810000,
    6.800001,
    6.790000,
    6.780001,
    6.770000,
    6.760000,
    6.750000,
    6.740000,
    6.730000,
    6.720000,
    6.710001,
    6.700000,
    6.690001,
    6.680000,
    6.670001,
    6.660000,
    6.650001,
    6.640000,
    6.630001,
    6.620000,
    6.610001,
    6.600000,
    6.590001,
    6.580000,
    6.570001,
    6.560000,
    6.550001,
    6.540000,
    6.530001,
    6.520000,
    6.510001,
    6.500000
};

// A_nT wird zur Simulation des Turbinendrehmoments gebraucht

static const double A_nT[101] = // Parameter: Turbinendrehzahl nT
{
    10.000000,
    9.809000,
    9.616000,
    9.421000,
    9.224000,
    9.025000,
    8.824000,
    8.621000,
    8.416000,
    8.209001,
    8.000000,
    7.786901,
    7.568534,
    7.346301,
    7.121601,
    6.895833,
    6.670400,
    6.446700,
    6.226133,
    6.010100,
    5.800000,
    5.594690,
    5.391787,
    5.190830,
    4.991360,
    4.792916,
    4.595040,
    4.397270,
    4.199147,
    4.000210,
    3.800001,
    3.595941,
    3.386721,
    3.173781,
    2.958561,
    2.742501,
    2.527042,
    2.313622,
    2.103682,
    1.898662,
    1.700002,
    1.545730,
    1.462148,
    1.433103,
    1.442442,
    1.474013,
    1.511663,
    1.539239,
    1.540590,
    1.499562,
    1.400003,
    1.264110,
    1.125343,
    0.984437,
    0.842128,
    0.699152,
    0.556244,
    0.414139,
    0.273574,
    0.135284,
    0.000004,
    -0.133755,
    -0.267713,
    -0.401484,
    -0.534678,
    -0.666907,
    -0.797784,
    -0.926919,
    -1.053925,
    -1.178413,
    -1.299996,
    -1.413196,
    -1.513597,
    -1.602397,
    -1.680797,
    -1.749997,
    -1.811198,
    -1.865598,
    -1.914398,
    -1.958798,
    -1.999998,
    -2.038198,
    -2.072710,
    -2.103399,
    -2.130132,
    -2.152777,
    -2.171199,
    -2.185266,
    -2.194844,
    -2.199800,
    -2.200000,
    -2.196200,
    -2.189156,
    -2.178734,
    -2.164801,
    -2.147223,
    -2.125868,
    -2.100602,
    -2.071291,
    -2.037802,
    -2.000003
};

// M_nT wird zur Simulation des Turbinendrehmoments gebraucht

static const double M_nT[101] = // Parameter: Turbinendrehzahl nT
{
    0.000000,
    -0.014400,
    -0.019200,
    -0.016800,
    -0.009600,
    -0.000000,
    0.009829,
    0.025486,
    0.056229,
    0.111314,
    0.200000,
    0.316543,
    0.447771,
    0.591800,
    0.746743,
    0.910714,
    1.081828,
    1.258200,
    1.437943,
    1.619172,
    1.800000,
    1.982672,
    2.169943,
    2.360701,
    2.553829,
    2.748215,
    2.942743,
    3.136300,
    3.327771,
    3.516043,
    3.700000,
    3.875008,
    4.037745,
    4.189061,
    4.329808,
    4.460836,
    4.582998,
    4.697144,
    4.804125,
    4.904793,
    4.999999,
    5.050109,
    5.027532,
    4.951181,
    4.839974,
    4.712825,
    4.588650,
    4.486364,
    4.424883,
    4.423122,
    4.499998,
    4.636527,
    4.797437,
    4.977206,
    5.170316,
    5.371245,
    5.574475,
    5.774485,
    5.965755,
    6.142766,
    6.299996,
    6.448300,
    6.599835,
    6.751030,
    6.898315,
    7.038121,
    7.166876,
    7.281012,
    7.376957,
    7.451143,
    7.499999,
    7.524250,
    7.528000,
    7.512751,
    7.480002,
    7.431252,
    7.368003,
    7.291754,
    7.204004,
    7.106255,
    7.000005,
    6.890005,
    6.780005,
    6.670005,
    6.560006,
    6.450006,
    6.340005,
    6.230006,
    6.120006,
    6.010006,
    5.900006,
    5.790006,
    5.680007,
    5.570006,
    5.460007,
    5.350007,
    5.240007,
    5.130007,
    5.020007,
    4.910007,
    4.800007
};

// Md0_s wird zur Simulation des Turbinendrehmoments gebraucht

static const double Md0_s[101] = // Parameter: Gaspedalstellung s
{
    0.000000,
    -0.006756,
    -0.008267,
    -0.006400,
    -0.003022,
    -0.000000,
    0.003502,
    0.011840,
    0.028427,
    0.056676,
    0.100000,
    0.208859,
    0.400176,
    0.627065,
    0.842635,
    1.000000,
    1.106063,
    1.203032,
    1.296968,
    1.393937,
    1.500000,
    1.619644,
    1.750969,
    1.890456,
    2.034590,
    2.179852,
    2.322726,
    2.459695,
    2.587242,
    2.701849,
    2.800000,
    2.879495,
    2.941538,
    2.987716,
    3.019615,
    3.038822,
    3.046923,
    3.045505,
    3.036154,
    3.020457,
    3.000000,
    2.978031,
    2.956246,
    2.933908,
    2.910277,
    2.884616,
    2.856185,
    2.824247,
    2.788062,
    2.746893,
    2.700001,
    2.650001,
    2.600001,
    2.550001,
    2.500001,
    2.450001,
    2.400001,
    2.350001,
    2.300001,
    2.250001,
    2.200001,
    2.150002,
    2.100002,
    2.050002,
    2.000002,
    1.950002,
    1.900002,
    1.850002,
    1.800002,
    1.750002,
    1.700002,
    1.657401,
    1.627201,
    1.605801,
    1.589601,
    1.575001,
    1.558401,
    1.536201,
    1.504802,
    1.460602,
    1.400003,
    1.330003,
    1.260003,
    1.190004,
    1.120004,
    1.050004,
    0.980004,
    0.910004,
    0.840004,
    0.770004,
    0.700004,
    0.630004,
    0.560004,
    0.490004,
    0.420004,
    0.350004,
    0.280004,
    0.210004,
    0.140004,
    0.070005,
    0.000005
};

// Michael Praxenthalers Vorschlag: Ein Vierganggetriebe. Führt leider völlig in die Irre;
// das Original nach Hartwich wird als wesentlich besser empfunden. Beim Vieganggetriebe
// stören die häufigen Schaltvorgänge im Stadtverkehr extrem.
//
// static const int SchaltErsterZuZweiter[21][20] =
// {
// //05 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 (jeweils bis xx km/h)
//   0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  0 bis Gas 0.05
//   0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  1 bis Gas 0.10
//   0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  2 bis Gas 0.15
//   0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  3 bis Gas 0.20
//   0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  4 bis Gas 0.25
//   0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  5 bis Gas 0.30
//   0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  6 bis Gas 0.35
//   0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  7 bis Gas 0.40
//   0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  8 bis Gas 0.45
//   0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  9 bis Gas 0.50
//   0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10 bis Gas 0.55
//   0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 11 bis Gas 0.60
//   0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 12 bis Gas 0.65
//   0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 13 bis Gas 0.70
//   0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 14 bis Gas 0.75
//   0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 15 bis Gas 0.80
//   0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 16 bis Gas 0.85
//   0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 17 bis Gas 0.90
//   0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 18 bis Gas 0.95
//   0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 19 bis Gas 1.00
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1  // 20 Kickdown
// };
//
// static const int SchaltZweiterZuErster[21][20] =
// {
// //05 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 (jeweils bis xx km/h)
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  0 bis Gas 0.05
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  1 bis Gas 0.10
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  2 bis Gas 0.15
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  3 bis Gas 0.20
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  4 bis Gas 0.25
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  5 bis Gas 0.30
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  6 bis Gas 0.35
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  7 bis Gas 0.40
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  8 bis Gas 0.45
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  9 bis Gas 0.50
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10 bis Gas 0.55
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 11 bis Gas 0.60
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 12 bis Gas 0.65
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 13 bis Gas 0.70
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 14 bis Gas 0.75
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 15 bis Gas 0.80
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 bis Gas 0.85
//   1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 17 bis Gas 0.90
//   1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 18 bis Gas 0.95
//   1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 19 bis Gas 1.00
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0  // 20 Kickdown
// };
//
// static const int SchaltZweiterZuDritter[21][20] =
// {
// //05 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 (jeweils bis xx km/h)
//   0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  0 bis Gas 0.05
//   0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  1 bis Gas 0.10
//   0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  2 bis Gas 0.15
//   0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  3 bis Gas 0.20
//   0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  4 bis Gas 0.25
//   0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  5 bis Gas 0.30
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  6 bis Gas 0.35
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  7 bis Gas 0.40
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  8 bis Gas 0.45
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  9 bis Gas 0.50
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10 bis Gas 0.55
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 11 bis Gas 0.60
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 12 bis Gas 0.65
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 13 bis Gas 0.70
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 14 bis Gas 0.75
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 15 bis Gas 0.80
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 16 bis Gas 0.85
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 17 bis Gas 0.90
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 18 bis Gas 0.95
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, // 19 bis Gas 1.00
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1  // 20 Kickdown
// };
//
// static const int SchaltDritterZuZweiter[21][20] =
// {
// //05 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 (jeweils bis xx km/h)
//   1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  0 bis Gas 0.05
//   1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  1 bis Gas 0.10
//   1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  2 bis Gas 0.15
//   1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  3 bis Gas 0.20
//   1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  4 bis Gas 0.25
//   1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  5 bis Gas 0.30
//   1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  6 bis Gas 0.35
//   1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  7 bis Gas 0.40
//   1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  8 bis Gas 0.45
//   1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  9 bis Gas 0.50
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10 bis Gas 0.55
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 11 bis Gas 0.60
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 12 bis Gas 0.65
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 13 bis Gas 0.70
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 14 bis Gas 0.75
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 15 bis Gas 0.80
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 bis Gas 0.85
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 17 bis Gas 0.90
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 18 bis Gas 0.95
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 19 bis Gas 1.00
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0  // 20 Kickdown
// };
//
// static const int SchaltDritterZuVierter[21][20] =
// {
// //05 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 (jeweils bis xx km/h)
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  0 bis Gas 0.05
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  1 bis Gas 0.10
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  2 bis Gas 0.15
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  3 bis Gas 0.20
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, //  4 bis Gas 0.25
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, //  5 bis Gas 0.30
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, //  6 bis Gas 0.35
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, //  7 bis Gas 0.40
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, //  8 bis Gas 0.45
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, //  9 bis Gas 0.50
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, // 10 bis Gas 0.55
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, // 11 bis Gas 0.60
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, // 12 bis Gas 0.65
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, // 13 bis Gas 0.70
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, // 14 bis Gas 0.75
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, // 15 bis Gas 0.80
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, // 16 bis Gas 0.85
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, // 17 bis Gas 0.90
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, // 18 bis Gas 0.95
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, // 19 bis Gas 1.00
//   0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1  // 20 Kickdown
// };
//
// static const int SchaltVierterZuDritter[21][20] =
// {
// //05 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 (jeweils bis xx km/h)
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  0 bis Gas 0.05
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  1 bis Gas 0.10
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  2 bis Gas 0.15
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  3 bis Gas 0.20
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  4 bis Gas 0.25
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  5 bis Gas 0.30
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  6 bis Gas 0.35
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  7 bis Gas 0.40
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, //  8 bis Gas 0.45
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, //  9 bis Gas 0.50
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, // 10 bis Gas 0.55
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, // 11 bis Gas 0.60
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 12 bis Gas 0.65
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 13 bis Gas 0.70
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, // 14 bis Gas 0.75
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 15 bis Gas 0.80
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, // 16 bis Gas 0.85
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 17 bis Gas 0.90
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, // 18 bis Gas 0.95
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, // 19 bis Gas 1.00
//   1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0  // 20 Kickdown
// };

static const int SchaltLowToDrive[21][20] =
{
//05 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 (jeweils bis xx km/h)
  0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  0 bis Gas 0.05
  0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  1 bis Gas 0.10
  0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  2 bis Gas 0.15
  0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  3 bis Gas 0.20
  0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  4 bis Gas 0.25
  0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  5 bis Gas 0.30
  0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  6 bis Gas 0.35
  0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  7 bis Gas 0.40
  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  8 bis Gas 0.45
  0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, //  9 bis Gas 0.50
  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 10 bis Gas 0.55
  0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 11 bis Gas 0.60
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 12 bis Gas 0.65
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 13 bis Gas 0.70
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 14 bis Gas 0.75
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, 1, // 15 bis Gas 0.80
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 16 bis Gas 0.85
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, 1, // 17 bis Gas 0.90
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, // 18 bis Gas 0.95
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1, 1, 1, 1, // 19 bis Gas 1.00
  0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 1, 1, 1, 1  // 20 Kickdown
};

static const int SchaltDriveToLow[21][20] =
{
//05 10 15 20 25 30 35 40 45 50 55 60 65 70 75 80 85 90 95 100 (jeweils bis xx km/h)
  1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  0 bis Gas 0.05
  1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  1 bis Gas 0.10
  1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  2 bis Gas 0.15
  1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  3 bis Gas 0.20
  1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  4 bis Gas 0.25
  1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  5 bis Gas 0.30
  1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  6 bis Gas 0.35
  1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  7 bis Gas 0.40
  1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  8 bis Gas 0.45
  1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, //  9 bis Gas 0.50
  1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 10 bis Gas 0.55
  1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 11 bis Gas 0.60
  1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 12 bis Gas 0.65
  1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 13 bis Gas 0.70
  1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 14 bis Gas 0.75
  1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 15 bis Gas 0.80
  1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 16 bis Gas 0.85
  1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 17 bis Gas 0.90
  1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 18 bis Gas 0.95
  1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, // 19 bis Gas 1.00
  1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 0, 0, 0, 0  // 20 Kickdown
};


// Tabelle der Geschwindigkeiten (km/h), die das Modell bei einer bestimmten Drosselklappenstellung (gleichgesetzt
// mit Gaspedalstellung erreicht). Wird zur Berechnung des Lastzustands des Motors benutzt. Die Werte wurden
// empirisch anhand einer Vorläuferversion der hartwich.dll bestimmt.
static const double AsymptoticSpeeds[101] =
{
  5,   // 1 % getreten  // Basispegel (alt: 0)
  5,   // 2 %           // Basispegel (alt: 0)
  5,   // 3 %           // Basispegel (alt: 1)
  5,   // 4 %           // Basispegel (alt: 2)
  5,   // 5 %           // Basispegel (alt: 4)
  6,   // 5 %
  8,   // 6 %
  10,  // 7 %
  12,  // 8 %
  14,  // 9 %
  17,  // 10 %
  20,  // 11 %
  24,  // 12 %
  28,  // 13 %
  32,  // 14 %
  36,  // 15 %
  39,  // 16 %
  42,  // 17 %
  45,  // 18 %
  47,  // 19 %
  49,  // 20 %
  53,  // 21 %
  55,  // 22 %
  57,  // 23 %
  61,  // 24 %
  63,  // 25 %
  66,  // 26 %
  68,  // 27 %
  70,  // 28 %
  72,  // 29 %
  75,  // 30 %
  78,  // 31 %
  81,  // 32 %
  84,  // 33 %
  87,  // 34 %
  90,  // 35 %
  91,  // 36 %
  93,  // 37 %
  95,  // 38 %
  97,  // 39 %
  99,  // 40 %
  101, // 41 %
  103, // 42 %
  105, // 43 %
  107, // 44 %
  109, // 45 %
  110, // 46 %
  112, // 47 %
  114, // 48 %
  115, // 49 %
  117, // 50 %
  119, // 51 %
  120, // 52 %
  122, // 53 %
  124, // 54 %
  125, // 55 %
  127, // 56 %
  128, // 57 %
  130, // 58 %
  131, // 59 %
  133, // 60 %
  134, // 61 %
  135, // 62 %
  137, // 63 %
  138, // 64 %
  140, // 65 %
  141, // 66 %
  142, // 67 %
  144, // 68 %
  145, // 69 %
  146, // 70 %
  148, // 71 %
  149, // 72 %
  151, // 73 %
  152, // 74 %
  154, // 75 %
  155, // 76 %
  156, // 77 %
  158, // 78 %
  159, // 79 %
  160, // 80 %
  162, // 81 %
  163, // 82 %
  164, // 83 %
  165, // 84 %
  166, // 85 %
  167, // 86 %
  169, // 87 %
  170, // 88 %
  171, // 89 %
  172, // 90 %
  173, // 91 %
  174, // 92 %
  175, // 93 %
  176, // 94 %
  177, // 95 %
  178, // 96 %
  180, // 97 %
  181, // 98 %
  182, // 99 %
  183  // 100 %
};

// Ende Lookup Tables

int FAR PASCAL LibMain(HANDLE hModule, WORD wDataSeg, WORD cbHeapSize, LPSTR lpszCmdLine)
{
  return TRUE;
}

int FAR PASCAL _WEP (int bSystemExit)
{
  return TRUE;
}

// Lookupfunktion für Turbinendrehmomentfunktionen, Parameter von 0. bis 1. normiert
double LookT(double param,const double *valueVector)
{
  int idx; // Index in die Tabelle, 0 bis 100

  if (param < 0. || param > 1.)
  {
    MessageBeep(MB_ICONHAND);
    return 0;
  }

  param *= 100.;
  idx = (int)param;
  return(valueVector[idx]);
}

// Turbinendrehmoment aus Turbinendrehzahl und Gespedalstellung berechnen
double getMT(double nT,double max_nT,double s,double max_s)
{
  double m_linear;
  double m_delta;
  double rel_nT = nT / max_nT;  // relative Turbinendrehzahl
  double rel_s = s / max_s;     // relative Gaspedalstellung

  GasRelativ = rel_s;           // Wird als Seiteneffekt global vermerkt

  // Das angeblich zum Bild 14 bei Hartwich führende Modell
  //  result = LookT(rel_nT,M0_nT) + LookT(rel_nT,Mstr_nT) +
  //           0.1 * ( LookT(rel_nT,A_nT) + LookT(rel_nT,M_nT) * rel_s ) * LookT(rel_s,Md0_s);

  // Da stimmt zwar was nicht, aber mit einigen Dimensionierungen paßt es dann doch wieder.
  // Die Multiplikation mit s die in Bild 17 eingezeichnet ist, aber in (40) fehlt, wurde eingefügt.

  // Lineare Komponente laut Hartwich, durch dimensionierende Multiplikation etwas auffrisiert
  m_linear = LookT(rel_nT,M0_nT) + (LookT(rel_nT,Mstr_nT) * rel_s * 8.);
  // Differenzdrehmoment laut Hartwich
  m_delta = 0.1 *  (LookT(rel_nT,A_nT) + LookT(rel_nT,M_nT) * rel_s) * LookT(rel_s,Md0_s);
  m_delta *= 6.;

  return(m_linear+m_delta);
}

// Hochsignifikante quadratische Kurvenanpassung, durchgeführt mit SPSS
double getFw(double v)
{
  return(19.5755 + 0.4210*v + 0.0029*(v*v));
}

// Hochsignifikante (wen wundert`s) lineare Kurvenanpassung, durchgeführt mit SPSS
// Fpb muß skaliert sein von 0 kp (nichts) bis 24 kp (maximale Trittkraft)
// Hartwich´s "tote Zone" wurde weitgehend entfernt, weil sie anachronistisch ist; der verbliebene
// Rest fungiert als Filter für technisch bedingten Noise.
// Steigung wurde verändert, weil Bremse als zu schwach empfunden wurde.
double getFb(double Fpb)
{
  // double fb = -160.05 + 29.5875*Fpb; original Hartwich
  double fb = -10. + 60.*Fpb;

  if (fb < 0)
    fb=0;

  return(fb);
}

// Antriebskraft und Turbinendrehzahl aus dem Inputvariablen
// Geschwindigkeit, Turbinendrehmoment und Gaspedalstellung
FA_NT getFAandnT(double v_in,double MT_in,double s_in)
{
  FA_NT result;
  double MA;                                  // Drehmomentnach Schaltgetriebe und Differential
  static SCHALTZUSTAND schalt = LOW;          // Schaltgetriebezustand
  int gasIdx=(int)s_in;                       // Gasindex in die Schalttabelle
  int speedIdx=(int)v_in;                     // Geschwindigkeitsindex in die Schalttabelle

  // Tabellenindizes berechnen
  gasIdx=(int)s_in;
  speedIdx=(int)v_in;

  if (gasIdx > 100)
  {
    gasIdx=100;
  }

  if (speedIdx > 99)
  {
    speedIdx=99;
  }

  gasIdx *= 2;
  speedIdx *= 2;

  gasIdx /= 10;    // Index geht jetzt von 0 bis 20 (eine der 21 Zeilen der Schalttabellen)
  speedIdx /= 10;  // Index geht jetzt von 0 bis 19 (eine der 19 Spalten der Schalttabellen)

  if (schalt == LOW)
  {
    if (SchaltLowToDrive[gasIdx][speedIdx])
    {
      schalt=DRIVE;
    }
  }
  else // DRIVE
  {
    if (SchaltDriveToLow[gasIdx][speedIdx])
    {
      schalt=LOW;
    }
  }

  // Wahl des Gangs mit den Schaltlogiktabellen vornehmen
  // Auskommentiert: das Praxenthaler´sche Vierganggetriebe
  // if (schalt == ERSTER_GANG)
  // {
  //   if (SchaltErsterZuZweiter[gasIdx][speedIdx])
  //   {
  //     schalt=ZWEITER_GANG;
  //   }
  // }
  // else if (schalt == ZWEITER_GANG)
  // {
  //   if (SchaltZweiterZuErster[gasIdx][speedIdx])
  //   {
  //     schalt=ERSTER_GANG;
  //   }
  //   else if (SchaltZweiterZuDritter[gasIdx][speedIdx])
  //   {
  //     schalt=DRITTER_GANG;
  //   }
  // }
  // else if (schalt == DRITTER_GANG)
  // {
  //   if (SchaltDritterZuZweiter[gasIdx][speedIdx])
  //   {
  //     schalt=ZWEITER_GANG;
  //   }
  //   else if (SchaltDritterZuVierter[gasIdx][speedIdx])
  //   {
  //     schalt=VIERTER_GANG;
  //   }
  // }
  // else // schalt == VIERTER_GANG
  // {
  //   if (SchaltVierterZuDritter[gasIdx][speedIdx])
  //   {
  //     schalt=DRITTER_GANG;
  //   }
  // }

  // // Getriebeübersetzung je nach Gang zuweisen
  // if (schalt == ERSTER_GANG)
  // {
  //   Uebersetzung=2.00;
  // }
  // else if (schalt == ZWEITER_GANG)
  // {
  //   Uebersetzung=1.78;
  // }
  // else if (schalt == DRITTER_GANG)
  // {
  //   Uebersetzung=1.56;
  // }
  // else // schalt == VIERTER_GANG
  // {
  //   Uebersetzung=1.35;
  // }

  if (schalt == LOW)
  {
    Uebersetzung=2.00;
  }
  else // DRIVE
  {
    Uebersetzung=1.35;
  }

  result.nT = (v_in * Uebersetzung * 20)/(3.141592654 * ROLLRADIUS);  // Turbinendrehzahl
  MA = MT_in * Uebersetzung;
  result.FA = MA / ROLLRADIUS;

  return result;
}

double getV(double Antriebskraft,double Fahrwiderstand,double Bremskraft)
{
  double newV;
  double deltaV;
  double Traegheitsmoment = Uebersetzung*Uebersetzung;
  double m_effTimesVdiff = Antriebskraft - Fahrwiderstand - Bremskraft;
  double m_eff = 1500. / 10. + Traegheitsmoment/(ROLLRADIUS*ROLLRADIUS);

  deltaV = m_effTimesVdiff / m_eff;

  newV = Fahrgeschwindigkeit + deltaV;

  if (newV < 0)
  {
    newV = 0;
  }

  return(newV);
}

// Call vom Aufrufenden Programm
double FAR PASCAL GetTurbinendrehmoment(double turbinendrehzahl,
                                        double max_turbinendrehzahl,
                                        double gaspedalstellung,
                                        double max_gaspedalstellung)
{
  return(getMT(turbinendrehzahl,max_turbinendrehzahl,gaspedalstellung,max_gaspedalstellung));
}

double FAR PASCAL GetFahrwiderstandskraft(double geschwindigkeit)
{
  return(getFw(geschwindigkeit));
}

double FAR PASCAL GetBremskraft(double bremspedalkraft)
{
  return(getFb(bremspedalkraft));
}

void FAR PASCAL SetModelQuiescence(void)
{
  Fahrgeschwindigkeit = 0;
  Turbinendrehmoment = 0;
  Turbinendrehzahl = 0;
  Antriebskraft = 0;
  Bremskraft = 0;
  Fahrwiderstand = 0;
}

void FAR PASCAL UpdateModel(double gasIn,double bremsIn)
{
  FA_NT fa_nt;

  if (Turbinendrehzahl < 0.)
    Turbinendrehzahl=0;
  if (Turbinendrehzahl > 5000)
    Turbinendrehzahl=5000;

  Turbinendrehmoment = getMT(Turbinendrehzahl,5000,gasIn,100);

  fa_nt = getFAandnT(Fahrgeschwindigkeit,Turbinendrehmoment,gasIn);

  Antriebskraft = fa_nt.FA;

  Turbinendrehzahl = fa_nt.nT;

  Bremskraft = getFb(bremsIn);

  Fahrwiderstand = getFw(Fahrgeschwindigkeit);

  Fahrgeschwindigkeit = getV(Antriebskraft,Fahrwiderstand,Bremskraft);
}

double FAR PASCAL ModeledFahrgeschwindigkeit(void)
{
  return Fahrgeschwindigkeit;
}

double FAR PASCAL ModeledTurbinendrehmoment(void)
{
  return Turbinendrehmoment;
}

double FAR PASCAL ModeledTurbinendrehzahl(void)
{
  return Turbinendrehzahl;
}

double FAR PASCAL ModeledBremskraft(void)
{
  return Bremskraft;
}

double FAR PASCAL ModeledAntriebskraft(void)
{
  return Antriebskraft;
}

double FAR PASCAL ModeledFahrwiderstandskraft(void)
{
  return Fahrwiderstand;
}

// Motorlast, von 0 bis 100 normiert
double FAR PASCAL PercentModeledMotorLast(void)
{
  static double last;        // Motorlast
  static double asymptoticV; // Geschwindigkeit, die bei einer bestimmten Gaspedalstellung erreicht wird

  asymptoticV = LookT(GasRelativ,AsymptoticSpeeds);

  // Last während der Beschleunigung berechnen (Fahrgeschwindigkeit < AsymptoticSpeeds)
  last = 1 - (Fahrgeschwindigkeit / asymptoticV);

  // Sonderfälle: Es wird gerade Gas weggenommen
  if (last < 0.05)
  {
    last = 0.05;
  }

  return(last * 100.);       // Auf % normiert zurückgeben
}
