//----------------------------------------------------------------------------------- void CAR::GraphsNewVals(double dt) // CAR { size_t gsi = pApp->graphs.size(); if (pApp->pSet->graphs_type != Gh_TireEdit) switch (pApp->pSet->graphs_type) { case Gh_BulletHit: /// bullet hit force,normvel, sndnum,scrap,screech if (gsi >= 6) { const CARDYNAMICS& cd = dynamics; pApp->graphs[0]->AddVal(std::min(1.f, cd.fHitForce * 2.f)); pApp->graphs[1]->AddVal(std::min(1.f, cd.fHitForce2)); pApp->graphs[2]->AddVal(std::min(1.f, cd.fHitForce3)); pApp->graphs[3]->AddVal(std::min(1.f, cd.fCarScrap)); pApp->graphs[4]->AddVal(std::min(1.f, cd.fCarScreech)); pApp->graphs[5]->AddVal(cd.fHitDmgA); } break; case Gh_CarAccelG: /// car accel x,y,z if (gsi >= 3) { MATHVECTOR<Dbl,3> v = dynamics.body.GetForce(); (-dynamics.Orientation()).RotateVector(v); float m = dynamics.body.GetMass(); //LogO("mass: "+fToStr(m,1,5)+" x: "+fToStr(v[0]/m,2,4)+" y: "+fToStr(v[1]/m,2,4)+" z: "+fToStr(v[2]/m,2,4)); for (int i=0; i < 3; ++i) pApp->graphs[i]->AddVal( std::max(0.f, std::min(1.f, float( v[i]/m *0.63f /9.81f/3.f + (i==2 ? 0.f : 0.5f) ) ))); } break; case Gh_TireSlips: /// tire slide,slip if (gsi >= 8) for (int i=0; i < 4; ++i) { pApp->graphs[i]->AddVal(negPow(dynamics.wheel[i].slips.slideratio, 0.2) * 0.12f +0.5f); //pApp->graphs[i]->AddVal(dynamics.wheel[i].slips.slide * 0.1f +0.5f); pApp->graphs[i+4]->AddVal(dynamics.wheel[i].slips.slipratio * 0.1f +0.5f); } break; case Gh_Suspension: /// suspension if (gsi >= 8) for (int i=0; i < 4; ++i) { const CARSUSPENSION& susp = dynamics.GetSuspension((WHEEL_POSITION)i); pApp->graphs[i+4]->AddVal(negPow(susp.GetVelocity(), 0.5) * 0.2f +0.5f); pApp->graphs[i]->AddVal(susp.GetDisplacementPercent()); } break; case Gh_TorqueCurve: /// torque curves, gears //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . { static int ii = 0; ++ii; // skip upd cntr if (ii >= 1/*! 10*/ && gsi >= 6*2) { ii = 0; const CARDYNAMICS& d = dynamics; const Dbl fin = d.diff_center.GetFinalDrive(); const Dbl r = 1.0 / (2 * PI_d * d.wheel[0].GetRadius()); String s0=" ratio\n", s1="rpmLow\n", s2="velMax\n"; // text legend for (int i=0; i < 6; ++i) { int g = i+1; bool bValid = i < d.transmission.GetForwardGears(); bool bCur = (g == GetGear()) && d.clutch.IsLocked(); const Dbl gr = bValid ? d.transmission.GetGearRatio(g) : 0.01, grfin = gr * fin; Dbl engRpm = d.engine.GetRPM(); Dbl downRpm = i>0 ? d.DownshiftRPM(g) : d.engine.GetStartRPM(); Dbl rmax = d.engine.GetRpmMax(), rmin = d.engine.GetStartRPM(), rng = rmax-rmin; Dbl rpmOld = 0; // graph ------ for (int x = 0; x < 512; ++x) { // 100 kmh = 28 car.m/s = 15 wh.rps = 102 eng.rps = 6100 eng.rpm // / 3.6 /1.95 (2*PI*r) *6.87 ratio = (3.9 * 1.76) 3rd gear Dbl xx = x/511.0; // 0..1 Dbl vel = xx * 250.0 / 3.6; // 250 kmh max, in m/s Dbl whrps = vel * r; // wheel revs per sec Dbl rpm = whrps * grfin * 60.0; // engine rpm Dbl tq = gr * d.engine.GetTorqueCurve(1.0, rpm); if (rpm > rmax) tq = 0.0; if (rpm < rmin) tq = 0.0; // lines down || Dbl v = tq / 2400.0; // 2400 max if (bCur && engRpm > rpmOld && engRpm <= rpm) // cur rpm mark ^ v = 1.0; pApp->graphs[i]->AddVal(v); // torque if (i>0) { v = rpm < downRpm //downRpm > rpmOld && downRpm <= rpm ? 0.0 : std::max(0.0, std::min(1.0, (rpm-rmin)/rng )); // rpm range pApp->graphs[i+6]->AddVal(v); } rpmOld = rpm; } pApp->graphs[i]->SetUpdate(); if (i>0) pApp->graphs[i+6]->SetUpdate(); // text ------ if (bValid) { Dbl velMax = 3.6 * d.engine.GetRpmMax() / (grfin * 60.0) / r; if (!bValid) velMax = 0; s0 += toStr(g)+": "+fToStr(gr,3,5)+"\n"; s1 += fToStr(downRpm,0,4)+"\n"; s2 += fToStr(velMax,0,3)+"\n"; } } s0 += " final\n "+fToStr(fin,3,5); pApp->graphs[0]->UpdTitle(s0); pApp->graphs[1]->UpdTitle(s1); pApp->graphs[2]->UpdTitle(s2); } } break; case Gh_Engine: /// engine torque, power { static int ii = 0; ++ii; // skip upd cntr if (ii >= 10 && gsi >= 2) { ii = 0; const CARENGINE& eng = dynamics.engine; float maxTrq = 0.f, maxPwr = 0.f; int rpmMaxTq = 0, rpmMaxPwr = 0; float rmin = eng.GetStartRPM(), rmax = eng.GetRpmMax(), rng = rmax - rmin; for (int x = 0; x < 512; ++x) { float r = x/512.f * rng + rmin; float tq = eng.GetTorqueCurve(1.0, r); float pwr = tq * 2.0 * PI_d * r / 60.0 * 0.001 * 1.341; //kW // 1kW = 1.341 bhp if (tq > maxTrq) { maxTrq = tq; rpmMaxTq = r; } if (pwr > maxPwr) { maxPwr = pwr; rpmMaxPwr = r; } pApp->graphs[0]->AddVal( tq / 600.0 ); pApp->graphs[1]->AddVal( pwr / 600.0 ); } pApp->graphs[0]->SetUpdate(); pApp->graphs[1]->SetUpdate(); //pApp->graphs[0]->UpdTitle(ss); } } break; case Gh_Clutch: /// clutch,rpm,gears if (gsi >= 4) { const CARENGINE& eng = dynamics.engine; const CARCLUTCH& clu = dynamics.clutch; pApp->graphs[0]->AddVal(eng.GetRPM() / 7500.0); #if 0 MATHVECTOR<Dbl,3> vel = dynamics.GetVelocity(), vx(1,0,0); dynamics.Orientation().RotateVector(vx); Dbl d = vel.dot(vx), velCar = vel.Magnitude() * (d >= 0.0 ? 1 : -1), velWh = dynamics.GetSpeedMPS(); //pApp->graphs[1]->AddVal(velCar * 0.02f)); //pApp->graphs[2]->AddVal(velWh * 0.02f); if (velWh < 1.1f && velWh > -1.1f) d = 1.f; else d = fabs(velCar >= velWh ? velCar/velWh : velWh/velCar); pApp->graphs[2]->AddVal(/*std::min(1.f, std::max(1.f,*/ d * 0.5f); #else pApp->graphs[1]->AddVal(clu.GetClutch() * 0.3f + 0.15f); pApp->graphs[2]->AddVal(clu.IsLocked() ? 0.15f : 0.f); #endif pApp->graphs[3]->AddVal(GetGear() / 6.f); } break; case Gh_Diffs: /// differentials if (gsi >= 6) for (int i=0; i < 3*2; ++i) { CARDIFFERENTIAL* diff; switch (i%3) { case 0: diff = &dynamics.diff_front; break; case 1: diff = &dynamics.diff_rear; break; case 2: diff = &dynamics.diff_center; break; } Dbl d; if (i/3==0) { d = diff->GetSide1Speed() - diff->GetSide2Speed(); d = negPow(d, 0.4)*0.07 + 0.5; } // blue else { d = diff->GetSide1Torque() - diff->GetSide2Torque(); d = d*0.0004 + 0.5; } // orange pApp->graphs[i]->AddVal(d); } break; } else ///Gh_TireEdit: /// tire pacejka //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . { static int ii = 0; ++ii; // skip upd cntr const int im = pApp->iUpdTireGr > 0 ? 2 : 8; // faster when editing val if (ii >= im && gsi >= TireNG*2) { ii = 0; pApp->iUpdTireGr = 0; const CARTIRE* tire = dynamics.GetTire(FRONT_LEFT); Dbl* ft = new Dbl[TireLenG]; Dbl fmin, fmax, frng, maxF; const bool common = 1; // common range for all const bool cust = 1; // RANGE gui sld .. const Dbl fMAX = 9000.0, max_y = pApp->sc->asphalt ? 40.0 : 80.0, max_x = 1.0; /// Fy lateral -- for (int i=0; i < TireNG; ++i) { bool comi = common || i == 0; if (comi) { fmin = FLT_MAX; fmax = FLT_MIN; frng = 0.0; } for (int x=0; x < TireLenG; ++x) { //Dbl yy = max_y * 2.0 * (x-LEN*0.5) / LEN; Dbl yy = max_y * x / TireLenG; Dbl n = (TireNG-1-i+1) * 0.65; Dbl fy = !pApp->iTireLoad ? tire->Pacejka_Fy(yy, n, 0, 1.0, maxF) // normF : tire->Pacejka_Fy(yy, 3, n-2, 1.0, maxF); // camber ft[x] = fy; if (comi) // get min, max { if (fy < fmin) fmin = fy; if (fy > fmax) fmax = fy; } } if (comi) // get range frng = 1.0 / (fmax - fmin); if (cust) { fmax = fMAX; fmin = 0.0; frng = 1.0 / (fmax - fmin); } for (int x = 0; x < TireLenG; ++x) pApp->graphs[i]->AddVal( (ft[x] - fmin) * frng ); pApp->graphs[i]->SetUpdate(); if (i==0) pApp->graphs[i]->UpdTitle("Fy Lateral--\n" //#33FF77 //"min: "+fToStr((float)fmin,2,4)+"\n"+ "max y "+fToStr((float)fmax,0,1)+ " x "+fToStr(max_y,0,1)+"\n"); } /// Fx long | for (int i=0; i < TireNG; ++i) { bool comi = common || i == 0; if (comi) { fmin = FLT_MAX; fmax = FLT_MIN; frng = 0.0; } for (int x=0; x < TireLenG; ++x) { //Dbl xx = max_x * 2.0 * (x-LEN*0.5) / LEN; Dbl xx = max_x * x / TireLenG; Dbl n = (TireNG-1-i+1) * 0.65; Dbl fx = pApp->iEdTire != 2 ? tire->Pacejka_Fx(xx, n, 1.0, maxF) // normF : (!pApp->iTireLoad ? tire->Pacejka_Mz(xx, 0, n, 0.0, 1.0, maxF) // align- norm : tire->Pacejka_Mz(0, xx, n, 0.0, 1.0, maxF)); // align- camber ft[x] = fx; if (comi) // get min, max { if (fx < fmin) fmin = fx; if (fx > fmax) fmax = fx; } } if (comi) // get range frng = 1.0 / (fmax - fmin); if (cust) { fmax = fMAX; fmin = 0.0; frng = 1.0 / (fmax - fmin); } for (int x = 0; x < TireLenG; ++x) pApp->graphs[i+TireNG]->AddVal( (ft[x] - fmin) * frng ); pApp->graphs[i+TireNG]->SetUpdate(); if (i==0) pApp->graphs[i+TireNG]->UpdTitle("Fx Longit |\n" //"min: "+fToStr((float)fmin,2,4)+"\n"+ "max y "+fToStr((float)fmax,0,1)+ " x "+fToStr(max_x,0,1)+"\n"); } delete[]ft; // update edit values text and descr ///---------------------------------------------------- const static String sLateral[15][2] = { " a0","#F0FFFFShape factor", " a1","#C0E0FFLoad infl. on friction coeff", " a2","#F0FFFFLateral friction coeff at load = 0", " a3","#F0FFFFMaximum stiffness", " a4","#F0FFFFLoad at maximum stiffness", " a5","#C0E0FF-Camber infl. on stiffness", " a6","Curvature change with load", " a7","Curvature at load = 0", " a8","#A0C0D0 -Horiz. shift because of camber", " a9"," Load infl. on horizontal shift", " a10"," Horizontal shift at load = 0", "a111"," -Camber infl. on vertical shift", "a112"," -Camber infl. on vertical shift", " a12"," Load infl. on vertical shift", " a13"," Vertical shift at load = 0" }; const static String sLongit[13][2] = { " b0","#FFFFF0Shape factor", " b1","#F0F0A0Load infl. on long. friction coeff", " b2","#FFFFF0Longit. friction coeff at load = 0", " b3","#F0F0A0Curvature factor of stiffness", " b4","#F0F0A0Change of stiffness with load at load = 0", " b5","#E0C080Change of progressivity/load", //of stiffness " b6","Curvature change with load^2", " b7","Curvature change with load", " b8","Curvature at load = 0", " b9","#D0D0A0 Load infl. on horizontal shift", " b10"," Horizontal shift at load = 0", " b11"," Load infl. on vertical shift", " b12"," Vertical shift at load = 0" }; const static String sAlign[18][2] = { " c0","#E0FFE0Shape factor", " c1","Load infl. of peak value", " c2","Load infl. of peak value", " c3","Curvature factor of stiffness", " c4","Change of stiffness with load at load = 0", " c5","Change of progressivity/load", " c6","-Camber infl. on stiffness", " c7","Curvature change with load", " c8","Curvature change with load", " c9","Curvature at load = 0", "c10","-Camber infl. of stiffness", "c11"," -Camber infl. on horizontal shift", "c12"," Load infl. on horizontal shift", "c13"," Horizontal shift at load = 0", "c14"," -Camber infl. on vertical shift", "c15"," -Camber infl. on vertical shift", "c16"," Load infl. on vertical shift", "c17"," Vertical shift at load = 0" }; const static String sCommon = "#C8C8F0Pacejka's Magic Formula coeffs\n"; String ss,sd; if (pApp->iEdTire == 0) { ss += "#A0F0FF--Lateral--\n"; sd += sCommon; for (int i=0; i < tire->lateral.size(); ++i) { //ss += (i == pApp->iCurLat) ? "." : " "; float f = tire->lateral[i]; char p = f > 100 ? 0 : (f > 10 ? 1 : (f > 1 ? 2 : 3)); bool cur = (i == pApp->iCurLat); ss += cur ? "#A0EEFF" : "#E0FFFF"; ss += sLateral[i][0] +" "+ fToStr(f, p,5); ss += cur ? " <\n" : "\n"; sd += sLateral[i][1] +"\n"; } ss += "\n#C0F0F0alpha hat\n"; //for (int a=0; a < tire->alpha_hat.size(); ++a) // ss += " "+fToStr( tire->alpha_hat[a], 3,5) + "\n"; int z = (int)tire->alpha_hat.size()-1; ss += " "+fToStr( tire->alpha_hat[0], 3,5) + "\n"; ss += " "+fToStr( tire->alpha_hat[z/2], 3,5) + "\n"; ss += " "+fToStr( tire->alpha_hat[z], 3,5) + "\n"; } else if (pApp->iEdTire == 1) { ss += "#FFFF70| Longit |\n"; sd += sCommon; for (int i=0; i < tire->longitudinal.size(); ++i) { //ss += (i == pApp->iCurLong) ? "." : " "; float f = tire->longitudinal[i]; char p = f > 100 ? 0 : (f > 10 ? 1 : (f > 1 ? 2 : 3)); bool cur = (i == pApp->iCurLong); ss += cur ? "#FFE090" : "#FFFFD0"; ss += sLongit[i][0] +" "+ fToStr(f, p,5); ss += cur ? " <\n" : "\n"; sd += sLongit[i][1] +"\n"; } ss += "\n#F0F0C0sigma hat\n"; //for (int a=0; a < tire->sigma_hat.size(); ++a) // ss += " "+fToStr( tire->sigma_hat[a], 3,5) + "\n"; int z = (int)tire->sigma_hat.size()-1; ss += " "+fToStr( tire->sigma_hat[0], 3,5) + "\n"; ss += " "+fToStr( tire->sigma_hat[z/2], 3,5) + "\n"; ss += " "+fToStr( tire->sigma_hat[z], 3,5) + "\n"; } else //if (pApp->iEdTire == 2) { ss += "#D0FFD0o Align o\n"; sd += sCommon; for (int i=0; i < tire->aligning.size(); ++i) { float f = tire->aligning[i]; char p = f > 100 ? 0 : (f > 10 ? 1 : (f > 1 ? 2 : 3)); bool cur = (i == pApp->iCurAlign); ss += cur ? "#80FF80" : "#E0FFE0"; ss += sAlign[i][0] +" "+ fToStr(f, p,5); ss += cur ? " <\n" : "\n"; sd += sAlign[i][1] +"\n"; } } pApp->graphs[gsi-2]->UpdTitle(ss); pApp->graphs[gsi-1]->UpdTitle(sd); pApp->graphs[2]->UpdTitle(TireVar[pApp->iTireLoad]); //- } } }
//----------------------------------------------------------------------------------- void CAR::GraphsNewVals(double dt) // CAR { size_t gsi = pApp->graphs.size(); bool tireEdit = false; // RANGE gui sld .. //const Dbl fMAX = 9000.0, max_y = 80.0, max_x = 1.0; //const Dbl fMAX = 7000.0, max_y = 180.0, max_x = 12.0, pow_x = 1.0; //const Dbl fMAX = 7000.0, max_y = 5080.0, max_x = 502.0, pow_x = 5.5; Dbl fMAX = pSet->te_yf, max_y = pSet->te_xfy, max_x = pSet->te_xfx, pow_x = pSet->te_xf_pow; if (pApp->scn->sc->asphalt) max_y *= 0.5; switch (pApp->pSet->graphs_type) { case Gh_BulletHit: /// bullet hit force,normvel, sndnum,scrap,screech if (gsi >= 6) { const CARDYNAMICS& cd = dynamics; pApp->graphs[0]->AddVal(std::min(1.f, cd.fHitForce * 2.f)); pApp->graphs[1]->AddVal(std::min(1.f, cd.fHitForce2)); pApp->graphs[2]->AddVal(std::min(1.f, cd.fHitForce3)); pApp->graphs[3]->AddVal(std::min(1.f, cd.fCarScrap)); pApp->graphs[4]->AddVal(std::min(1.f, cd.fCarScreech)); pApp->graphs[5]->AddVal(cd.fHitDmgA); } break; case Gh_CarAccelG: /// car accel x,y,z if (gsi >= 3) { MATHVECTOR<Dbl,3> v = dynamics.body.GetForce(); (-dynamics.Orientation()).RotateVector(v); float m = dynamics.body.GetMass(); //LogO("mass: "+fToStr(m,1,5)+" x: "+fToStr(v[0]/m,2,4)+" y: "+fToStr(v[1]/m,2,4)+" z: "+fToStr(v[2]/m,2,4)); for (int i=0; i < 3; ++i) pApp->graphs[i]->AddVal( std::max(0.f, std::min(1.f, float( v[i]/m *0.63f /9.81f/3.f + (i==2 ? 0.f : 0.5f) ) ))); } break; case Gh_CamBounce: /// cam bounce x,y,z if (gsi >= 3) { const MATHVECTOR<Dbl,3> v = dynamics.cam_body.GetPosition(); for (int i=0; i < 3; ++i) pApp->graphs[i]->AddVal( std::max(0.f, std::min(1.f, (float)v[i] * 3.f + 0.5f))); } break; case Gh_TireSlips: /// tire slide,slip if (gsi >= 8) for (int i=0; i < 4; ++i) { pApp->graphs[i]->AddVal(negPow(dynamics.wheel[i].slips.slideratio, 0.2) * 0.12f +0.5f); //pApp->graphs[i]->AddVal(dynamics.wheel[i].slips.slide * 0.1f +0.5f); pApp->graphs[i+4]->AddVal(dynamics.wheel[i].slips.slipratio * 0.1f +0.5f); } break; case Gh_Suspension: /// suspension if (gsi >= 8) for (int i=0; i < 4; ++i) { const CARSUSPENSION& susp = dynamics.GetSuspension((WHEEL_POSITION)i); pApp->graphs[i+4]->AddVal( dynamics.hover ? susp.GetVelocity() * 0.2f +0.5f : negPow(susp.GetVelocity(), 0.5) * 0.2f +0.5f); pApp->graphs[i]->AddVal(susp.GetDisplacementPercent()); } break; case Gh_TorqueCurve: /// torque curves, gears //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . { static int ii = 0; ++ii; // skip upd cntr if (ii >= 1/*! 10*/ && gsi >= 6*2) { ii = 0; const CARDYNAMICS& d = dynamics; const Dbl fin = d.diff_center.GetFinalDrive(); const Dbl r = 1.0 / (2 * PI_d * d.wheel[0].GetRadius()); String s0=" ratio\n", s1="rpmLow\n", s2="velMax\n"; // text legend for (int i=0; i < 6; ++i) { int g = i+1; bool bValid = i < d.transmission.GetForwardGears(); bool bCur = (g == GetGear()) && d.clutch.IsLocked(); const Dbl gr = bValid ? d.transmission.GetGearRatio(g) : 0.01, grfin = gr * fin; Dbl engRpm = d.engine.GetRPM(); Dbl downRpm = i>0 ? d.DownshiftRPM(g) : d.engine.GetStartRPM(); Dbl rmax = d.engine.GetRpmMax(), rmin = d.engine.GetStartRPM(), rng = rmax-rmin; Dbl rpmOld = 0; // graph ------ for (int x = 0; x < 512; ++x) { // 100 kmh = 28 car.m/s = 15 wh.rps = 102 eng.rps = 6100 eng.rpm // / 3.6 /1.95 (2*PI*r) *6.87 ratio = (3.9 * 1.76) 3rd gear Dbl xx = x/511.0; // 0..1 Dbl vel = xx * 250.0 / 3.6; // 250 kmh max, in m/s Dbl whrps = vel * r; // wheel revs per sec Dbl rpm = whrps * grfin * 60.0; // engine rpm Dbl tq = gr * d.engine.GetTorqueCurve(1.0, rpm); if (rpm > rmax) tq = 0.0; if (rpm < rmin) tq = 0.0; // lines down || Dbl v = tq / 2400.0; // 2400 max if (bCur && engRpm > rpmOld && engRpm <= rpm) // cur rpm mark ^ v = 1.0; pApp->graphs[i]->AddVal(v); // torque if (i>0) { v = rpm < downRpm //downRpm > rpmOld && downRpm <= rpm ? 0.0 : std::max(0.0, std::min(1.0, (rpm-rmin)/rng )); // rpm range pApp->graphs[i+6]->AddVal(v); } rpmOld = rpm; } pApp->graphs[i]->SetUpdate(); if (i>0) pApp->graphs[i+6]->SetUpdate(); // text ------ if (bValid) { Dbl velMax = 3.6 * d.engine.GetRpmMax() / (grfin * 60.0) / r; if (!bValid) velMax = 0; s0 += toStr(g)+": "+fToStr(gr,3,5)+"\n"; s1 += fToStr(downRpm,0,4)+"\n"; s2 += fToStr(velMax,0,3)+"\n"; } } s0 += " final\n "+fToStr(fin,3,5); pApp->graphs[0]->UpdTitle(s0); pApp->graphs[1]->UpdTitle(s1); pApp->graphs[2]->UpdTitle(s2); } } break; case Gh_Engine: /// engine torque, power { static int ii = 0; ++ii; // skip upd cntr if (ii >= 10 && gsi >= 2) { ii = 0; const CARENGINE& eng = dynamics.engine; float maxTrq = 0.f, maxPwr = 0.f; int rpmMaxTq = 0, rpmMaxPwr = 0; float rmin = eng.GetStartRPM(), rmax = eng.GetRpmMax(), rng = rmax - rmin; for (int x = 0; x < 512; ++x) { float r = x/512.f * rng + rmin; float tq = eng.GetTorqueCurve(1.0, r); float pwr = tq * 2.0 * PI_d * r / 60.0 * 0.001 * 1.341; //kW // 1kW = 1.341 bhp if (tq > maxTrq) { maxTrq = tq; rpmMaxTq = r; } if (pwr > maxPwr) { maxPwr = pwr; rpmMaxPwr = r; } pApp->graphs[0]->AddVal( tq / 600.0 ); pApp->graphs[1]->AddVal( pwr / 600.0 ); } pApp->graphs[0]->SetUpdate(); pApp->graphs[1]->SetUpdate(); //pApp->graphs[0]->UpdTitle(ss); } } break; case Gh_Clutch: /// clutch,rpm,gears if (gsi >= 4) { const CARENGINE& eng = dynamics.engine; const CARCLUTCH& clu = dynamics.clutch; pApp->graphs[0]->AddVal(eng.GetRPM() / 7500.0); #if 0 MATHVECTOR<Dbl,3> vel = dynamics.GetVelocity(), vx(1,0,0); dynamics.Orientation().RotateVector(vx); Dbl d = vel.dot(vx), velCar = vel.Magnitude() * (d >= 0.0 ? 1 : -1), velWh = dynamics.GetSpeedMPS(); //pApp->graphs[1]->AddVal(velCar * 0.02f)); //pApp->graphs[2]->AddVal(velWh * 0.02f); if (velWh < 1.1f && velWh > -1.1f) d = 1.f; else d = fabs(velCar >= velWh ? velCar/velWh : velWh/velCar); pApp->graphs[2]->AddVal(/*std::min(1.f, std::max(1.f,*/ d * 0.5f); #else pApp->graphs[1]->AddVal(clu.GetClutch() * 0.3f + 0.15f); pApp->graphs[2]->AddVal(clu.IsLocked() ? 0.15f : 0.f); #endif pApp->graphs[3]->AddVal(GetGear() / 6.f); } break; case Gh_Diffs: /// differentials if (gsi >= 6) for (int i=0; i < 3*2; ++i) { CARDIFFERENTIAL* diff; switch (i%3) { case 0: diff = &dynamics.diff_front; break; case 1: diff = &dynamics.diff_rear; break; case 2: diff = &dynamics.diff_center; break; } Dbl d; if (i/3==0) { d = diff->GetSide1Speed() - diff->GetSide2Speed(); d = negPow(d, 0.4)*0.07 + 0.5; } // blue else { d = diff->GetSide1Torque() - diff->GetSide2Torque(); d = d*0.0004 + 0.5; } // orange pApp->graphs[i]->AddVal(d); } break; case Gh_TireEdit: /// tire pacejka //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . { static int ii = 0; ++ii; // skip upd cntr const int im = pApp->iUpdTireGr > 0 ? 2 : 8; // faster when editing val if (ii >= im && gsi >= TireNG*2) { ii = 0; pApp->iUpdTireGr = 0; const CARTIRE* tire = dynamics.GetTire(FRONT_LEFT); Dbl* ft = new Dbl[TireLenG]; Dbl fmin, fmax, frng, maxF; const bool common = 1; // common range for all const bool cust = 1; /// Fy lateral -- for (int i=0; i < TireNG; ++i) { bool comi = common || i == 0; if (comi) { fmin = FLT_MAX; fmax = FLT_MIN; frng = 0.0; } for (int x=0; x < TireLenG; ++x) { Dbl x0 = Dbl(x) / TireLenG; //Dbl yy = max_y * 2.0 * (x-LEN*0.5) / LEN; Dbl yy = max_y * pow(x0, pow_x); Dbl n = (TireNG-1-i+1) * 0.65; Dbl fy = !pApp->iTireLoad ? tire->Pacejka_Fy(yy, n, 0, 1.0, maxF) // normF : tire->Pacejka_Fy(yy, 3, n-2, 1.0, maxF); // camber ft[x] = fy; if (comi) // get min, max { if (fy < fmin) fmin = fy; if (fy > fmax) fmax = fy; } } if (comi) // get range frng = 1.0 / (fmax - fmin); if (cust) { fmax = fMAX; fmin = 0.0; frng = 1.0 / (fmax - fmin); } for (int x = 0; x < TireLenG; ++x) pApp->graphs[i]->AddVal( (ft[x] - fmin) * frng ); pApp->graphs[i]->SetUpdate(); if (i==0) pApp->graphs[i]->UpdTitle("Fy Lateral--\n" "max y "+fToStr((float)fmax,0,1)+" x "+fToStr(max_y,0,1)+"\n"); } /// Fx long | for (int i=0; i < TireNG; ++i) { bool comi = common || i == 0; if (comi) { fmin = FLT_MAX; fmax = FLT_MIN; frng = 0.0; } for (int x=0; x < TireLenG; ++x) { Dbl x0 = Dbl(x) / TireLenG; Dbl xx = max_x * pow(x0, pow_x); Dbl n = (TireNG-1-i+1) * 0.65; Dbl fx = pApp->iEdTire != 2 ? tire->Pacejka_Fx(xx, n, 1.0, maxF) // normF : (!pApp->iTireLoad ? tire->Pacejka_Mz(xx, 0, n, 0.0, 1.0, maxF) // align- norm : tire->Pacejka_Mz(0, xx, n, 0.0, 1.0, maxF)); // align- camber ft[x] = fx; if (comi) // get min, max { if (fx < fmin) fmin = fx; if (fx > fmax) fmax = fx; } } if (comi) // get range frng = 1.0 / (fmax - fmin); if (cust) { fmax = fMAX; fmin = 0.0; frng = 1.0 / (fmax - fmin); } for (int x = 0; x < TireLenG; ++x) pApp->graphs[i+TireNG]->AddVal( (ft[x] - fmin) * frng ); pApp->graphs[i+TireNG]->SetUpdate(); if (i==0) pApp->graphs[i+TireNG]->UpdTitle("Fx Longit |\n" "max y "+fToStr((float)fmax,0,1)+" x "+fToStr(max_x,0,1)+"\n"); } delete[]ft; } } tireEdit = true; break; case Gh_Tires4Edit: /// all tires pacejka vis, edit //. . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . . { static int ii = 0; ++ii; // skip upd cntr const int im = 1; //pApp->iUpdTireGr > 0 ? 2 : 8; // faster when editing val if (ii >= im && gsi >= TireNG*2) { ii = 0; pApp->iUpdTireGr = 0; Dbl* ft = new Dbl[TireLenG]; Dbl fmin, fmax, frng, maxF; const bool common = 1; // common range for all const bool cust = 1; /// Fy lateral -- ........ for (int i=0; i < TireNG; ++i) { WHEEL_POSITION wp = (WHEEL_POSITION)i; const CARTIRE* tire = dynamics.GetTire(wp); const CARWHEEL& wh = dynamics.GetWheel(wp); const CARWHEEL::SlideSlip& t = wh.slips; bool comi = common || i == 0; if (comi) { fmin = FLT_MAX; fmax = FLT_MIN; frng = 0.0; } Dbl yyo=0; for (int x=0; x < TireLenG; ++x) { Dbl x0 = Dbl(x) / TireLenG; Dbl yy = max_y * pow(x0, pow_x); Dbl fy = fabs(t.fy_ar * tire->Pacejka_Fy(yy, t.Fz, t.gamma, t.frict, maxF)); if (t.fy_rar > yyo && t.fy_rar <= yy) fy = 0.0; // cur mark | yyo = yy; ft[x] = fy; if (comi) // get min, max { if (fy < fmin) fmin = fy; if (fy > fmax) fmax = fy; } } if (comi) // get range frng = 1.0 / (fmax - fmin); if (cust) { fmax = fMAX; fmin = 0.0; frng = 1.0 / (fmax - fmin); } for (int x = 0; x < TireLenG; ++x) pApp->graphs[i]->AddVal( (ft[x] - fmin) * frng ); pApp->graphs[i]->SetUpdate(); if (i==0) pApp->graphs[i]->UpdTitle("Fy Lateral -- " /*"max y "+fToStr((float)fmax,0,1)+" x "+fToStr(max_y,0,1)+"\n"/**/); } /// Fx long | ........ for (int i=0; i < TireNG; ++i) { WHEEL_POSITION wp = (WHEEL_POSITION)i; const CARTIRE* tire = dynamics.GetTire(wp); const CARWHEEL& wh = dynamics.GetWheel(wp); const CARWHEEL::SlideSlip& t = wh.slips; bool comi = common || i == 0; if (comi) { fmin = FLT_MAX; fmax = FLT_MIN; frng = 0.0; } Dbl xxo=0; for (int x=0; x < TireLenG; ++x) { Dbl x0 = Dbl(x) / TireLenG; Dbl xx = max_x * pow(x0, pow_x); Dbl fx = fabs(t.fx_sr * tire->Pacejka_Fx(xx, t.Fz, t.frict, maxF)); if (t.fx_rsr > xxo && t.fx_rsr <= xx) fx = 0.0; // cur mark | xxo = xx; ft[x] = fx; if (comi) // get min, max { if (fx < fmin) fmin = fx; if (fx > fmax) fmax = fx; } } if (comi) // get range frng = 1.0 / (fmax - fmin); if (cust) { fmax = fMAX; fmin = 0.0; frng = 1.0 / (fmax - fmin); } for (int x = 0; x < TireLenG; ++x) pApp->graphs[i+TireNG]->AddVal( (ft[x] - fmin) * frng ); pApp->graphs[i+TireNG]->SetUpdate(); if (i==0) pApp->graphs[i+TireNG]->UpdTitle("Fx Longit | " /*"max y "+fToStr((float)fmax,0,1)+" x "+fToStr(max_x,0,1)+"\n"/**/); } delete[]ft; } } tireEdit = true; break; } if (tireEdit) { const CGui* g = pApp->gui; const CARTIRE* tire = dynamics.GetTire(FRONT_LEFT); String ss,sd; if (pApp->iEdTire == 0) { ss += "#A0F0FF--Lateral--\n"; sd += g->sCommon; for (int i=0; i < tire->lateral.size(); ++i) { float f = tire->lateral[i]; char p = f > 100 ? 0 : (f > 10 ? 1 : (f > 1 ? 2 : 3)); bool cur = (i == pApp->iCurLat); ss += cur ? "#A0EEFF" : "#E0FFFF"; ss += g->csLateral[i][0] +" "+ fToStr(f, p,5); ss += cur ? " <\n" : "\n"; sd += g->csLateral[i][1] +"\n"; } ss += "\n#C0F0F0alpha hat\n"; int z = (int)tire->alpha_hat.size()-1; ss += " "+fToStr( tire->alpha_hat[0], 3,5) + "\n"; ss += " "+fToStr( tire->alpha_hat[z/2], 3,5) + "\n"; ss += " "+fToStr( tire->alpha_hat[z], 3,5) + "\n"; } else if (pApp->iEdTire == 1) { ss += "#FFFF70| Longit |\n"; sd += g->sCommon; for (int i=0; i < tire->longitudinal.size(); ++i) { float f = tire->longitudinal[i]; char p = f > 100 ? 0 : (f > 10 ? 1 : (f > 1 ? 2 : 3)); bool cur = (i == pApp->iCurLong); ss += cur ? "#FFE090" : "#FFFFD0"; ss += g->csLongit[i][0] +" "+ fToStr(f, p,5); ss += cur ? " <\n" : "\n"; sd += g->csLongit[i][1] +"\n"; } ss += "\n#F0F0C0sigma hat\n"; int z = (int)tire->sigma_hat.size()-1; ss += " "+fToStr( tire->sigma_hat[0], 3,5) + "\n"; ss += " "+fToStr( tire->sigma_hat[z/2], 3,5) + "\n"; ss += " "+fToStr( tire->sigma_hat[z], 3,5) + "\n"; } pApp->graphs[gsi-2]->UpdTitle(ss); pApp->graphs[gsi-1]->UpdTitle(sd); } }