17
0
mirror of https://github.com/MaSzyna-EU07/maszyna.git synced 2026-11-11 14:39:00 +01:00
Files
maszyna/McZapkie/Oerlikon_ESt.cpp
pwarszawski bb43f559e8 ESt3: spring preload, minimum stage, releaser time and AL2 timing
Corrections to the TNESt3 distributor, checked against the ESt3 data
and acceptance requirements (orange book tables 3-5, 3-7 and 3-9) and
discussed with youBy:

- The main control device settles at (control reservoir - pipe - 0.21)
  times the ratio instead of using a 0.05 bar offset. The 0.21 bar is the
  spring preload; without it the first stage came 0.2 bar of pipe drop
  too early. BVM is derived from the same offset, so a full service drop
  still gives MaxBP.
- When the valve brakes it gives at least the minimum stage of 0.28 bar
  (acceptance tests 12 and 22 require 0.25-0.30 bar); when the target
  drops to zero the cylinder vents completely.
- The automatic releaser vents the 15 l control reservoir from 5.0 to
  0.4 bar in about 23 s (test 27: 23 +/- 3 s) instead of 5.6 s.
- 12" cylinder fill nozzle dTN is 1.62, not 1.65 (typo).
- With the AL2 relay the impulse chamber is 1 l and the cylinder nozzles
  are scaled so that the fill and release times meet table 3-9; before,
  the AL2 timings had been set by eye.

On a valve test bench running the acceptance procedures, the number of
results out of tolerance drops from 77 to 40. The remaining ones need
parts that are not modelled yet (accelerator venting, ZP/ZS filling,
intermediate chamber).
2026-11-02 20:07:32 +01:00

692 lines
17 KiB
C++

/*
This Source Code Form is subject to the
terms of the Mozilla Public License, v.
2.0. If a copy of the MPL was not
distributed with this file, You can
obtain one at
http://mozilla.org/MPL/2.0/.
*/
/*
MaSzyna EU07 - SPKS
Brakes. Oerlikon ESt.
Copyright (C) 2007-2014 Maciej Cierniak
*/
#include "stdafx.h"
#include "Oerlikon_ESt.h"
#include "utilities/utilities.h"
// wstepny nacisk sprezyn na glowny przyrzad rozrzadczy, wyrazony jako roznica cisnien ZS - PG [bar]
static double const dPSprezyny = 0.21;
// najmniejszy stopien hamowania w cylindrze [bar] (tablica 3-9, proby 12 i 22: 0,25-0,30)
static double const pStopnia = 0.28;
double d2A( double const d )
{
return d * d * 0.7854 / 1000.0;
}
// ------ RURA ------
double TRura::P(void)
{
return Next->P();
}
void TRura::Update(double dt)
{
Next->Flow(dVol);
dVol = 0;
}
// ------ PRZECIWPOSLIG ------
void TPrzeciwposlizg::SetPoslizg(bool flag)
{
Poslizg = flag;
}
void TPrzeciwposlizg::Update(double dt)
{
if (true == Poslizg)
{
BrakeRes->Flow(dVol);
Next->Flow(PF(Next->P(), 0, d2A(10)) * dt);
}
else
Next->Flow(dVol);
dVol = 0;
}
// ------ PRZEKLADNIK ------
void TPrzekladnik::Update(double dt)
{
double dV;
double BCP{ Next->P() };
double BVP{ BrakeRes->P() };
if ( BCP > P() )
dV = -PFVd(BCP, 0, d2A(10), P()) * dt;
else {
if( BCP < P() )
dV = PFVa( BVP, BCP, d2A( 10 ), P() ) * dt;
else
dV = 0;
}
Next->Flow(dV);
if (dV > 0)
BrakeRes->Flow(-dV);
}
// ------ PRZEKLADNIK RAPID ------
void TRapid::SetRapidParams(double mult, double size)
{
RapidMult = mult;
RapidStatus = false;
if (size > 0.1) // dopasowywanie srednicy przekladnika
{
DN = d2A(size * 0.4);
DL = d2A(size * 0.4);
}
else
{
DN = d2A(5.0);
DL = d2A(5.0);
}
}
void TRapid::SetRapidStatus(bool rs)
{
RapidStatus = rs;
}
void TRapid::Update(double dt)
{
double BVP{ BrakeRes->P() };
double BCP{ Next->P() };
double ActMult;
double dV;
if ( true == RapidStatus )
{
ActMult = RapidMult;
}
else
{
ActMult = 1.0;
}
if (BCP * RapidMult > P() * ActMult)
dV = -PFVd(BCP, 0, DL, P() * ActMult / RapidMult) * dt;
else if (BCP * RapidMult < P() * ActMult)
dV = PFVa(BVP, BCP, DN, P() * ActMult / RapidMult) * dt;
else
dV = 0.0;
Next->Flow(dV);
if (dV > 0.0)
BrakeRes->Flow(-dV);
}
// ------ PRZEKŁADNIK CIĄGŁY ------
void TPrzekCiagly::SetMult(double m)
{
Mult = m;
}
void TPrzekCiagly::Update(double dt)
{
double const BVP{ BrakeRes->P() };
double const BCP{ Next->P() };
double dV;
if ( BCP > P() * Mult)
dV = -PFVd(BCP, 0, d2A(8.0), P() * Mult) * dt;
else if (BCP < P() * Mult)
dV = PFVa(BVP, BCP, d2A(8.0), P() * Mult) * dt;
else
dV = 0.0;
Next->Flow(dV);
if (dV > 0.0)
BrakeRes->Flow(-dV);
}
// ------ PRZEKŁADNIK CIĄGŁY ------
void TPrzek_PZZ::SetLBP(double P)
{
LBP = P;
}
void TPrzek_PZZ::Update(double dt)
{
double const BVP{ BrakeRes->P() };
double const BCP{ Next->P() };
double const Pgr{ std::max( LBP, P() ) };
double dV;
if (BCP > Pgr)
dV = -PFVd(BCP, 0, d2A(8.0), Pgr) * dt;
else if (BCP < Pgr)
dV = PFVa(BVP, BCP, d2A(8.0), Pgr) * dt;
else
dV = 0.0;
Next->Flow(dV);
if (dV > 0.0)
BrakeRes->Flow(-dV);
}
// ------ PRZECIWPOSLIG ------
void TPrzekED::SetP(double P)
{
MaxP = P;
}
void TPrzekED::Update(double dt)
{
if (Next->P() > MaxP)
{
BrakeRes->Flow(dVol);
Next->Flow(PFVd(Next->P(), 0, d2A(10.0) * dt, MaxP));
}
else
Next->Flow(dVol);
dVol = 0.0;
}
// ------ OERLIKON EST NA BOGATO ------
double TNESt3::GetPF( double const PP, double const dt, double const Vel ) // przeplyw miedzy komora wstepna i PG
{
double const BVP{ BrakeRes->P() };
double const VVP{ ValveRes->P() };
// BCP:=BrakeCyl.P;
double const BCP{ Przekladniki[ 1 ]->P() };
double const CVP{ CntrlRes->P() };
double const MPP{ Miedzypoj->P() };
double dV{ 0.0 };
double dV1{ 0.0 };
auto const nastG = static_cast<double>(BrakeDelayFlag & bdelay_G);
// sprawdzanie stanu
CheckState(BCP, dV1);
CheckReleaser(dt);
// luzowanie
double const cel{ CelBCP( CVP, VVP ) };
if ((BrakeStatus & b_hld) == b_off)
dV =
PF(0.0, BCP, Nozzles[dTO] * nastG + (1.0 - nastG) * Nozzles[dOO])
* dt * (0.1 + 4.9 * std::min(0.2, BCP - (cel > 0.0 ? cel + 0.1 : 0.0))); // bez stopnia luzuje do zera
else
dV = 0.0;
// BrakeCyl.Flow(-dV);
Przekladniki[1]->Flow(-dV);
if ( (BrakeStatus & b_on) == b_on && Przekladniki[1]->P() * HBG300 < MaxBP )
dV =
PF( BVP, BCP, Nozzles[dTN] * (nastG + 2.0 * (BCP < Podskok ? 1.0 : 0.0)) + Nozzles[dON] * (1.0 - nastG) )
* dt * (0.1 + 4.9 * std::min( 0.2, cel - BCP ) );
else
dV = 0;
// BrakeCyl.Flow(-dV);
Przekladniki[1]->Flow(-dV);
BrakeRes->Flow(dV);
for (int i = 1; i < 4; ++i)
Przekladniki[i]->Update(dt);
if( PrzekRapid != nullptr ) {
RapidStatus = (BrakeDelayFlag & bdelay_R) == bdelay_R && (std::abs(Vel) > 70.0 || (std::abs(Vel) > 50.0 && RapidStatus) || RapidStaly);
PrzekRapid->SetRapidStatus(RapidStatus);
}
if( PrzekPoslizg != nullptr )
PrzekPoslizg->SetPoslizg((BrakeStatus & b_asb) == b_asb);
if( PrzekED != nullptr ) {
if( Vel < -15.0 )
PrzekED->SetP( 0.0 );
else
PrzekED->SetP( MaxBP * 3.0 );
}
if( PrzekCiagly != nullptr )
PrzekCiagly->SetMult(LoadC);
if( PrzekPZZ != nullptr )
PrzekPZZ->SetLBP(LBP);
// przeplyw testowy miedzypojemnosci
dV = PF(MPP, VVP, BVs(BCP)) + PF(MPP, CVP, CVs(BCP));
if (MPP - 0.05 > BVP)
dV += PF(MPP - 0.05, BVP, Nozzles[dPT] * nastG + (1.0 - nastG) * Nozzles[dPO]);
if (MPP > VVP)
dV += PF(MPP, VVP, d2A(5.0));
Miedzypoj->Flow(dV * dt * 0.15);
// przeplyw ZS <-> PG
double const temp = CVs(BCP);
dV = PF(CVP, MPP, temp) * dt;
CntrlRes->Flow(dV);
ValveRes->Flow(-0.02 * dV);
dV1 += 0.98 * dV;
// przeplyw ZP <-> MPJ
if (MPP - 0.05 > BVP)
dV = PF(BVP, MPP - 0.05, Nozzles[dPT] * nastG + (1.0 - nastG) * Nozzles[dPO]) * dt;
else
dV = 0.0;
BrakeRes->Flow(dV);
dV1 += dV * 0.98;
ValveRes->Flow(-0.02 * dV);
// przeplyw PG <-> rozdzielacz
dV = PF(PP, VVP, 0.005) * dt; // 0.01
ValveRes->Flow(-dV);
ValveRes->Act();
BrakeCyl->Act();
BrakeRes->Act();
CntrlRes->Act();
Miedzypoj->Act();
Przekladniki[1]->Act();
Przekladniki[2]->Act();
Przekladniki[3]->Act();
return dV - dV1;
}
void TNESt3::EStParams( double const /*i_crc*/ ) const // parametry charakterystyczne dla ESt
{
// no effect for this device type
}
void TNESt3::Init( double const PP, double const HPP, double const LPP, double const BP, int const BDF )
{
TBrake::Init(PP, HPP, LPP, BP, BDF);
ValveRes->CreatePress(PP);
BrakeCyl->CreatePress(BP);
BrakeRes->CreatePress(PP);
CntrlRes = std::make_shared<TReservoir>();
CntrlRes->CreateCap(15.0);
CntrlRes->CreatePress(HPP);
BrakeStatus = BP > 1.0 ? 1 : 0;
Miedzypoj = std::make_shared<TReservoir>();
Miedzypoj->CreateCap(5.0);
Miedzypoj->CreatePress(PP);
BVM = 1.0 / (HPP - dPSprezyny - LPP) * MaxBP;
BrakeDelayFlag = BDF;
Zamykajacy = false;
auto const &frictionmaterial { *FM };
auto const &frictionmaterialtype { typeid( frictionmaterial ) };
if ( frictionmaterialtype == typeid(TDisk1) || frictionmaterialtype == typeid(TDisk2) ) // jesli zeliwo to schodz
RapidStaly = true;
else
RapidStaly = false;
}
double TNESt3::GetRapidRatio(double const Vel) const
{
// ESt3 has no rapid relay, and with disc brakes the rapid step stays engaged at all speeds
if( ( PrzekRapid == nullptr ) || RapidStaly ) {
return 1.0;
}
// a braking vehicle comes from above, so the step is still engaged down to the speed
// at which GetPF() drops it, not the one at which it engages
return ( Vel < 50.0 ? 1.0 / PrzekRapid->GetRapidMult() : 1.0 );
}
double TNESt3::GetCRP()
{
return CntrlRes->P();
// return Przekladniki[1].P;
// return Miedzypoj.P;
}
double TNESt3::CelBCP( double const CVP, double const VVP ) const // docelowe cisnienie w cylindrze
{
double const cel{ ( CVP - dPSprezyny - VVP ) * BVM };
// gdy zawor hamuje, nie daje mniej niz najmniejszy stopien
return ( cel > 0.0 ? std::max( cel, pStopnia ) : cel );
}
void TNESt3::CheckState(double const BCP, double & /*dV1*/) // glowny przyrzad rozrzadczy
{
double const VVP{ ValveRes->P() };
double const CVP{ CntrlRes->P() };
double const MPP{ Miedzypoj->P() };
if (BCP < 0.25 && VVP + 0.08 > CVP)
Przys_blok = false;
// sprawdzanie stanu
double const cel{ CelBCP( CVP, VVP ) };
if (BCP < cel - 0.01 * BVM && Przys_blok)
BrakeStatus |= b_on | b_hld; // hamowanie stopniowe;
else if (BCP - 0.1 > cel + 0.01 * BVM)
BrakeStatus &= ~( b_on | b_hld ); // luzowanie;
else if (BCP > cel)
BrakeStatus &= ~b_on; // zatrzymanie napelaniania;
else if (BCP - 0.1 < cel && BCP > 0.25) // zatrzymanie luzowania
BrakeStatus |= b_hld;
if( ( BrakeStatus & b_hld ) == 0 )
SoundFlag |= sf_CylU;
// poczatek hamowania
if (VVP + 0.10 < CVP && BCP < 0.25 && false == Przys_blok)
{
ValveRes->CreatePress(0.1 * VVP);
SoundFlag |= sf_Acc;
ValveRes->Act();
Przys_blok = true;
}
if (BCP > 0.5)
Zamykajacy = true;
else if (VVP - 0.6 < MPP)
Zamykajacy = false;
}
void TNESt3::CheckReleaser(double const dt) // odluzniacz
{
double const VVP{ ValveRes->P() };
double const CVP{ CntrlRes->P() };
// odluzniacz automatyczny
if ((BrakeStatus & b_rls) == b_rls)
{
CntrlRes->Flow(PF(CVP, 0, 0.0049) * dt); // ZS 15 l z 5,0 do 0,4 bar w 23 s (proba odbioru nr 27)
if (CVP < VVP + 0.3 || false == autom)
BrakeStatus &= ~b_rls;
}
}
double TNESt3::CVs(double const /*BP*/) const // napelniacz sterujacego
{
double const CVP{ CntrlRes->P() };
double const MPP{ Miedzypoj->P() };
// przeplyw ZS <-> PG
if (MPP < CVP - 0.17)
return 0.0;
else if (MPP > CVP - 0.08)
return Nozzles[dSd];
else
return Nozzles[dSm];
}
double TNESt3::BVs(double const BCP) const // napelniacz pomocniczego
{
double const CVP{ CntrlRes->P() };
double const MPP{ Miedzypoj->P() };
// przeplyw ZP <-> rozdzielacz
if (MPP < CVP - 0.3)
return Nozzles[dP];
else if( BCP < 0.5 ) {
if( true == Zamykajacy )
return Nozzles[ dPm ]; // 1.25
else
return Nozzles[ dPd ];
}
else
return 0.0;
}
void TNESt3::PLC(double const mass)
{
LoadC = 1.0 +
( mass < LoadM ?
(TareBP + (MaxBP - TareBP) * (mass - TareM) / (LoadM - TareM)) / MaxBP - 1.0 :
0.0 );
}
void TNESt3::ForceEmptiness()
{
ValveRes->CreatePress(0);
BrakeRes->CreatePress(0);
Miedzypoj->CreatePress(0);
CntrlRes->CreatePress(0);
ValveRes->Act();
BrakeRes->Act();
Miedzypoj->Act();
CntrlRes->Act();
}
void TNESt3::SetLP(double const TM, double const LM, double const TBP)
{
TareM = TM;
LoadM = LM;
TareBP = TBP;
}
void TNESt3::SetLBP(double const P)
{
LBP = P;
}
void TNESt3::SetSize( int const size, std::string const &params ) // ustawianie dysz (rozmiaru ZR)
{
static double const dNO1l = 1.250;
static double const dNT1l = 0.510;
static double const dOO1l = 0.907;
static double const dOT1l = 0.524;
PrzekRapid.reset();
PrzekPoslizg.reset();
PrzekED.reset();
PrzekCiagly.reset();
PrzekPZZ.reset();
if (contains( params, "ESt3" ) )
{
Podskok = 0.7;
Przekladniki[1] = std::make_shared<TRura>();
Przekladniki[3] = std::make_shared<TRura>();
}
else
{
Podskok = -1.0;
PrzekRapid = std::make_shared<TRapid>();
Przekladniki[1] = PrzekRapid;
if (contains( params,"-ED") )
{
PrzekRapid->SetRapidParams(2, 18);
PrzekED = std::make_shared<TPrzekED>();
Przekladniki[3] = PrzekED;
}
else
{
if (contains( params, "-s216" ) )
PrzekRapid->SetRapidParams(2, 16);
else
PrzekRapid->SetRapidParams(2, 0);
PrzekPoslizg = std::make_shared<TPrzeciwposlizg>();
Przekladniki[3] = PrzekPoslizg;
}
}
if (contains(params,"AL2") )
{
PrzekCiagly = std::make_shared<TPrzekCiagly>();
Przekladniki[2] = PrzekCiagly;
}
else if (contains(params,"PZZ") )
{
PrzekPZZ = std::make_shared<TPrzek_PZZ>();
Przekladniki[2] = PrzekPZZ;
}
else
Przekladniki[2] = std::make_shared<TRura>();
if( contains(params, "3d")
|| contains(params, "4d") ) {
autom = false;
}
else
autom = true;
if (contains(params, "HBG300"))
HBG300 = 1.0;
else
HBG300 = 0.0;
switch (size)
{
case 16:
{ // dON,dOO,dTN,dTO,dP,dS
Nozzles[dON] = 5.0; // 5.0;
Nozzles[dOO] = 3.4; // 3.4;
Nozzles[dTN] = 2.0;
Nozzles[dTO] = 1.75;
Nozzles[dP] = 3.8;
Nozzles[dPd] = 2.70;
Nozzles[dPm] = 1.25;
Nozzles[dPO] = Nozzles[dON];
Nozzles[dPT] = Nozzles[dTN];
break;
}
case 14:
{ // dON,dOO,dTN,dTO,dP,dS
Nozzles[dON] = 4.3;
Nozzles[dOO] = 2.85;
Nozzles[dTN] = 1.83;
Nozzles[dTO] = 1.57;
Nozzles[dP] = 3.4;
Nozzles[dPd] = 2.20;
Nozzles[dPm] = 1.10;
Nozzles[dPO] = Nozzles[dON];
Nozzles[dPT] = Nozzles[dTN];
break;
}
case 12:
{ // dON,dOO,dTN,dTO,dP,dS
Nozzles[dON] = 3.7;
Nozzles[dOO] = 2.50;
Nozzles[dTN] = 1.62;
Nozzles[dTO] = 1.39;
Nozzles[dP] = 2.65;
Nozzles[dPd] = 1.80;
Nozzles[dPm] = 0.85;
Nozzles[dPO] = Nozzles[dON];
Nozzles[dPT] = Nozzles[dTN];
break;
}
case 10:
{ // dON,dOO,dTN,dTO,dP,dS
Nozzles[dON] = 3.1;
Nozzles[dOO] = 2.0;
Nozzles[dTN] = 1.35;
Nozzles[dTO] = 1.13;
Nozzles[dP] = 1.6;
Nozzles[dPd] = 1.55;
Nozzles[dPm] = 0.7;
Nozzles[dPO] = Nozzles[dON];
Nozzles[dPT] = Nozzles[dTN];
break;
}
case 200:
{ // dON,dOO,dTN,dTO,dP,dS
Nozzles[dON] = dNO1l;
Nozzles[dOO] = dOO1l / 1.15;
Nozzles[dTN] = dNT1l;
Nozzles[dTO] = dOT1l;
Nozzles[dP] = 7.4;
Nozzles[dPd] = 5.3;
Nozzles[dPm] = 2.5;
Nozzles[dPO] = 7.28;
Nozzles[dPT] = 2.96;
break;
}
case 375:
{ // dON,dOO,dTN,dTO,dP,dS
Nozzles[dON] = dNO1l;
Nozzles[dOO] = dOO1l / 1.15;
Nozzles[dTN] = dNT1l;
Nozzles[dTO] = dOT1l;
Nozzles[dP] = 13.0;
Nozzles[dPd] = 9.6;
Nozzles[dPm] = 4.4;
Nozzles[dPO] = 9.92;
Nozzles[dPT] = 3.99;
break;
}
case 150:
{ // dON,dOO,dTN,dTO,dP,dS
Nozzles[dON] = dNO1l;
Nozzles[dOO] = dOO1l;
Nozzles[dTN] = dNT1l;
Nozzles[dTO] = dOT1l;
Nozzles[dP] = 5.8;
Nozzles[dPd] = 4.1;
Nozzles[dPm] = 1.9;
Nozzles[dPO] = 6.33;
Nozzles[dPT] = 2.58;
break;
}
case 100:
{ // dON,dOO,dTN,dTO,dP,dS
Nozzles[dON] = dNO1l;
Nozzles[dOO] = dOO1l;
Nozzles[dTN] = dNT1l;
Nozzles[dTO] = dOT1l;
Nozzles[dP] = 4.2;
Nozzles[dPd] = 2.9;
Nozzles[dPm] = 1.4;
Nozzles[dPO] = 5.19;
Nozzles[dPT] = 2.14;
break;
}
default:
{
Nozzles[dON] = 0;
Nozzles[dOO] = 0;
Nozzles[dTN] = 0;
Nozzles[dTO] = 0;
Nozzles[dP] = 0;
Nozzles[dPd] = 0;
Nozzles[dPm] = 0;
}
}
Nozzles[dSd] = 1.1;
Nozzles[dSm] = 0.9;
if( PrzekCiagly != nullptr ) {
// dysze cylindra skalibrowane na komore impulsowa przekladnika AL2 (1 l) wg czasow z tablicy 3-9
Nozzles[dON] *= 0.914;
Nozzles[dTN] *= 0.885;
Nozzles[dOO] *= 0.82;
Nozzles[dTO] *= 0.8;
}
// przeliczanie z mm^2 na l/m
for (auto &nozzle : Nozzles)
{
nozzle = d2A(nozzle); //(/1000^2*pi/4*1000)
}
for (int i = 1; i < 4; ++i)
{
Przekladniki[i]->BrakeRes = BrakeRes;
// komora impulsowa przekladnika AL2 ma 1 l
Przekladniki[i]->CreateCap( ( Przekladniki[i] == PrzekCiagly ) ? 1.0 : i );
Przekladniki[i]->CreatePress(BrakeCyl->P());
if (i < 3)
Przekladniki[i]->Next = Przekladniki[i + 1];
else
Przekladniki[i]->Next = BrakeCyl;
}
}
// END