unit _mover; {fizyka ruchu dla symulatora lokomotywy} (* MaSzyna EU07 locomotive simulator Copyright (C) 2001-2004 Maciej Czapkiewicz and others *) (* (C) McZapkie v.2004.02 Co brakuje: 6. brak pantografow itp 'Nie do konca, juz czesc zrobiona - Winger 7. brak efektu grzania oporow rozruchowych, silnika, osi 9. ulepszyc sprzeg sztywny oraz automatyczny 10. klopoty z EN57 ... n. Inne lokomotywy oprocz elektrowozu pradu stalego *) (* Zrobione: 1. model szeregowego silnika elektrycznego sterowanego reostatem 2. fizyka ruchu - sily oporu, nachylenia, przyspieszenia styczne i normalne, przyczepnosc/poslizg przy hamowaniu i rozruchu 3. docisk klockow hamulcowych -hamulec reczny oraz pomocniczy hamulec pneumatyczny 4. ubytki cisnienia wskutek hamowania, kompresor - ladowanie zbiornika 5. niektore uszkodzenia i awarie - logika rozmyta a) silnik elektryczny - za duzy prad, napiecie, obroty b) sprzegi - zerwanie gdy zbyt duze sily 6. flagi niektorych dzwiekow 7. hamulec zasadniczy - elektropneumatyczny (impulsowanie), pneumatyczny - zmiany cisnienia zwiekszenie nacisku przy duzych predkosciach w hamulcach Oerlikona 8. sprzegi - sila, tlumiennosc 9. lok. el. - wylacznik glowny, odlacznik uszkodzonych silnikow 10. parametry trakcji 11. opoznienia w zalaczaniu stycznikow 12. trakcja wielokrotna 13. informacja na temat zrodla mocy dla silnikow trakcyjnych, ogrzewania, oswietlenia 14. dumb - uproszczony model lokomotywy (tylko dla AI) 15. ladunki - ilosc, typ, szybkosc na- i rozladunku, funkcje przetestowac! 16. ulepszony model fizyczny silnika elektrycznego (hamowanie silnikiem, ujemne napiecia) 17. poprawione hamulce - parametry cylindrow itp 18. ulepszone hamulce - napelnianie uderzeniowe, stopnie hamowania 19. poprawione hamulce - wyszczegolnenie cisnienia dla stopni hamowania 20. poprawione hamulce elektropneumatyczne 21. poprawione hamowanie przeciwposlizgowe i odluzniacz 22. dodany model mechanicznego napedu recznego (drezyna) 23. poprawiona szybkosc hamowania pomocniczego i przeciwposlizgowego, odlaczanie silnikow, odlaczanie bocznikow 24. wprowadzone systemy zabezpieczenia: SHP, Czuwak, sygnalizacja kabinowa (nie dzialaja w DebugMode). 25. poprawiona predkosc propagacji fali cisnienia (normalizacja przez kwadrat dlugosci) //to jest zdeka liniowe 26. uwzgledniona masa ladunku, przesuniecie w/m toru ruchu 27. lampy/sygnaly przednie/tylne 28. wprowadzona pozycja odciecia hamulca (yB: tja, ale oerlikona....) 29. rozne poprawki: slizganie, wykolejanie itp 30. model silnika spalinowego z przekladnia mechaniczna 31. otwieranie drzwi, sprezarka, przetwornica 32. wylaczanie obliczen dla nieruchomych wagonow 33. Zbudowany model rozdzielacza powietrza roznych systemow 34. Poprawiona pozycja napelniania uderzeniowego i hamulec EP 35. Dodane baterie akumulatorow (KURS90) 36. Hamowanie elektrodynamiczne w ET42 i poprawione w EP09 37. jednokierunkowosc walu kulakowego w EZT (nie do konca) 38. wal kulakowy w ET40 39. poprawiona blokada nastawnika w ET40 ... *) interface uses mctools,sysutils,hamulce,Oerlikon_ESt; CONST Go=true; Hold=false; {dla CheckLocomotiveParameters} ResArraySize=64; {dla silnikow elektrycznych} MotorParametersArraySize=10; maxcc=4; {max. ilosc odbierakow pradu} LocalBrakePosNo=10; {ilosc nastaw hamulca pomocniczego} MainBrakeMaxPos=10; {max. ilosc nastaw hamulca zasadniczego} ManualBrakePosNo=20; {ilosc nastaw hamulca recznego} LightsSwitchPosNo=16; {uszkodzenia toru} dtrack_railwear=2; dtrack_freerail=4; dtrack_thinrail=8; dtrack_railbend=16; dtrack_plants=32; dtrack_nomove=64; dtrack_norail=128; {uszkodzenia taboru} dtrain_thinwheel=1; {dla lokomotyw} dtrain_loadshift=1; {dla wagonow} dtrain_wheelwear=2; dtrain_bearing=4; dtrain_coupling=8; dtrain_ventilator=16; {dla lokomotywy el.} dtrain_loaddamage=16; {dla wagonow} dtrain_engine=32; {dla lokomotyw} dtrain_loaddestroyed=32;{dla wagonow} dtrain_axle=64; dtrain_out=128; {wykolejenie} {wagi prawdopodobienstwa dla funkcji FuzzyLogic} p_elengproblem = 0.01; p_elengdamage = 0.1; p_coupldmg = 0.02; p_derail=0.001; p_accn=0.1; p_slippdmg=0.001; {typ sprzegu} ctrain_virtual=0; //gdy pojazdy na tym samym torze się widzą wzajemnie ctrain_coupler=1; //sprzeg fizyczny ctrain_pneumatic=2; //przewody hamulcowe ctrain_controll=4; //przewody sterujące (ukrotnienie) ctrain_power=8; //przewody zasilające (WN) ctrain_passenger=16; //mostek przejściowy ctrain_scndpneumatic=32; //przewody 8 atm (żółte; zasilanie powietrzem) ctrain_heating=64; //przewody ogrzewania WN ctrain_depot=128; //nie rozłączalny podczas zwykłych manewrów (międzyczłonowy), we wpisie wartość ujemna {typ hamulca elektrodynamicznego} dbrake_none=0; dbrake_passive=1; dbrake_switch=2; dbrake_reversal=4; dbrake_automatic=8; {status czuwaka/SHP} //hunter-091012: rozdzielenie alarmow, dodanie testu czuwaka s_waiting=1; //działa s_aware=2; //czuwak miga s_active=4; //SHP świeci s_CAalarm=8; //buczy s_SHPalarm=16; //buczy s_CAebrake=32; //hamuje s_SHPebrake=64; //hamuje s_CAtest=128; {dzwieki} sound_none=0; sound_loud=1; sound_couplerstretch=2; sound_bufferclamp=4; sound_bufferbump=8; sound_relay=16; sound_manyrelay=32; sound_brakeacc=64; PhysicActivationFlag: boolean=false; //szczególne typy pojazdów (inna obsługa) dla zmiennej TrainType //zamienione na flagi bitowe, aby szybko wybierać grupę (np. EZT+SZT) dt_Default=0; dt_EZT=1; dt_ET41=2; dt_ET42=4; dt_PseudoDiesel=8; dt_ET22=$10; //używane od Megapacka dt_SN61=$20; //nie używane w warunkach, ale ustawiane z CHK dt_EP05=$40; dt_ET40=$80; dt_181=$100; //stałe dla asynchronów eimc_s_dfic=0; eimc_s_dfmax=1; eimc_s_p=2; eimc_s_cfu=3; eimc_s_cim=4; eimc_s_icif=5; eimc_f_Uzmax=7; eimc_f_Uzh=8; eimc_f_DU=9; eimc_f_I0=10; eimc_f_cfu=11; eimc_p_F0=13; eimc_p_a1=14; eimc_p_Pmax=15; eimc_p_Fh=16; eimc_p_Ph=17; eimc_p_Vh0=18; eimc_p_Vh1=19; eimc_p_Imax=20; eimc_p_abed=21; eimc_p_eped=22; //zmienne dla asynchronów eimv_FMAXMAX=0; eimv_Fmax=1; eimv_ks=2; eimv_df=3; eimv_fp=4; eimv_U=5; eimv_pole=6; eimv_Ic=7; eimv_If=8; eimv_M=9; eimv_Fr=10; eimv_Ipoj=11; eimv_Pm=12; eimv_Pe=13; eimv_eta=14; eimv_fkr=15; eimv_Uzsmax=16; eimv_Pmax=17; eimv_Fzad=18; eimv_Imax=19; eimv_Fful=20; bom_PS = 1; bom_PN = 2; bom_EP = 4; bom_MED = 8; TYPE {ogolne} TLocation = record X,Y,Z: real; {lokacja} end; TRotation = record Rx,Ry,Rz: real; {rotacja} end; TDimension= record W,L,H: real; {wymiary} end; TCommand = record Command: string; {komenda} Value1,Value2: real; {argumenty komendy} Location: TLocation; end; {tory} TTrackShape= record {ksztalt odcinka - promien, dlugosc, nachylenie, przechylka} R, Len, dHtrack, dHrail: real; end; TTrackParam= record {parametry odcinka - szerokosc, tarcie statyczne, kategoria, obciazalnosc w t/os, uszkodzenia} Width, friction: real; CategoryFlag, QualityFlag, DamageFlag: byte; Velmax:real; {dla uzytku maszynisty w ai_driver} end; TTractionParam= record TractionVoltage: real; {napiecie} TractionFreq: real; {czestotliwosc} TractionMaxCurrent: real; {obciazalnosc} TractionResistivity: real; {rezystancja styku} end; {powyzsze parametry zwiazane sa z torem po ktorym aktualnie pojazd jedzie} {typy hamulcow zespolonych} TBrakeSystem = (Individual, Pneumatic, ElectroPneumatic); {podtypy hamulcow zespolonych} TBrakeSubSystem = (ss_None, ss_W, ss_K, ss_KK, ss_Hik, ss_ESt, ss_KE, ss_LSt, ss_MT, ss_Dako); TBrakeValve = (NoValve, W, W_Lu_VI, W_Lu_L, W_Lu_XR, K, Kg, Kp, Kss, Kkg, Kkp, Kks, Hikg1, Hikss, Hikp1, KE, SW, EStED, NESt3, ESt3, LSt, ESt4, ESt3AL2, EP1, EP2, M483, CV1_L_TR, CV1, CV1_R, Other); TBrakeHandle = (NoHandle, West, FV4a, M394, M254, FVel1, FVel6, D2, Knorr, FD1, BS2, testH, St113, MHZ_P, MHZ_T, MHZ_EN57); {typy hamulcow indywidualnych} TLocalBrake = (NoBrake, ManualBrake, PneumaticBrake, HydraulicBrake); TBrakeDelayTable= array[1..4] of real; {dla osob/towar: opoznienie hamowania/odhamowania} TBrakePressure= record PipePressureVal: real; BrakePressureVal: real; FlowSpeedVal: real; BrakeType: TBrakeSystem; end; TBrakePressureTable= array[-2..MainBrakeMaxPos] of TBrakePressure; {typy napedow} TEngineTypes = (None, Dumb, WheelsDriven, ElectricSeriesMotor, ElectricInductionMotor, DieselEngine, SteamEngine, DieselElectric); {postac dostarczanej energii} TPowerType = (NoPower, BioPower, MechPower, ElectricPower, SteamPower); {rodzaj paliwa} TFuelType = (Undefined, Coal, Oil); {rodzaj rusztu} TGrateType = record FuelType: TFuelType; GrateSurface: real; FuelTransportSpeed: real; IgnitionTemperature: real; MaxTemperature: real; end; {rodzaj kotla} TBoilerType = record BoilerVolume: real; BoilerHeatSurface: real; SuperHeaterSurface: real; MaxWaterVolume,MinWaterVolume: real; MaxPressure: real; end; {rodzaj odbieraka pradu} TCurrentCollector = record CollectorsNo: longint; //musi być tu, bo inaczej się kopie MinH,MaxH: real; //zakres ruchu pantografu, nigdzie nie używany CSW: real; //szerokość części roboczej (styku) ślizgacza MinV,MaxV: real; //minimalne i maksymalne akceptowane napięcie OVP: real; //czy jest przekaznik nadnapieciowy InsetV: real; //minimalne napięcie wymagane do załączenia MinPress: real; //minimalne ciśnienie do załączenia WS MaxPress: real; //maksymalne ciśnienie za reduktorem end; {typy źródeł mocy} TPowerSource = (NotDefined, InternalSource, Transducer, Generator, Accumulator, CurrentCollector, PowerCable, Heater); {parametry źródeł mocy} TPowerParameters = record MaxVoltage: real; MaxCurrent: real; IntR: real; case SourceType: TPowerSource of NotDefined,InternalSource : (PowerType: TPowerType); Transducer : (InputVoltage: real); Generator : (GeneratorEngine: TEngineTypes); Accumulator: (RAccumulator:record MaxCapacity:real; RechargeSource:TPowerSource end); CurrentCollector: (CollectorParameters: TCurrentCollector); PowerCable : (RPowerCable:record PowerTrans:TPowerType; SteamPressure:real end); Heater : (RHeater:record Grate:TGrateType; Boiler:TBoilerType end); end; {dla lokomotyw elektrycznych:} TScheme= record Relay: byte; {numer pozycji rozruchu samoczynnego} R: real; {opornik rozruchowy} {dla dizla napelnienie} Bn,Mn:byte; {ilosc galezi i silnikow w galezi} {dla dizla Mn: czy luz czy nie} AutoSwitch: boolean; {czy dana pozycja nastawniana jest recznie czy autom.} ScndAct: byte; {jesli ma bocznik w nastawniku, to ktory bocznik na ktorej pozycji} end; TSchemeTable = array[0..ResArraySize] of TScheme; {tablica rezystorow rozr.} TDEScheme= record RPM: real; {obroty diesla} GenPower: real; {moc maksymalna} Umax: real; {napiecie maksymalne} Imax: real; {prad maksymalny} end; TDESchemeTable = array[0..32] of TDEScheme; {tablica rezystorow rozr.} TShuntScheme = record Umin: real; Umax: real; Pmin: real; Pmax: real; end; TShuntSchemeTable = array[0..32] of TShuntScheme; TMPTRelay = record {lista przekaznikow bocznikowania} Iup: real; Idown: real; end; TMPTRelayTable = array[0..7] of TMPTRelay; TMotorParameters = record mfi,mIsat,mfi0:real; // aproksymacja M(I) silnika} {dla dizla mIsat=przekladnia biegu fi,Isat,fi0: real; // aproksymacja E(n)=fi*n} {dla dizla fi, mfi: predkosci przelozenia biegu <-> AutoSwitch: boolean; end; TSecuritySystem= record SystemType:byte; {0: brak, 1: czuwak aktywny, 2: SHP/sygnalizacja kabinowa} AwareDelay:real; //czas powtarzania czuwaka AwareMinSpeed:real; //minimalna prędkość załączenia czuwaka, normalnie 10% Vmax SoundSignalDelay,EmergencyBrakeDelay:real; Status: byte; {0: wylaczony, 1: wlaczony, 2: czuwak, 4: shp, 8: alarm, 16: hamowanie awaryjne} //SystemTimer, SystemSoundTimer, SystemBrakeTimer: real; SystemTimer, SystemSoundCATimer, SystemSoundSHPTimer, SystemBrakeCATimer, SystemBrakeSHPTimer, SystemBrakeCATestTimer: real; //hunter-091012 VelocityAllowed, NextVelocityAllowed: integer; {predkosc pokazywana przez sygnalizacje kabinowa} RadioStop:boolean; //czy jest RadioStop end; //Ra: to oddzielnie, bo się kompilatorowi miesza TTransmision= record //liczba zebow przekladni} NToothM, NToothW : byte; Ratio: real; {NToothW/NToothM} end; {sprzegi} TCouplerType=(NoCoupler,Articulated,Bare,Chain,Screw,Automatic); //Ra: T_MoverParameters jako klasa jest już wskaźnikiem na poziomie Pascala //P_MoverParameters=^T_MoverParameters T_MoverParameters=class; TCoupling = record {parametry} SpringKB,SpringKC,beta:real; {stala sprezystosci zderzaka/sprzegu, %tlumiennosci } DmaxB,FmaxB,DmaxC,FmaxC: real; {tolerancja scisku/rozciagania, sila rozerwania} CouplerType: TCouplerType; {typ sprzegu} {zmienne} CouplingFlag : byte; {0 - wirtualnie, 1 - sprzegi, 2 - pneumatycznie, 4 - sterowanie, 8 - kabel mocy} AllowedFlag : Integer; //Ra: znaczenie jak wyżej, maska dostępnych Render: boolean; {ABu: czy rysowac jak zaczepiony sprzeg} CoupleDist: real; {ABu: optymalizacja - liczenie odleglosci raz na klatkę, bez iteracji} Connected: T_MoverParameters; {co jest podlaczone} ConnectedNr: byte; //Ra: od której strony podłączony do (Connected): 0=przód, 1=tył CForce: real; {sila z jaka dzialal} Dist: real; {strzalka ugiecia zderzaków} CheckCollision: boolean; {czy sprawdzac sile czy pedy} end; //TCouplers= array[0..1] of TCoupling; //TCouplerNr= array[0..1] of byte; //ABu: nr sprzegu z ktorym polaczony; Ra: wrzucić do TCoupling {----------------------------------------------} {glowny obiekt} T_MoverParameters = class(TObject) //Ra: dodana kreska w celu zrobienia wrappera dMoveLen:real; filename:string; {---opis lokomotywy, wagonu itp} {--opis serii--} CategoryFlag: byte; {1 - pociag, 2 - samochod, 4 - statek, 8 - samolot} {--sekcja stalych typowych parametrow} TypeName: string; {nazwa serii/typu} //TrainType: string; {typ: EZT/elektrowoz - Winger 040304} TrainType: integer; {Ra: powinno być szybciej niż string} EngineType: TEngineTypes; {typ napedu} EnginePowerSource: TPowerParameters; {zrodlo mocy dla silnikow} SystemPowerSource: TPowerParameters; {zrodlo mocy dla systemow sterowania/przetwornic/sprezarek} HeatingPowerSource: TPowerParameters; {zrodlo mocy dla ogrzewania} AlterHeatPowerSource: TPowerParameters; {alternatywne zrodlo mocy dla ogrzewania} LightPowerSource: TPowerParameters; {zrodlo mocy dla oswietlenia} AlterLightPowerSource: TPowerParameters;{alternatywne mocy dla oswietlenia} Vmax,Mass,Power: real; {max. predkosc kontrukcyjna, masa wlasna, moc} Mred: real; {Ra: zredukowane masy wirujące; potrzebne do obliczeń hamowania} TotalMass:real; {wyliczane przez ComputeMass} HeatingPower, LightPower: real; {moc pobierana na ogrzewanie/oswietlenie} BatteryVoltage: real; {Winger - baterie w elektrykach} Battery: boolean; {Czy sa zalavzone baterie} EpFuse: boolean; {Czy sa zalavzone baterie} Signalling: boolean; {Czy jest zalaczona sygnalizacja hamowania ostatniego wagonu} DoorSignalling: boolean; {Czy jest zalaczona sygnalizacja blokady drzwi} Radio: boolean; {Czy jest zalaczony radiotelefon} NominalBatteryVoltage: real; {Winger - baterie w elektrykach} Dim: TDimension; {wymiary} Cx: real; {wsp. op. aerodyn.} Floor: real; //poziom podłogi dla ładunków WheelDiameter : real; {srednica kol napednych} WheelDiameterL : real; //Ra: srednica kol tocznych przednich WheelDiameterT : real; //Ra: srednica kol tocznych tylnych TrackW: real; {nominalna szerokosc toru [m]} AxleInertialMoment: real; {moment bezwladnosci zestawu kolowego} AxleArangement : string; {uklad osi np. Bo'Bo' albo 1'C} NPoweredAxles : byte; {ilosc osi napednych liczona z powyzszego} NAxles : byte; {ilosc wszystkich osi j.w.} BearingType: byte; {lozyska: 0 - slizgowe, 1 - toczne} ADist, BDist: real; {odlegosc osi oraz czopow skretu} {hamulce:} NBpA : byte; {ilosc el. ciernych na os: 0 1 2 lub 4} SandCapacity: integer; {zasobnik piasku [kg]} BrakeSystem: TBrakeSystem;{rodzaj hamulca zespolonego} BrakeSubsystem: TBrakeSubsystem; BrakeValve: TBrakeValve; BrakeHandle: TBrakeHandle; BrakeLocHandle: TBrakeHandle; MBPM: real; {masa najwiekszego cisnienia} Hamulec: TBrake; Handle: THandle; LocHandle: THandle; Pipe, Pipe2: TReservoir; LocalBrake: TLocalBrake; {rodzaj hamulca indywidualnego} BrakePressureTable: TBrakePressureTable; {wyszczegolnienie cisnien w rurze} BrakePressureActual: TBrakePressure; //wartości ważone dla aktualnej pozycji kranu ASBType: byte; {0: brak hamulca przeciwposlizgowego, 1: reczny, 2: automat} TurboTest: byte; MaxBrakeForce: real; {maksymalna sila nacisku hamulca} MaxBrakePress: array[0..4] of real; //pomocniczy, proz, sred, lad, pp P2FTrans: real; TrackBrakeForce: real; {sila nacisku hamulca szynowego} BrakeMethod: byte; {flaga rodzaju hamulca} {max. cisnienie w cyl. ham., stala proporcjonalnosci p-K} HighPipePress,LowPipePress,DeltaPipePress: real; {max. i min. robocze cisnienie w przewodzie glownym oraz roznica miedzy nimi} CntrlPipePress: real; //ciśnienie z zbiorniku sterującym BrakeVolume, BrakeVVolume, VeselVolume: real; {pojemnosc powietrza w ukladzie hamulcowym, w ukladzie glownej sprezarki [m^3] } BrakeCylNo: integer; {ilosc cylindrow ham.} BrakeCylRadius, BrakeCylDist: real; BrakeCylMult: array[0..2] of real; LoadFlag: byte; {promien cylindra, skok cylindra, przekladnia hamulcowa} BrakeCylSpring: real; {suma nacisku sprezyn powrotnych, kN} BrakeSlckAdj: real; {opor nastawiacza skoku tloka, kN} BrakeRigEff: real; {sprawnosc przekladni dzwigniowej} RapidMult: real; {przelozenie rapidu} BrakeValveSize: integer; BrakeValveParams: string; Spg: real; MinCompressor,MaxCompressor,CompressorSpeed:real; {cisnienie wlaczania, zalaczania sprezarki, wydajnosc sprezarki} BrakeDelay: TBrakeDelayTable; {opoznienie hamowania/odhamowania t/o} BrakeCtrlPosNo:byte; {ilosc pozycji hamulca} {nastawniki:} MainCtrlPosNo: byte; {ilosc pozycji nastawnika} ScndCtrlPosNo: byte; LightsPosNo, LightsDefPos: byte; LightsWrap: boolean; Lights: array [0..1] of array [1..16] of byte; ScndInMain: boolean; {zaleznosc bocznika od nastawnika} MBrake: boolean; {Czy jest hamulec reczny} StopBrakeDecc: real; SecuritySystem: TSecuritySystem; {-sekcja parametrow dla lokomotywy elektrycznej} RList: TSchemeTable; {lista rezystorow rozruchowych i polaczen silnikow, dla dizla: napelnienia} RlistSize: integer; MotorParam: array[0..MotorParametersArraySize] of TMotorParameters; {rozne parametry silnika przy bocznikowaniach} {dla lokomotywy spalinowej z przekladnia mechaniczna: przelozenia biegow} Transmision : TTransmision; // record {liczba zebow przekladni} // NToothM, NToothW : byte; // Ratio: real; {NToothW/NToothM} // end; NominalVoltage: real; {nominalne napiecie silnika} WindingRes : real; u: real; //wspolczynnik tarcia yB wywalic!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!!! CircuitRes : real; {rezystancje silnika i obwodu} IminLo,IminHi: integer; {prady przelacznika automatycznego rozruchu, uzywane tez przez ai_driver} ImaxLo,ImaxHi: integer; {maksymalny prad niskiego i wysokiego rozruchu} nmax: real; {maksymalna dop. ilosc obrotow /s} InitialCtrlDelay, {ile sek. opoznienia po wl. silnika} CtrlDelay: real; { -//- -//- miedzy kolejnymi poz.} CtrlDownDelay: real; { -//- -//- przy schodzeniu z poz.} {hunter-101012} FastSerialCircuit: byte;{0 - po kolei zamyka styczniki az do osiagniecia szeregowej, 1 - natychmiastowe wejscie na szeregowa} {hunter-111012} AutoRelayType: byte; {0 -brak, 1 - jest, 2 - opcja} CoupledCtrl: boolean; {czy mainctrl i scndctrl sa sprzezone} //CouplerNr: TCouplerNr; {ABu: nr sprzegu podlaczonego w drugim obiekcie} IsCoupled: boolean; {czy jest sprzezony ale jedzie z tylu} DynamicBrakeType: byte; {patrz dbrake_*} RVentType: byte; {0 - brak, 1 - jest, 2 - automatycznie wlaczany} RVentnmax: real; {maks. obroty wentylatorow oporow rozruchowych} RVentCutOff: real; {rezystancja wylaczania wentylatorow dla RVentType=2} CompressorPower: integer; {0: bezp. z obwodow silnika, 1: z przetwornicy, reczne, 2: w przetwornicy, stale, 5: z silnikowego} SmallCompressorPower: integer; {Winger ZROBIC} Trafo: boolean; {pojazd wyposażony w transformator} {-sekcja parametrow dla lokomotywy spalinowej z przekladnia mechaniczna} dizel_Mmax, dizel_nMmax, dizel_Mnmax, dizel_nmax, dizel_nominalfill: real; {parametry aproksymacji silnika spalinowego} dizel_Mstand: real; {moment oporow ruchu silnika dla enrot=0} { dizel_auto_min, dizel_auto_max: real; {predkosc obrotowa przelaczania automatycznej skrzyni biegow} dizel_nmax_cutoff: real; {predkosc obrotowa zadzialania ogranicznika predkosci} dizel_nmin: real; {najmniejsza dopuszczalna predkosc obrotowa} dizel_minVelfullengage: real; {najmniejsza predkosc przy jezdzie ze sprzeglem bez poslizgu} dizel_AIM: real; {moment bezwladnosci walu itp} dizel_engageDia, dizel_engageMaxForce, dizel_engagefriction: real; {parametry sprzegla} {- dla lokomotyw spalinowo-elektrycznych -} AnPos: real; // pozycja sterowania dokladnego (analogowego) AnalogCtrl: boolean; // AnMainCtrl: boolean; // ShuntModeAllow: boolean; ShuntMode: boolean; Flat: boolean; Vhyp: real; DElist: TDESchemeTable; Vadd: real; MPTRelay: TMPTRelayTable; RelayType: byte; SST: TShuntSchemeTable; PowerCorRatio: real; //Wspolczynnik korekcyjny {- dla uproszczonego modelu silnika (dumb) oraz dla drezyny} Ftmax:real; {- dla lokomotyw z silnikami indukcyjnymi -} eimc: array [0..25] of real; {-dla wagonow} MaxLoad: longint; {masa w T lub ilosc w sztukach - ladownosc} LoadAccepted, LoadQuantity: string; {co moze byc zaladowane, jednostki miary} OverLoadFactor: real; {ile razy moze byc przekroczona ladownosc} LoadSpeed,UnLoadSpeed: real;{szybkosc na- i rozladunku jednostki/s} DoorOpenCtrl,DoorCloseCtrl: byte; {0: przez pasazera, 1: przez maszyniste, 2: samoczynne (zamykanie)} DoorStayOpen: real; {jak dlugo otwarte w przypadku DoorCloseCtrl=2} DoorClosureWarning: boolean; {czy jest ostrzeganie przed zamknieciem} DoorOpenSpeed, DoorCloseSpeed: real; {predkosc otwierania i zamykania w j.u. } DoorMaxShiftL,DoorMaxShiftR,DoorMaxPlugShift: real;{szerokosc otwarcia lub kat} DoorOpenMethod: byte; {sposob otwarcia - 1: przesuwne, 2: obrotowe, 3: trójelementowe} PlatformSpeed: real; {szybkosc stopnia} PlatformMaxShift: real; {wysuniecie stopnia} PlatformOpenMethod: byte; {sposob animacji stopnia} ScndS: boolean; {Czy jest bocznikowanie na szeregowej} {--sekcja zmiennych} {--opis konkretnego egzemplarza taboru} Loc: TLocation; //pozycja pojazdów do wyznaczenia odległości pomiędzy sprzęgami Rot: TRotation; Name: string; {nazwa wlasna} Couplers: array[0..1] of TCoupling; //urzadzenia zderzno-sprzegowe, polaczenia miedzy wagonami HVCouplers: array[0..1] of array[0..1] of real; //przewod WN ScanCounter: integer; {pomocnicze do skanowania sprzegow} EventFlag: boolean; {!o true jesli cos nietypowego sie wydarzy} SoundFlag: byte; {!o patrz stale sound_ } DistCounter: real; {! licznik kilometrow } V: real; //predkosc w [m/s] względem sprzęgów (dodania gdy jedzie w stronę 0) Vel: real; //moduł prędkości w [km/h], używany przez AI AccS: real; //efektywne przyspieszenie styczne w [m/s^2] (wszystkie siły) AccN: real; //przyspieszenie normalne w [m/s^2] AccV: real; nrot: real; {! rotacja kol [obr/s]} EnginePower: real; {! chwilowa moc silnikow} dL, Fb, Ff : real; {przesuniecie, sila hamowania i tarcia} FTrain,FStand: real; {! sila pociagowa i oporow ruchu} FTotal: real; {! calkowita sila dzialajaca na pojazd} UnitBrakeForce: real; {!s siła hamowania przypadająca na jeden element} Ntotal: real; {!s siła nacisku klockow} SlippingWheels,SandDose: boolean; {! poslizg kol, sypanie piasku} Sand: real; {ilosc piasku} BrakeSlippingTimer:real; {pomocnicza zmienna do wylaczania przeciwposlizgu} dpBrake,dpPipe,dpMainValve,dpLocalValve: real; {! przyrosty cisnienia w kroku czasowym} ScndPipePress: real; {cisnienie w przewodzie zasilajacym} BrakePress:real; {!o cisnienie w cylindrach hamulcowych} LocBrakePress:real; {!o cisnienie w cylindrach hamulcowych z pomocniczego} PipeBrakePress:real; {!o cisnienie w cylindrach hamulcowych z przewodu} PipePress: real; {!o cisnienie w przewodzie glownym} EqvtPipePress: real; {!o cisnienie w przewodzie glownym skladu} Volume: real; {objetosc spr. powietrza w zbiorniku hamulca} CompressedVolume:real; {objetosc spr. powietrza w ukl. zasilania} PantVolume:real; {objetosc spr. powietrza w ukl. pantografu} Compressor: real; {! cisnienie w ukladzie zasilajacym} CompressorFlag: boolean; {!o czy wlaczona sprezarka} PantCompFlag: boolean; {!o czy wlaczona sprezarka pantografow} CompressorAllow: boolean; {! zezwolenie na uruchomienie sprezarki NBMX} ConverterFlag: boolean; {! czy wlaczona przetwornica NBMX} ConverterAllow: boolean; {zezwolenie na prace przetwornicy NBMX} BrakeCtrlPos:integer; {nastawa hamulca zespolonego} BrakeCtrlPosR:real; {nastawa hamulca zespolonego - plynna dla FV4a} BrakeCtrlPos2:real; {nastawa hamulca zespolonego - kapturek dla FV4a} LocalBrakePos:byte; {nastawa hamulca indywidualnego} ManualBrakePos:byte; {nastawa hamulca recznego} LocalBrakePosA: real; BrakeStatus: byte; {0 - odham, 1 - ham., 2 - uszk., 4 - odluzniacz, 8 - antyposlizg, 16 - uzyte EP, 32 - pozycja R, 64 - powrot z R} EmergencyBrakeFlag: boolean; {hamowanie nagle} BrakeDelayFlag: byte; {nastawa opoznienia ham. osob/towar/posp/exp 0/1/2/4} BrakeDelays: byte; {nastawy mozliwe do uzyskania} BrakeOpModeFlag: byte; {nastawa trybu pracy PS/PN/EP/MED 1/2/4/8} BrakeOpModes: byte; {nastawy mozliwe do uzyskania} DynamicBrakeFlag: boolean; {czy wlaczony hamulec elektrodymiczny} // NapUdWsp: integer; LimPipePress: real; {stabilizator cisnienia} ActFlowSpeed: real; {szybkosc stabilizatora} DamageFlag: byte; //kombinacja bitowa stalych dtrain_* } EngDmgFlag: byte; //kombinacja bitowa stalych usterek} DerailReason: byte; //przyczyna wykolejenia //EndSignalsFlag: byte; {ABu 060205: zmiany - koncowki: 1/16 - swiatla prz/tyl, 2/31 - blachy prz/tyl} //HeadSignalsFlag: byte; {ABu 060205: zmiany - swiatla: 1/2/4 - przod, 16/32/63 - tyl} CommandIn: TCommand; {komenda przekazywana przez PutCommand} {i wykonywana przez RunInternalCommand} CommandOut: string; {komenda przekazywana przez ExternalCommand} CommandLast: string; //Ra: ostatnio wykonana komenda do podglądu ValueOut: real; {argument komendy która ma byc przekazana na zewnatrz} RunningShape:TTrackShape;{geometria toru po ktorym jedzie pojazd} RunningTrack:TTrackParam;{parametry toru po ktorym jedzie pojazd} OffsetTrackH, OffsetTrackV: real; {przesuniecie poz. i pion. w/m osi toru} {-zmienne dla lokomotyw} Mains: boolean; {polozenie glownego wylacznika} MainCtrlPos: byte; {polozenie glownego nastawnika} ScndCtrlPos: byte; {polozenie dodatkowego nastawnika} LightsPos: byte; ActiveDir: integer; //czy lok. jest wlaczona i w ktorym kierunku: //względem wybranej kabiny: -1 - do tylu, +1 - do przodu, 0 - wylaczona CabNo: integer; //numer kabiny, z której jest sterowanie: 1 lub -1; w przeciwnym razie brak sterowania - rozrzad DirAbsolute: integer; //zadany kierunek jazdy względem sprzęgów (1=w strone 0,-1=w stronę 1) ActiveCab: integer; //numer kabiny, w ktorej jest obsada (zwykle jedna na skład) LastSwitchingTime: real; {czas ostatniego przelaczania czegos} //WarningSignal: byte; {0: nie trabi, 1,2: trabi} DepartureSignal: boolean; {sygnal odjazdu} InsideConsist: boolean; {-zmienne dla lokomotywy elektrycznej} RunningTraction:TTractionParam;{parametry sieci trakcyjnej najblizej lokomotywy} enrot, Im, Itot,IHeating,ITraction, TotalCurrent, Mm, Mw, Fw, Ft: real; {ilosc obrotow, prad silnika i calkowity, momenty, sily napedne} //Ra: Im jest ujemny, jeśli lok jedzie w stronę sprzęgu 1 //a ujemne powinien być przy odwróconej polaryzacji sieci... //w wielu miejscach jest używane abs(Im) Imin,Imax: integer; {prad przelaczania automatycznego rozruchu, prad bezpiecznika} Voltage: real; {aktualne napiecie sieci zasilajacej} MainCtrlActualPos: byte; {wskaznik RList} ScndCtrlActualPos: byte; {wskaznik MotorParam} DelayCtrlFlag: boolean; //czy czekanie na 1. pozycji na załączenie? LastRelayTime: real; {czas ostatniego przelaczania stycznikow} AutoRelayFlag: boolean; {mozna zmieniac jesli AutoRelayType=2} FuseFlag: boolean; {!o bezpiecznik nadmiarowy} ConvOvldFlag: boolean; {! nadmiarowy przetwornicy i ogrzewania} StLinFlag: boolean; {!o styczniki liniowe} ResistorsFlag: boolean; {!o jazda rezystorowa} RventRot: real; {!s obroty wentylatorow rozruchowych} UnBrake: boolean; {w EZT - nacisniete odhamowywanie} PantPress: real; {Cisnienie w zbiornikach pantografow} s_CAtestebrake: boolean; //hunter-091012: zmienna dla testu ca {-zmienne dla lokomotywy spalinowej z przekladnia mechaniczna} dizel_fill: real; {napelnienie} dizel_engagestate: real; {sprzeglo skrzyni biegow: 0 - luz, 1 - wlaczone, 0.5 - wlaczone 50% (z poslizgiem)} dizel_engage: real; {sprzeglo skrzyni biegow: aktualny docisk} dizel_automaticgearstatus: real; {0 - bez zmiany, -1 zmiana na nizszy +1 zmiana na wyzszy} dizel_enginestart: boolean; {czy trwa rozruch silnika} dizel_engagedeltaomega: real; {roznica predkosci katowych tarcz sprzegla} {- zmienne dla lokomotyw z silnikami indukcyjnymi -} eimv: array [0..20] of real; {-zmienne dla drezyny} PulseForce :real; {przylozona sila} PulseForceTimer: real; PulseForceCount: integer; {dla drezyny, silnika spalinowego i parowego} eAngle: real; {-dla wagonow} Load: longint; {masa w T lub ilosc w sztukach - zaladowane} LoadType: string; {co jest zaladowane} LoadStatus: byte; //+1=trwa rozladunek,+2=trwa zaladunek,+4=zakończono,0=zaktualizowany model LastLoadChangeTime: real; //raz (roz)ładowania DoorBlocked: boolean; //Czy jest blokada drzwi DoorLeftOpened: boolean; //stan drzwi DoorRightOpened: boolean; PantFrontUp: boolean; //stan patykow 'Winger 160204 PantRearUp: boolean; PantFrontSP: boolean; //dzwiek patykow 'Winger 010304 PantRearSP: boolean; PantFrontStart: integer; //stan patykow 'Winger 160204 PantRearStart: integer; PantFrontVolt: real; //pantograf pod napieciem? 'Winger 160404 PantRearVolt: real; PantSwitchType: string; ConvSwitchType: string; Heating: boolean; //ogrzewanie 'Winger 020304 DoubleTr: integer; //trakcja ukrotniona - przedni pojazd 'Winger 160304 PhysicActivation: boolean; {ABu: stale dla wyznaczania sil (i nie tylko) po optymalizacji} FrictConst1: real; FrictConst2s: real; FrictConst2d: real; TotalMassxg : real; {TotalMass*g} {--funkcje} function GetTrainsetVoltage: real; function Physic_ReActivation: boolean; { function BrakeRatio: real; } function LocalBrakeRatio: real; function ManualBrakeRatio: real; function PipeRatio: real; {ile napelniac} function RealPipeRatio: real; {jak szybko} function BrakeVP: real; function DynamicBrakeSwitch(Switch:boolean):boolean; {! przesylanie komend sterujacych} function SendCtrlBroadcast(CtrlCommand:string; ctrlvalue:real):boolean; function SendCtrlToNext(CtrlCommand:string;ctrlvalue,dir:real):boolean; function CabActivisation:boolean; function CabDeactivisation:boolean; {! funkcje zwiekszajace/zmniejszajace nastawniki} {! glowny nastawnik:} function IncMainCtrl(CtrlSpeed:integer): boolean; function DecMainCtrl(CtrlSpeed:integer): boolean; {! pomocniczy nastawnik:} function IncScndCtrl(CtrlSpeed:integer): boolean; function DecScndCtrl(CtrlSpeed:integer): boolean; function AddPulseForce(Multipler:integer): boolean; {dla drezyny} {wlacza/wylacza sypanie piasku} function SandDoseOn : boolean; {! zbijanie czuwaka/SHP} function SecuritySystemReset:boolean; {test czuwaka/SHP} procedure SecuritySystemCheck(dt:real); function BatterySwitch(State:boolean):boolean; function EpFuseSwitch(State:boolean):boolean; {! stopnie hamowania - hamulec zasadniczy} function IncBrakeLevelOld:boolean; function DecBrakeLevelOld:boolean; {! stopnie hamowania - hamulec pomocniczy} function IncLocalBrakeLevel(CtrlSpeed:byte):boolean; function DecLocalBrakeLevel(CtrlSpeed:byte):boolean; {! ABu 010205: - skrajne polozenia ham. pomocniczego} function IncLocalBrakeLevelFAST:boolean; function DecLocalBrakeLevelFAST:boolean; {! stopnie hamowania - hamulec reczny} function IncManualBrakeLevel(CtrlSpeed:byte):boolean; function DecManualBrakeLevel(CtrlSpeed:byte):boolean; {! hamulec bezpieczenstwa} function EmergencyBrakeSwitch(Switch:boolean): boolean; {hamulec przeciwposlizgowy} function AntiSlippingBrake: boolean; {odluzniacz} function BrakeReleaser(state: byte):boolean; function SwitchEPBrake(state: byte):boolean; {! reczny wlacznik urzadzen antyposlizgowych} function AntiSlippingButton: boolean; {funkcje dla ukladow pneumatycznych} function IncBrakePress(var brake:real;PressLimit,dp:real):boolean; function DecBrakePress(var brake:real;PressLimit,dp:real):boolean; function BrakeDelaySwitch(BDS:byte): boolean; {! przelaczanie nastawy opoznienia} function IncBrakeMult(): boolean; {przelaczanie prozny/ladowny} function DecBrakeMult(): boolean; {pomocnicze funkcje dla ukladow pneumatycznych} procedure UpdateBrakePressure(dt: real); procedure UpdatePipePressure(dt:real); procedure CompressorCheck(dt:real); {wlacza, wylacza kompresor, laduje zbiornik} procedure UpdateScndPipePressure(dt:real); //procedure UpdateBatteryVoltage(dt:real); function GetDVc(dt:real):real; {! funkcje laczace/rozlaczajace sprzegi} //Ra: przeniesione do C++ {funkcje obliczajace sily} procedure ComputeConstans; //ABu: wczesniejsze wyznaczenie stalych dla liczenia sil //procedure SetCoupleDist; //ABu: wyznaczenie odleglosci miedzy wagonami function ComputeMass:real; function Adhesive(staticfriction:real): real; function TractionForce(dt:real):real; function FrictionForce(R:real;TDamage:byte):real; function BrakeForce(Track:TTrackParam):real; function CouplerForce(CouplerN:byte; dt:real):real; procedure CollisionDetect(CouplerN:byte; dt:real); {obrot kol uwzgledniajacy poslizg} function ComputeRotatingWheel(WForce,dt,n:real): real; {komendy} function SetInternalCommand(NewCommand:string; NewValue1,NewValue2:real):boolean; {! do wpisywania komend przez zewnetrzne zdarzenia} function GetExternalCommand(var Command:string):real; function RunCommand(command:string; CValue1,CValue2:real):boolean; function RunInternalCommand:boolean; procedure PutCommand(NewCommand:string; NewValue1,NewValue2:real; NewLocation:TLocation); {--funkcje dla lokomotyw} {! kierunek ruchu} //function DirectionForward: boolean; function DirectionBackward: boolean; {! wylacznik glowny} function MainSwitch(State:boolean): boolean; // procedure SwitchMainKey; {! zmiana kabiny i resetowanie ustawien} //function ChangeCab(direction:integer): boolean; {! wl/wyl przetwornicy} function ConverterSwitch(State:boolean):boolean; {! wl/wyl sprezarki} function CompressorSwitch(State:boolean):boolean; { function SmallCompressorSwitch(State:boolean):boolean;} {procedure ConverterCheck; ->C++} {-funkcje typowe dla lokomotywy elektrycznej} {! wlaczanie bezpiecznika nadmiarowego} function FuseOn: boolean; function FuseFlagCheck: boolean; {sprawdzanei flagi nadmiarowego} procedure FuseOff; {wywalanie bezpiecznika nadmiarowego} {!o pokazuje bezwgl. wartosc pradu na wybranym amperomierzu} function ShowCurrent(AmpN:byte): integer; {!o pokazuje bezwgl. wartosc obrotow na obrotomierzu jednego z 3 pojazdow} {function ShowEngineRotation(VehN:byte): integer; //Ra 2014-06: przeniesione do C++} {funkcje uzalezniajace sile pociagowa od predkosci: v2n, n2r, current, momentum} function v2n:real; function current(n,U:real): real; function Momentum(I:real): real; function MomentumF(I, Iw :real; SCP:byte ): real; {! odlaczanie uszkodzonych silnikow} function CutOffEngine: boolean; {! przelacznik pradu wysokiego rozruchu} function MaxCurrentSwitch(State:boolean):boolean; {sprawdzanie kontrolki rezystorow rozrochowych NBMX} function ResistorsFlagCheck: boolean; {! przelacznik pradu automatycznego rozruchu} function MinCurrentSwitch(State:boolean):boolean; {! przelacznik automatycznego rozruchu} function AutoRelaySwitch(State:boolean):boolean; {symulacja automatycznego rozruchu} function AutoRelayCheck: boolean; {-funkcje typowe dla lokomotywy spalinowej z przekladnia mechaniczna} function dizel_EngageSwitch(state: real): boolean; function dizel_EngageChange(dt: real): boolean; function dizel_AutoGearCheck: boolean; function dizel_fillcheck(mcp:byte): real; { function dizel_rotateengine(Momentum,dt,n,engage:real): real; } function dizel_Momentum(dizel_fill,n,dt:real): real; function dizel_Update(dt:real): boolean; {-funkcje dla wagonow} function LoadingDone(LSpeed: real; LoadInit:string):boolean; {! WAZNA FUNKCJA - oblicza sile wypadkowa} procedure ComputeTotalForce(dt: real; dt1: real; FullVer: boolean); {! BARDZO WAZNA FUNKCJA - oblicza przesuniecie lokomotywy lub wagonu} function ComputeMovement(dt:real; dt1:real; Shape:TTrackShape; var Track:TTrackParam; var ElectricTraction:TTractionParam; NewLoc:TLocation; var NewRot:TRotation):real; {dt powinno byc 10ms lub mniejsze} {NewRot na wejsciu daje aktualna orientacje pojazdu, na wyjsciu daje dodatkowe wychylenia od tej orientacji} {! JESZCZE WAZNIEJSZA FUNKCJA - ABu: - mocno zoptymalizowanana ComputeMovement} function FastComputeMovement(dt:real; Shape:TTrackShape; var Track:TTrackParam; NewLoc:TLocation; var NewRot:TRotation):real; //Shape:TTrackShape; var Track:TTrackParam; var ElectricTraction:TTractionParam; NewLoc:TLocation; var NewRot:TRotation):real; {dt powinno byc 10ms lub mniejsze} {NewRot na wejsciu daje aktualna orientacje pojazdu, na wyjsciu daje dodatkowe wychylenia od tej orientacji} {dla samochodow} function ChangeOffsetH(DeltaOffset:real): boolean; {! procedury I/O} constructor Init(//LocInitial:TLocation; RotInitial:TRotation; VelInitial:real; TypeNameInit, NameInit: string; LoadInitial:longint; LoadTypeInitial: string; Cab:integer); {wywolac najpierw to} function LoadChkFile(chkpath:string):Boolean; {potem zaladowac z pliku} function CheckLocomotiveParameters(ReadyFlag:boolean;Dir:longint): boolean; {a nastepnie sprawdzic} function EngineDescription(what:integer): string; {opis stanu lokomotywy} {obsluga drzwi} function DoorLeft(State: Boolean): Boolean; {obsluga dzwi lewych} function DoorRight(State: Boolean): Boolean; function DoorBlockedFlag: Boolean; //czy blokada drzwi jest aktualnie załączona {obsluga pantografow - Winger 160204} function PantFront(State: Boolean): Boolean; function PantRear(State: Boolean): Boolean; {ogrzewanie - Winger 020304} //function Heating(State: Boolean): Boolean; //private //function TotalMass:real; { function GetFTotal(CN:byte): real; function GetMass(CN:byte): real; procedure SendAVL(AccS,AccN,V,dL:real; CN:byte); } end; {ufff} function Distance(Loc1,Loc2: TLocation; Dim1,Dim2:TDimension) : real; {----------------------------------------------------------------} {========================McZapkie'2001===========================} {----------------------------------------------------------------} implementation const Steel2Steel_friction=0.15; {tarcie statyczne} g=9.81; {przyspieszenie ziemskie} SandSpeed=0.1; {ile kg/s} RVentSpeed=0.4; {rozpedzanie sie wentylatora obr/s^2} RVentMinI=50.0; {przy jakim pradzie sie wylaczaja} CouplerTune:real=0.1; {skalowanie tlumiennosci} Pirazy2=Pi*2; {------------------------------------------} {funkcje pomocnicze} function s2NPW(s:string):byte; {wylicza ilosc osi napednych ze stringu opisujacego uklad osi} {np. 2'A' daje 1, Bo'Bo' daje 4, 1'E daje 5 itp} const A=ord('A')-1; var k,NPW:byte; begin NPW:=0; for k:=1 to Length(s) do begin if s[k] in ['A'..'Z'] then NPW:=NPW+Ord(s[k])-A; end; s2NPW:=NPW; end; function s2NNW(s:string):byte; {wylicza ilosc osi nienapednych ze stringu opisujacego uklad osi} {np. 2'A' daje 2, Bo'Bo' daje 0, 1'E daje 1 itp} const Zero=ord('0'); var k,NNW:byte; begin NNW:=0; for k:=1 to Length(s) do begin if s[k] in ['1'..'9'] then NNW:=NNW+Ord(s[k])-Zero; end; s2NNW:=NNW; end; function Distance(Loc1,Loc2:TLocation;Dim1,Dim2:TDimension):real; //zwraca odległość pomiędzy pojazdami (Loc1) i (Loc2) z uwzględnieneim ich długości (kule!) var Dist:real; begin Dist:=SQRT(SQR(Loc2.x-Loc1.x)+SQR(Loc1.y-Loc2.y)); Distance:=Dist-Dim2.L/2.0-Dim1.L/2.0; { Distance:=Hypot(Loc2.x-Loc1.x,Loc2.y-Loc1.y)-(Dim2.L+Dim1.L)/2; } end; {oblicza zmiane predkosci i przyrost pedu wskutek kolizji} function ComputeCollision(var v1,v2:real; m1,m2,beta:real;vc:boolean):real; var CCP,w1,w2,m1m2:real; begin if (v1Coupler2) then DirPatch:=1 else DirPatch:=-1; end; function DirF(CouplerN:byte): real; begin case CouplerN of 0: DirF:=-1; 1: DirF:=1 else DirF:=0; end; end; {yB: funkcje dodatkowe hamulcowe} function PR(p1,p2:real): real; var ph,pl:real; begin ph:=Max0R(p1,p2)+0.1; pl:=p1+p2-ph+0.2; PR:=(ph-pl)/(1.13*ph-pl); end; function SPR(ph,pl:real): real; begin SPR:=0.674*(ph-pl)/(1.13*ph-pl+0.013); end; {---------rozwiniecie deklaracji metod obiektu T_MoverParameters--------} (* function T_MoverParameters.GetTrainsetVoltage: real; //ABu: funkcja zwracajaca napiecie dla calego skladu, przydatna dla EZT var volt: real; begin volt:=0.0; if Couplers[1].Connected<>nil then if (TestFlag(Couplers[1].CouplingFlag,ctrain_power)) then //czy jest sprzęg WN begin //najczęściej silnikowy jest z tyłu if (Couplers[1].Connected.PantFrontVolt<>0.0) then volt:=Couplers[1].Connected.PantFrontVolt else if (Couplers[1].Connected.PantRearVolt<>0.0) then volt:=Couplers[1].Connected.PantRearVolt; end; if (volt=0.0) then if Couplers[0].Connected<>nil then if (TestFlag(Couplers[0].CouplingFlag,ctrain_power)) then //czy jest sprzęg WN begin if (Couplers[0].Connected.PantFrontVolt<>0.0) then volt:=Couplers[0].Connected.PantFrontVolt else if (Couplers[0].Connected.PantRearVolt<>0.0) then volt:=Couplers[0].Connected.PantRearVolt; end; GetTrainsetVoltage:=volt; end; *) function T_MoverParameters.GetTrainsetVoltage: real; //ABu: funkcja zwracajaca napiecie dla calego skladu, przydatna dla EZT //var volt: real; begin GetTrainsetVoltage:=Max0R(HVCouplers[1][1],HVCouplers[0][1]); end; function T_MoverParameters.Physic_ReActivation: boolean; begin if PhysicActivation then Physic_Reactivation:=false else begin PhysicActivation:=true; LastSwitchingTime:=0; Physic_Reactivation:=true; end; end; {stosunek obecnego nastawienia sily hamowania do maksymalnej nastawy} { function T_MoverParameters.BrakeRatio: real; begin if BrakeCtrlPosNo>0 then begin if BrakeCtrlPos<0 then BrakeRatio:=1 else BrakeRatio:=1-BrakeCtrlPos/BrakeCtrlPosNo end else BrakeRatio:=0; end; } function T_MoverParameters.LocalBrakeRatio: real; var LBR:real; begin if BrakeHandle=MHZ_EN57 then if (BrakeOpModeFlag>=bom_EP) then LBR:=(Handle as TMHZ_EN57).GetEP(BrakeCtrlPosR) else LBR:=0 else if LocalBrakePosNo>0 then LBR:=LocalBrakePos/LocalBrakePosNo else LBR:=0; // if TestFlag(BrakeStatus,b_antislip) then // LBR:=Max0R(LBR,PipeRatio)+0.4; LocalBrakeRatio:=LBR; end; function T_MoverParameters.ManualBrakeRatio: real; var MBR:real; begin if ManualBrakePosNo>0 then MBR:=ManualBrakePos/ManualBrakePosNo else MBR:=0; ManualBrakeRatio:=MBR; end; function T_MoverParameters.PipeRatio: real; var pr:real; begin if DeltaPipePress>0 then if (false) then //SPKS!! begin if (3*PipePress)>(HighPipePress+LowPipePress+LowPipePress) then pr:=(HighPipePress-Min0R(HighPipePress,PipePress))/(DeltaPipePress*4.0/3.0) else pr:=(HighPipePress-1.0/3.0*DeltaPipePress-Max0R(LowPipePress,PipePress))/(DeltaPipePress*2.0/3.0); // if (not TestFlag(BrakeStatus,b_Ractive)) and (BrakeMethod and 1 = 0) and TestFlag(BrakeDelays,bdelay_R) and (Power<1) and (BrakeCtrlPos<1) then // pr:=Min0R(0.5,pr); //if (Compressor>0.5) then // pr:=pr*1.333; //dziwny rapid wywalamy end else pr:=(HighPipePress-Max0R(LowPipePress,Min0R(HighPipePress,PipePress)))/DeltaPipePress else pr:=0; PipeRatio:=pr; end; function T_MoverParameters.RealPipeRatio: real; var rpp:real; begin if DeltaPipePress>0 then rpp:=(CntrlPipePress-PipePress)/(DeltaPipePress) else rpp:=0; RealPipeRatio:=rpp; end; function T_MoverParameters.BrakeVP: real; begin if BrakeVVolume>0 then BrakeVP:=Volume/(10.0*BrakeVVolume) else BrakeVP:=0; end; {reczne przelaczanie hamulca elektrodynamicznego} function T_MoverParameters.DynamicBrakeSwitch(Switch:boolean):boolean; var b:byte; begin if (DynamicBrakeType=dbrake_switch) and (MainCtrlPos=0) then begin DynamicBrakeFlag:=Switch; DynamicBrakeSwitch:=true; for b:=0 to 1 do with Couplers[b] do if TestFlag(CouplingFlag,ctrain_controll) then Connected.DynamicBrakeFlag:=DynamicBrakeFlag; {end; if (DynamicBrakeType=dbrake_passive) and (TrainType=dt_ET42) then begin DynamicBrakeFlag:=false; DynamicBrakeSwitch:=false;} end else DynamicBrakeSwitch:=false; end; function T_MoverParameters.SendCtrlBroadcast(CtrlCommand:string;ctrlvalue:real):boolean; var b:byte; OK:boolean; begin OK:=((CtrlCommand<>CommandIn.Command) and (ctrlvalue<>CommandIn.Value1)); if OK then for b:=0 to 1 do with Couplers[b] do if TestFlag(CouplingFlag,ctrain_controll) then if Connected.SetInternalCommand(CtrlCommand,ctrlvalue,DirF(b)) then OK:=Connected.RunInternalCommand or OK; SendCtrlBroadcast:=OK; end; function T_MoverParameters.SendCtrlToNext(CtrlCommand:string;ctrlvalue,dir:real):boolean; //wysłanie komendy w kierunku dir (1=przod,-1=tył) do kolejnego pojazdu (jednego) var OK:Boolean; d:Integer; //numer sprzęgu w kierunku którego wysyłamy begin //Ra: był problem z propagacją, jeśli w składzie jest pojazd wstawiony odwrotnie //Ra: problem jest również, jeśli AI będzie na końcu składu OK:=(dir<>0); // and Mains; d:=(1+Sign(dir)) div 2; //dir=-1=>d=0, dir=1=>d=1 - wysyłanie tylko w tył if OK then //musi być wybrana niezerowa kabina with Couplers[d] do //własny sprzęg od strony (d) if TestFlag(CouplingFlag,ctrain_controll) then if ConnectedNr<>d then //jeśli ten nastpęny jest zgodny z aktualnym begin if Connected.SetInternalCommand(CtrlCommand,ctrlvalue,dir) then OK:=Connected.RunInternalCommand and OK; //tu jest rekurencja end else //jeśli następny jest ustawiony przeciwnie, zmieniamy kierunek if Connected.SetInternalCommand(CtrlCommand,ctrlvalue,-dir) then OK:=Connected.RunInternalCommand and OK; //tu jest rekurencja SendCtrlToNext:=OK; end; function T_MoverParameters.CabActivisation:boolean; //załączenie rozrządu var OK:boolean; begin OK:=(CabNo=0); //numer kabiny, z której jest sterowanie if (OK) then begin CabNo:=ActiveCab; //sterowanie jest z kabiny z obsadą DirAbsolute:=ActiveDir*CabNo; SendCtrlToNext('CabActivisation',1,CabNo); end; CabActivisation:=OK; end; function T_MoverParameters.CabDeactivisation:boolean; //wyłączenie rozrządu var OK:boolean; begin OK:=(CabNo=ActiveCab); //o ile obsada jest w kabinie ze sterowaniem if (OK) then begin CabNo:=0; DirAbsolute:=ActiveDir*CabNo; DepartureSignal:=false; //nie buczeć z nieaktywnej kabiny SendCtrlToNext('CabActivisation',0,ActiveCab); //CabNo==0! end; CabDeactivisation:=OK; end; { procedure MainCtrlBroadcast(Couplers:TCouplers; MainCtrlPos,MainCtrlActualPos:byte); var b:byte; begin for b:=0 to 1 do with Couplers[b] do if TestFlag(CouplingFlag,ctrain_controll) then begin Connected^.MainCtrlPos:=MainCtrlPos; Connected^.MainCtrlActualPos:=MainCtrlActualPos; end; poprawic to!!! end; procedure ScndCtrlBroadcast(Couplers:TCouplers; ScndCtrlPos,ScndCtrlActualPos:byte); var b:byte; begin for b:=0 to 1 do with Couplers[b] do if TestFlag(CouplingFlag,ctrain_controll) then begin Connected^.ScndCtrlPos:=ScndCtrlPos; Connected^.ScndCtrlActualPos:=ScndCtrlActualPos; end; end; } {funkcje zwiekszajace/zmniejszajace nastawniki} function T_MoverParameters.IncMainCtrl(CtrlSpeed:integer): boolean; var //b:byte; OK:boolean; begin OK:=false; if (MainCtrlPosNo>0) and (CabNo<>0) then begin if MainCtrlPosdt_ET22) or ((TrainType=dt_ET22) and (ScndCtrlPos=0)) then //w ET22 nie da się kręcić nastawnikiem przy włączonym boczniku case EngineType of None, Dumb, DieselElectric, ElectricInductionMotor: if ((CtrlSpeed=1) and (TrainType<>dt_EZT)) or ((CtrlSpeed=1) and (TrainType=dt_EZT)and (activedir<>0)) then begin //w EZT nie da się załączyć pozycji bez ustawienia kierunku inc(MainCtrlPos); OK:=true; end else if ((CtrlSpeed>1) and (TrainType<>dt_EZT)) or ((CtrlSpeed>1) and (TrainType=dt_EZT)and (activedir<>0)) then OK:=IncMainCtrl(1) and IncMainCtrl(CtrlSpeed-1); ElectricSeriesMotor: if (CtrlSpeed=1) and (ActiveDir<>0) then begin inc(MainCtrlPos); OK:=true; if Imax=ImaxHi then if RList[MainCtrlPos].Bn>1 then begin if(TrainType=dt_ET42)then begin dec(MainCtrlPos); OK:=false; end; if MaxCurrentSwitch(false) then SetFlag(SoundFlag,sound_relay); {wylaczanie wysokiego rozruchu} { if (EngineType=ElectricSeriesMotor) and (MainCtrlPos=1) then MainCtrlActualPos:=1; } end; if (CtrlSpeed=1) and (ActiveDir=-1) and (RList[MainCtrlPos].Bn>1) and (TrainType<>dt_pseudodiesel) then begin //blokada wejścia na równoległą podczas jazdy do tyłu dec(MainCtrlPos); OK:=false; end; {if (TrainType='et40') then if Abs(Im)>IminHi then begin dec(MainCtrlPos); //Blokada nastawnika po przekroczeniu minimalnego pradu OK:=false; end; } if(DynamicBrakeFlag)then if(TrainType=dt_ET42)then if MainCtrlPos>20 then begin dec(MainCtrlPos); OK:=false; end; end else if (CtrlSpeed>1) and (ActiveDir<>0) {and (ScndCtrlPos=0)} and (TrainType<>dt_ET40) then begin //szybkie przejście na bezoporową while (RList[MainCtrlPos].R>0) and IncMainCtrl(1) do ; //OK:=true ; {takie chamskie, potem poprawie} <-Ra: kto miał to poprawić i po co? if ActiveDir=-1 then while (RList[MainCtrlPos].Bn>1) and IncMainCtrl(1) do dec(MainCtrlPos); OK:=false; {if (TrainType=dt_ET40) then while Abs (Im)>IminHi do dec(MainCtrlPos); OK:=false ; } if(DynamicBrakeFlag)then if(TrainType=dt_ET42)then while(MainCtrlPos>20)do dec(MainCtrlPos); OK:=false; end; DieselEngine: if CtrlSpeed=1 then begin inc(MainCtrlPos); OK:=true; if MainCtrlPos>0 then CompressorAllow:=true else CompressorAllow:=false; end else if CtrlSpeed>1 then begin while (MainCtrlPos=MainCtrlPosNo if (CoupledCtrl) then //wspólny wał nastawnika jazdy i bocznikowania begin if (ScndCtrlPos false begin inc(ScndCtrlPos); OK:=true; end else OK:=false; end; if OK then begin {OK:=}SendCtrlToNext('MainCtrl',MainCtrlPos,CabNo); {???} {OK:=}SendCtrlToNext('ScndCtrl',ScndCtrlPos,CabNo); end; end else {nie ma sterowania} OK:=false; //if OK then LastRelayTime:=0; //hunter-101012: poprawka //poprzedni warunek byl niezbyt dobry, bo przez to przy trzymaniu + //styczniki tkwily na tej samej pozycji (LastRelayTime byl caly czas 0 i rosl //po puszczeniu plusa) if OK then begin if (DelayCtrlFlag) then begin if (LastRelayTime>=InitialCtrlDelay)and(MainCtrlPos=1) then LastRelayTime:=0 end else if (LastRelayTime>CtrlDelay) then LastRelayTime:=0; end; IncMainCtrl:=OK; end; function T_MoverParameters.DecMainCtrl(CtrlSpeed:integer): boolean; var //b:byte; OK:boolean; begin OK:=false; if (MainCtrlPosNo>0) and (CabNo<>0) then begin if MainCtrlPos>0 then begin if ((TrainType<>dt_ET22) or (ScndCtrlPos=0)) then //Ra: ET22 blokuje nastawnik przy boczniku begin if CoupledCtrl and (ScndCtrlPos>0) then begin dec(ScndCtrlPos); {wspolny wal} OK:=true; end else case EngineType of None, Dumb, DieselElectric, ElectricInductionMotor: if ((CtrlSpeed=1) and {(ScndCtrlPos=0) and} (EngineType<>DieselElectric)) or ((CtrlSpeed=1)and(EngineType=DieselElectric))then begin dec(MainCtrlPos); OK:=true; end else if CtrlSpeed>1 then OK:=DecMainCtrl(1) and DecMainCtrl(2); //CtrlSpeed-1); ElectricSeriesMotor: if (CtrlSpeed=1) {and (ScndCtrlPos=0)} then begin dec(MainCtrlPos); // if (MainCtrlPos=0) and (ScndCtrlPos=0) and (TrainType<>dt_ET40)and(TrainType<>dt_EP05) then // StLinFlag:=false; // if (MainCtrlPos=0) and (TrainType<>dt_ET40) and (TrainType<>dt_EP05) then // MainCtrlActualPos:=0; //yBARC: co to tutaj robi? ;) OK:=true; end else if (CtrlSpeed>1) {and (ScndCtrlPos=0)} then begin OK:=true; if (RList[MainCtrlPos].R=0) then DecMainCtrl(1); while (RList[MainCtrlPos].R>0) and DecMainCtrl(1) do ; {takie chamskie, potem poprawie} end; DieselEngine: if CtrlSpeed=1 then begin dec(MainCtrlPos); OK:=true; end else if CtrlSpeed>1 then begin while (MainCtrlPos>0) or (RList[MainCtrlPos].Mn>0) do DecMainCtrl(1); OK:=true; end; end; end; end else if EngineType=WheelsDriven then OK:=AddPulseForce(-CtrlSpeed) else OK:=false; if OK then begin {OK:=}SendCtrlToNext('MainCtrl',MainCtrlPos,CabNo); {hmmmm...???!!!} {OK:=}SendCtrlToNext('ScndCtrl',ScndCtrlPos,CabNo); end; end else OK:=false; //if OK then LastRelayTime:=0; //hunter-101012: poprawka if OK then begin if DelayCtrlFlag then begin if (LastRelayTime>=InitialCtrlDelay) then LastRelayTime:=0; end else if (LastRelayTime>CtrlDownDelay) then LastRelayTime:=0; end; DecMainCtrl:=OK; end; function T_MoverParameters.IncScndCtrl(CtrlSpeed:integer): boolean; var //b:byte; OK:boolean; begin if (MainCtrlPos=0)and(CabNo<>0)and(TrainType=dt_ET42)and(ScndCtrlPos=0)and(DynamicBrakeFlag)then begin OK:=DynamicBrakeSwitch(false); end else if (ScndCtrlPosNo>0) and (CabNo<>0) and not ((TrainType=dt_ET42)and((Imax=ImaxHi)or((DynamicBrakeFlag)and(MainCtrlPos>0)))) then begin { if (RList[MainCtrlPos].R=0) and (MainCtrlPos>0) and (ScndCtrlPosDieselElectric) or (not AutoRelayFlag)) then begin if CtrlSpeed=1 then begin inc(ScndCtrlPos); end else if CtrlSpeed>1 then begin ScndCtrlPos:=ScndCtrlPosNo; {takie chamskie, potem poprawie} end; OK:=true; end else {nie mozna zmienic} OK:=false; if OK then begin {OK:=}SendCtrlToNext('MainCtrl',MainCtrlPos,CabNo); {???} {OK:=}SendCtrlToNext('ScndCtrl',ScndCtrlPos,CabNo); end; end else {nie ma sterowania} OK:=false; //if OK then LastRelayTime:=0; //hunter-101012: poprawka if OK then if (LastRelayTime>CtrlDelay) then LastRelayTime:=0; if (OK) and (EngineType=ElectricInductionMotor) then if (Vmax<250) then ScndCtrlActualPos:=Round(Vel+0.5) else ScndCtrlActualPos:=Round(Vel/2+0.5); IncScndCtrl:=OK; end; function T_MoverParameters.DecScndCtrl(CtrlSpeed:integer): boolean; var //b:byte; OK:boolean; begin if (MainCtrlPos=0)and(CabNo<>0)and(TrainType=dt_ET42)and(ScndCtrlPos=0)and not(DynamicBrakeFlag)and(CtrlSpeed=1)then begin //Ra: AI wywołuje z CtrlSpeed=2 albo gdy ScndCtrlPos>0 OK:=DynamicBrakeSwitch(true); end else if (ScndCtrlPosNo>0) and (CabNo<>0) then begin if (ScndCtrlPos>0) and (not CoupledCtrl) and ((EngineType<>DieselElectric) or (not AutoRelayFlag))then begin if CtrlSpeed=1 then begin dec(ScndCtrlPos); end else if CtrlSpeed>1 then begin ScndCtrlPos:=0; {takie chamskie, potem poprawie} end; OK:=true; end else OK:=false; if OK then begin {OK:=}SendCtrlToNext('MainCtrl',MainCtrlPos,CabNo); {???} {OK:=}SendCtrlToNext('ScndCtrl',ScndCtrlPos,CabNo); end; end else OK:=false; //if OK then LastRelayTime:=0; //hunter-101012: poprawka if OK then if (LastRelayTime>CtrlDownDelay) then LastRelayTime:=0; if (OK) and (EngineType=ElectricInductionMotor) then ScndCtrlActualPos:=0; DecScndCtrl:=OK; end; function T_MoverParameters.DirectionBackward: boolean; begin if (ActiveDir=1) and (MainCtrlPos=0) and (TrainType=dt_EZT) then if MinCurrentSwitch(false) then begin DirectionBackward:=true; // Exit; end; if (MainCtrlPosNo>0) and (ActiveDir>-1) and (MainCtrlPos=0) then begin if EngineType=WheelsDriven then dec(CabNo); { else} dec(ActiveDir); DirAbsolute:=ActiveDir*CabNo; if (DirAbsolute<>0) then if (Battery) then //jeśli bateria jest już załączona BatterySwitch(true); //to w ten oto durny sposób aktywuje się CA/SHP DirectionBackward:=true; SendCtrltoNext('Direction',ActiveDir,CabNo); end else DirectionBackward:=false; end; function T_MoverParameters.MainSwitch(State:boolean): boolean; begin MainSwitch:=false; //Ra: przeniesione z końca if ((Mains<>State) and (MainCtrlPosNo>0)) then begin if (State=false) or ({(MainCtrlPos=0) and} (ScndCtrlPos=0) and ((ConvOvldFlag=false)or(TrainType=dt_EZT)) and (LastSwitchingTime>CtrlDelay) and not TestFlag(DamageFlag,dtrain_out) and not TestFlag(EngDmgFlag,1)) then begin if Mains then //jeśli był załączony SendCtrlToNext('MainSwitch',ord(State),CabNo); //wysłanie wyłączenia do pozostałych? Mains:=State; if Mains then //jeśli został załączony SendCtrlToNext('MainSwitch',ord(State),CabNo); //wyslanie po wlaczeniu albo przed wylaczeniem MainSwitch:=true; //wartość zwrotna LastSwitchingTime:=0; if (EngineType=DieselEngine) and Mains then begin dizel_enginestart:=State; end; if ((TrainType=dt_EZT)and(not State)) then ConvOvldFlag:=true; //if (State=false) then //jeśli wyłączony // begin //SetFlag(SoundFlag,sound_relay); //hunter-091012: przeniesione do Train.cpp, zeby sie nie zapetlal // if (SecuritySystem.Status<>12) then // SecuritySystem.Status:=0; //deaktywacja czuwaka; Ra: a nie baterią? // end //else //if (SecuritySystem.Status<>12) then // SecuritySystem.Status:=s_waiting; //aktywacja czuwaka end end //else MainSwitch:=false; end; function T_MoverParameters.BatterySwitch(State:boolean):boolean; begin //Ra: ukrotnienie załączania baterii jest jakąś fikcją... if (Battery<>State) then begin Battery:=State; end; if (Battery=true) then SendCtrlToNext('BatterySwitch',1,CabNo) else SendCtrlToNext('BatterySwitch',0,CabNo); BatterySwitch:=true; if (Battery) and (ActiveCab<>0) {or (TrainType=dt_EZT)} then SecuritySystem.Status:=SecuritySystem.Status or s_waiting //aktywacja czuwaka else SecuritySystem.Status:=0; //wyłączenie czuwaka end; function T_MoverParameters.EpFuseSwitch(State:boolean):boolean; begin if (EpFuse<>State) then begin EpFuse:=State; EpFuseSwitch:=true; end else EpFuseSwitch:=false; // if (EpFuse=true) then SendCtrlToNext('EpFuseSwitch',1,CabNo) // else SendCtrlToNext('EpFuseSwitch',0,CabNo); end; {wl/wyl przetwornicy} function T_MoverParameters.ConverterSwitch(State:boolean):boolean; begin ConverterSwitch:=false; //Ra: normalnie chyba false? if (ConverterAllow<>State) then begin ConverterAllow:=State; ConverterSwitch:=true; if CompressorPower=2 then CompressorAllow:=ConverterAllow; end; if (ConverterAllow=true) then SendCtrlToNext('ConverterSwitch',1,CabNo) else SendCtrlToNext('ConverterSwitch',0,CabNo) end; {wl/wyl sprezarki} function T_MoverParameters.CompressorSwitch(State:boolean):boolean; begin CompressorSwitch:=false; //Ra: normalnie chyba tak? // if State=true then // if ((CompressorPower=2) and (not ConverterAllow)) then // State:=false; //yB: to juz niepotrzebne if (CompressorAllow<>State)and(CompressorPower<2)then begin CompressorAllow:=State; CompressorSwitch:=true; end; if (CompressorAllow=true) then SendCtrlToNext('CompressorSwitch',1,CabNo) else SendCtrlToNext('CompressorSwitch',0,CabNo) end; {wl/wyl malej sprezarki} {function T_MoverParameters.SmallCompressorSwitch(State:boolean):boolean; begin if State=true then if ((SmallCompressorPower=1) then State:=false; if (SmallCompressorAllow<>State) then begin SmallCompressorAllow:=State; SmallCompressorSwitch:=true; end; end; } {sypanie piasku} function T_MoverParameters.SandDoseOn : boolean; begin if (SandCapacity>0) then begin SandDoseOn:=true; if SandDose then SandDose:=false else if Sand>0 then SandDose:=true; if CabNo<>0 then SendCtrlToNext('SandDoseOn',1,CabNo); end else SandDoseOn:=false; end; (* //Ra: to jest do przejrzenia i uporządkowania function T_MoverParameters.SecuritySystemReset : boolean; //zbijanie czuwaka/SHP procedure Reset; begin with SecuritySystem do if not(TestFlag(SystemType,2) and TestFlag(Status,s_active)) then SecuritySystem.SystemTimer:=0; SecuritySystem.SystemBrakeTimer:=0; SecuritySystem.SystemSoundTimer:=0; SecuritySystem.Status:=s_waiting; //aktywacja czuwaka SecuritySystem.VelocityAllowed:=-1; end; procedure ResetSHP; begin SecuritySystem.SystemBrakeTimer:=0; SecuritySystem.SystemSoundTimer:=0; SecuritySystem.VelocityAllowed:=-1; SecuritySystem.Status:=s_waiting; end; begin with SecuritySystem do begin if (Status=3) or (Status=2) or (Status=11) or (Status=26)or(Status=27) then begin SecuritySystemReset:=true; if (Status0)) or (Status=28) then {Wlaczone tylko SHP} { begin SecuritySystemReset:=true; if (Status0) and (Status>0) and ((status<>12) or ((status=12) and (activedir<>0))) then //if (SystemType>0) and (Status>0) then begin SecuritySystemReset:=true; if not (ActiveDir=0) then if not TestFlag(Status,s_CAebrake) or not TestFlag(Status,s_SHPebrake) then Reset; //else // if EmergencyBrakeSwitch(false) then // Reset; end else SecuritySystemReset:=false; // SendCtrlToNext('SecurityReset',0,CabNo); end; {testowanie czuwaka/SHP} procedure T_MoverParameters.SecuritySystemCheck(dt:real); begin with SecuritySystem do begin if (SystemType>0) and (Status>0) then begin SystemTimer:=SystemTimer+dt; if TestFlag(Status,s_aware) or TestFlag(Status,s_active) then //jeśli świeci albo miga SystemSoundTimer:=SystemSoundTimer+dt; if TestFlag(Status,s_alarm) then //jeśli buczy SystemBrakeTimer:=SystemBrakeTimer+dt; if TestFlag(SystemType,1) then if (SystemTimer>AwareDelay) and (AwareDelay>=0) then {-1 blokuje} if not SetFlag(Status,s_aware) then {juz wlaczony sygnal swietlny} if (SystemSoundTimer>SoundSignalDelay) and (SoundSignalDelay>=0) then if not SetFlag(Status,s_alarm) then {juz wlaczony sygnal dzwiekowy} if (SystemBrakeTimer>EmergencyBrakeDelay) and (EmergencyBrakeDelay>=0) then SetFlag(Status,s_ebrake); {przeterminowanie czuwaka, hamowanie awaryjne} if TestFlag(SystemType,2) and TestFlag(Status,s_active) then if (Vel>VelocityAllowed) and (VelocityAllowed>=0) then SetFlag(Status,s_ebrake) else if ((SystemSoundTimer>SoundSignalDelay) and (SoundSignalDelay>=0)) or ((Vel>NextVelocityAllowed) and (NextVelocityAllowed>=0)) then if not SetFlag(Status,s_alarm) then {juz wlaczony sygnal dzwiekowy} if (SystemBrakeTimer>EmergencyBrakeDelay) and (EmergencyBrakeDelay>=0) then SetFlag(Status,s_ebrake); if TestFlag(Status,s_ebrake) then if not EmergencyBrakeFlag then EmergencyBrakeSwitch(true); end; end; end; *) //hunter-091012: rozbicie alarmow, dodanie testu czuwaka function T_MoverParameters.SecuritySystemReset : boolean; //zbijanie czuwaka/SHP procedure Reset; begin SecuritySystem.SystemTimer:=0; if TestFlag(SecuritySystem.Status,s_aware) then begin SecuritySystem.SystemBrakeCATimer:=0; SecuritySystem.SystemSoundCATimer:=0; SetFlag(SecuritySystem.Status,-s_aware); SetFlag(SecuritySystem.Status,-s_CAalarm); SetFlag(SecuritySystem.Status,-s_CAebrake); // EmergencyBrakeFlag:=false; //YB-HN SecuritySystem.VelocityAllowed:=-1; end else if TestFlag(SecuritySystem.Status,s_active) then begin SecuritySystem.SystemBrakeSHPTimer:=0; SecuritySystem.SystemSoundSHPTimer:=0; SetFlag(SecuritySystem.Status,-s_active); SetFlag(SecuritySystem.Status,-s_SHPalarm); SetFlag(SecuritySystem.Status,-s_SHPebrake); // EmergencyBrakeFlag:=false; //YB-HN SecuritySystem.VelocityAllowed:=-1; end; end; begin with SecuritySystem do if (SystemType>0) and (Status>0) then begin SecuritySystemReset:=true; if ((TrainType=dt_EZT)or(ActiveDir<>0)) then //Ra 2014-03: w EZT nie trzeba ustawiać kierunku if not TestFlag(Status,s_CAebrake) or not TestFlag(Status,s_SHPebrake) then Reset; //else // if EmergencyBrakeSwitch(false) then // Reset; end else SecuritySystemReset:=false; // SendCtrlToNext('SecurityReset',0,CabNo); end; procedure T_MoverParameters.SecuritySystemCheck(dt:real); begin //Ra: z CA/SHP w EZT jest ten problem, że w rozrządczym nie ma kierunku, a w silnikowym nie ma obsady //poza tym jest zdefiniowany we wszystkich 3 członach EN57 with SecuritySystem do begin if (not Radio) then EmergencyBrakeSwitch(false); if (SystemType>0) and (Status>0) and (Battery) then //Ra: EZT ma teraz czuwak w rozrządczym begin //CA if (Vel>=AwareMinSpeed) then //domyślnie predkość większa od 10% Vmax, albo podanej jawnie w FIZ begin SystemTimer:=SystemTimer+dt; if TestFlag(SystemType,1) and TestFlag(Status,s_aware) then //jeśli świeci albo miga SystemSoundCATimer:=SystemSoundCATimer+dt; if TestFlag(SystemType,1) and TestFlag(Status,s_CAalarm) then //jeśli buczy SystemBrakeCATimer:=SystemBrakeCATimer+dt; if TestFlag(SystemType,1) then if (SystemTimer>AwareDelay) and (AwareDelay>=0) then {-1 blokuje} if not SetFlag(Status,s_aware) then {juz wlaczony sygnal swietlny} if (SystemSoundCATimer>SoundSignalDelay) and (SoundSignalDelay>=0) then if not SetFlag(Status,s_CAalarm) then {juz wlaczony sygnal dzwiekowy} if (SystemBrakeCATimer>EmergencyBrakeDelay) and (EmergencyBrakeDelay>=0) then SetFlag(Status,s_CAebrake); //SHP if TestFlag(SystemType,2) and TestFlag(Status,s_active) then //jeśli świeci albo miga SystemSoundSHPTimer:=SystemSoundSHPTimer+dt; if TestFlag(SystemType,2) and TestFlag(Status,s_SHPalarm) then //jeśli buczy SystemBrakeSHPTimer:=SystemBrakeSHPTimer+dt; if TestFlag(SystemType,2) and TestFlag(Status,s_active) then if (Vel>VelocityAllowed) and (VelocityAllowed>=0) then SetFlag(Status,s_SHPebrake) else if ((SystemSoundSHPTimer>SoundSignalDelay) and (SoundSignalDelay>=0)) or ((Vel>NextVelocityAllowed) and (NextVelocityAllowed>=0)) then if not SetFlag(Status,s_SHPalarm) then {juz wlaczony sygnal dzwiekowy} if (SystemBrakeSHPTimer>EmergencyBrakeDelay) and (EmergencyBrakeDelay>=0) then SetFlag(Status,s_SHPebrake); end; //else SystemTimer:=0; //TEST CA if TestFlag(Status,s_CAtest) then //jeśli świeci albo miga SystemBrakeCATestTimer:=SystemBrakeCATestTimer+dt; if TestFlag(SystemType,1) then if TestFlag(Status,s_CAtest) then {juz wlaczony sygnal swietlny} if (SystemBrakeCATestTimer>EmergencyBrakeDelay) and (EmergencyBrakeDelay>=0) then s_CAtestebrake:=true; //wdrazanie hamowania naglego // if TestFlag(Status,s_SHPebrake) or TestFlag(Status,s_CAebrake) or (s_CAtestebrake=true) then // EmergencyBrakeFlag:=true; //YB-HN end else if not (Battery) then begin //wyłączenie baterii deaktywuje sprzęt EmergencyBrakeSwitch(false); //SecuritySystem.Status:=0; //deaktywacja czuwaka end; end; end; {nastawy hamulca} function T_MoverParameters.IncBrakeLevelOld:boolean; //var b:byte; begin if (BrakeCtrlPosNo>0) {and (LocalBrakePos=0)} then begin if BrakeCtrlPos0); SendCtrlToNext('BrakeCtrl',BrakeCtrlPos,CabNo); end else SendCtrlToNext('BrakeCtrl',-2,CabNo); // else // if not TestFlag(BrakeStatus,b_dmg) then // BrakeStatus:=b_on;} //youBy: EP po nowemu IncBrakeLevelOld:=true; if (BrakePressureActual.PipePressureVal<0)and(BrakePressureTable[BrakeCtrlPos-1].PipePressureVal>0) then LimPipePress:=PipePress; if (BrakeSystem=ElectroPneumatic) then if (BrakeSubSystem<>ss_K) then begin if (BrakeCtrlPos*BrakeCtrlPos)=1 then begin // SendCtrlToNext('Brake',BrakeCtrlPos,CabNo); // SetFlag(BrakeStatus,b_epused); end else begin // SendCtrlToNext('Brake',0,CabNo); // SetFlag(BrakeStatus,-b_epused); end; end; end else begin IncBrakeLevelOld:=false; { if BrakeSystem=Pneumatic then EmergencyBrakeSwitch(true); } end; end else IncBrakeLevelOld:=false; end; function T_MoverParameters.DecBrakeLevelOld:boolean; //var b:byte; begin if (BrakeCtrlPosNo>0) {and (LocalBrakePos=0)} then begin if (BrakeCtrlPos>-1-Byte(BrakeHandle=FV4a)) then begin dec(BrakeCtrlPos); // BrakeCtrlPosR:=BrakeCtrlPos; //// if EmergencyBrakeFlag then //yB: czy to jest potrzebne? //// begin //// EmergencyBrakeFlag:=false; {!!!} //// SendCtrlToNext('Emergency_brake',0,CabNo); //// end; //youBy: wywalilem to, jak jest EP, to sa przenoszone sygnaly nt. co ma robic, a nie poszczegolne pozycje; // wystarczy spojrzec na Knorra i Oerlikona EP w EN57; mogly ze soba wspolapracowac { if (BrakeSystem=ElectroPneumatic) then if BrakePressureActual.BrakeType=ElectroPneumatic then begin // BrakeStatus:=ord(BrakeCtrlPos>0); SendCtrlToNext('BrakeCtrl',BrakeCtrlPos,CabNo); end else SendCtrlToNext('BrakeCtrl',-2,CabNo); // else} // if (not TestFlag(BrakeStatus,b_dmg) and (not TestFlag(BrakeStatus,b_release))) then // BrakeStatus:=b_off; {luzowanie jesli dziala oraz nie byl wlaczony odluzniacz} //youBy: EP po nowemu DecBrakeLevelOld:=true; // if (BrakePressureTable[BrakeCtrlPos].PipePressureVal<0.0)and(BrakePressureTable[BrakeCtrlPos+1].PipePressureVal>0) then // LimPipePress:=PipePress; if (BrakeSystem=ElectroPneumatic) then if (BrakeSubSystem<>ss_K) then begin if (BrakeCtrlPos*BrakeCtrlPos)=1 then begin // SendCtrlToNext('Brake',BrakeCtrlPos,CabNo); // SetFlag(BrakeStatus,b_epused); end else begin // SendCtrlToNext('Brake',0,CabNo); // SetFlag(BrakeStatus,-b_epused); end; end; (* for b:=0 to 1 do {poprawic to!} with Couplers[b] do if CouplingFlag and ctrain_controll=ctrain_controll then Connected^.BrakeCtrlPos:=BrakeCtrlPos; *) end else DecBrakeLevelOld:=false; end else DecBrakeLevelOld:=false; end; function T_MoverParameters.IncLocalBrakeLevelFAST:boolean; begin if (LocalBrakePos0) do begin inc(LocalBrakePos); dec(CtrlSpeed); end; IncLocalBrakeLevel:=true; end else IncLocalBrakeLevel:=false; UnBrake:=true; end; function T_MoverParameters.IncManualBrakeLevel(CtrlSpeed:byte):boolean; begin if (ManualBrakePos0) do begin inc(ManualBrakePos); dec(CtrlSpeed); end; IncManualBrakeLevel:=true; end else IncManualBrakeLevel:=false; end; function T_MoverParameters.DecLocalBrakeLevelFAST():boolean; begin if LocalBrakePos>0 then begin LocalBrakePos:=0; DecLocalBrakeLevelFAST:=true; end else DecLocalBrakeLevelFAST:=false; UnBrake:=true; end; function T_MoverParameters.DecLocalBrakeLevel(CtrlSpeed:byte):boolean; begin if LocalBrakePos>0 then begin while (CtrlSpeed>0) and (LocalBrakePos>0) do begin dec(LocalBrakePos); dec(CtrlSpeed); end; DecLocalBrakeLevel:=true; end else DecLocalBrakeLevel:=false; UnBrake:=true; end; function T_MoverParameters.DecManualBrakeLevel(CtrlSpeed:byte):boolean; begin if ManualBrakePos>0 then begin while (CtrlSpeed>0) and (ManualBrakePos>0) do begin dec(ManualBrakePos); dec(CtrlSpeed); end; DecManualBrakeLevel:=true; end else DecManualBrakeLevel:=false; end; function T_MoverParameters.EmergencyBrakeSwitch(Switch:boolean): boolean; begin if (BrakeSystem<>Individual) and (BrakeCtrlPosNo>0) then begin if (not EmergencyBrakeFlag) and Switch then begin EmergencyBrakeFlag:=Switch; EmergencyBrakeSwitch:=true; end else begin if (Abs(V)<0.1) and (Switch=false) then {odblokowanie hamulca bezpieczenistwa tylko po zatrzymaniu} begin EmergencyBrakeFlag:=Switch; EmergencyBrakeSwitch:=true; end else EmergencyBrakeSwitch:=false; end; end else EmergencyBrakeSwitch:=false; {nie ma hamulca bezpieczenstwa gdy nie ma hamulca zesp.} end; function T_MoverParameters.AntiSlippingBrake: boolean; begin AntiSlippingBrake:=false; //Ra: przeniesione z końca if ASBType=1 then begin AntiSlippingBrake:=true; //SPKS!! Hamulec.ASB(1); BrakeSlippingTimer:=0; end end; function T_MoverParameters.AntiSlippingButton: boolean; var OK:boolean; begin OK:=SandDoseOn; AntiSlippingButton:=(AntiSlippingBrake or OK); end; function T_MoverParameters.BrakeDelaySwitch(BDS:byte): boolean; begin // if BrakeCtrlPosNo>0 then if BrakeHandle=MHZ_EN57 then begin if (BDS<>BrakeOpModeFlag) and ((BDS and BrakeOpModes) > 0) then begin BrakeOpModeFlag:=BDS; BrakeDelaySwitch:=true; end else BrakeDelaySwitch:=false; end else if Hamulec.SetBDF(BDS) then begin BrakeDelayFlag:=BDS; BrakeDelaySwitch:=true; BrakeStatus:=(BrakeStatus and 191); //kopowanie nastawy hamulca do kolejnego czlonu - do przemyślenia if CabNo<>0 then SendCtrlToNext('BrakeDelay',BrakeDelayFlag,CabNo); end else BrakeDelaySwitch:=false; end; function T_MoverParameters.IncBrakeMult(): boolean; begin if (LoadFlag>0) and (MBPM<2) and (LoadFlag<3) then begin if (MaxBrakePress[2]>0) and (LoadFlag=1) then LoadFlag:=2 else LoadFlag:=3; IncBrakeMult:=true; if BrakeCylMult[2]>0 then BrakeCylMult[0]:=BrakeCylMult[2]; end else IncBrakeMult:=false; end; function T_MoverParameters.DecBrakeMult(): boolean; begin if (LoadFlag>1) and (MBPM<2) then begin if (MaxBrakePress[2]>0) and (LoadFlag=3) then LoadFlag:=2 else LoadFlag:=1; DecBrakeMult:=true; if BrakeCylMult[1]>0 then BrakeCylMult[0]:=BrakeCylMult[1]; end else DecBrakeMult:=false; end; function T_MoverParameters.BrakeReleaser(state: byte): boolean; var OK:boolean; begin Hamulec.Releaser(state); if CabNo<>0 then //rekurencyjne wysłanie do następnego OK:=SendCtrlToNext('BrakeReleaser',state,CabNo); BrakeReleaser:=OK; end; function T_MoverParameters.SwitchEPBrake(state: byte):boolean; var OK:boolean; temp: real; begin OK:=false; if (BrakeHandle = St113) and (ActiveCab<>0) then begin if(state>0)then temp:=(Handle as TSt113).GetCP else temp:=0; Hamulec.SetEPS(temp); SendCtrlToNext('Brake',temp,CabNo); end; // OK:=SetFlag(BrakeStatus,((2*State-1)*b_epused)); // SendCtrlToNext('Brake',(state*(2*BrakeCtrlPos-1)),CabNo); SwitchEPBrake:=OK; end; {uklady pneumatyczne} function T_MoverParameters.IncBrakePress(var brake:real;PressLimit,dp:real):boolean; begin // if (DynamicBrakeType<>dbrake_switch) and (DynamicBrakeType<>dbrake_none) and ((BrakePress>2.0) or (PipePress<3.7{(LowPipePress+0.5)})) then if (DynamicBrakeType<>dbrake_switch) and (DynamicBrakeType<>dbrake_none) and (BrakePress>2.0) and (TrainType<>dt_EZT) then //yB radzi nie sprawdzać ciśnienia w przewodzie //hunter-301211: dla EN57 silnikow nie odlaczamy begin DynamicBrakeFlag:=true; {uruchamianie hamulca ED albo odlaczanie silnikow} if (DynamicBrakeType=dbrake_automatic) and (abs(Im)>60) then {nie napelniaj wiecej, jak na EP09} dp:=0.0; end; if brake+dpPressLimit then begin brake:=brake-dp; DecBrakePress:=true; end else begin DecBrakePress:=false; brake:=PressLimit; end; // if (DynamicBrakeType<>dbrake_switch) and ((BrakePress<0.1) and (PipePress>0.45{(LowPipePress+0.06)})) then if (DynamicBrakeType<>dbrake_switch) and (BrakePress<0.1) then //yB radzi nie sprawdzać ciśnienia w przewodzie DynamicBrakeFlag:=false; {wylaczanie hamulca ED i/albo zalaczanie silnikow} end; procedure T_MoverParameters.UpdateBrakePressure(dt:real); const LBDelay=5.0; {stala czasowa hamulca} var Rate,Speed,dp,sm:real; begin dpLocalValve:=0; dpBrake:=0; BrakePress:=Hamulec.GetBCP; // BrakePress:=(Hamulec as TEst4).ImplsRes.pa; Volume:=Hamulec.GetBRP; end; {updatebrakepressure} function T_MoverParameters.GetDVc(dt:real):real; var c:T_MoverParameters;dv1,dv2,dv:real; begin dv1:=0; dv2:=0; //sprzeg 1 if Couplers[0].Connected<>nil then if TestFlag(Couplers[0].CouplingFlag,ctrain_pneumatic) then begin //*0.85 c:=Couplers[0].Connected; //skrot //0.08 //e/D * L/D = e/D^2 * L dv1:=0.5*dt*PF(PipePress,c.PipePress,(Spg)/(1+0.015/Spg*Dim.L)); if (dv1*dv1>0.00000000000001) then c.Physic_Reactivation; c.Pipe.Flow(-dv1); end; //sprzeg 2 if Couplers[1].Connected<>nil then if TestFlag(Couplers[1].CouplingFlag,ctrain_pneumatic) then begin c:=Couplers[1].Connected; //skrot dv2:=0.5*dt*PF(PipePress,c.PipePress,(Spg)/(1+0.015/Spg*Dim.L)); if (dv2*dv2>0.00000000000001) then c.Physic_Reactivation; c.Pipe.Flow(-dv2); end; if (Couplers[1].Connected<>nil)and(Couplers[0].Connected<>nil) then if (TestFlag(Couplers[0].CouplingFlag,ctrain_pneumatic))and(TestFlag(Couplers[1].CouplingFlag,ctrain_pneumatic))then begin dv:=0.05*dt*PF(Couplers[0].Connected.PipePress,Couplers[1].Connected.PipePress,(Spg*0.85)/(1+0.03*Dim.L))*0; Couplers[0].Connected.Pipe.Flow(+dv); Couplers[1].Connected.Pipe.Flow(-dv); end; //suma GetDVc:=dv2+dv1; end; procedure T_MoverParameters.UpdatePipePressure(dt:real); const LBDelay=100;kL=0.5; var {b: byte;} dV{,PWSpeed}{,PPP}:real; c: T_MoverParameters; temp: real; b: byte; begin PipePress:=Pipe.P; // PPP:=PipePress; dpMainValve:=0; if (BrakeCtrlPosNo>1) {and(ActiveCab<>0)}then with BrakePressureTable[BrakeCtrlPos] do begin if(EngineType<>ElectricInductionMotor)then dpLocalValve:=LocHandle.GetPF(Max0R(LocalBrakePos/LocalBrakePosNo,LocalBrakePosA), Hamulec.GetBCP, ScndPipePress, dt, 0) else dpLocalValve:=LocHandle.GetPF(LocalBrakePosA, Hamulec.GetBCP, ScndPipePress, dt, 0); if(BrakeHandle=FV4a)and((PipePress<2.75)and((Hamulec.GetStatus and b_rls)=0))and(BrakeSubsystem=ss_LSt)and(TrainType<>dt_EZT)then temp:=PipePress+0.00001 else temp:=ScndPipePress; Handle.SetReductor(BrakeCtrlPos2); if (BrakeOpModeFlag<>bom_PS) then if (BrakeOpModeFlagMHZ_EN57) then dpMainValve:=Handle.GetPF(BrakeCtrlPosR, PipePress, temp, dt, EqvtPipePress) else dpMainValve:=Handle.GetPF(0, PipePress, temp, dt, EqvtPipePress); if (dpMainValve<0){and(PipePressureVal>0.01)} then {50} if Compressor>ScndPipePress then begin CompressedVolume:=CompressedVolume+dpMainValve/1500; Pipe2.Flow(dpMainValve/3); end else Pipe2.Flow(dpMainValve); end; // if(EmergencyBrakeFlag)and(BrakeCtrlPosNo=0)then {ulepszony hamulec bezp.} if(EmergencyBrakeFlag)or TestFlag(SecuritySystem.Status,s_SHPebrake) or TestFlag(SecuritySystem.Status,s_CAebrake) or (s_CAtestebrake=true) or (TestFlag(EngDmgFlag,32)){ or (not Battery)}then {ulepszony hamulec bezp.} dpMainValve:=dpMainValve/1+PF(0,PipePress,0.15)*dt; //0.2*Spg Pipe.Flow(-dpMainValve); Pipe.Flow(-(PipePress)*0.001*dt); // if Heating then // Pipe.Flow(PF(PipePress,0,d2A(7))*dt); // if ConverterFlag then // Pipe.Flow(PF(PipePress,0,d2A(12))*dt); dpMainValve:=dpMainValve/(Dim.L*Spg*20); CntrlPipePress:=Hamulec.GetVRP; //ciśnienie komory wstępnej rozdzielacza case BrakeValve of W: begin if (BrakeLocHandle<>NoHandle) then begin LocBrakePress:=LocHandle.GetCP; (Hamulec as TWest).SetLBP(LocBrakePress); end; if MBPM<2 then (Hamulec as TWest).PLC(MaxBrakePress[LoadFlag]) else (Hamulec as TWest).PLC(TotalMass); end; LSt,EStED: begin LocBrakePress:=LocHandle.GetCP; for b:=0 to 1 do if((TrainType and (dt_ET41 or dt_ET42))>0)and(Couplers[b].Connected<>nil)then //nie podoba mi się to rozwiązanie, chyba trzeba dodać jakiś wpis do fizyki na to if((Couplers[b].Connected.TrainType and (dt_ET41 or dt_ET42))>0)and((Couplers[b].CouplingFlag and 36) = 36)then LocBrakePress:=Max0R(Couplers[b].Connected.LocHandle.GetCP,LocBrakePress); if(DynamicBrakeFlag)and(EngineType=ElectricInductionMotor)then begin (Hamulec as TLSt).SetLBP(LocBrakePress); // if(Vel>10)then LocBrakePress:=0 else // if(Vel>5)then LocBrakePress:=(10-Vel)/5*LocBrakePress end else (Hamulec as TLSt).SetLBP(LocBrakePress); if (BrakeValve = EStED) then if MBPM<2 then (Hamulec as TEStED).PLC(MaxBrakePress[LoadFlag]) else (Hamulec as TEStED).PLC(TotalMass); end; CV1_L_TR: begin LocBrakePress:=LocHandle.GetCP; (Hamulec as TCV1L_TR).SetLBP(LocBrakePress); end; EP2: (Hamulec as TEStEP2).PLC(TotalMass); ESt3AL2,NESt3,ESt4,ESt3: begin if MBPM<2 then (Hamulec as TNESt3).PLC(MaxBrakePress[LoadFlag]) else (Hamulec as TNESt3).PLC(TotalMass); LocBrakePress:=LocHandle.GetCP; (Hamulec as TNESt3).SetLBP(LocBrakePress); end; KE: begin LocBrakePress:=LocHandle.GetCP; (Hamulec as TKE).SetLBP(LocBrakePress); if MBPM<2 then (Hamulec as TKE).PLC(MaxBrakePress[LoadFlag]) else (Hamulec as TKE).PLC(TotalMass); end; end; if (BrakeHandle = FVel6) and (ActiveCab<>0) then begin if (Battery) and (ActiveDir<>0) and (EpFuse) then //tu powinien byc jeszcze bezpiecznik EP i baterie - temp:=(Handle as TFVel6).GetCP else temp:=0; Hamulec.SetEPS(temp); SendCtrlToNext('Brake',temp,CabNo); //Ra 2014-11: na tym się wysypuje, ale nie wiem, w jakich warunkach end; Pipe.Act; PipePress:=Pipe.P; if (BrakeStatus and 128)=128 then //jesli hamulec wyłączony temp:=0 //odetnij else temp:=1; //połącz Pipe.Flow(temp*Hamulec.GetPF(temp*PipePress,dt,Vel)+GetDVc(dt)); if ASBType=128 then Hamulec.ASB(Byte(SlippingWheels)); dpPipe:=0; //yB: jednokrokowe liczenie tego wszystkiego Pipe.Act; PipePress:=Pipe.P; dpMainValve:=dpMainValve/(100*dt); //normalizacja po czasie do syczenia; if PipePress<-1 then begin PipePress:=-1; Pipe.CreatePress(-1); Pipe.Act; end; if CompressedVolume<0 then CompressedVolume:=0; end; {updatepipepressure} procedure T_MoverParameters.CompressorCheck(dt:real); begin //if (CompressorSpeed>0.0) then //ten warunek został sprawdzony przy wywołaniu funkcji if (VeselVolume>0) then begin if MaxCompressor-MinCompressor<0.0001 then begin { if Mains and (MainCtrlPos>1) then} if CompressorAllow and Mains and (MainCtrlPos>0) then begin if (Compressor0) then CompressedVolume:=CompressedVolume+dt*CompressorSpeed*(2*MaxCompressor-Compressor)/MaxCompressor*(DEList[MainCtrlPos].rpm/DEList[MainCtrlPosNo].rpm) else begin CompressedVolume:=CompressedVolume+dt*CompressorSpeed*(2*MaxCompressor-Compressor)/MaxCompressor; TotalCurrent:=TotalCurrent+0.0015*Voltage; //tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę end else begin CompressedVolume:=CompressedVolume*0.8; SetFlag(SoundFlag,sound_relay); SetFlag(SoundFlag,sound_loud); end; end; end else begin if (CompressorFlag) then //jeśli sprężarka załączona begin //sprawdzić możliwe warunki wyłączenia sprężarki if (CompressorPower=5) then //jeśli zasilanie z sąsiedniego członu begin //zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) if (Couplers[1].Connected<>NIL) then CompressorFlag:=Couplers[1].Connected.CompressorAllow and Couplers[1].Connected.ConverterFlag and Couplers[1].Connected.Mains else CompressorFlag:=false; //bez tamtego członu nie zadziała end else if (CompressorPower=4) then //jeśli zasilanie z poprzedniego członu begin //zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) if (Couplers[0].Connected<>NIL) then CompressorFlag:=Couplers[0].Connected.CompressorAllow and Couplers[0].Connected.ConverterFlag and Couplers[0].Connected.Mains else CompressorFlag:=false; //bez tamtego członu nie zadziała end else CompressorFlag:=(CompressorAllow) and ((ConverterFlag) or (CompressorPower=0)) and (Mains); if (Compressor>MaxCompressor) then //wyłącznik ciśnieniowy jest niezależny od sposobu zasilania CompressorFlag:=false; end else //jeśli nie załączona if (CompressorCtrlDelay) then //jeśli nie załączona, a ciśnienie za małe begin //załączenie przy małym ciśnieniu if (CompressorPower=5) then //jeśli zasilanie z następnego członu begin //zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) if (Couplers[1].Connected<>NIL) then CompressorFlag:=Couplers[1].Connected.CompressorAllow and Couplers[1].Connected.ConverterFlag and Couplers[1].Connected.Mains else CompressorFlag:=false; //bez tamtego członu nie zadziała end else if (CompressorPower=4) then //jeśli zasilanie z poprzedniego członu begin //zasilanie sprężarki w członie ra z członu silnikowego (sprzęg 1) if (Couplers[0].Connected<>NIL) then CompressorFlag:=Couplers[0].Connected.CompressorAllow and Couplers[0].Connected.ConverterFlag and Couplers[0].Connected.Mains else CompressorFlag:=false; //bez tamtego członu nie zadziała end else CompressorFlag:=(CompressorAllow) and ((ConverterFlag) or (CompressorPower=0)) and (Mains); if (CompressorFlag) then //jeśli została załączona LastSwitchingTime:=0; //to trzeba ograniczyć ponowne włączenie end; // for b:=0 to 1 do //z Megapacka // with Couplers[b] do // if TestFlag(CouplingFlag,ctrain_scndpneumatic) then // Connected.CompressorFlag:=CompressorFlag; if CompressorFlag then if (EngineType=DieselElectric) and (CompressorPower>0) then CompressedVolume:=CompressedVolume+dt*CompressorSpeed*(2*MaxCompressor-Compressor)/MaxCompressor*(DEList[MainCtrlPos].rpm/DEList[MainCtrlPosNo].rpm) else begin CompressedVolume:=CompressedVolume+dt*CompressorSpeed*(2*MaxCompressor-Compressor)/MaxCompressor; if (CompressorPower=5)and(Couplers[1].Connected<>NIL) then Couplers[1].Connected.TotalCurrent:=Couplers[1].Connected.TotalCurrent+0.0015*Couplers[1].Connected.Voltage //tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę else if (CompressorPower=4)and(Couplers[0].Connected<>NIL) then Couplers[0].Connected.TotalCurrent:=Couplers[0].Connected.TotalCurrent+0.0015*Couplers[0].Connected.Voltage //tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę else TotalCurrent:=TotalCurrent+0.0015*Voltage; //tymczasowo tylko obciążenie sprężarki, tak z 5A na sprężarkę end end; end; end; {Ra 2014-07: do C++ procedure T_MoverParameters.ConverterCheck; begin //sprawdzanie przetwornicy if (ConverterAllow=true)and(Mains=true) then ConverterFlag:=true else ConverterFlag:=false; end; } //youBy - przewod zasilajacy procedure T_MoverParameters.UpdateScndPipePressure(dt: real); const Spz=0.5067; var c:T_MoverParameters;dv1,dv2,dv:real; begin dv1:=0; dv2:=0; //sprzeg 1 if Couplers[0].Connected<>nil then if TestFlag(Couplers[0].CouplingFlag,ctrain_scndpneumatic) then begin c:=Couplers[0].Connected; //skrot dv1:=0.5*dt*PF(ScndPipePress,c.ScndPipePress,Spz*0.75); if (dv1*dv1>0.00000000000001) then c.Physic_Reactivation; c.Pipe2.Flow(-dv1); end; //sprzeg 2 if Couplers[1].Connected<>nil then if TestFlag(Couplers[1].CouplingFlag,ctrain_scndpneumatic) then begin c:=Couplers[1].Connected; //skrot dv2:=0.5*dt*PF(ScndPipePress,c.ScndPipePress,Spz*0.75); if (dv2*dv2>0.00000000000001) then c.Physic_Reactivation; c.Pipe2.Flow(-dv2); end; if(Couplers[1].Connected<>nil)and(Couplers[0].Connected<>nil)then if (TestFlag(Couplers[0].CouplingFlag,ctrain_scndpneumatic))and(TestFlag(Couplers[1].CouplingFlag,ctrain_scndpneumatic))then begin dv:=0.00025*dt*PF(Couplers[0].Connected.ScndPipePress,Couplers[1].Connected.ScndPipePress,Spz*0.25); Couplers[0].Connected.Pipe2.Flow(+dv); Couplers[1].Connected.Pipe2.Flow(-dv); end; Pipe2.Flow(Hamulec.GetHPFlow(ScndPipePress, dt)); if ((Compressor>ScndPipePress) and (CompressorSpeed>0.0001)) or (TrainType=dt_EZT) then begin dV:=PF(Compressor,ScndPipePress,Spz)*dt; CompressedVolume:=CompressedVolume+dV/1000; Pipe2.Flow(-dV); end; Pipe2.Flow(dv1+dv2); Pipe2.Act; ScndPipePress:=Pipe2.P; if ScndPipePress<-1 then begin ScndPipePress:=-1; Pipe2.CreatePress(-1); Pipe2.Act; end; end; {lokomotywy} function T_MoverParameters.ComputeRotatingWheel(WForce,dt,n:real): real; var newn,eps:real; begin if (n=0) and (WForce*Sign(V)<0) then newn:=0 else begin eps:=WForce*WheelDiameter/(2.0*AxleInertialMoment); newn:=n+eps*dt; if (newn*n<=0) and (eps*n<0) then newn:=0; end; ComputeRotatingWheel:=newn; end; {----------------------} {LOKOMOTYWA ELEKTRYCZNA} function T_MoverParameters.FuseFlagCheck: boolean; var b:byte; begin FuseFlagCheck:=false; if Power>0.01 then FuseFlagCheck:=FuseFlag else {pobor pradu jezeli niema mocy} for b:=0 to 1 do with Couplers[b] do if TestFlag(CouplingFlag,ctrain_controll) then if Connected.Power>0.01 then FuseFlagCheck:=Connected.FuseFlagCheck(); end; function T_MoverParameters.FuseOn: boolean; begin FuseOn:=false; if (MainCtrlPos=0) and (ScndCtrlPos=0) and (TrainType<>dt_ET40) and ((Mains) or (TrainType<>dt_EZT)) and (not TestFlag(EngDmgFlag,1)) then begin //w ET40 jest blokada nastawnika, ale czy działa dobrze? SendCtrlToNext('FuseSwitch',1,CabNo); if ((EngineType=ElectricSeriesMotor)or((EngineType=DieselElectric))) and FuseFlag then begin FuseFlag:=false; {wlaczenie ponowne obwodu} FuseOn:=true; SetFlag(SoundFlag,sound_relay); SetFlag(SoundFlag,sound_loud); end; end; end; procedure T_MoverParameters.FuseOff; begin if not FuseFlag then begin FuseFlag:=true; EventFlag:=true; SetFlag(SoundFlag,sound_relay); SetFlag(SoundFlag,sound_loud); end; end; function T_MoverParameters.ShowCurrent(AmpN:byte): integer; var b,Bn:byte; Grupowy: boolean; begin ClearPendingExceptions; ShowCurrent:=0; Grupowy:=(DelayCtrlFlag) and (TrainType=dt_et22); //przerzucanie walu grupowego w ET22; Bn:=RList[MainCtrlActualPos].Bn; //ile równoległych gałęzi silników if (DynamicBrakeType=dbrake_automatic) and (DynamicBrakeFlag) then Bn:=2; if Power>0.01 then begin if AmpN>0 then //podać prąd w gałęzi begin if (Bn0.01 then ShowCurrent:=Connected.ShowCurrent(AmpN); end; {Ra 2014-06: przeniesione do C++ function T_MoverParameters.ShowEngineRotation(VehN:byte): integer; var b:Byte; //,Bn:byte; begin ClearPendingExceptions; ShowEngineRotation:=0; case VehN of 1: ShowEngineRotation:=Trunc(Abs(enrot)); 2: for b:=0 to 1 do with Couplers[b] do if TestFlag(CouplingFlag,ctrain_controll) then if Connected.Power>0.01 then ShowEngineRotation:=Trunc(Abs(Connected.enrot)); 3: if Couplers[1].Connected<>nil then if TestFlag(Couplers[1].CouplingFlag,ctrain_controll) then if Couplers[1].Connected.Couplers[1].Connected<>nil then if TestFlag(Couplers[1].Connected.Couplers[1].CouplingFlag,ctrain_controll) then if Couplers[1].Connected.Couplers[1].Connected.Power>0.01 then ShowEngineRotation:=Trunc(Abs(Couplers[1].Connected.Couplers[1].Connected.enrot)); end; end; } {funkcje uzalezniajace sile pociagowa od predkosci: V2n, n2R, Current, Momentum} {----------------} function T_MoverParameters.V2n:real; {przelicza predkosc liniowa na obrotowa} const dmgn=0.5; var n,deltan:real; begin n:=V/(Pi*WheelDiameter); //predkosc obrotowa wynikajaca z liniowej [obr/s] deltan:=n-nrot; //"pochodna" prędkości obrotowej if SlippingWheels then if Abs(deltan)<0.01 then SlippingWheels:=false; {wygaszenie poslizgu} if SlippingWheels then {nie ma zwiazku z predkoscia liniowa V} begin {McZapkie-221103: uszkodzenia kol podczas poslizgu} if deltan>dmgn then if FuzzyLogic(deltan,dmgn,p_slippdmg) then if SetFlag(DamageFlag,dtrain_wheelwear) {podkucie} then EventFlag:=true; if deltan<-dmgn then if FuzzyLogic(-deltan,dmgn,p_slippdmg) then if SetFlag(DamageFlag,dtrain_thinwheel) {wycieranie sie obreczy} then EventFlag:=true; n:=nrot; {predkosc obrotowa nie zalezy od predkosci liniowej} end; V2n:=n; end; function T_MoverParameters.Current(n,U:real): real; {wazna funkcja - liczy prad plynacy przez silniki polaczone szeregowo lub rownolegle} {w zaleznosci od polozenia nastawnikow MainCtrl i ScndCtrl oraz predkosci obrotowej n} {a takze wywala bezpiecznik nadmiarowy gdy za duzy prad lub za male napiecie} {jest takze mozliwosc uszkodzenia silnika wskutek nietypowych parametrow} const ep09resED=5.8; {TODO: dobrac tak aby sie zgadzalo ze wbudzeniem} var //Rw, R,MotorCurrent:real; Rz,Delta,Isf:real; Mn: integer; Bn: real; SP: byte; U1: real; //napiecie z korekta begin MotorCurrent:=0; //i dzialanie hamulca ED w EP09 if (DynamicBrakeType=dbrake_automatic) then begin if (((Hamulec as TLSt).GetEDBCP<0.25)and(Vadd<1))or(BrakePress>2.1) then DynamicBrakeFlag:=false else if (BrakePress>0.25) and ((Hamulec as TLSt).GetEDBCP>0.25) then DynamicBrakeFlag:=true; DynamicBrakeFlag:=DynamicBrakeFlag and ConverterFlag; end; //wylacznik cisnieniowy yBARC - to jest chyba niepotrzebne tutaj // if BrakePress>2 then // begin // StLinFlag:=true; // DelayCtrlFlag:=(TrainType<>dt_EZT); //EN57 nie ma czekania na 1. pozycji // DynamicBrakeFlag:=false; // end; if(BrakeSubSystem=ss_LSt)then if(DynamicBrakeFlag)then (Hamulec as TLSt).SetED(Abs(Im/350)) //hamulec ED na EP09 dziala az do zatrzymania lokomotywy else (Hamulec as TLSt).SetED(0); ResistorsFlag:=(RList[MainCtrlActualPos].R>0.01){ and (not DelayCtrlFlag)}; ResistorsFlag:=ResistorsFlag or ((DynamicBrakeFlag=true) and (DynamicBrakeType=dbrake_automatic)); if(TrainType=dt_ET22)and(DelayCtrlFlag)and(MainCtrlActualPos>1)then Bn:=1-1/RList[MainCtrlActualPos].Bn else Bn:=1; R:=RList[MainCtrlActualPos].R*Bn+CircuitRes; if (TrainType<>dt_EZT)or(Imin<>IminLo)or(not ScndS) then //yBARC - boczniki na szeregu poprawnie Mn:=RList[MainCtrlActualPos].Mn else Mn:=RList[MainCtrlActualPos].Mn*RList[MainCtrlActualPos].Bn; //z Megapacka // if DynamicBrakeFlag and (TrainType=dt_ET42) then { KURS90 azeby mozna bylo hamowac przy opuszczonych pantografach } // SP:=ScndCtrlActualPos; // if(ScndInMain)then // if not (RList[MainCtrlActualPos].ScndAct=255) then // SP:=RList[MainCtrlActualPos].ScndAct; // with MotorParam[SP] do // begin // Rz:=WindingRes+R; // MotorCurrent:=-fi*n/Rz; // end; if DynamicBrakeFlag and (not FuseFlag) and (DynamicBrakeType=dbrake_automatic) and ConverterFlag and Mains then {hamowanie EP09} with MotorParam[0] do //TUHEX begin MotorCurrent:=-Max0R(fi*(Vadd/(Vadd+Isat)-fi0),0)*n*2/ep09resED; {TODO: zrobic bardziej uniwersalne nie tylko dla EP09} // if abs(MotorCurrent)>500 then // MotorCurrent:=sign(MotorCurrent)*500 {TODO: zrobic bardziej finezyjnie} end else if (RList[MainCtrlActualPos].Bn=0) {or FuseFlag} or (not StLinFlag) {or DelayCtrlFlag} then //if (RList[MainCtrlActualPos].Bn=0) or FuseFlag or StLinFlag or DelayCtrlFlag or ((TrainType=dt_ET42)and(not(ConverterFlag)and not(DynamicBrakeFlag))) then //z Megapacka MotorCurrent:=0 {wylaczone} else {wlaczone} begin SP:=ScndCtrlActualPos; if(ScndCtrlActualPos<255)then {tak smiesznie bede wylaczal } begin if(ScndInMain)then if not (RList[MainCtrlActualPos].ScndAct=255) then SP:=RList[MainCtrlActualPos].ScndAct; with MotorParam[SP] do begin Rz:=Mn*WindingRes+R; if DynamicBrakeFlag then {hamowanie} begin if DynamicBrakeType>1 then begin //if DynamicBrakeType<>dbrake_automatic then // MotorCurrent:=-fi*n/Rz {hamowanie silnikiem na oporach rozruchowych} (* begin U:=0; Isf:=Isat; Delta:=SQR(Isf*Rz+Mn*fi*n-U)+4*U*Isf*Rz; MotorCurrent:=(U-Isf*Rz-Mn*fi*n+SQRT(Delta))/(2*Rz) end*) if (DynamicBrakeType=dbrake_switch) and (TrainType=dt_ET42) then begin //z Megapacka Rz:=WindingRes+R; MotorCurrent:=-fi*n/Rz; //{hamowanie silnikiem na oporach rozruchowych} end; end else MotorCurrent:=0; {odciecie pradu od silnika} end else begin U1:=U+Mn*n*fi0*fi; Isf:=Sign(U1)*Isat; Delta:=SQR(Isf*Rz+Mn*fi*n-U1)+4*U1*Isf*Rz; if Mains then begin if U>0 then MotorCurrent:=(U1-Isf*Rz-Mn*fi*n+SQRT(Delta))/(2.0*Rz) else MotorCurrent:=(U1-Isf*Rz-Mn*fi*n-SQRT(Delta))/(2.0*Rz) end else MotorCurrent:=0; end;{else DBF} end;{with} end{255} else MotorCurrent:=0; end; { if Abs(CabNo)<2 then Im:=MotorCurrent*ActiveDir*CabNo else Im:=0; } if (DynamicBrakeType=dbrake_switch) and ((BrakePress>2.0) or (PipePress<3.6)) then begin Im:=0; MotorCurrent:=0; //Im:=0; Itot:=0; end else Im:=MotorCurrent; Current:=Im; {prad brany do liczenia sily trakcyjnej} { EnginePower:=Im*Im*RList[MainCtrlActualPos].Bn*RList[MainCtrlActualPos].Mn*WindingRes;} EnginePower:=Abs(Itot)*(1+RList[MainCtrlActualPos].Mn)*Abs(U); {awarie} MotorCurrent:=Abs(Im); {zmienna pomocnicza} if Motorcurrent>0 then begin if FuzzyLogic(Abs(n),nmax*1.1,p_elengproblem) then if MainSwitch(false) then EventFlag:=true; {zbyt duze obroty - wywalanie wskutek ognia okreznego} if TestFlag(DamageFlag,dtrain_engine) then if FuzzyLogic(MotorCurrent,ImaxLo/10.0,p_elengproblem) then if MainSwitch(false) then EventFlag:=true; {uszkodzony silnik (uplywy)} if (FuzzyLogic(Abs(Im),Imax*2,p_elengproblem) or FuzzyLogic(Abs(n),nmax*1.11,p_elengproblem)) then { or FuzzyLogic(Abs(U/Mn),2*NominalVoltage,1)) then } {poprawic potem} if (SetFlag(DamageFlag,dtrain_engine)) then EventFlag:=true; {! dorobic grzanie oporow rozruchowych i silnika} end; end; function T_MoverParameters.Momentum(I:real): real; {liczy moment sily wytwarzany przez silnik elektryczny} var SP: byte; begin SP:=ScndCtrlActualPos; if (ScndInMain) then if not (RList[MainCtrlActualPos].ScndAct=255) then SP:=RList[MainCtrlActualPos].ScndAct; with MotorParam[SP] do // Momentum:=mfi*I*(1-1.0/(Abs(I)/mIsat+1)); Momentum:=mfi*I*(Abs(I)/(Abs(I)+mIsat)-mfi0); end; function T_MoverParameters.MomentumF(I, Iw :real; SCP: byte): real; begin //umozliwia dokladne sterowanie wzbudzeniem with MotorParam[SCP] do MomentumF:=mfi*I*Max0R(Abs(Iw)/(Abs(Iw)+mIsat)-mfi0,0); end; function T_MoverParameters.dizel_Momentum(dizel_fill,n,dt:real): real; {liczy moment sily wytwarzany przez silnik spalinowy} var Moment, enMoment, eps, newn, friction: real; begin { friction:=dizel_engagefriction*(11-2*random)/10; } friction:=dizel_engagefriction; if enrot>0 then begin Moment:=dizel_Mmax*dizel_fill-(dizel_Mmax-dizel_Mnmax*dizel_fill)*sqr(enrot/(dizel_nmax-dizel_nMmax*dizel_fill))-dizel_Mstand; { Moment:=Moment*(1+sin(eAngle*4))-dizel_Mstand*(1+cos(eAngle*4));} end else Moment:=-dizel_Mstand; if enrot(dizel_engageMaxForce*dizel_engage*dizel_engageDia*friction*2) then {zerwanie przyczepnosci sprzegla} enrot:=enrot+dt*Moment/dizel_AIM else begin dizel_engagedeltaomega:=0; enrot:=abs(n); {jest przyczepnosc tarcz} end (* end end else begin if (enrot=0) and (Moment<0) then newn:=0 else begin //!! abs dizel_engagedeltaomega:=enrot-n; {sliganie tarcz} enMoment:=Moment-sign(dizel_engagedeltaomega)*dizel_engageMaxForce*dizel_engage*dizel_engageDia*friction; Moment:=sign(dizel_engagedeltaomega)*dizel_engageMaxForce*dizel_engage*dizel_engageDia*friction; dizel_engagedeltaomega:=abs(enrot-abs(n)); eps:=enMoment/dizel_AIM; newn:=enrot+eps*dt; if (newn*enrot<=0) and (eps*enrot<0) then newn:=0; end; enrot:=newn; end; dizel_Momentum:=Moment; if (enrot=0) and (not dizel_enginestart) then Mains:=false; end; function T_MoverParameters.CutOffEngine: boolean; {wylacza uszkodzony silnik} begin CutOffEngine:=false; //Ra: wartość domyślna, sprawdzić to trzeba if (NPoweredAxles>0) and (CabNo=0) and (EngineType=ElectricSeriesMotor) then begin if SetFlag(DamageFlag,-dtrain_engine) then begin NPoweredAxles:=NPoweredAxles div 2; CutOffEngine:=true; end; end end; {przelacznik pradu wysokiego rozruchu} function T_MoverParameters.MaxCurrentSwitch(State:boolean):boolean; begin MaxCurrentSwitch:=false; if (EngineType=ElectricSeriesMotor) then if (ImaxHi>ImaxLo) then begin if State and (Imax=ImaxLo) and (RList[MainCtrlPos].Bn<2) and not ((TrainType=dt_ET42)and(MainctrlPos>0)) then begin Imax:=ImaxHi; MaxCurrentSwitch:=true; if CabNo<>0 then SendCtrlToNext('MaxCurrentSwitch',1,CabNo); end; if (not State) then if (Imax=ImaxHi) then if not ((TrainType=dt_ET42)and(MainctrlPos>0)) then begin Imax:=ImaxLo; MaxCurrentSwitch:=true; if CabNo<>0 then SendCtrlToNext('MaxCurrentSwitch',0,CabNo); end; end; end; {przelacznik pradu automatycznego rozruchu} function T_MoverParameters.MinCurrentSwitch(State:boolean):boolean; begin MinCurrentSwitch:=false; if ((EngineType=ElectricSeriesMotor) and (IminHi>IminLo)) or (TrainType=dt_EZT) then begin if State and (Imin=IminLo) then begin Imin:=IminHi; MinCurrentSwitch:=true; if CabNo<>0 then SendCtrlToNext('MinCurrentSwitch',1,CabNo); end; if (not State) and (Imin=IminHi) then begin Imin:=IminLo; MinCurrentSwitch:=true; if CabNo<>0 then SendCtrlToNext('MinCurrentSwitch',0,CabNo); end; end; end; {reczne przelaczanie samoczynnego rozruchu} function T_MoverParameters.AutoRelaySwitch(State:boolean):boolean; begin if (AutoRelayType=2) and (AutoRelayFlag<>State) then begin AutoRelayFlag:=State; AutoRelaySwitch:=true; SendCtrlToNext('AutoRelaySwitch',ord(State),CabNo); end else AutoRelaySwitch:=false; end; function T_MoverParameters.AutoRelayCheck: boolean; var OK:boolean; b:byte; begin // if ((TrainType=dt_EZT{) or (TrainType=dt_ET22)}) and (Imin=IminLo)) or ((ActiveDir<0) and (TrainType<>dt_PseudoDiesel')) then // if RList[MainCtrlActualPos].Bn>1 then // begin // dec(MainCtrlActualPos); // AutoRelayCheck:=false; // Exit; // end; //yB: wychodzenie przy odcietym pradzie if (ScndCtrlActualPos=255)then begin AutoRelayCheck:=false; MainCtrlActualPos:=0; end else //if (not Mains) or (FuseFlag) or (StLinFlag) then //hunter-111211: wylacznik cisnieniowy //if ((not Mains) or (FuseFlag)) and not((DynamicBrakeFlag) and (TrainType=dt_ET42)) then if ((not Mains) or (FuseFlag) or (StLinFlag)) and not((DynamicBrakeFlag) and (TrainType=dt_ET42)) then //hunter-111211: wylacznik cisnieniowy begin AutoRelayCheck:=false; MainCtrlActualPos:=0; ScndCtrlActualPos:=0; end else begin OK:=false; if DelayCtrlFlag and (MainCtrlPos=1) and (MainCtrlActualPos=1) and (LastRelayTime>InitialCtrlDelay) then begin DelayCtrlFlag:=false; SetFlag(SoundFlag,sound_relay); SetFlag(SoundFlag,sound_loud); end; //if (TrainType<>dt_EZT) then //Ra: w EZT można dać od razu na S albo R, wał kułakowy sobie dokręci if (LastRelayTime>CtrlDelay) and not DelayCtrlFlag then begin if (MainCtrlPos=0) and (TrainType<>dt_ET40) and (TrainType<>dt_EP05) then DelayCtrlFlag:=true; //(TrainType<>dt_EZT); //EN57 nie ma czekania na 1. pozycji if (MainCtrlPos=0) and ((TrainType=dt_ET40)or(TrainType=dt_EP05)) and (MainCtrlActualPos=0) then DelayCtrlFlag:=true; //(TrainType<>dt_EZT); //EN57 nie ma czekania na 1. pozycji if (((RList[MainCtrlActualPos].R=0) and ((not CoupledCtrl) or ((Imin=IminLo) and (ScndS=true)))) or (MainCtrlActualPos=RListSize)) and ((ScndCtrlActualPos>0) or (ScndCtrlPos>0)) then begin {zmieniaj scndctrlactualpos} if (not AutoRelayFlag) or (not MotorParam[ScndCtrlActualPos].AutoSwitch) then begin {scnd bez samoczynnego rozruchu} OK:=true; if (ScndCtrlActualPosScndCtrlPos) and (TrainType<>dt_EZT) then dec(ScndCtrlActualPos) else if (ScndCtrlActualPos>ScndCtrlPos) and (TrainType=dt_EZT) then Exit {utkniecie walu kulakowego} else OK:=false; end else begin {scnd z samoczynnym rozruchem} if (ScndCtrlPosdt_EZT) then begin dec(ScndCtrlActualPos); OK:=true; end else if (ScndCtrlPosScndCtrlActualPos) then if Abs(Im)1 then begin AutoRelayCheck:=false; Exit; end; if (not AutoRelayFlag) or (not RList[MainCtrlActualPos].AutoSwitch) then begin {main bez samoczynnego rozruchu} OK:=true; if RList[MainCtrlActualPos].RelayRList[MainCtrlPos].Mn)and (RList[MainCtrlActualPos+1].Mn0) and (TrainType=dt_ET22) and (LastRelayTime0 then //if (RList[MainCtrlActualPos].R=0) and ((RList[MainCtrlActualPos].ScndAct=0) or (RList[MainCtrlActualPos].ScndAct=255)) then {dzwieki przechodzenia na bezoporowa} if (RList[MainCtrlActualPos].R=0) and (not (MainCtrlActualPos=MainCtrlPosNo)) then //wejscie na bezoporowa begin SetFlag(SoundFlag,sound_manyrelay); SetFlag(SoundFlag,sound_loud); end else if (RList[MainCtrlActualPos].R>0) and (RList[MainCtrlActualPos-1].R=0) then //wejscie na drugi uklad begin SetFlag(SoundFlag,sound_manyrelay); end; end else if (RList[MainCtrlActualPos].Relay>MainCtrlPos) and (TrainType<>dt_EZT) then begin if not ((RList[MainCtrlActualPos].MnRList[MainCtrlActualPos].Mn)and (TrainType=dt_ET22) and (LastRelayTime0 then //hunter-111211: poprawki //if (RList[MainCtrlActualPos+1].R=0) and ((RList[MainCtrlActualPos+1].ScndAct=0) or (RList[MainCtrlActualPos+1].ScndAct=255)) then {dzwieki schodzenia z bezoporowej} if RList[MainCtrlActualPos].R=0 then {dzwieki schodzenia z bezoporowej} begin SetFlag(SoundFlag,sound_manyrelay); end; end else begin Itot:=0; Im:=0; OK:=false; {odciecie pradu, przy przelaczaniu silnikow w ET22} end; end else if (RList[MainCtrlActualPos].Relay>MainCtrlPos) and (TrainType=dt_EZT) and (MainCtrlPos>0) then //K90 begin Exit; {utkniecie walu kulakowego} end else if (TrainType=dt_EZT) and (MainCtrlPos=0) then MainCtrlActualPos:=0 else if (RList[MainCtrlActualPos].R>0) and (ScndCtrlActualPos>0) and (TrainType<>dt_EZT) then Dec(ScndCtrlActualPos) {boczniki nie dzialaja na poz. oporowych} else if (ScndCtrlPosdt_EZT) then begin if not ((RList[MainCtrlActualPos].MnRList[MainCtrlActualPos].Mn) and (TrainType=dt_ET22) and (LastRelayTime0 then if (RList[MainCtrlActualPos+1].R=0) and ((RList[MainCtrlActualPos+1].ScndAct=0) or (RList[MainCtrlActualPos+1].ScndAct=255)) then {dzwieki schodzenia z bezoporowej} begin SetFlag(SoundFlag,sound_manyrelay); end; end else begin Itot:=0; Im:=0; OK:=false; {odciecie pradu, przy przelaczaniu silnikow w ET22} end; end else if (MainCtrlPos0) and (TrainType=dt_EZT) then begin AutoRelayCheck:=false; Exit; {utkniecie walu} end else if (TrainType=dt_EZT) and (MainCtrlPos=0) then begin MainCtrlActualPos:=0; ScndCtrlActualPos:=0; end else if ((ScndCtrlPosRList[MainCtrlActualPos].Relay) or ((MainCtrlActualPosRList[MainCtrlPos].Mn) and(RList[MainCtrlActualPos+1].Mn0 then if (RList[MainCtrlActualPos].R=0) and ((RList[MainCtrlActualPos].ScndAct=0) or (RList[MainCtrlActualPos].ScndAct=255)) then {dzwieki przechodzenia na bezoporowa} begin SetFlag(SoundFlag,sound_manyrelay); SetFlag(SoundFlag,sound_loud); end; end; end; end; end; end else {DelayCtrlFlag} if ((MainCtrlPos>1) and (MainCtrlActualPos>0) and DelayCtrlFlag) then begin //if (TrainType<>dt_EZT) then //Ra: w EZT można dać od razu na S albo R, wał kułakowy sobie dokręci MainCtrlActualPos:=0; //Ra: tu jest chyba wyłączanie przy zbyt szybkim wejściu na drugą pozycję OK:=true; end else if ((MainCtrlPos=0) and (TrainType=dt_EZT)) then begin MainCtrlActualPos:=0; ScndCtrlActualPos:=0; {zejscie walu kulakowego do 0 po ustawieniu nastawnika na 0} OK:=true; end else if (MainCtrlPos=1) and (MainCtrlActualPos=0) then MainCtrlActualPos:=1 else if (MainCtrlPos=0) and (MainCtrlActualPos>0) and (TrainType<>dt_EZT) and (TrainType<>dt_ET40) and (TrainType<>dt_EP05) then begin dec(MainCtrlActualPos); OK:=true; end; if (MainCtrlPos=0) and (MainCtrlActualPos>0) and ((TrainType=dt_ET40)or(TrainType=dt_EP05)) and (LastRelayTime>(InitialCtrlDelay*2)) then begin dec(MainCtrlActualPos); OK:=true; {wal kulakowy w ET40} end; if OK then LastRelayTime:=0; AutoRelayCheck:=OK; end; end; *) end else begin if (enrot=0) and (Moment<0) then newn:=0 else begin //!! abs dizel_engagedeltaomega:=enrot-n; {sliganie tarcz} enMoment:=Moment-sign(dizel_engagedeltaomega)*dizel_engageMaxForce*dizel_engage*dizel_engageDia*friction; Moment:=sign(dizel_engagedeltaomega)*dizel_engageMaxForce*dizel_engage*dizel_engageDia*friction; dizel_engagedeltaomega:=abs(enrot-abs(n)); eps:=enMoment/dizel_AIM; newn:=enrot+eps*dt; if (newn*enrot<=0) and (eps*enrot<0) then newn:=0; end; enrot:=newn; end; dizel_Momentum:=Moment; if (enrot=0) and (not dizel_enginestart) then Mains:=false; end; function T_MoverParameters.CutOffEngine: boolean; {wylacza uszkodzony silnik} begin CutOffEngine:=false; //Ra: wartość domyślna, sprawdzić to trzeba if (NPoweredAxles>0) and (CabNo=0) and (EngineType=ElectricSeriesMotor) then begin if SetFlag(DamageFlag,-dtrain_engine) then begin NPoweredAxles:=NPoweredAxles div 2; CutOffEngine:=true; end; end end; {przelacznik pradu wysokiego rozruchu} function T_MoverParameters.MaxCurrentSwitch(State:boolean):boolean; begin MaxCurrentSwitch:=false; if (EngineType=ElectricSeriesMotor) then if (ImaxHi>ImaxLo) then begin if State and (Imax=ImaxLo) and (RList[MainCtrlPos].Bn<2) and not ((TrainType=dt_ET42)and(MainctrlPos>0)) then begin Imax:=ImaxHi; MaxCurrentSwitch:=true; if CabNo<>0 then SendCtrlToNext('MaxCurrentSwitch',1,CabNo); end; if (not State) then if (Imax=ImaxHi) then if not ((TrainType=dt_ET42)and(MainctrlPos>0)) then begin Imax:=ImaxLo; MaxCurrentSwitch:=true; if CabNo<>0 then SendCtrlToNext('MaxCurrentSwitch',0,CabNo); end; end; end; {przelacznik pradu automatycznego rozruchu} function T_MoverParameters.MinCurrentSwitch(State:boolean):boolean; begin MinCurrentSwitch:=false; if ((EngineType=ElectricSeriesMotor) and (IminHi>IminLo)) or (TrainType=dt_EZT) then begin if State and (Imin=IminLo) then begin Imin:=IminHi; MinCurrentSwitch:=true; if CabNo<>0 then SendCtrlToNext('MinCurrentSwitch',1,CabNo); end; if (not State) and (Imin=IminHi) then begin Imin:=IminLo; MinCurrentSwitch:=true; if CabNo<>0 then SendCtrlToNext('MinCurrentSwitch',0,CabNo); end; end; end; {reczne przelaczanie samoczynnego rozruchu} function T_MoverParameters.AutoRelaySwitch(State:boolean):boolean; begin if (AutoRelayType=2) and (AutoRelayFlag<>State) then begin AutoRelayFlag:=State; AutoRelaySwitch:=true; SendCtrlToNext('AutoRelaySwitch',ord(State),CabNo); end else AutoRelaySwitch:=false; end; function T_MoverParameters.AutoRelayCheck: boolean; var OK:boolean; //b:byte; ARFASI, ARFASI2 :boolean; //sprawdzenie wszystkich warunkow (AutoRelayFlag, AutoSwitch, Im2.1)and(TrainType<>dt_EZT)) or (ActiveDir=0) then //hunter-111211: wylacznik cisnieniowy begin StLinFlag:=false; //yBARC - rozlaczenie stycznikow liniowych AutoRelayCheck:=false; if not DynamicBrakeFlag then begin Im:=0; Itot:=0; ResistorsFlag:=false; end; end; ARFASI2:=(not AutoRelayFlag) or ((MotorParam[ScndCtrlActualPos].AutoSwitch) and (Abs(Im)0) or (ScndCtrlPos>0)) and (not(CoupledCtrl)or(RList[MainCtrlActualPos].Relay=MainCtrlPos))then begin //zmieniaj scndctrlactualpos begin {scnd bez samoczynnego rozruchu} if (ScndCtrlActualPosCtrlDelay)and(ARFASI2) then begin inc(ScndCtrlActualPos); OK:=true; end end else if ScndCtrlActualPos>ScndCtrlPos then begin if (LastRelayTime>CtrlDownDelay)and(TrainType<>dt_EZT) then begin dec(ScndCtrlActualPos); OK:=true; end end else OK:=false; end; end else begin //zmieniaj mainctrlactualpos if ((ActiveDir<0) and (TrainType<>dt_PseudoDiesel)) then if RList[MainCtrlActualPos+1].Bn>1 then begin AutoRelayCheck:=false; Exit; //Ra: to powoduje, że EN57 nie wyłącza się przy IminLo end; begin //main bez samoczynnego rozruchu if (RList[MainCtrlActualPos].Relay0) and (not (MainCtrlPos=MainCtrlPosNo)) and (FastSerialCircuit=1) then begin inc(MainCtrlActualPos); // MainCtrlActualPos:=MainCtrlPos; //hunter-111012: szybkie wchodzenie na bezoporowa (303E) OK:=true; SetFlag(SoundFlag,sound_manyrelay); SetFlag(SoundFlag,sound_loud); end else if (LastRelayTime>CtrlDelay)and(ARFASI) then begin if (TrainType=dt_ET22)and(MainCtrlPos>1)and((RList[MainCtrlActualPos].Bn4*CtrlDelay) then //przejscie begin DelayCtrlFlag:=false; OK:=true; end else else //nie ET22 z wałem grupowym begin inc(MainCtrlActualPos); OK:=true; end; //--------- //hunter-111211: poprawki if MainCtrlActualPos>0 then if (RList[MainCtrlActualPos].R=0) and (not (MainCtrlActualPos=MainCtrlPosNo)) then //wejscie na bezoporowa begin SetFlag(SoundFlag,sound_manyrelay); SetFlag(SoundFlag,sound_loud); end else if (RList[MainCtrlActualPos].R>0) and (RList[MainCtrlActualPos-1].R=0) then //wejscie na drugi uklad begin SetFlag(SoundFlag,sound_manyrelay); end; end end else if RList[MainCtrlActualPos].Relay>MainCtrlPos then begin if (RList[MainCtrlPos].R=0) and (MainCtrlPos>0) and (not (MainCtrlPos=MainCtrlPosNo)) and (FastSerialCircuit=1) then begin dec(MainCtrlActualPos); // MainCtrlActualPos:=MainCtrlPos; //hunter-111012: szybkie wchodzenie na bezoporowa (303E) OK:=true; SetFlag(SoundFlag,sound_manyrelay); end else if (LastRelayTime>CtrlDownDelay) then begin if (TrainType<>dt_EZT) then //tutaj powinien być tryb sterowania wałem begin dec(MainCtrlActualPos); OK:=true; end; if MainCtrlActualPos>0 then //hunter-111211: poprawki if RList[MainCtrlActualPos].R=0 then {dzwieki schodzenia z bezoporowej} begin SetFlag(SoundFlag,sound_manyrelay); end; end end else if (RList[MainCtrlActualPos].R>0) and (ScndCtrlActualPos>0) then begin if (LastRelayTime>CtrlDownDelay) then begin Dec(ScndCtrlActualPos); {boczniki nie dzialaja na poz. oporowych} OK:=true; end end else OK:=false; end; end; end else {not StLinFlag} begin OK:=false; //ybARC - tutaj sa wszystkie warunki, jakie musza byc spelnione, zeby mozna byla zalaczyc styczniki liniowe if ((MainCtrlPos=1)or((TrainType=dt_EZT)and(MainCtrlPos>0)))and(not FuseFlag)and(Mains)and((BrakePress<1.0)or(TrainType=dt_EZT))and(MainCtrlActualPos=0)and(ActiveDir<>0) then begin DelayCtrlFlag:=true; if (LastRelayTime>=InitialCtrlDelay) then begin StLinFlag:=true; //ybARC - zalaczenie stycznikow liniowych MainCtrlActualPos:=1; DelayCtrlFlag:=false; SetFlag(SoundFlag,sound_relay); SetFlag(SoundFlag,sound_loud); OK:=true; end; end else DelayCtrlFlag:=false; if (not StLinFlag)and((MainCtrlActualPos>0)or(ScndCtrlActualPos>0)) then if (TrainType=dt_EZT)and(CoupledCtrl)then //EN57 wal jednokierunkowy calosciowy begin if(MainCtrlActualPos=1)then begin MainCtrlActualPos:=0; OK:=true; end else if(LastRelayTime>CtrlDownDelay)then begin if(MainCtrlActualPosCtrlDownDelay) then begin if (ScndCtrlActualPos>0) then dec(ScndCtrlActualPos) else dec(MainCtrlActualPos); OK:=true; end end else begin MainCtrlActualPos:=0; ScndCtrlActualPos:=0; OK:=true; end; end; if OK then LastRelayTime:=0; AutoRelayCheck:=OK; end; end; function T_MoverParameters.ResistorsFlagCheck:boolean; {sprawdzanie wskaznika oporow} var b:byte; begin ResistorsFlagCheck:=false; if Power>0.01 then ResistorsFlagCheck:=ResistorsFlag else {pobor pradu jezeli niema mocy} for b:=0 to 1 do with Couplers[b] do if TestFlag(CouplingFlag,ctrain_controll) then if Connected.Power>0.01 then ResistorsFlagCheck:=Connected.ResistorsFlagCheck(); end; function T_MoverParameters.dizel_EngageSwitch(state: real): boolean; {zmienia parametr do ktorego dazy sprzeglo} begin if (EngineType=DieselEngine) and (state<=1) and (state>=0) and (state<>dizel_engagestate) then begin dizel_engagestate:=state; dizel_EngageSwitch:=true end else dizel_EngageSwitch:=false; end; function T_MoverParameters.dizel_EngageChange(dt: real): boolean; {zmienia parametr do ktorego dazy sprzeglo} const engagedownspeed=0.9; engageupspeed=0.5; var engagespeed:real; //OK:boolean; begin dizel_EngageChange:=false; if dizel_engage-dizel_engagestate>0 then engagespeed:=engagedownspeed else engagespeed:=engageupspeed; if dt>0.2 then dt:=0.1; if abs(dizel_engage-dizel_engagestate)<0.11 then begin if (dizel_engage<>dizel_engagestate) then begin dizel_EngageChange:=true; dizel_engage:=dizel_engagestate; end //else OK:=false; //już jest false end else begin dizel_engage:=dizel_engage+engagespeed*dt*(dizel_engagestate-dizel_engage); //OK:=false; end; //dizel_EngageChange:=OK; end; (* function T_MoverParameters.dizel_rotateengine(Momentum,dt,n,engage:real): real; {oblicza obroty silnika} var newn,eps:real; begin if (Momentum<0) and (n=0) and (enrot=0) then newn:=0 else begin if (enrot0) then Momentum:=0 {nie dziala przy b. malych obrotach} else if enrotPi/2) then Momentum:=Momentum-2*dizel_Mstand end else if enrotPi) then Momentum:=Momentum-dizel_Mstand; {wstrzymywanie przy malych obrotach} eps:=Momentum/dizel_AIM; if engage<0.9 then {niepelny docisk - poslizg} begin newn:=(1-engage)*(enrot+eps*dt)+engage*(n+eps*dt); if (newn*enrot<=0) and (eps*enrot<0) then newn:=0; end else newn:=n; {bez poslizgu sprzegla} end; dizel_rotateengine:=newn; {todo: uwzglednianie AIM przy ruszaniu} end; *) function T_MoverParameters.dizel_fillcheck(mcp:byte): real; {oblicza napelnienie, uzwglednia regulator obrotow} var realfill,nreg: real; begin realfill:=0; nreg:=0; if Mains and (MainCtrlPosNo>0) then begin if dizel_enginestart and (LastSwitchingTime>=0.9*InitialCtrlDelay) then {wzbogacenie przy rozruchu} realfill:=1 else realfill:=RList[mcp].R; {napelnienie zalezne od MainCtrlPos} if dizel_nmax_cutoff>0 then begin case RList[MainCtrlPos].Mn of 0,1: nreg:=dizel_nmin; 2: if(dizel_automaticgearstatus=0)then nreg:=dizel_nmax else nreg:=dizel_nmin; else realfill:=0; {sluczaj} end; if enrot>nreg then realfill:=realfill*(3.9-3.0*abs(enrot)/nreg); if enrot>dizel_nmax_cutoff then realfill:=realfill*(9.8-9.0*abs(enrot)/dizel_nmax_cutoff); if enrot1 then realfill:=1; dizel_fillcheck:=realfill; end; function T_MoverParameters.dizel_AutoGearCheck: boolean; {automatycznie zmienia biegi gdy predkosc przekroczy widelki} var OK: boolean; begin OK:=false; if MotorParam[ScndCtrlActualPos].AutoSwitch and Mains then begin if (RList[MainCtrlPos].Mn=0) then begin if (dizel_engagestate>0) then dizel_EngageSwitch(0); if (MainCtrlPos=0) and (ScndCtrlActualPos>0) then dizel_automaticgearstatus:=-1 end else begin if MotorParam[ScndCtrlActualPos].AutoSwitch and (dizel_automaticgearstatus=0) then {sprawdz czy zmienic biegi} begin if (Vel>MotorParam[ScndCtrlActualPos].mfi) and (ScndCtrlActualPos0) then begin dizel_automaticgearstatus:=-1; OK:=true end; end; end; if (dizel_engage<0.1) and (dizel_automaticgearstatus<>0) then begin if dizel_automaticgearstatus=1 then inc(ScndCtrlActualPos) else dec(ScndCtrlActualPos); dizel_automaticgearstatus:=0; {} dizel_EngageSwitch(1.0); {} OK:=true; end end; if Mains then begin if (dizel_automaticgearstatus=0) then {ustaw cisnienie w silowniku sprzegla} case RList[MainCtrlPos].Mn of 1: dizel_EngageSwitch(0.5); 2: dizel_EngageSwitch(1.0); else dizel_EngageSwitch(0.0) end else dizel_EngageSwitch(0.0); if not (MotorParam[ScndCtrlActualPos].mIsat>0) then dizel_EngageSwitch(0.0); //wylacz sprzeglo na pozycjach neutralnych if not AutoRelayFlag then ScndCtrlActualPos:=ScndCtrlPos; end; dizel_AutoGearCheck:=OK; end; function T_MoverParameters.dizel_Update(dt:real): boolean; {odświeża informacje o silniku} //var OK:boolean; const fillspeed=2; begin //dizel_Update:=false; if dizel_enginestart and (LastSwitchingTime>=InitialCtrlDelay) then begin dizel_enginestart:=false; LastSwitchingTime:=0; enrot:=dizel_nmin/2.0; {TODO: dac zaleznie od temperatury i baterii} end; {OK:=}dizel_EngageChange(dt); // if AutoRelayFlag then Poprawka na SM03 dizel_Update:=dizel_AutoGearCheck; { dizel_fill:=(dizel_fill+dizel_fillcheck(MainCtrlPos))/2; } dizel_fill:=dizel_fill+fillspeed*dt*(dizel_fillcheck(MainCtrlPos)-dizel_fill); //dizel_Update:=OK; end; {przyczepnosc} function T_MoverParameters.Adhesive(staticfriction:real): real; //var Adhesion: real; begin {Adhesion:=0; case SlippingWheels of true: if SandDose then Adhesion:=0.48 else Adhesion:=staticfriction*0.2; false: if SandDose then Adhesion:=Max0R(staticfriction*(100+Vel)/(50+Vel)*1.1,0.48) else Adhesion:=staticfriction*(100+Vel)/(50+Vel) end; Adhesion:=Adhesion*(11-2*random)/10; Adhesive:=Adhesion;} //ABu: male przerobki, tylko czy to da jakikolwiek skutek w FPS? // w kazdym razie zaciemni kod na pewno :) if SlippingWheels=false then begin if SandDose then Adhesive:=(Max0R(staticfriction*(100.0+Vel)/((50.0+Vel)*11.0),0.048))*(11.0-2.0*random) else Adhesive:=(staticfriction*(100.0+Vel)/((50.0+Vel)*10))*(11.0-2.0*random); end else begin if SandDose then Adhesive:=(0.048)*(11-2*random) else Adhesive:=(staticfriction*0.02)*(11-2*random); end; end; {SILY} function T_MoverParameters.TractionForce(dt:real):real; const kv=0.2; ksum=0.05; var PosRatio,dmoment,dtrans,tmp,tmpV: real; i: byte; {oblicza sile trakcyjna lokomotywy (dla elektrowozu tez calkowity prad)} begin Ft:=0; dtrans:=0; dmoment:=0; // tmpV:=Abs(nrot*WheelDiameter/2); //youBy if (EngineType=DieselElectric) then begin tmp:=DEList[MainCtrlPos].rpm/60.0; if (Heating) and (HeatingPower>0) and (MainCtrlPosNo>MainCtrlPos) then begin i:=MainCtrlPosNo; while (DEList[i-2].rpm/60.0>tmp) do i:=i-1; tmp:=DEList[i].rpm/60.0 end; if enrot<>tmp*Byte(ConverterFlag) then if ABS(tmp*Byte(ConverterFlag) - enrot) < 0.001 then enrot:=tmp*Byte(ConverterFlag) else if (enrotDieselEngine then enrot:=Transmision.Ratio*nrot else //dla DieselEngine begin if (ShuntMode) then //dodatkowa przekładnia np. dla 2Ls150 dtrans:=AnPos*Transmision.Ratio*MotorParam[ScndCtrlActualPos].mIsat else dtrans:=Transmision.Ratio*MotorParam[ScndCtrlActualPos].mIsat; dmoment:=dizel_Momentum(dizel_fill,ActiveDir*1*dtrans*nrot,dt); {oblicza tez enrot} end; eAngle:=eAngle+enrot*dt; if eAngle>Pirazy2 then //eAngle:=Pirazy2-eAngle; <- ABu: a nie czasem tak, jak nizej? eAngle:=eAngle-Pirazy2; //hunter-091012: przeniesione z if ActiveDir<>0 (zeby po zejsciu z kierunku dalej spadala predkosc wentylatorow) if (EngineType=ElectricSeriesMotor) then begin case RVentType of {wentylatory rozruchowe} 1: if (ActiveDir<>0) and (RList[MainCtrlActualPos].R>RVentCutOff) then RventRot:=RventRot+(RVentnmax-RventRot)*RVentSpeed*dt else RventRot:=RventRot*(1-RVentSpeed*dt); 2: if (Abs(Itot)>RVentMinI) and (RList[MainCtrlActualPos].R>RVentCutOff) then RventRot:=RventRot+(RVentnmax*Abs(Itot)/(ImaxLo*RList[MainCtrlActualPos].Bn)-RventRot)*RVentSpeed*dt else if (DynamicBrakeType=dbrake_automatic) and (DynamicBrakeFlag) then RventRot:=RventRot+(RVentnmax*Im/ImaxLo-RventRot)*RVentSpeed*dt else begin RventRot:=RventRot*(1-RVentSpeed*dt); if RventRot<0.1 then RventRot:=0; end; end; {case} end; {if} if ActiveDir<>0 then case EngineType of Dumb: begin PosRatio:=(MainCtrlPos+ScndCtrlPos)/(MainCtrlPosNo+ScndCtrlPosNo+0.01); if Mains and (ActiveDir<>0) and (CabNo<>0) then begin if Vel>0.1 then begin Ft:=Min0R(1000.0*Power/Abs(V),Ftmax)*PosRatio; end else Ft:=Ftmax*PosRatio; Ft:=Ft*DirAbsolute; //ActiveDir*CabNo; end else Ft:=0; EnginePower:=1000*Power*PosRatio; end; WheelsDriven: begin if EnginePowerSource.SourceType=InternalSource then if EnginePowerSource.PowerType=BioPower then Ft:=sign(sin(eAngle))*PulseForce*Transmision.Ratio; PulseForceTimer:=PulseForceTimer+dt; if PulseForceTimer>CtrlDelay then begin PulseForce:=0; if PulseForceCount>0 then dec(PulseForceCount); end; EnginePower:=Ft*(1+Vel); end; ElectricSeriesMotor: begin { enrot:=Transmision.Ratio*nrot; } //yB: szereg dwoch sekcji w ET42 if(TrainType=dt_ET42)and(Imax=ImaxHi)then Voltage:=Voltage/2.0; Mm:=Momentum(Current(enrot,Voltage)); {oblicza tez prad p/slinik} if(TrainType=dt_ET42)then begin if(Imax=ImaxHi)then Voltage:=Voltage*2; if(DynamicBrakeFlag)and(Abs(Im)>300)then FuseOff; end; if (DynamicBrakeType=dbrake_automatic)and(DynamicBrakeFlag) then begin if ((Vadd+Abs(Im))>760)or((Hamulec as TLSt).GetEDBCP<0.25) then begin Vadd:=Vadd-500*dt; if(Vadd<1)then Vadd:=0; end else if (DynamicBrakeFlag)and((Vadd+Abs(Im))<740) then begin Vadd:=Vadd+70*dt; Vadd:=Min0R(Max0R(Vadd,60),400); end; if(Vadd>0)then Mm:=MomentumF(Im,Vadd,0); end; if(TrainType=dt_ET22)and(DelayCtrlFlag)then //szarpanie przy zmianie układu w byku Mm:=Mm*RList[MainCtrlActualPos].Bn/(RList[MainCtrlActualPos].Bn+1); //zrobione w momencie, żeby nie dawac elektryki w przeliczaniu sił if (Abs(Im)>Imax) then Vhyp:=Vhyp+dt//*(Abs(Im)/Imax-0.9)*10 //zwieksz czas oddzialywania na PN else Vhyp:=0; if (Vhyp>CtrlDelay/2) then //jesli czas oddzialywania przekroczony // dec(MainCtrlActualPos); FuseOff; {wywalanie bezpiecznika z powodu przetezenia silnikow} if (Mains) then //nie wchodzić w funkcję bez potrzeby if (Abs(Voltage)EnginePowerSource.CollectorParameters.MaxV) then if MainSwitch(false) then EventFlag:=true; //wywalanie szybkiego z powodu niewłaściwego napięcia if (((DynamicBrakeType=dbrake_automatic)or(DynamicBrakeType=dbrake_switch)) and (DynamicBrakeFlag)) then Itot:=Im*2 {2x2 silniki w EP09} else if (TrainType=dt_EZT)and(Imin=IminLo)and(ScndS) then //yBARC - boczniki na szeregu poprawnie Itot:=Im else Itot:=Im*RList[MainCtrlActualPos].Bn; {prad silnika * ilosc galezi} Mw:=Mm*Transmision.Ratio; Fw:=Mw*2.0/WheelDiameter; Ft:=Fw*NPoweredAxles; {sila trakcyjna} end; DieselEngine: begin EnginePower:=dmoment*enrot; if MainCtrlPos>1 then dmoment:=dmoment-dizel_Mstand*(0.2*enrot/nmax); {dodatkowe opory z powodu sprezarki} Mm:=dizel_engage*dmoment; Mw:=Mm*dtrans; {dmoment i dtrans policzone przy okazji enginerotation} Fw:=Mw*2.0/WheelDiameter; Ft:=Fw*NPoweredAxles; {sila trakcyjna} Ft:=Ft*DirAbsolute; //ActiveDir*CabNo; end; DieselElectric: //youBy begin // tmpV:=V*CabNo*ActiveDir; tmpV:=nrot*Pirazy2*0.5*WheelDiameter*DirAbsolute; //*CabNo*ActiveDir; //jazda manewrowa if (ShuntMode) then begin Voltage:=(SST[MainCtrlPos].Umax * AnPos) + (SST[MainCtrlPos].Umin * (1 - AnPos)); tmp:=(SST[MainCtrlPos].Pmax * AnPos) + (SST[MainCtrlPos].Pmin * (1 - AnPos)); Ft:=tmp * 1000.0 / (abs(tmpV)+1.6); PosRatio:=1; end else //jazda ciapongowa begin tmp:=Min0R(DEList[MainCtrlPos].genpower,Power-HeatingPower*byte(Heating)); PosRatio:=DEList[MainCtrlPos].genpower / DEList[MainCtrlPosNo].genpower; {stosunek mocy teraz do mocy max} if (MainCtrlPos>0) and (ConverterFlag) then if tmpV < (Vhyp*(Power-HeatingPower*byte(Heating))/DEList[MainCtrlPosNo].genpower) then //czy na czesci prostej, czy na hiperboli Ft:=(Ftmax - ((Ftmax - 1000.0 * DEList[MainCtrlPosNo].genpower / (Vhyp+Vadd)) * (tmpV/Vhyp) / PowerCorRatio)) * PosRatio //posratio - bo sila jakos tam sie rozklada //Ft:=(Ftmax - (Ftmax - (1000.0 * DEList[MainCtrlPosNo].genpower / (Vhyp+Vadd) / PowerCorRatio)) * (tmpV/Vhyp)) * PosRatio //wersja z Megapacka else //na hiperboli //1.107 - wspolczynnik sredniej nadwyzki Ft w symku nad charakterystyka Ft:=1000.0 * tmp / (tmpV+Vadd) / PowerCorRatio //tu jest zawarty stosunek mocy else Ft:=0; //jak nastawnik na zero, to sila tez zero PosRatio:=tmp/DEList[MainCtrlPosNo].genpower; end; if (FuseFlag) then Ft:=0 else Ft:=Ft*DirAbsolute; //ActiveDir * CabNo; //zwrot sily i jej wartosc Fw:=Ft/NPoweredAxles; //sila na obwodzie kola Mw:=Fw*WheelDiameter / 2.0; // moment na osi kola Mm:=Mw/Transmision.Ratio; // moment silnika trakcyjnego with MotorParam[ScndCtrlPos] do if ABS(Mm) > fi then Im:=NPoweredAxles * ABS(ABS(Mm) / mfi + mIsat) else Im:=NPoweredAxles * sqrt(ABS(Mm * Isat)); if (ShuntMode) then begin EnginePower:=Voltage * Im/1000.0; if (EnginePower > tmp) then begin EnginePower:=tmp*1000.0; Voltage:=EnginePower/Im; end; if (EnginePower < tmp) then Ft:=Ft * EnginePower / tmp; end else begin if (ABS(Im) > DEList[MainCtrlPos].Imax) then begin //nie ma nadmiarowego, tylko Imax i zwarcie na pradnicy Ft:=Ft/Im*DEList[MainCtrlPos].Imax;Im:=DEList[MainCtrlPos].Imax; end; if (Im > 0) then //jak pod obciazeniem if (Flat) then //ograniczenie napiecia w pradnicy - plaszczak u gory Voltage:=1000.0 * tmp / ABS(Im) else //charakterystyka pradnicy obcowzbudnej (elipsa) - twierdzenie Pitagorasa begin Voltage:=sqrt(ABS(sqr(DEList[MainCtrlPos].Umax)-sqr(DEList[MainCtrlPos].Umax*Im/DEList[MainCtrlPos].Imax)))*(MainCtrlPos-1)+ (1-Im/DEList[MainCtrlPos].Imax)*DEList[MainCtrlPos].Umax*(MainCtrlPosNo-MainCtrlPos); Voltage:=Voltage/(MainCtrlPosNo-1); Voltage:=Min0R(Voltage,(1000.0 * tmp / ABS(Im))); if Voltage<(Im*0.05) then Voltage:=Im*0.05; end; if (Voltage > DEList[MainCtrlPos].Umax) or (Im = 0) then //gdy wychodzi za duze napiecie Voltage:=DEList[MainCtrlPos].Umax * byte(ConverterFlag); //albo przy biegu jalowym (jest cos takiego?) EnginePower:=Voltage * Im / 1000.0; if (tmpV>2) and (EnginePower1) and (Im>Imax) then FuseOff; if FuseFlag then Voltage:=0; //przekazniki bocznikowania, kazdy inny dla kazdej pozycji if (MainCtrlPos = 0) or (ShuntMode) then ScndCtrlPos:=0 else if AutoRelayFlag then case RelayType of 0: begin if (Im <= (MPTRelay[ScndCtrlPos].Iup*PosRatio)) and (ScndCtrlPos= (MPTRelay[ScndCtrlPos].Idown*PosRatio)) and (ScndCtrlPos>0) then dec(ScndCtrlPos); end; 1: begin if (MPTRelay[ScndCtrlPos].IupVel) and (ScndCtrlPos>0) then dec(ScndCtrlPos); end; 2: begin if (MPTRelay[ScndCtrlPos].Iup0) then dec(ScndCtrlPos); end; 41: begin if (MainCtrlPos=MainCtrlPosNo) and (tmpV*3.6>MPTRelay[ScndCtrlPos].Iup) and (ScndCtrlPosMPTRelay[ScndCtrlPos].Idown)and (ScndCtrlPos>0) then dec(ScndCtrlPos); end; 45: begin //wzrastanie if (MainCtrlPos>11) and (ScndCtrlPosIm) then inc(ScndCtrlPos) else else if (MPTRelay[ScndCtrlPos].Iup0)and(MainCtrlPos<12)then if (ScndCtrlPos=ScndCtrlPosNo)then if (MPTRelay[ScndCtrlPos].IdownVel)then dec(ScndCtrlPos); if (MainCtrlPos<11)and(ScndCtrlPos>2) then ScndCtrlPos:=2; if (MainCtrlPos<9)and(ScndCtrlPos>0) then ScndCtrlPos:=0; end; 46: begin //wzrastanie if (MainCtrlPos>9) and (ScndCtrlPosIm) then inc(ScndCtrlPos) else else if (MPTRelay[ScndCtrlPos-1].Iup>Im) and (MPTRelay[ScndCtrlPos].Iup0)then if (ScndCtrlPos) mod 2 = 0 then if (MPTRelay[ScndCtrlPos].IdownVel)then dec(ScndCtrlPos); if (MainCtrlPos<9)and(ScndCtrlPos>2) then ScndCtrlPos:=2; if (MainCtrlPos<6)and(ScndCtrlPos>0) then ScndCtrlPos:=0; end; end; end; ElectricInductionMotor: begin if (Mains) then //nie wchodzić w funkcję bez potrzeby if (Abs(Voltage)EnginePowerSource.CollectorParameters.MaxV+200) then begin MainSwitch(false); end; tmpV:=abs(nrot)*(Pi*WheelDiameter)*3.6;//*DirAbsolute*eimc[eimc_s_p]; - do przemyslenia dzialanie pp if (MainS) then begin dtrans:=(Hamulec as TLSt).GetEDBCP; if ((DoorLeftOpened)or(DoorRightOpened)) then DynamicBrakeFlag:=true else if ((dtrans<0.25) and (LocHandle.GetCP<0.25) and (AnPos<0.01)) or ((dtrans<0.25) and (ShuntModeAllow) and (LocalBrakePos=0)) then DynamicBrakeFlag:=false else if (((BrakePress>0.25) and (dtrans>0.25) or (LocHandle.GetCP>0.25))) or (AnPos>0.02) then DynamicBrakeFlag:=true; dtrans:=(Hamulec as TLSt).GetEDBCP*eimc[eimc_p_abed]; //stala napedu if(DynamicBrakeFlag)then begin if eimv[eimv_Fmax]*sign(V)*DirAbsolute<-1 then begin PosRatio:=-sign(V)*DirAbsolute*eimv[eimv_Fr]/(eimc[eimc_p_Fh]*Max0R(dtrans/MaxBrakePress[0],AnPos){dizel_fill}); end else PosRatio:=0; PosRatio:=round(20*Posratio)/20; if PosRatio<19.5/20 then PosRatio:=PosRatio*0.9; // if PosRatio<0 then // PosRatio:=2+PosRatio-2; (Hamulec as TLSt).SetED(Max0R(0.0,Min0R(PosRatio,1))); // (Hamulec as TLSt).SetLBP(LocBrakePress*(1-PosRatio)); PosRatio:=-Max0R(Min0R(dtrans/MaxBrakePress[0],1),AnPos)*Max0R(0,Min0R(1,(Vel-eimc[eimc_p_Vh0])/(eimc[eimc_p_Vh1]-eimc[eimc_p_Vh0]))); eimv[eimv_Fzad]:=-Max0R(LocalBrakeRatio,dtrans/MaxBrakePress[0]); tmp:=5; end else begin PosRatio:=(MainCtrlPos/MainCtrlPosNo); eimv[eimv_Fzad]:=PosRatio; if(Flat)and(eimc[eimc_p_F0]*eimv[eimv_Fful]>0)then PosRatio:=Min0R(PosRatio*eimc[eimc_p_F0]/eimv[eimv_Fful],1); if ScndCtrlActualPos>0 then if (Vmax<250) then PosRatio:=Min0R(PosRatio,Max0R(-1,0.5*(ScndCtrlActualPos-Vel))) else PosRatio:=Min0R(PosRatio,Max0R(-1,0.5*(ScndCtrlActualPos*2-Vel))); PosRatio:=1.0*(PosRatio*0+1)*PosRatio; (Hamulec as TLSt).SetED(0); // (Hamulec as TLSt).SetLBP(LocBrakePress); if (PosRatio>dizel_fill) then tmp:=1 else tmp:=4; //szybkie malenie, powolne wzrastanie end; // if SlippingWheels then begin PosRatio:=0; tmp:=10; SandDoseOn; end;//przeciwposlizg // if(Flat)then //PRZECIWPOŚLIZG dmoment:=eimv[eimv_Fful]; // else // dmoment:=eimc[eimc_p_F0]*0.99; if (abs((PosRatio+9.66*dizel_fill)*dmoment*100)>0.95*Adhesive(RunningTrack.friction)*TotalMassxg) then begin PosRatio:=0; tmp:=4; SandDoseOn; end;//przeciwposlizg if (abs((PosRatio+9.80*dizel_fill)*dmoment*100)>0.95*Adhesive(RunningTrack.friction)*TotalMassxg) then begin PosRatio:=0; tmp:=9; SandDoseOn; end;//przeciwposlizg if (SlippingWheels) then begin PosRatio:=-PosRatio*0; tmp:=9; SandDoseOn; end;//przeciwposlizg dizel_fill:=dizel_fill+Max0R(Min0R(PosRatio-dizel_fill,0.1),-0.1)*2*(tmp{2{+4*byte(PosRatio=0) then Vadd:=Vadd*(1-2*dt) else if (Voltage1) or (abs(tmpV)>0.1))and(RlistSize>0) then begin i:=0; while (i0 then NBrakeAxles:=NPoweredAxles else NBrakeAxles:=NAxles; case LocalBrake of NoBrake : K:=0; ManualBrake : K:=MaxBrakeForce*ManualBrakeRatio; HydraulicBrake : K:=MaxBrakeForce*LocalBrakeRatio; PneumaticBrake:if CompressorNtotal)then //histereza na nacisku klockow Ntotal:=u*BrakeRigEff else begin u:=(BrakePress*P2FTrans)*BrakeCylMult[0]-BrakeSlckAdj; if (u*(2-1*BrakeRigEff)0) then begin if Ntotal>0 then {nie luz} K:=K+Ntotal; {w kN} K:=K*BrakeCylNo/(NBrakeAxles*NBpA); {w kN na os} end; if (BrakeSystem=Pneumatic)or(BrakeSystem=ElectroPneumatic) then begin u:=Hamulec.GetFC(Vel, K); UnitBrakeForce:=u*K*1000; {sila na jeden klocek w N} end else UnitBrakeForce:=K*1000; if (NBpA*UnitBrakeForce>TotalMassxg*Adhesive(RunningTrack.friction)/NAxles) and (Abs(V)>0.001) then {poslizg} begin { Fb:=Adhesive(Track.friction)*Mass*g; } SlippingWheels:=true; end; { else begin { SlippingWheels:=false;} // if (LocalBrake=ManualBrake)or(MBrake=true)) and (BrakePress<0.3) then // Fb:=UnitBrakeForce*NBpA {ham. reczny dziala na jedna os} // else //yB: to nie do konca ma sens, ponieważ ręczny w wagonie działa na jeden cylinder hamulcowy/wózek, dlatego potrzebne są oddzielnie liczone osie Fb:=UnitBrakeForce*NBrakeAxles*Max0R(1,NBpA); // u:=((BrakePress*P2FTrans)-BrakeCylSpring*BrakeCylMult[BCMFlag]/BrakeCylNo-0.83*BrakeSlckAdj/(BrakeCylNo))*BrakeCylNo; { end; } BrakeForce:=Fb; end; function T_MoverParameters.CouplerForce(CouplerN:byte;dt:real):real; //wyliczenie siły na sprzęgu var tempdist,newdist,distDelta,CF,dV,absdv,Fmax,BetaAvg:real; CNext:byte; const MaxDist=405.0; {ustawione + 5 m, bo skanujemy do 400 m } MinDist=0.5; {ustawione +.5 m, zeby nie rozlaczac przy malych odleglosciach} MaxCount=1500; begin CF:=0; //distDelta:=0; //Ra: value never used CNext:=Couplers[CouplerN].ConnectedNr; { if Couplers[CouplerN].CForce=0 then {nie bylo uzgadniane wiec policz} with Couplers[CouplerN] do begin CheckCollision:=false; newdist:=CoupleDist; //odległość od sprzęgu sąsiada //newdist:=Distance(Loc,Connected^.Loc,Dim,Connected^.Dim); if (CouplerN=0) then begin //ABu: bylo newdist+10*((... tempdist:=((Connected.dMoveLen*DirPatch(0,ConnectedNr))-dMoveLen); newdist:=newdist+10.0*tempdist; //tempdist:=tempdist+CoupleDist; //ABu: proby szybkiego naprawienia bledu end else begin //ABu: bylo newdist+10*((... tempdist:=((dMoveLen-(Connected.dMoveLen*DirPatch(1,ConnectedNr)))); newdist:=newdist+10.0*tempdist; //tempdist:=tempdist+CoupleDist; //ABu: proby szybkiego naprawienia bledu end; //blablabla //ABu: proby znalezienia problemu ze zle odbijajacymi sie skladami //***if (Couplers[CouplerN].CouplingFlag=ctrain_virtual) and (newdist>0) then if (Couplers[CouplerN].CouplingFlag=ctrain_virtual) and (CoupleDist>0) then begin CF:=0; {kontrola zderzania sie - OK} inc(ScanCounter); if (newdist>MaxDist) or ((ScanCounter>MaxCount)and(newdist>MinDist)) then //***if (tempdist>MaxDist) or ((ScanCounter>MaxCount)and(tempdist>MinDist)) then begin {zerwij kontrolnie wirtualny sprzeg} //Connected.Couplers[CNext].Connected:=nil; //Ra: ten podłączony niekoniecznie jest wirtualny Connected:=nil; ScanCounter:=Random(500); end; end else begin if CouplingFlag=ctrain_virtual then begin BetaAvg:=beta; Fmax:=(FmaxC+FmaxB)*CouplerTune; end else {usrednij bo wspolny sprzeg} begin BetaAvg:=(beta+Connected.Couplers[CNext].beta)/2.0; Fmax:=(FmaxC+FmaxB+Connected.Couplers[CNext].FmaxC+Connected.Couplers[CNext].FmaxB)*CouplerTune/2.0; end; dV:=V-DirPatch(CouplerN,CNext)*Connected.V; absdv:=abs(dV); if (newdist<-0.001) and (Dist>=-0.001) and (absdv>0.010) then {090503: dzwieki pracy zderzakow} begin if SetFlag(SoundFlag,sound_bufferclamp) then if absdV>0.5 then SetFlag(SoundFlag,sound_loud); end else if (newdist>0.002) and (Dist<=0.002) and (absdv>0.005) then {090503: dzwieki pracy sprzegu} begin if CouplingFlag>0 then if SetFlag(SoundFlag,sound_couplerstretch) then if absdV>0.1 then SetFlag(SoundFlag,sound_loud); end; distDelta:=abs(newdist)-abs(Dist); //McZapkie-191103: poprawka na histereze Dist:=newdist; if Dist>0 then begin if distDelta>0 then CF:=(-(SpringKC+Connected.Couplers[CNext].SpringKC)*Dist/2.0)*DirF(CouplerN)-Fmax*dV*betaAvg else CF:=(-(SpringKC+Connected.Couplers[CNext].SpringKC)*Dist/2.0)*DirF(CouplerN)*betaAvg-Fmax*dV*betaAvg; {liczenie sily ze sprezystosci sprzegu} if Dist>(DmaxC+Connected.Couplers[CNext].DmaxC) then {zderzenie} //***if tempdist>(DmaxC+Connected^.Couplers[CNext].DmaxC) then {zderzenie} CheckCollision:=true; end; if Dist<0 then begin if distDelta>0 then CF:=(-(SpringKB+Connected.Couplers[CNext].SpringKB)*Dist/2.0)*DirF(CouplerN)-Fmax*dV*betaAvg else CF:=(-(SpringKB+Connected.Couplers[CNext].SpringKB)*Dist/2.0)*DirF(CouplerN)*betaAvg-Fmax*dV*betaAvg; {liczenie sily ze sprezystosci zderzaka} if -Dist>(DmaxB+Connected.Couplers[CNext].DmaxB) then {zderzenie} //***if -tempdist>(DmaxB+Connected^.Couplers[CNext].DmaxB)/10 then {zderzenie} begin CheckCollision:=true; if (CouplerType=Automatic) and (CouplingFlag=0) then {sprzeganie wagonow z samoczynnymi sprzegami} //CouplingFlag:=ctrain_coupler+ctrain_pneumatic+ctrain_controll+ctrain_passenger+ctrain_scndpneumatic; CouplingFlag:=ctrain_coupler+ctrain_pneumatic+ctrain_controll; //EN57 end; end; end; if (CouplingFlag<>ctrain_virtual) then {uzgadnianie prawa Newtona} Connected.Couplers[1-CouplerN].CForce:=-CF; end; CouplerForce:=CF; end; procedure T_MoverParameters.CollisionDetect(CouplerN:byte; dt:real); var CCF,Vprev,VprevC:real; VirtualCoupling:boolean; begin CCF:=0; with Couplers[CouplerN] do if (Connected<>nil) then begin VirtualCoupling:=(CouplingFlag=ctrain_virtual); Vprev:=V; VprevC:=Connected.V; case CouplerN of 0 : CCF:=ComputeCollision(V,Connected.V,TotalMass,Connected.TotalMass,(beta+Connected.Couplers[ConnectedNr].beta)/2.0,VirtualCoupling)/(dt{+0.01}); //yB: ej ej ej, a po 1 : CCF:=ComputeCollision(Connected.V,V,Connected.TotalMass,TotalMass,(beta+Connected.Couplers[ConnectedNr].beta)/2.0,VirtualCoupling)/(dt{+0.01}); //czemu tu jest +0.01?? end; AccS:=AccS+(V-Vprev)/dt; //korekta przyspieszenia o siły wynikające ze zderzeń? Connected.AccS:=Connected.AccS+(Connected.V-VprevC)/dt; if (Dist>0) and (not VirtualCoupling) then if FuzzyLogic(Abs(CCF),5*(FmaxC+1),p_coupldmg) then begin {! zerwanie sprzegu} if SetFlag(DamageFlag,dtrain_coupling) then EventFlag:=true; if (Couplers[CouplerN].CouplingFlag and ctrain_pneumatic>0) then EmergencyBrakeFlag:=true; {hamowanie nagle - zerwanie przewodow hamulcowych} CouplingFlag:=0; case CouplerN of {wyzerowanie flag podlaczenia ale ciagle sa wirtualnie polaczone} 0 : Connected.Couplers[1].CouplingFlag:=0; 1 : Connected.Couplers[0].CouplingFlag:=0; end end ; end; end; procedure T_MoverParameters.ComputeConstans; var BearingF,RollF,HideModifier: real; Curvature: real; //Ra 2014-07: odwrotność promienia begin TotalCurrent:=0; //Ra 2014-04: tu zerowanie, aby EZT mogło pobierać prąd innemu członowi TotalMass:=ComputeMass; TotalMassxg:=TotalMass*g; {TotalMass*g} BearingF:=2*(DamageFlag and dtrain_bearing); HideModifier:=0;//Byte(Couplers[0].CouplingFlag>0)+Byte(Couplers[1].CouplingFlag>0); with Dim do begin if BearingType=0 then RollF:=0.05 {slizgowe} else RollF:=0.015; {toczne} RollF:=RollF+BearingF/200.0; (* if NPoweredAxles>0 then RollF:=RollF*1.5; {dodatkowe lozyska silnikow}*) if (NPoweredAxles>0) then //drobna optymalka begin RollF:=RollF+0.025; { if(Ft*Ft<1)then HideModifier:=HideModifier-3; } end; Ff:=TotalMassxg*(BearingF+RollF*V*V/10.0)/1000.0; {dorobic liczenie temperatury lozyska!} FrictConst1:=((TotalMassxg*RollF)/10000.0)+(Cx*W*H); Curvature:=abs(RunningShape.R); //zero oznacza nieskończony promień if (Curvature>0.0) then Curvature:=1.0/Curvature; //opór składu na łuku (youBy): +(500*TrackW/R)*TotalMassxg*0.001 do FrictConst2s/d FrictConst2s:= (TotalMassxg*((500.0*TrackW*Curvature)+ 2.5 - HideModifier + 2*BearingF/dtrain_bearing))*0.001; FrictConst2d:= (TotalMassxg*((500.0*TrackW*Curvature)+ 2.0 - HideModifier + BearingF/dtrain_bearing))*0.001; end; end; (* poprawione opory ruchu czekajace na lepsze cx w chk procedure T_MoverParameters.ComputeConstans2(R:real); var BearingF,RollF,HideModifier: real; begin TotalMass:=ComputeMass; TotalMassxg:=TotalMass*g; {TotalMass*g} BearingF:=2*(DamageFlag and dtrain_bearing); HideModifier:=Byte(Couplers[0].CouplingFlag>0)+Byte(Couplers[1].CouplingFlag>0); with Dim do begin if BearingType=0 then RollF:=10 {slizgowe} else RollF:=8; {toczne} if NPoweredAxles>0 then RollF:=RollF+2; {dodatkowe lozyska silnikow} RollF:=RollF+BearingF/100.0; //stala do ustalenia {dorobic liczenie temperatury lozyska!} //stale do wzoru CNTK FrictConst1:=(Cx*W*H)*(6.0-2.5*HideModifier)/100; //dwa czola, kazde ma +2.5 (lokomotywa i wagon) //V2 FrictConst2s:=Totalmass*0.001*0.15; //V1 if(R0.01) then FrictionForce:=(FrictConst1*V*V)+FrictConst2d else FrictionForce:=(FrictConst1*V*V)+FrictConst2s; end; (* poprawione opory ruchu czekajace na lepsze cx w chk function T_MoverParameters.FrictionForce2(R:real;TDamage:byte):real; begin //ABu 240205: chyba juz ekstremalnie zoptymalizowana funkcja liczaca sily tarcia FrictionForce2:=(FrictConst1*Vel*Vel)+(FrictConst2s*Vel)+FrictConst2d; end; *) function T_MoverParameters.AddPulseForce(Multipler:integer): boolean; {dla drezyny} begin if (EngineType=WheelsDriven) and (EnginePowerSource.SourceType=InternalSource) and (EnginePowerSource.PowerType=BioPower) then begin ActiveDir:=CabNo; DirAbsolute:=ActiveDir*CabNo; if Vel>0 then PulseForce:=Min0R(1000.0*Power/(Abs(V)+0.1),Ftmax) else PulseForce:=Ftmax; if PulseForceCount>1000.0 then PulseForce:=0 else PulseForce:=PulseForce*Multipler; PulseForceCount:=PulseForceCount+Abs(Multipler); AddPulseForce:=(PulseForce>0); end else AddPulseForce:=false; end; function T_MoverParameters.LoadingDone(LSpeed:real; LoadInit:string): boolean; //test zakończenia załadunku/rozładunku var LoadChange:longint; begin ClearPendingExceptions; //zabezpieczenie dla Trunc() //LoadingDone:=false; //nie zakończone if (LoadInit<>'') then //nazwa ładunku niepusta begin if Load>MaxLoad then LoadChange:=Abs(Trunc(LSpeed*LastLoadChangeTime/2.0)) //przeładowanie? else LoadChange:=Abs(Trunc(LSpeed*LastLoadChangeTime)); if LSpeed<0 then //gdy rozładunek begin LoadStatus:=2; //trwa rozładunek (włączenie naliczania czasu) if LoadChange<>0 then //jeśli coś przeładowano begin LastLoadChangeTime:=0; //naliczony czas został zużyty Load:=Load-LoadChange; //zmniejszenie ilości ładunku CommandIn.Value1:=CommandIn.Value1-LoadChange; //zmniejszenie ilości do rozładowania if Load<0 then Load:=0; //ładunek nie może być ujemny if (Load=0) or (CommandIn.Value1<0) then //pusto lub rozładowano żądaną ilość LoadStatus:=4; //skończony rozładunek if Load=0 then LoadType:=''; //jak nic nie ma, to nie ma też nazwy end end else if LSpeed>0 then //gdy załadunek begin LoadStatus:=1; //trwa załadunek (włączenie naliczania czasu) if LoadChange<>0 then //jeśli coś przeładowano begin LastLoadChangeTime:=0; //naliczony czas został zużyty LoadType:=LoadInit; //nazwa Load:=Load+LoadChange; //zwiększenie ładunku CommandIn.Value1:=CommandIn.Value1-LoadChange; if (Load>=MaxLoad*(1+OverLoadFactor)) or (CommandIn.Value1<0) then LoadStatus:=4; //skończony załadunek end end else LoadStatus:=4; //zerowa prędkość zmiany, to koniec end; LoadingDone:=(LoadStatus>=4); end; {-------------------------------------------------------------------} {WAZNA FUNKCJA - oblicza siłę wypadkową} procedure T_MoverParameters.ComputeTotalForce(dt: real; dt1: real; FullVer: boolean); var b: byte; begin if PhysicActivation then begin { EventFlag:=false; {jesli cos sie zlego wydarzy to ustawiane na true} { SoundFlag:=0; {jesli ma byc jakis dzwiek to zapalany jet odpowiedni bit} {to powinno byc zerowane na zewnatrz} //juz zoptymalizowane: FStand:=FrictionForce(RunningShape.R,RunningTrack.DamageFlag); //siła oporów ruchu Vel:=Abs(V)*3.6; //prędkość w km/h nrot:=V2n(); //przeliczenie prędkości liniowej na obrotową if TestFlag(BrakeMethod,bp_MHS) and (PipePress<3.0) and (Vel>45) and TestFlag(BrakeDelayFlag,bdelay_M) then //ustawione na sztywno na 3 bar FStand:=Fstand+{(RunningTrack.friction)*}TrackBrakeForce; //doliczenie hamowania hamulcem szynowym //w charakterystykach jest wartość siły hamowania zamiast nacisku // if(FullVer=true) then // begin //ABu: to dla optymalizacji, bo chyba te rzeczy wystarczy sprawdzac 1 raz na klatke? LastSwitchingTime:=LastSwitchingTime+dt1; if EngineType=ElectricSeriesMotor then LastRelayTime:=LastRelayTime+dt1; // end; if Mains and {(Abs(CabNo)<2) and} (EngineType=ElectricSeriesMotor) then //potem ulepszyc! pantogtrafy! begin //Ra 2014-03: uwzględnienie kierunku jazdy w napięciu na silnikach, a powinien być zdefiniowany nawrotnik if CabNo=0 then Voltage:=RunningTraction.TractionVoltage*ActiveDir else Voltage:=RunningTraction.TractionVoltage*DirAbsolute; //ActiveDir*CabNo; end {bo nie dzialalo} else if (EngineType=ElectricInductionMotor) or (((Couplers[0].CouplingFlag and ctrain_power)=ctrain_power) or ((Couplers[1].CouplingFlag and ctrain_power)=ctrain_power)) then //potem ulepszyc! pantogtrafy! Voltage:=Max0R(Max0R(RunningTraction.TractionVoltage,HVCouplers[0][1]),HVCouplers[1][1]) else Voltage:=0; //end; if Power>0 then FTrain:=TractionForce(dt) else FTrain:=0; Fb:=BrakeForce(RunningTrack); if Max0R(Abs(FTrain),Fb)>TotalMassxg*Adhesive(RunningTrack.friction) then {poslizg} SlippingWheels:=true; if SlippingWheels then begin { TrainForce:=TrainForce-Fb; } nrot:=ComputeRotatingWheel((FTrain-Fb*Sign(V)-Fstand)/NAxles-Sign(nrot*Pi*WheelDiameter-V)*Adhesive(RunningTrack.friction)*TotalMass,dt,nrot); FTrain:=sign(FTrain)*TotalMassxg*Adhesive(RunningTrack.friction); Fb:=Min0R(Fb,TotalMassxg*Adhesive(RunningTrack.friction)); end; { else SlippingWheels:=false; } { FStand:=0; } for b:=0 to 1 do if (Couplers[b].Connected<>nil) {and (Couplers[b].CouplerType<>Bare) and (Couplers[b].CouplerType<>Articulated)} then begin //doliczenie sił z innych pojazdów Couplers[b].CForce:=CouplerForce(b,dt); FTrain:=FTrain+Couplers[b].CForce end else Couplers[b].CForce:=0; //FStand:=Fb+FrictionForce(RunningShape.R,RunningTrack.DamageFlag); FStand:=Fb+FStand; FTrain:=FTrain+TotalMassxg*RunningShape.dHtrack; //doliczenie składowej stycznej grawitacji {!niejawne przypisanie zmiennej!} FTotal:=FTrain-Sign(V)*FStand; end; {McZapkie-031103: sprawdzanie czy warto liczyc fizyke i inne updaty} {ABu 300105: cos tu mieszalem , dziala teraz troche lepiej, wiec zostawiam zakomentowalem PhysicActivationFlag bo cos nie dzialalo i fizyka byla liczona zawsze.} //if PhysicActivationFlag then // begin if (CabNo=0) and (Vel<0.0001) and (abs(AccS)<0.0001) and (TrainType<>dt_EZT) then begin if not PhysicActivation then begin if Couplers[0].Connected<>nil then if (Couplers[0].Connected.Vel>0.0001) or (Abs(Couplers[0].Connected.AccS)>0.0001) then Physic_ReActivation; if Couplers[1].Connected<>nil then if (Couplers[1].Connected.Vel>0.0001) or (Abs(Couplers[1].Connected.AccS)>0.0001) then Physic_ReActivation; end; if LastSwitchingTime>5 then //10+Random(100) then PhysicActivation:=false; {zeby nie brac pod uwage braku V po uruchomieniu programu} end else PhysicActivation:=true; // end; end; {------------------------------------------------------------} {OBLICZENIE PRZEMIESZCZENIA} function T_MoverParameters.ComputeMovement(dt:real; dt1:real; Shape:TTrackShape; var Track:TTrackParam; var ElectricTraction:TTractionParam; NewLoc:TLocation; var NewRot:TRotation):real; var b:byte; Vprev,AccSprev:real; // Iheat:real; prad ogrzewania hvc: real; const Vepsilon=1e-5; Aepsilon=1e-3; //ASBSpeed=0.8; begin TotalCurrent:=0; hvc:=Max0R(Max0R(PantFrontVolt,PantRearVolt),ElectricTraction.TractionVoltage*0.9); for b:=0 to 1 do //przekazywanie napiec if ((Couplers[b].CouplingFlag and ctrain_power) = ctrain_power)or(((Couplers[b].CouplingFlag and ctrain_heating) = ctrain_heating)and(Heating)) then begin HVCouplers[1-b][1]:=Max0R(Abs(hvc),Couplers[b].Connected.HVCouplers[Couplers[b].ConnectedNr][1]-HVCouplers[b][0]*0.02); end else HVCouplers[1-b][1]:=Abs(hvc)-HVCouplers[b][0]*0.02;//Max0R(Abs(Voltage),0); // end; hvc:=HVCouplers[0][1]+HVCouplers[1][1]; if (Abs(PantFrontVolt)+Abs(PantRearVolt)<1) and (hvc>1)then //bez napiecia, ale jest cos na sprzegach: begin for b:=0 to 1 do //przekazywanie pradow if ((Couplers[b].CouplingFlag and ctrain_power) = ctrain_power)or(((Couplers[b].CouplingFlag and ctrain_heating) = ctrain_heating)and(Heating)) then //jesli spiety begin HVCouplers[b][0]:=Couplers[b].Connected.HVCouplers[1-Couplers[b].ConnectedNr][0]+Itot*HVCouplers[b][1]/hvc; //obciążenie rozkladane stosownie do napiec end else //pierwszy pojazd begin HVCouplers[b][0]:=Itot*HVCouplers[b][1]/hvc; end; end else begin if ((Couplers[0].CouplingFlag and ctrain_power) = ctrain_power)or(((Couplers[0].CouplingFlag and ctrain_heating) = ctrain_heating)and(Heating)) then TotalCurrent:=TotalCurrent+Couplers[0].Connected.HVCouplers[1-Couplers[0].ConnectedNr][0]; if ((Couplers[1].CouplingFlag and ctrain_power) = ctrain_power)or(((Couplers[1].CouplingFlag and ctrain_heating) = ctrain_heating)and(Heating)) then TotalCurrent:=TotalCurrent+Couplers[1].Connected.HVCouplers[1-Couplers[1].ConnectedNr][0]; HVCouplers[0][0]:=0; HVCouplers[1][0]:=0; end; ClearPendingExceptions; if not TestFlag(DamageFlag,dtrain_out) then begin //Ra: to przepisywanie tu jest bez sensu RunningShape:=Shape; RunningTrack:=Track; RunningTraction:=ElectricTraction; with ElectricTraction do if not DynamicBrakeFlag then RunningTraction.TractionVoltage:=TractionVoltage{-Abs(TractionResistivity*(Itot+HVCouplers[0][0]+HVCouplers[1][0]))} else RunningTraction.TractionVoltage:=TractionVoltage-Abs(TractionResistivity*Itot*0); //zasadniczo ED oporowe nie zmienia napięcia w sieci end; if CategoryFlag=4 then OffsetTrackV:=TotalMass/(Dim.L*Dim.W*1000.0) else if TestFlag(CategoryFlag,1) and TestFlag(RunningTrack.CategoryFlag,1) then if TestFlag(DamageFlag,dtrain_out) then begin OffsetTrackV:=-0.2; OffsetTrackH:=sign(RunningShape.R)*0.2; end; Loc:=NewLoc; Rot:=NewRot; with NewRot do begin Rx:=0; Ry:=0; Rz:=0; end; if dL=0 then {oblicz przesuniecie} begin Vprev:=V; AccSprev:=AccS; {dt:=ActualTime-LastUpdatedTime;} {przyrost czasu} {przyspieszenie styczne} AccS:=(FTotal/TotalMass+AccSprev)/2.0; //prawo Newtona ale z wygladzaniem (średnia z poprzednim) if TestFlag(DamageFlag,dtrain_out) then AccS:=-Sign(V)*g*Random; {przyspieszenie normalne} if Abs(Shape.R)>0.01 then AccN:=SQR(V)/Shape.R+g*Shape.dHrail/TrackW else AccN:=g*Shape.dHrail/TrackW; {szarpanie} if FuzzyLogic((10+Track.DamageFlag)*Mass*Vel/Vmax,500000,p_accn) then {Ra: czemu tu masa bez ładunku?} AccV:=sqrt((1+Track.DamageFlag)*random(Trunc(50*Mass/1000000.0))*Vel/(Vmax*(10+(Track.QualityFlag and 31)))) else AccV:=AccV/2.0; if AccV>1.0 then AccN:=AccN+(7-random(5))*(100.0+Track.DamageFlag/2.0)*AccV/2000.0; {wykolejanie na luku oraz z braku szyn} if TestFlag(CategoryFlag,1) then begin if FuzzyLogic((AccN/g)*(1+0.1*(Track.DamageFlag and dtrack_freerail)),TrackW/Dim.H,1) or TestFlag(Track.DamageFlag,dtrack_norail) then if SetFlag(DamageFlag,dtrain_out) then begin EventFlag:=true; MainS:=false; RunningShape.R:=0; if (TestFlag(Track.DamageFlag,dtrack_norail)) then DerailReason:=1 //Ra: powód wykolejenia: brak szyn else DerailReason:=2; //Ra: powód wykolejenia: przewrócony na łuku end; {wykolejanie na poszerzeniu toru} if FuzzyLogic(Abs(Track.Width-TrackW),TrackW/10.0,1) then if SetFlag(DamageFlag,dtrain_out) then begin EventFlag:=true; MainS:=false; RunningShape.R:=0; DerailReason:=3; //Ra: powód wykolejenia: za szeroki tor end; end; {wykolejanie wkutek niezgodnosci kategorii toru i pojazdu} if not TestFlag(RunningTrack.CategoryFlag,CategoryFlag) then if SetFlag(DamageFlag,dtrain_out) then begin EventFlag:=true; MainS:=false; DerailReason:=4; //Ra: powód wykolejenia: nieodpowiednia trajektoria end; V:=V+(3*AccS-AccSprev)*dt/2.0; {przyrost predkosci} if TestFlag(DamageFlag,dtrain_out) then if Vel<1 then begin V:=0; AccS:=0; end; if (V*Vprev<=0) and (Abs(FStand)>Abs(FTrain)) then {tlumienie predkosci przy hamowaniu} begin {zahamowany} V:=0; //AccS:=0; //Ra 2014-03: ale siła grawitacji działa, więc nie może być zerowe end; (* else if (Abs(V)0.01 then // AccN:=SQR(V)/Shape.R+g*Shape.dHrail/TrackW // else AccN:=g*Shape.dHrail/TrackW; {szarpanie} if FuzzyLogic((10+Track.DamageFlag)*Mass*Vel/Vmax,500000,p_accn) then AccV:=sqrt((1+Track.DamageFlag)*random(Trunc(50*Mass/1000000.0))*Vel/(Vmax*(10+(Track.QualityFlag and 31)))) else AccV:=AccV/2.0; if AccV>1.0 then AccN:=AccN+(7-random(5))*(100.0+Track.DamageFlag/2.0)*AccV/2000.0; // {wykolejanie na luku oraz z braku szyn} // if TestFlag(CategoryFlag,1) then // begin // if FuzzyLogic((AccN/g)*(1+0.1*(Track.DamageFlag and dtrack_freerail)),TrackW/Dim.H,1) // or TestFlag(Track.DamageFlag,dtrack_norail) then // if SetFlag(DamageFlag,dtrain_out) then // begin // EventFlag:=true; // MainS:=false; // RunningShape.R:=0; // end; // {wykolejanie na poszerzeniu toru} // if FuzzyLogic(Abs(Track.Width-TrackW),TrackW/10,1) then // if SetFlag(DamageFlag,dtrain_out) then // begin // EventFlag:=true; // MainS:=false; // RunningShape.R:=0; // end; // end; // {wykolejanie wkutek niezgodnosci kategorii toru i pojazdu} // if not TestFlag(RunningTrack.CategoryFlag,CategoryFlag) then // if SetFlag(DamageFlag,dtrain_out) then // begin // EventFlag:=true; // MainS:=false; // end; V:=V+(3.0*AccS-AccSprev)*dt/2.0; {przyrost predkosci} if TestFlag(DamageFlag,dtrain_out) then if Vel<1 then begin V:=0; AccS:=0; //Ra 2014-03: ale siła grawitacji działa, więc nie może być zerowe end; if (V*Vprev<=0) and (Abs(FStand)>Abs(FTrain)) then {tlumienie predkosci przy hamowaniu} begin {zahamowany} V:=0; AccS:=0; end; dL:=(3*V-Vprev)*dt/2.0; {metoda Adamsa-Bashfortha} {ale jesli jest kolizja (zas. zach. pedu) to...} for b:=0 to 1 do if Couplers[b].CheckCollision then CollisionDetect(b,dt); {zmienia niejawnie AccS, V !!!} end; {liczone dL, predkosc i przyspieszenie} {Ra: reszta przeniesiona do Mover.cpp} end; {FastComputeMovement} function T_MoverParameters.ComputeMass: real; var M:real; begin if Load>0 then begin //zakładamy, że ładunek jest pisany małymi literami if LoadQuantity='tonns' then M:=Load*1000 else if (LoadType='passengers') then M:=Load*80 else if LoadType='luggage' then M:=Load*100 else if LoadType='cars' then M:=Load*800 else if LoadType='containers' then M:=Load*8000 else if LoadType='transformers' then M:=Load*50000 else M:=Load*1000; end else M:=0; {Ra: na razie tak, ale nie wszędzie masy wirujące się wliczają} ComputeMass:=Mass+M+Mred; end; {-----------------------------------------------------------------} {funkcje wejscia/wyjscia} {przekazywanie komend i parametrow} function T_MoverParameters.SetInternalCommand(NewCommand:string; NewValue1,NewValue2:real):boolean; begin if (CommandIn.Command=Newcommand) and (commandIn.Value1=NewValue1) and (commandIn.Value2=NewValue2) then SetInternalCommand:=false else with CommandIn do begin Command:=NewCommand; Value1:=NewValue1; Value2:=NewValue2; SetInternalCommand:=true; LastLoadChangeTime:=0; //zerowanie czasu (roz)ładowania end; end; function T_MoverParameters.GetExternalCommand(var Command:string):real; begin Command:=CommandOut; GetExternalCommand:=ValueOut; end; function T_MoverParameters.DoorBlockedFlag:Boolean; begin //if (DoorBlocked=true) and (Vel<5.0) then DoorBlockedFlag:=false; if (DoorBlocked=true) and (Vel>=5.0) then DoorBlockedFlag:=true end; function T_MoverParameters.RunCommand(command:string; CValue1,CValue2:real):boolean; //wysłanie komendy otrzymanej z kierunku CValue2 (względem sprzęgów: 1=przod,-1=tył) // Ra: Jest tu problem z rekurencją. Trzeba by oddzielić wykonywanie komend od mechanizmu // ich propagacji w składzie. Osobnym problemem może być propagacja tylko w jedną stronę. // Jeśli jakiś człon jest wstawiony odwrotnie, to również odwrotnie musi wykonywać // komendy związane z kierunkami (PantFront, PantRear, DoorLeft, DoorRight). // Komenda musi być zdefiniowana tutaj, a jeśli się wywołuje funkcję, to ona nie może // sama przesyłać do kolejnych pojazdów. Należy też się zastanowić, czy dla uzyskania // jakiejś zmiany (np. IncMainCtrl) lepiej wywołać funkcję, czy od razu wysłać komendę. var OK:boolean; testload:string; Begin {$B+} {cholernie mi sie nie podoba ta dyrektywa!!!} OK:=false; ClearPendingExceptions(); {test komend sterowania ukrotnionego} if command='MainCtrl' then begin if MainCtrlPosNo>=Trunc(CValue1) then MainCtrlPos:=Trunc(CValue1); OK:=SendCtrlToNext(command,CValue1,CValue2); end else if command='ScndCtrl' then begin if (EngineType=ElectricInductionMotor) then if (ScndCtrlPos=0) and (Trunc(CValue1)>0) then if (Vmax<250) then ScndCtrlActualPos:=Round(Vel+0.5) else ScndCtrlActualPos:=Round(Vel/2+0.5) else if (Trunc(CValue1)=0) then ScndCtrlActualPos:=0; if ScndCtrlPosNo>=Trunc(CValue1) then ScndCtrlPos:=Trunc(CValue1); OK:=SendCtrlToNext(command,CValue1,CValue2); end (* else if command='BrakeCtrl' then begin if BrakeCtrlPosNo>=Trunc(CValue1) then begin BrakeCtrlPos:=Trunc(CValue1); OK:=SendCtrlToNext(command,CValue1,CValue2); end; end *) else if command='Brake' then //youBy - jak sie EP hamuje, to trza sygnal wyslac... begin Hamulec.SetEPS(CValue1); //fBrakeCtrlPos:=BrakeCtrlPos; //to powinnno być w jednym miejscu, aktualnie w C++!!! BrakePressureActual:=BrakePressureTable[BrakeCtrlPos]; OK:=SendCtrlToNext(command,CValue1,CValue2); end //youby - odluzniacz hamulcow, przyda sie else if command='BrakeReleaser' then begin OK:=BrakeReleaser(Round(CValue1)); //samo się przesyła dalej //OK:=SendCtrlToNext(command,CValue1,CValue2); //to robiło kaskadę 2^n end else if command='MainSwitch' then begin if CValue1=1 then begin Mains:=true; if (EngineType=DieselEngine) and Mains then dizel_enginestart:=true; end else Mains:=false; OK:=SendCtrlToNext(command,CValue1,CValue2); end else if command='Direction' then begin ActiveDir:=Trunc(CValue1); DirAbsolute:=ActiveDir*CabNo; OK:=SendCtrlToNext(command,CValue1,CValue2); end else if command='CabActivisation' then begin // OK:=Power>0.01; case Trunc(CValue1*CValue2) of //CValue2 ma zmieniany znak przy niezgodności sprzęgów 1 : CabNo:= 1; -1 : CabNo:=-1; else CabNo:=0; //gdy CValue1==0 end; DirAbsolute:=ActiveDir*CabNo; OK:=SendCtrlToNext(command,CValue1,CValue2); end else if command='AutoRelaySwitch' then begin if (CValue1=1) and (AutoRelayType=2) then AutoRelayFlag:=true else AutoRelayFlag:=false; OK:=SendCtrlToNext(command,CValue1,CValue2); end else if command='FuseSwitch' then begin if ((EngineType=ElectricSeriesMotor)or(EngineType=DieselElectric)) and FuseFlag and (CValue1=1) and (MainCtrlActualPos=0) and (ScndCtrlActualPos=0) and Mains then { if (EngineType=ElectricSeriesMotor) and (CValue1=1) and (MainCtrlActualPos=0) and (ScndCtrlActualPos=0) and Mains then} FuseFlag:=false; {wlaczenie ponowne obwodu} // if ((EngineType=ElectricSeriesMotor)or(EngineType=DieselElectric)) and not FuseFlag and (CValue1=0) and Mains then // FuseFlag:=true; OK:=SendCtrlToNext(command,CValue1,CValue2); end else if command='ConverterSwitch' then {NBMX} begin if (CValue1=1) then ConverterAllow:=true else if (CValue1=0) then ConverterAllow:=false; OK:=SendCtrlToNext(command,CValue1,CValue2); end else if command='BatterySwitch' then {NBMX} begin if (CValue1=1) then Battery:=true else if (CValue1=0) then Battery:=false; if (Battery) and (ActiveCab<>0) {or (TrainType=dt_EZT)} then SecuritySystem.Status:=SecuritySystem.Status or s_waiting //aktywacja czuwaka else SecuritySystem.Status:=0; //wyłączenie czuwaka OK:=SendCtrlToNext(command,CValue1,CValue2); end // else if command='EpFuseSwitch' then {NBMX} // begin // if (CValue1=1) then EpFuse:=true // else if (CValue1=0) then EpFuse:=false; // OK:=SendCtrlToNext(command,CValue1,CValue2); // end else if command='CompressorSwitch' then {NBMX} begin if (CValue1=1) then CompressorAllow:=true else if (CValue1=0) then CompressorAllow:=false; OK:=SendCtrlToNext(command,CValue1,CValue2); end else if command='DoorOpen' then {NBMX} begin //Ra: uwzględnić trzeba jeszcze zgodność sprzęgów if (CValue2>0) then begin //normalne ustawienie pojazdu if (CValue1=1) OR (CValue1=3) then DoorLeftOpened:=true; if (CValue1=2) OR (CValue1=3) then DoorRightOpened:=true; end else begin //odwrotne ustawienie pojazdu if (CValue1=2) OR (CValue1=3) then DoorLeftOpened:=true; if (CValue1=1) OR (CValue1=3) then DoorRightOpened:=true; end; OK:=SendCtrlToNext(command,CValue1,CValue2); end else if command='DoorClose' then {NBMX} begin //Ra: uwzględnić trzeba jeszcze zgodność sprzęgów if (CValue2>0) then begin //normalne ustawienie pojazdu if (CValue1=1) OR (CValue1=3) then DoorLeftOpened:=false; if (CValue1=2) OR (CValue1=3) then DoorRightOpened:=false; end else begin //odwrotne ustawienie pojazdu if (CValue1=2) OR (CValue1=3) then DoorLeftOpened:=false; if (CValue1=1) OR (CValue1=3) then DoorRightOpened:=false; end; OK:=SendCtrlToNext(command,CValue1,CValue2); end else if command='PantFront' then {Winger 160204} begin //Ra: uwzględnić trzeba jeszcze zgodność sprzęgów //Czemu EZT ma być traktowane inaczej? Ukrotnienie ma, a człon może być odwrócony if (TrainType=dt_EZT) then begin //'ezt' if (CValue1=1) then begin PantFrontUp:=true; PantFrontStart:=0; end else if (CValue1=0) then begin PantFrontUp:=false; PantFrontStart:=1; end; end else begin //nie 'ezt' - odwrotne ustawienie pantografów: ^-.-^ zamiast ^-.^- if (CValue1=1) then if (TestFlag(Couplers[1].CouplingFlag,ctrain_controll)and(CValue2= 1)) or(TestFlag(Couplers[0].CouplingFlag,ctrain_controll)and(CValue2=-1)) then begin PantFrontUp:=true; PantFrontStart:=0; end else begin PantRearUp:=true; PantRearStart:=0; end else if (CValue1=0) then if (TestFlag(Couplers[1].CouplingFlag,ctrain_controll)and(CValue2= 1)) or(TestFlag(Couplers[0].CouplingFlag,ctrain_controll)and(CValue2=-1)) then begin PantFrontUp:=false; PantFrontStart:=1; end else begin PantRearUp:=false; PantRearStart:=1; end; end; OK:=SendCtrlToNext(command,CValue1,CValue2); end else if command='PantRear' then {Winger 160204, ABu 310105 i 030305} begin //Ra: uwzględnić trzeba jeszcze zgodność sprzęgów if (TrainType=dt_EZT) then begin {'ezt'} if (CValue1=1) then begin PantRearUp:=true; PantRearStart:=0; end else if (CValue1=0) then begin PantRearUp:=false; PantRearStart:=1; end; end else begin {nie 'ezt'} if (CValue1=1) then {if ostatni polaczony sprz. sterowania} if (TestFlag(Couplers[1].CouplingFlag,ctrain_controll)and(CValue2= 1)) or(TestFlag(Couplers[0].CouplingFlag,ctrain_controll)and(CValue2=-1)) then begin PantRearUp:=true; PantRearStart:=0; end else begin PantFrontUp:=true; PantFrontStart:=0; end else if (CValue1=0) then if (TestFlag(Couplers[1].CouplingFlag,ctrain_controll)and(CValue2= 1)) or(TestFlag(Couplers[0].CouplingFlag,ctrain_controll)and(CValue2=-1)) then begin PantRearUp:=false; PantRearStart:=1; end else begin PantFrontUp:=false; PantFrontStart:=1; end; end; OK:=SendCtrlToNext(command,CValue1,CValue2); end else if command='MaxCurrentSwitch' then begin OK:=MaxCurrentSwitch(CValue1=1); end else if command='MinCurrentSwitch' then begin OK:=MinCurrentSwitch(CValue1=1); end {test komend oddzialywujacych na tabor} else if command='SetDamage' then begin if CValue2=1 then OK:=SetFlag(DamageFlag,Trunc(CValue1)); if CValue2=-1 then OK:=SetFlag(DamageFlag,-Trunc(CValue1)); end else if command='Emergency_brake' then begin if EmergencyBrakeSwitch(Trunc(CValue1)=1) then //YB: czy to jest potrzebne? OK:=true else OK:=false; end else if command='BrakeDelay' then begin BrakeDelayFlag:=Trunc(CValue1); OK:=true; end else if command='SandDoseOn' then begin if SandDoseOn then OK:=true else OK:=false; end else if command='CabSignal' then {SHP,Indusi} begin //Ra: to powinno działać tylko w członie obsadzonym if {(TrainType=dt_EZT)or} (ActiveCab<>0) and (Battery) and TestFlag(SecuritySystem.SystemType,2) then //jeśli kabina jest obsadzona (silnikowy w EZT?) with SecuritySystem do begin VelocityAllowed:=Trunc(CValue1); NextVelocityAllowed:=Trunc(CValue2); SystemSoundSHPTimer:=0; //hunter-091012 SetFlag(Status,s_active); end; //else OK:=false; OK:=true; //true, gdy można usunąć komendę end {naladunek/rozladunek} else if Pos('Load=',command)=1 then begin OK:=false; //będzie powtarzane aż się załaduje if (Vel=0) and (MaxLoad>0) and (Load0 then //nazwa jest obecna w CHK OK:=LoadingDone(Min0R(CValue2,LoadSpeed),testload); //zmienia LoadStatus end; //if OK then LoadStatus:=0; //nie udalo sie w ogole albo juz skonczone end else if Pos('UnLoad=',command)=1 then begin OK:=false; //będzie powtarzane aż się rozładuje if (Vel=0) and (Load>0) then //czy jest co rozladowac? if Distance(Loc,CommandIn.Location,Dim,Dim)<10 then //ten peron begin testload:=DUE(command); //zgodność nazwy ładunku z CHK if LoadType=testload then {mozna to rozladowac} OK:=LoadingDone(-Min0R(CValue2,LoadSpeed),testload); end; //if OK then LoadStatus:=0; end; RunCommand:=OK; //dla true komenda będzie usunięta, dla false wykonana ponownie {$B-} End; function T_MoverParameters.RunInternalCommand:boolean; var OK:boolean; begin if CommandIn.Command<>'' then begin OK:=RunCommand(CommandIn.Command,CommandIn.Value1,CommandIn.Value2); if OK then with CommandIn do begin Command:=''; {kasowanie bo rozkaz wykonany} Value1:=0; Value2:=0; Location.x:=0; Location.y:=0; Location.z:=0; if not PhysicActivation then Physic_ReActivation; end; end else OK:=false; RunInternalCommand:=OK; end; procedure T_MoverParameters.PutCommand(NewCommand:string; NewValue1,NewValue2:real; NewLocation:TLocation); begin CommandLast:=NewCommand; //zapamiętanie komendy with CommandIn do begin Command:=NewCommand; Value1:=NewValue1; Value2:=NewValue2; Location:=NewLocation; end; {czy uruchomic tu RunInternalCommand? nie wiem} end; {dla samochodow - kolej nie wężykuje} function T_MoverParameters.ChangeOffsetH(DeltaOffset:real):boolean; begin if TestFlag(CategoryFlag,2) and TestFlag(RunningTrack.CategoryFlag,2) then begin OffsetTrackH:=OffsetTrackH+DeltaOffset; // if abs(OffsetTrackH)>(RunningTrack.Width/1.95-TrackW/2.0) then if abs(OffsetTrackH)>(0.5*(RunningTrack.Width-Dim.W)-0.05) then //Ra: może pół pojazdu od brzegu? ChangeOffsetH:=false {kola na granicy drogi} else ChangeOffsetH:=true; end else ChangeOffsetH:=false; end; {inicjalizacja} constructor T_MoverParameters.Init(//LocInitial:TLocation; RotInitial:TRotation; VelInitial:real; TypeNameInit, NameInit: string; LoadInitial:longint; LoadTypeInitial: string; Cab:integer); {predkosc pocz. w km/h, ilosc ladunku, typ ladunku, numer kabiny} var b,k:integer; begin {inicjalizacja stalych} dMoveLen:=0; CategoryFlag:=1; EngineType:=None; for b:=0 to ResArraySize do begin RList[b].Relay:=0; RList[b].R:=0; RList[b].Bn:=0; RList[b].Mn:=0; RList[b].AutoSwitch:=false; end; WheelDiameter:=1.0; BrakeCtrlPosNo:=0; LightsPosNo:=0; LightsDefPos:=1; for k:=-1 to MainBrakeMaxPos do with BrakePressureTable[k] do begin PipePressureVal:=0; BrakePressureVal:=0; FlowSpeedVal:=0; end; with BrakePressureTable[-2] do {pozycja odciecia} begin PipePressureVal:=-1; BrakePressureVal:=-1; FlowSpeedVal:=0; end; Transmision.Ratio:=1; NBpA:=0; DynamicBrakeType:=0; ASBType:=0; AutoRelayType:=0; for b:=0 to 1 do //Ra: kto tu zrobił "for b:=1 to 2 do" ??? with Couplers[b] do begin CouplerType:=NoCoupler; SpringkB:=1; SpringkC:=1; DmaxB:=0.1; FmaxB:=1000; DmaxC:=0.1; FmaxC:=1000; end; Power:=0; MaxLoad:=0; LoadAccepted:=''; LoadSpeed:=0; UnLoadSpeed:=0; HeatingPower:=0; LightPower:=0; with HeatingPowerSource do begin MaxVoltage:=0; MaxCurrent:=0; IntR:=0.001; SourceType:=NotDefined; PowerType:=NoPower; RPowerCable.PowerTrans:=NoPower; end; with AlterHeatPowerSource do begin MaxVoltage:=0; MaxCurrent:=0; IntR:=0.001; SourceType:=NotDefined; PowerType:=NoPower; RPowerCable.PowerTrans:=NoPower; end; with LightPowerSource do begin MaxVoltage:=0; MaxCurrent:=0; IntR:=0.001; SourceType:=NotDefined; PowerType:=NoPower; RPowerCable.PowerTrans:=NoPower; end; with AlterLightPowerSource do begin MaxVoltage:=0; MaxCurrent:=0; IntR:=0.001; SourceType:=NotDefined; PowerType:=NoPower; RPowerCable.PowerTrans:=NoPower; end; TypeName:=TypeNameInit; HighPipePress:=0; LowPipePress:=0; DeltaPipePress:=0; BrakeCylNo:=0; BrakeCylRadius:=0; BrakeCylDist:=0; for b:=0 to 3 do BrakeCylMult[b]:=0; VeselVolume:=0; BrakeVolume:=0; RapidMult:=1; dizel_Mmax:=1; dizel_nMmax:=1; dizel_Mnmax:=2; dizel_nmax:=2; dizel_nominalfill:=0; dizel_Mstand:=0; dizel_nmax_cutoff:=0; dizel_nmin:=0; dizel_minVelfullengage:=0; dizel_AIM:=1; dizel_engageDia:=0.5; dizel_engageMaxForce:=6000; dizel_engagefriction:=0.5; DoorOpenCtrl:=0; DoorCloseCtrl:=0; DoorStayOpen:=0; DoorClosureWarning:=false; DoorOpenSpeed:=1; DoorCloseSpeed:=1; DoorMaxShiftL:=0.5; DoorMaxShiftR:=0.5; DoorOpenMethod:=2; DepartureSignal:=false; InsideConsist:=false; CompressorPower:=1; SmallCompressorPower:=0; for b:=0 to 25 do eimc[b]:=0; eimc[eimc_p_eped]:=1.5; StopBrakeDecc:=0; ScndInMain:=false; Vhyp:=1; Vadd:=1; PowerCorRatio:=1; {inicjalizacja zmiennych} //Loc:=LocInitial; //Ra: to i tak trzeba potem przesunąć, po ustaleniu pozycji na torze (potrzebna długość) //Rot:=RotInitial; for b:=0 to 1 do with Couplers[b] do begin AllowedFlag:=3; //domyślnie hak i hamulec, inne trzeba włączyć jawnie w FIZ CouplingFlag:=0; Connected:=nil; ConnectedNr:=0; //Ra: to nie ma znaczenia jak nie podłączony Render:=false; CForce:=0; Dist:=0; CheckCollision:=false; end; ScanCounter:=0; BrakeCtrlPos:=-2; //to nie ma znaczenia, konstruktor w Mover.cpp zmienia na -2 BrakeDelayFlag:=0; BrakeStatus:=b_off; EmergencyBrakeFlag:=false; MainCtrlPos:=0; ScndCtrlPos:=0; MainCtrlActualPos:=0; ScndCtrlActualPos:=0; LightsPos:=0; Heating:=false; Mains:=false; ActiveDir:=0; //kierunek nie ustawiony CabNo:=0; //sterowania nie ma, ustawiana przez CabActivization() ActiveCab:=Cab; //obsada w podanej kabinie DirAbsolute:=0; SlippingWheels:=false; SandDose:=false; FuseFlag:=false; ConvOvldFlag:=false; //hunter-251211 StLinFlag:=false; ResistorsFlag:=false; Rventrot:=0; enrot:=0; nrot:=0; Itot:=0; EnginePower:=0; BrakePress:=0; Compressor:=0; ConverterFlag:=false; CompressorAllow:=false; DoorLeftOpened:=false; DoorRightOpened:=false; battery:=false; EpFuse:=true; Signalling:=false; Radio:=true; DoorSignalling:=false; UnBrake:=false; //Winger 160204 PantVolume:=0.48; //aby podniesione pantografy opadły w krótkim czasie przy wyłączonej sprężarce PantFrontUp:=false; PantRearUp:=false; PantFrontStart:=0; PantRearStart:=0; PantFrontSP:=true; PantRearSP:=true; DoubleTr:=1; BrakeSlippingTimer:=0; dpBrake:=0; dpPipe:=0; dpMainValve:=0; dpLocalValve:=0; MBPM:=1; DynamicBrakeFlag:=false; BrakeSystem:=Individual; BrakeSubsystem:=ss_None; Ft:=0; Ff:=0; Fb:=0; Ftotal:=0; FStand:=0; FTrain:=0; AccS:=0; AccN:=0; AccV:=0; EventFlag:=false; SoundFlag:=0; Vel:=Abs(VelInitial); V:=VelInitial/3.6; LastSwitchingTime:=0; LastRelayTime:=0; DistCounter:=0; PulseForce:=0; PulseForceTimer:=0; PulseForceCount:=0; eAngle:=1.5; dizel_fill:=0; dizel_engagestate:=0; dizel_engage:=0; dizel_automaticgearstatus:=0; dizel_enginestart:=false; dizel_engagedeltaomega:=0; PhysicActivation:=true; for b:=1 to 20 do eimv[b]:=0; with RunningShape do begin R:=0; Len:=1; dHtrack:=0; dHrail:=0; end; RunningTrack.CategoryFlag:=CategoryFlag; with RunningTrack do begin Width:=TrackW; friction:=Steel2Steel_friction; QualityFlag:=20; DamageFlag:=0; Velmax:=100; {dla uzytku maszynisty w ai_driver} end; with RunningTraction do begin TractionVoltage:=0; TractionFreq:=0; TractionMaxCurrent:=0; TractionResistivity:=1; end; OffsetTrackH:=0; OffsetTrackV:=0; with CommandIn do begin Command:=''; Value1:=0; Value2:=0; Location.x:=0; Location.y:=0; Location.z:=0; end; {czesciowo stale, czesciowo zmienne} with SecuritySystem do begin SystemType:=0; AwareDelay:=-1; SoundSignalDelay:=-1; EmergencyBrakeDelay:=-1; Status:=0; SystemTimer:=0; SystemBrakeCATimer:=0; SystemBrakeSHPTimer:=0; //hunter-091012 VelocityAllowed:=-1; NextVelocityAllowed:=-1; RadioStop:=false; //domyślnie nie ma AwareMinSpeed:=0.1*Vmax; end; //ABu 240105: //CouplerNr[0]:=1; //CouplerNr[1]:=0; {TO POTEM TU UAKTYWNIC A WYWALIC Z CHECKPARAM} { if Pos(LoadTypeInitial,LoadAccepted)>0 then begin } LoadType:=LoadTypeInitial; Load:=LoadInitial; LoadStatus:=0; LastLoadChangeTime:=0; { end else Load:=0; } Name:=NameInit; DerailReason:=0; //Ra: powód wykolejenia TotalCurrent:=0; ShuntModeAllow:=false; ShuntMode:=false; end; function T_MoverParameters.EngineDescription(what:integer): string; {opis stanu lokomotywy} var outstr: string; begin outstr:=''; case what of 0: begin if DamageFlag=255 then outstr:='Totally destroyed!' else begin if TestFlag(DamageFlag,dtrain_thinwheel) then if Power>0.1 then outstr:='Thin wheel,' else outstr:='Load shifted,'; if TestFlag(DamageFlag,dtrain_wheelwear) then outstr:='Wheel wear,'; if TestFlag(DamageFlag,dtrain_bearing) then outstr:='Bearing damaged,'; if TestFlag(DamageFlag,dtrain_coupling) then outstr:='Coupler broken,'; if TestFlag(DamageFlag,dtrain_loaddamage) then if Power>0.1 then outstr:='Ventilator damaged,' else outstr:='Load damaged,'; if TestFlag(DamageFlag,dtrain_loaddestroyed) then if Power>0.1 then outstr:='Engine damaged,' else outstr:='Load destroyed!,'; if TestFlag(DamageFlag,dtrain_axle) then outstr:='Axle broken,'; if TestFlag(DamageFlag,dtrain_out) then outstr:='DERAILED!'; if outstr='' then outstr:='OK!'; end; end; else outstr:='Invalid qualifier'; end; EngineDescription:=outstr; end; function T_MoverParameters.CheckLocomotiveParameters(ReadyFlag:boolean;Dir:longint): boolean; var //k:integer; OK:boolean; b:byte; bcmsno: byte; bcmss: byte; const DefBrakeTable:array[1..8]of Byte=(15,4,25,25,13,3,12,2); begin OK:=true; AutoRelayFlag:=(AutoRelayType=1); Sand:=SandCapacity; if (Pos('o',AxleArangement)>0) and (EngineType=ElectricSeriesMotor) then OK:=(RList[1].Bn*RList[1].Mn=NPoweredAxles); {test poprawnosci ilosci osi indywidualnie napedzanych} if (Pos(LoadType,LoadAccepted)=0) and (LoadType<>'') then begin Load:=0; OK:=false; end; if BrakeSystem=Individual then if BrakeSubSystem<>ss_None then OK:=false; {!} if(BrakeVVolume=0)and(MaxBrakePress[3]>0)and(BrakeSystem<>Individual)then BrakeVVolume:=MaxBrakePress[3]/(5-MaxBrakePress[3])*(BrakeCylRadius*BrakeCylRadius*BrakeCylDist*BrakeCylNo*pi)*1000; if BrakeVVolume=0 then BrakeVVolume:=0.01; // Hamulec.Free; //(i_mbp, i_bcr, i_bcd, i_brc: real; i_bcn, i_BD, i_mat, i_ba, i_nbpa: byte) case BrakeValve of W, K : begin Hamulec := TWest.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA); if(MBPM<2)then //jesli przystawka wazaca (Hamulec as TWest).SetLP(0,MaxBrakePress[3],0) else (Hamulec as TWest).SetLP(Mass, MBPM, MaxBrakePress[1]); end; KE : begin Hamulec := TKE.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA); (Hamulec as TKE).SetRM(RapidMult); if(MBPM<2)then //jesli przystawka wazaca (Hamulec as TKE).SetLP(0,MaxBrakePress[3],0) else (Hamulec as TKE).SetLP(Mass, MBPM, MaxBrakePress[1]) end; NEst3, ESt3, ESt3AL2, ESt4: begin Hamulec := TNESt3.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA); (Hamulec as TNEst3).SetSize(BrakeValveSize,BrakeValveParams); if(MBPM<2)then //jesli przystawka wazaca (Hamulec as TNESt3).SetLP(0,MaxBrakePress[3],0) else (Hamulec as TNESt3).SetLP(Mass, MBPM, MaxBrakePress[1]) end; { ESt3, ESt3AL2: if (MaxBrakePress[1])>0 then begin Hamulec := TESt3AL2.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA); if(MBPM<2)then (Hamulec as TESt3AL2).SetLP(0,MaxBrakePress[3],0) else (Hamulec as TESt3AL2).SetLP(Mass, MBPM, MaxBrakePress[1]) end else Hamulec := TESt3.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);} LSt :begin Hamulec := TLSt.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA); (Hamulec as TLSt).SetRM(RapidMult); end; EStED :begin Hamulec := TEStED.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA); (Hamulec as TEStED).SetRM(RapidMult); if(MBPM<2)then //jesli przystawka wazaca (Hamulec as TEStED).SetLP(0,MaxBrakePress[3],0) else (Hamulec as TEStED).SetLP(Mass, MBPM, MaxBrakePress[1]); end; EP2:begin Hamulec :=TEStEP2.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA); (Hamulec as TEStEP2).SetLP(Mass, MBPM, MaxBrakePress[1]); end; { ESt4 :if (BrakeDelays and bdelay_R)=bdelay_R then Hamulec:=TESt4R.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA) else Hamulec:= TESt.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA);} CV1 : Hamulec:= TCV1.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA); CV1_L_TR:Hamulec:= TCV1L_TR.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA) else Hamulec := TBrake.Create(MaxBrakePress[3], BrakeCylRadius, BrakeCylDist, BrakeVVolume, BrakeCylNo, BrakeDelays, BrakeMethod, NAxles, NBpA); end; Hamulec.SetASBP(MaxBrakePress[4]); case BrakeHandle of FV4a: Handle := TFV4aM.Create; MHZ_EN57: Handle := TMHZ_EN57.Create; FVel6: Handle := TFVel6.Create; testH: Handle := Ttest.Create; M394: Handle := TM394.Create; Knorr: Handle := TH14K1.Create; St113: Handle := TSt113.Create; else Handle := THandle.Create; end; case BrakeLocHandle of FD1: begin LocHandle := TFD1.Create; LocHandle.Init(MaxBrakePress[0]); if(TrainType=dt_EZT)then (LocHandle as TFD1).SetSpeed(3.5); end; Knorr: begin LocHandle := TH1405.Create; LocHandle.Init(MaxBrakePress[0]); end; else LocHandle := THandle.Create; end; //ustalanie srednicy przewodu glownego (lokomotywa lub napędowy if (TestFlag(BrakeDelays,bdelay_G))and((not TestFlag(BrakeDelays,bdelay_R)) or (Power>1))then Spg:=0.792 else Spg:=0.507; Pipe:= TReservoir.Create; Pipe2:= TReservoir.Create; //zabezpieczenie, bo sie PG wywala... :( Pipe.CreateCap((Max0R(Dim.L,14)+0.5)*Spg*1); //dlugosc x przekroj x odejscia i takie tam Pipe2.CreateCap((Max0R(Dim.L,14)+0.5)*Spg*1); if LightsPosNo>0 then LightsPos:=LightsDefPos; {to dac potem do init} if ReadyFlag then {gotowy do drogi} begin CompressedVolume:=VeselVolume*MinCompressor*(9.8+Random)/10; ScndPipePress:=CompressedVolume/VeselVolume; PipePress:=CntrlPipePress; BrakePress:=0; LocalBrakePos:=0; // if (BrakeSystem=Pneumatic) and (BrakeCtrlPosNo>0) then if CabNo=0 then // BrakeCtrlPos:=-2; //odcięcie na zespolonym; Ra: hamulec jest poprawiany w DynObj.cpp BrakeCtrlPos:=Trunc(Handle.GetPos(bh_NP)) else BrakeCtrlPos:=Trunc(Handle.GetPos(bh_RP)); MainSwitch(false); PantFront(true); PantRear(true); MainSwitch(true); ActiveDir:=0; //Dir; //nastawnik kierunkowy - musi być ustawiane osobno! DirAbsolute:=ActiveDir*CabNo; //kierunek jazdy względem sprzęgów LimPipePress:=CntrlPipePress; end else begin {zahamowany} Volume:=BrakeVVolume*MaxBrakePress[3]; CompressedVolume:=VeselVolume*MinCompressor*0.55; ScndPipePress:=5.1; PipePress:=LowPipePress; PipeBrakePress:=MaxBrakePress[3]*0.5; BrakePress:=MaxBrakePress[3]*0.5; LocalBrakePos:=0; // if (BrakeSystem=Pneumatic) and (BrakeCtrlPosNo>0) then // BrakeCtrlPos:=-2; //Ra: hamulec jest poprawiany w DynObj.cpp BrakeCtrlPos:=Trunc(Handle.GetPos(bh_NP)); LimPipePress:=LowPipePress; end; ActFlowSpeed:=0; BrakeCtrlPosR:=BrakeCtrlPos; if(BrakeLocHandle=Knorr)then LocalBrakePos:=5; Pipe.CreatePress(PipePress); Pipe2.CreatePress(ScndPipePress); Pipe.Act;Pipe2.Act; EqvtPipePress:=PipePress; //// fv4ac:=Pipe.P; //// fv4ar:=Pipe.P; Handle.Init(PipePress); ComputeConstans(); if(LoadFlag>0)then begin if(Load=MaxLoad*0.45)then begin IncBrakeMult(); if(Load>=MaxLoad*0.55)then IncBrakeMult(); end; end; //taki mini automat - powinno byc ladnie dobrze :) BrakeDelayFlag:=bdelay_P; if(TestFlag(BrakeDelays,bdelay_G))and not(TestFlag(BrakeDelays,bdelay_R))then BrakeDelayFlag:=bdelay_G; if(TestFlag(BrakeDelays,bdelay_R))and not(TestFlag(BrakeDelays,bdelay_G))then BrakeDelayFlag:=bdelay_R; //ustawianie PS/PN/EP/MED BrakeOpModeFlag:=bom_PN; if (BrakeOpModes and bom_PS)>0 then BrakeOpModeFlag:=bom_PS; // if (BrakeOpModes and bom_EP)>0 then BrakeOpModeFlag:=bom_EP; // if (BrakeOpModes and bom_MED)>0 then BrakeOpModeFlag:=bom_MED; // //yB: jesli pojazdy nie maja zadeklarowanych czasow, to wsadz z przepisow +-16,(6)% for b:=1 to 4 do begin if BrakeDelay[b]=0 then BrakeDelay[b]:=DefBrakeTable[b]; BrakeDelay[b]:=BrakeDelay[b]*(2.5+Random)/3.0; end; if(TrainType=dt_ET22)then CompressorPower:=0; // Hamulec.Init(10*PipePress, 10*HighPipePress-0.15, 10*LowPipePress-0.15, 10*BrakePress, BrakeDelayFlag); Hamulec.Init(PipePress, HighPipePress, LowPipePress, BrakePress, BrakeDelayFlag); // Hamulec.Init(0, 0, -1.5, 0, BrakeDelayFlag); // PipePress:=PipePress; ScndPipePress:=Compressor; CheckLocomotiveParameters:=OK; end; function T_MoverParameters.DoorLeft(State: Boolean):Boolean; begin if (DoorLeftOpened<>State) and (DoorBlockedFlag=false) and (Battery=true) then begin DoorLeft:=true; DoorLeftOpened:=State; if (State=true) then begin if (CabNo>0) then SendCtrlToNext('DoorOpen',1,CabNo) //1=lewe, 2=prawe else SendCtrlToNext('DoorOpen',2,CabNo); //zamiana CompressedVolume:=CompressedVolume-0.003; end else begin if (CabNo>0) then SendCtrlToNext('DoorClose',1,CabNo) else SendCtrlToNext('DoorClose',2,CabNo); end; end else DoorLeft:=false; end; function T_MoverParameters.DoorRight(State: Boolean):Boolean; begin if (DoorRightOpened<>State) and (DoorBlockedFlag=false) and (Battery=true) then begin DoorRight:=true; DoorRightOpened:=State; if (State=true) then begin if (CabNo>0) then SendCtrlToNext('DoorOpen',2,CabNo) //1=lewe, 2=prawe else SendCtrlToNext('DoorOpen',1,CabNo); //zamiana CompressedVolume:=CompressedVolume-0.003; end else begin if (CabNo>0) then SendCtrlToNext('DoorClose',2,CabNo) else SendCtrlToNext('DoorClose',1,CabNo); end; end else DoorRight:=false; end; //Winger 160204 - pantografy function T_MoverParameters.PantFront(State: Boolean):Boolean; var pf1: Real; begin if (battery=true){ and ((TrainType<>dt_ET40)or ((TrainType=dt_ET40) and (EnginePowerSource.CollectorsNo>1)))}then begin PantFront:=true; if (State=true) then pf1:=1 else pf1:=0; if (PantFrontUp<>State) then begin PantFrontUp:=State; if (State=true) then begin PantFrontStart:=0; SendCtrlToNext('PantFront',1,CabNo); end else begin PantFront:=false; PantFrontStart:=1; SendCtrlToNext('PantFront',0,CabNo); {Ra: nie ma potrzeby opuszczać obydwu na raz, jak mozemy każdy osobno if (TrainType=dt_EZT) and (ActiveCab=1) then begin PantRearUp:=false; PantRearStart:=1; SendCtrlToNext('PantRear',0,CabNo); end; } end; end else SendCtrlToNext('PantFront',pf1,CabNo); end end; function T_MoverParameters.PantRear(State: Boolean):Boolean; var pf1: Real; begin if battery=true then begin PantRear:=true; if (State=true) then pf1:=1 else pf1:=0; if (PantRearUp<>State) then begin PantRearUp:=State; if (State=true) then begin PantRearStart:=0; SendCtrlToNext('PantRear',1,CabNo); end else begin PantRear:=false; PantRearStart:=1; SendCtrlToNext('PantRear',0,CabNo); end; end else SendCtrlToNext('PantRear',pf1,CabNo); end end; {function T_MoverParameters.Heating(State: Boolean):Boolean; begin if (Heating<>State) then begin Heating:=State; { if (State=true) then begin // SendCtrlToNext('PantRear',1,CabNo); end else begin // SendCtrlToNext('PantRear',0,CabNo); end; } { end { else SendCtrlToNext('PantRear',0,CabNo); } {end;} function T_MoverParameters.LoadChkFile(chkpath:string):Boolean; const param_ok=1; wheels_ok=2; dimensions_ok=4; var lines,s: string; bl,i,k:integer; b,OKflag:byte; fin: text; OK: boolean; procedure BrakeValveDecode(s:string); begin if s='W' then BrakeValve:=W else if s='W_Lu_L' then BrakeValve:=W_Lu_L else if s='W_Lu_XR' then BrakeValve:=W_Lu_XR else if s='W_Lu_VI' then BrakeValve:=W_Lu_VI else if s='K' then BrakeValve:=W else if s='Kkg' then BrakeValve:=Kkg else if s='Kkp' then BrakeValve:=Kkp else if s='Kks' then BrakeValve:=Kks else if s='Hikp1' then BrakeValve:=Hikp1 else if s='Hikss' then BrakeValve:=Hikss else if s='Hikg1' then BrakeValve:=Hikg1 else if s='KE' then BrakeValve:=KE else if s='EStED' then BrakeValve:=EStED else if Pos('ESt',s)>0 then BrakeValve:=ESt3 else if s='LSt' then BrakeValve:=LSt else if s='EP2' then BrakeValve:=EP2 else if s='EP1' then BrakeValve:=EP1 else if s='CV1' then BrakeValve:=CV1 else if s='CV1_L_TR' then BrakeValve:=CV1_L_TR else BrakeValve:=Other; end; procedure BrakeSubsystemDecode; begin case BrakeValve of W,W_Lu_L,W_Lu_VI,W_Lu_XR: BrakeSubsystem:=ss_W; ESt3,ESt3AL2,ESt4,EP2,EP1: BrakeSubsystem:=ss_ESt; KE: BrakeSubsystem:=ss_KE; CV1, CV1_L_TR: BrakeSubsystem:=ss_Dako; LSt, EStED: BrakeSubsystem:=ss_LSt; else BrakeSubsystem:=ss_None; end; end; function EngineDecode(s:string):TEngineTypes; begin if s='ElectricSeriesMotor' then EngineDecode:=ElectricSeriesMotor else if s='DieselEngine' then EngineDecode:=DieselEngine else if s='SteamEngine' then EngineDecode:=SteamEngine else if s='WheelsDriven' then EngineDecode:=WheelsDriven else if s='Dumb' then EngineDecode:=Dumb else if s='DieselElectric' then EngineDecode:=DieselElectric //youBy: spal-ele else if s='DumbDE' then EngineDecode:=DieselElectric //youBy: spal-ele else if s='ElectricInductionMotor' then EngineDecode:=ElectricInductionMotor { else if s='EZT' then {dla kibla} { EngineDecode:=EZT } else EngineDecode:=None; end; function PowerSourceDecode(s:string):TPowerSource; begin if s='Transducer' then PowerSourceDecode:=Transducer else if s='Generator' then PowerSourceDecode:=Generator else if s='Accu' then PowerSourceDecode:=Accumulator else if s='CurrentCollector' then PowerSourceDecode:=CurrentCollector else if s='PowerCable' then PowerSourceDecode:=PowerCable else if s='Heater' then PowerSourceDecode:=Heater else if s='Internal' then PowerSourceDecode:=InternalSource else PowerSourceDecode:=NotDefined; end; function PowerDecode(s:string): TPowerType; begin if s='BioPower' then PowerDecode:=BioPower else if s='BioPower' then PowerDecode:=BioPower else if s='MechPower' then PowerDecode:=MechPower else if s='ElectricPower' then PowerDecode:=ElectricPower else if s='SteamPower' then PowerDecode:=SteamPower else PowerDecode:=NoPower; end; procedure PowerParamDecode(lines,prefix:string; var PowerParamDecode:TPowerParameters); begin with PowerParamDecode do begin case SourceType of NotDefined : PowerType:=PowerDecode(DUE(ExtractKeyWord(lines,prefix+'PowerType='))); InternalSource : PowerType:=PowerDecode(DUE(ExtractKeyWord(lines,prefix+'PowerType='))); Transducer : InputVoltage:=s2rE(DUE(ExtractKeyWord(lines,prefix+'TransducerInputV='))); Generator : GeneratorEngine:=EngineDecode(DUE(ExtractKeyWord(lines,prefix+'GeneratorEngine='))); Accumulator: begin RAccumulator.MaxCapacity:=s2r(DUE(ExtractKeyWord(lines,prefix+'Cap='))); s:=DUE(ExtractKeyWord(lines,prefix+'RS=')); RAccumulator.RechargeSource:=PowerSourceDecode(s); end; CurrentCollector: begin with CollectorParameters do begin CollectorsNo:=s2lE(DUE(ExtractKeyWord(lines,'CollectorsNo='))); MinH:=s2rE(DUE(ExtractKeyWord(lines,'MinH='))); MaxH:=s2rE(DUE(ExtractKeyWord(lines,'MaxH='))); CSW:=s2rE(DUE(ExtractKeyWord(lines,'CSW='))); //szerokość części roboczej MaxV:=s2rE(DUE(ExtractKeyWord(lines,'MaxVoltage='))); s:=ExtractKeyWord(lines,'OverVoltProt='); //przekaźnik nadnapięciowy if s='Yes' then OVP:=1 else OVP:=0; s:=ExtractKeyWord(lines,'MinV='); //napięcie rozłączające WS if s='' then MinV:=0.5*MaxV //gdyby parametr nie podany else MinV:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'InsetV='); //napięcie wymagane do załączenia WS if s='' then InsetV:=0.6*MaxV //gdyby parametr nie podany else InsetV:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'MinPress='); //ciśnienie rozłączające WS if s='' then MinPress:=2.0 //domyślnie 2 bary do załączenia WS else MinPress:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'MaxPress='); //maksymalne ciśnienie za reduktorem if s='' then MaxPress:=5.0+0.001*(random(50)-random(50)) else MaxPress:=s2rE(DUE(s)); end; end; PowerCable : begin RPowerCable.PowerTrans:=PowerDecode(DUE(ExtractKeyWord(lines,prefix+'PowerTrans='))); if RPowerCable.PowerTrans=SteamPower then RPowerCable.SteamPressure:=s2r(DUE(ExtractKeyWord(lines,prefix+'SteamPress='))); end; Heater : begin {jeszcze nie skonczone!} end; end; if (SourceType<>Heater) and (SourceType<>InternalSource) then if not ((SourceType=PowerCable) and (RPowerCable.PowerTrans=SteamPower)) then begin { PowerTrans:=ElectricPower; } MaxVoltage:=s2rE(DUE(ExtractKeyWord(lines,prefix+'MaxVoltage='))); MaxCurrent:=s2r(DUE(ExtractKeyWord(lines,prefix+'MaxCurrent='))); IntR:=s2r(DUE(ExtractKeyWord(lines,prefix+'IntR='))); end; end; end; begin //OK:=true; OKflag:=0; LineCount:=0; ConversionError:=666; Mass:=0; filename:=chkpath+TypeName+'.fiz';//'.chk'; assignfile(fin,filename); {$I-} reset(fin); {$I+} if IOresult<>0 then begin OK:=false; ConversionError:=-8; end else begin ConversionError:=0; while not (eof(fin) or (ConversionError<>0)) do begin readln(fin,lines); inc(LineCount); if Pos('/',lines)=0 then {nie komentarz} begin if Pos('Param.',lines)>0 then {stale parametry} begin SetFlag(OKFlag,param_ok); s:=DUE(ExtractKeyWord(lines,'Category=')); if s='train' then CategoryFlag:=1 else if s='road' then CategoryFlag:=2 else if s='ship' then CategoryFlag:=4 else if s='airplane' then CategoryFlag:=8 else if s='unimog' then CategoryFlag:=3 else ConversionError:=-7; s:=ExtractKeyWord(lines,'M='); Mass:=s2rE(DUE(s)); {w kg} s:=ExtractKeyWord(lines,'Mred='); {zredukowane masy wirujące} if s='' then Mred:=0 else Mred:=s2rE(DUE(s)); {w kg} s:=ExtractKeyWord(lines,'Vmax='); Vmax:=s2rE(DUE(s)); {w km/h} s:=ExtractKeyWord(lines,'PWR='); Power:=s2r(DUE(s)); {w kW} s:=ExtractKeyWord(lines,'HeatingP='); HeatingPower:=s2r(DUE(s)); {w kW} s:=ExtractKeyWord(lines,'LightP='); LightPower:=s2r(DUE(s)); {w kW} s:=ExtractKeyWord(lines,'SandCap='); SandCapacity:=s2i(DUE(s)); {w kg} TrainType:=dt_Default; s:=Ups(DUE(ExtractKeyWord(lines,'Type='))); //wielkimi if s='EZT' then begin TrainType:=dt_EZT; IminLo:=1;IminHi:=2;Imin:=1; //wirtualne wartości dla rozrządczego end else if s='ET41' then TrainType:=dt_ET41 else if s='ET42' then TrainType:=dt_ET42 else if s='ET22' then TrainType:=dt_ET22 else if s='ET40' then TrainType:=dt_ET40 else if s='EP05' then TrainType:=dt_EP05 else if s='SN61' then TrainType:=dt_SN61 else if s='PSEUDODIESEL' then TrainType:=dt_PseudoDiesel else if s='181' then TrainType:=dt_181 else if s='182' then TrainType:=dt_181; {na razie tak} end else if Pos('Load:',lines)>0 then {stale parametry} begin LoadAccepted:=LowerCase(DUE(ExtractKeyWord(lines,'LoadAccepted='))); if LoadAccepted<>'' then begin s:=ExtractKeyWord(lines,'MaxLoad='); MaxLoad:=s2lE(DUE(s)); LoadQuantity:=DUE(ExtractKeyWord(lines,'LoadQ=')); s:=ExtractKeyWord(lines,'OverLoadFactor='); OverLoadFactor:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'LoadSpeed='); LoadSpeed:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'UnLoadSpeed='); UnLoadSpeed:=s2rE(DUE(s)); end; end else if Pos('Dimensions:',lines)>0 then {wymiary} begin with Dim do begin SetFlag(OKFlag,dimensions_ok); s:=ExtractKeyWord(lines,'L='); L:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'H='); H:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'W='); W:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'Cx='); Cx:=s2r(DUE(s)); if Cx=0 then Cx:=0.3; s:=ExtractKeyWord(lines,'Floor='); if s='' then begin if (H<=2.0) then Floor:=H //gdyby nie było parametru, lepsze to niż zero else Floor:=0.0; //zgodność wsteczna end else Floor:=s2rE(DUE(s)); end; end else if Pos('Wheels:',lines)>0 then {kola} begin { SetFlag(OKFlag,wheels_ok);} s:=ExtractKeyWord(lines,'D='); //średnica osi napędzających WheelDiameter:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'Dl='); //średnica przednich osi tocznych if s='' then WheelDiameterL:=WheelDiameter //gdyby nie było parametru, lepsze to niż zero else WheelDiameterL:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'Dt='); //średnica tylnych osi tocznych if s='' then WheelDiameterT:=WheelDiameter //gdyby nie było parametru, lepsze to niż zero else WheelDiameterT:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'Tw='); TrackW:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'AIM='); AxleInertialMoment:=s2r(DUE(s)); if AxleInertialMoment<=0 then AxleInertialMoment:=1; AxleArangement:=DUE(ExtractKeyWord(lines,'Axle=')); NPoweredAxles:=s2NPW(AxleArangement); NAxles:=NPoweredAxles+s2NNW(AxleArangement); if NAxles=0 then ConversionError:=-1; s:=DUE(ExtractKeyWord(lines,'BearingType=')); if s='Roll' then BearingType:=1 else BearingType:=0; s:=ExtractKeyWord(lines,'Ad='); ADist:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'Bd='); BDist:=s2r(DUE(s)); end else if Pos('Brake:',lines)>0 then {hamulce} begin BrakeValveParams:=DUE(ExtractKeyWord(lines,'BrakeValve=')); BrakeValveDecode(BrakeValveParams); BrakeSubSystemDecode; s:=ExtractKeyWord(lines,'NBpA='); NBpA:=s2b(DUE(s)); s:=ExtractKeyWord(lines,'MBF='); MaxBrakeForce:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'Size='); BrakeValveSize:=s2i(DUE(s)); s:=ExtractKeyWord(lines,'TBF='); TrackBrakeForce:=s2r(DUE(s))*1000; s:=ExtractKeyWord(lines,'MaxBP='); MaxBrakePress[3]:=s2r(DUE(s)); if MaxBrakePress[3]>0 then begin s:=ExtractKeyWord(lines,'BCN='); BrakeCylNo:=s2iE(DUE(s)); if BrakeCylNo>0 then begin s:=ExtractKeyWord(lines,'MaxLBP='); MaxBrakePress[0]:=s2r(DUE(s)); if MaxBrakePress[0]<0.01 then MaxBrakePress[0]:=MaxBrakePress[3]; s:=DUE(ExtractKeyWord(lines,'TareMaxBP=')); MaxBrakePress[1]:=s2r(s); s:=DUE(ExtractKeyWord(lines,'MedMaxBP=')); MaxBrakePress[2]:=s2r(s); s:=ExtractKeyWord(lines,'MaxASBP='); MaxBrakePress[4]:=s2r(DUE(s)); if MaxBrakePress[4]<0.01 then MaxBrakePress[4]:=0; s:=ExtractKeyWord(lines,'BCR='); BrakeCylRadius:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'BCD='); BrakeCylDist:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'BCS='); BrakeCylSpring:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'BSA='); BrakeSlckAdj:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'BRE='); if s<>'' then BrakeRigEff:=s2r(DUE(s)) else BrakeRigEff:=1; s:=ExtractKeyWord(lines,'BCM='); BrakeCylMult[0]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'BCMlo='); BrakeCylMult[1]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'BCMHi='); BrakeCylMult[2]:=s2r(DUE(s)); P2FTrans:=100*Pi*SQR(BrakeCylRadius); {w kN/bar} if (BrakeCylMult[1]>0) or (MaxBrakePress[1]>0) then LoadFlag:=1 else LoadFlag:=0; BrakeVolume:=Pi*SQR(BrakeCylRadius)*BrakeCylDist*BrakeCylNo; s:=ExtractKeyWord(lines,'BVV='); BrakeVVolume:=s2R(DUE(s)); s:=DUE(ExtractKeyWord(lines,'BM=')); if s='P10-Bg' then BrakeMethod:=bp_P10Bg else if s='P10-Bgu' then BrakeMethod:=bp_P10Bgu else if s='FR513' then BrakeMethod:=bp_FR513 else if s='FR510' then BrakeMethod:=bp_FR510 else if s='Cosid' then BrakeMethod:=bp_Cosid else if s='P10yBg' then BrakeMethod:=bp_P10yBg else if s='P10yBgu' then BrakeMethod:=bp_P10yBgu else if s='Disk1' then BrakeMethod:=bp_D1 else if s='Disk1+Mg' then BrakeMethod:=bp_D1+bp_MHS else if s='Disk2' then BrakeMethod:=bp_D2 else BrakeMethod:=0; s:=ExtractKeyWord(lines,'RM='); if s<>'' then RapidMult:=s2r(DUE(s)) else RapidMult:=1; end else ConversionError:=-5; end else P2FTrans:=0; s:=ExtractKeyWord(lines,'HiPP='); if s<>'' then CntrlPipePress:=s2r(DUE(s)) else CntrlPipePress:=5+0.001*(random(10)-random(10)); //Ra 2014-07: trochę niedokładności HighPipePress:=CntrlPipePress; s:=ExtractKeyWord(lines,'LoPP='); if s<>'' then LowPipePress:=s2r(DUE(s)) else LowPipePress:=Min0R(HighPipePress,3.5); DeltaPipePress:=HighPipePress-LowPipePress; s:=ExtractKeyWord(lines,'Vv='); VeselVolume:=s2r(DUE(s)); if VeselVolume=0 then VeselVolume:=0.01; s:=ExtractKeyWord(lines,'MinCP='); MinCompressor:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'MaxCP='); MaxCompressor:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'CompressorSpeed='); CompressorSpeed:=s2r(DUE(s)); s:=DUE(ExtractKeyWord(lines,'CompressorPower=')); if s='Converter' then CompressorPower:=2 else if s='Engine' then CompressorPower:=3 else if s='Coupler1' then CompressorPower:=4 //włączana w silnikowym EZT z przodu else if s='Coupler2' then CompressorPower:=5 //włączana w silnikowym EZT z tyłu else if s='Main' then CompressorPower:=0; end else if Pos('Doors:',lines)>0 then {drzwi} begin s:=DUE(ExtractKeyWord(lines,'OpenCtrl=')); if s='DriverCtrl' then DoorOpenCtrl:=1 else DoorOpenCtrl:=0; s:=DUE(ExtractKeyWord(lines,'CloseCtrl=')); if s='DriverCtrl' then DoorCloseCtrl:=1 else if s='AutomaticCtrl' then DoorCloseCtrl:=2 else DoorCloseCtrl:=0; if DoorCloseCtrl=2 then begin s:=ExtractKeyWord(lines,'DoorStayOpen='); DoorStayOpen:=s2rE(DUE(s)); end; s:=ExtractKeyWord(lines,'OpenSpeed='); DoorOpenSpeed:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'CloseSpeed='); DoorCloseSpeed:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'DoorMaxShiftL='); DoorMaxShiftL:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'DoorMaxShiftR='); DoorMaxShiftR:=s2r(DUE(s)); s:=DUE(ExtractKeyWord(lines,'DoorOpenMethod=')); if s='Shift' then DoorOpenMethod:=1 //przesuw else if s='Fold' then DoorOpenMethod:=3 //3 submodele się obracają else if s='Plug' then DoorOpenMethod:=4 //odskokowo-przesuwne else DoorOpenMethod:=2; //obrót s:=DUE(ExtractKeyWord(lines,'DoorClosureWarning=')); if s='Yes' then DoorClosureWarning:=true else DoorClosureWarning:=false; s:=DUE(ExtractKeyWord(lines,'DoorBlocked=')); if s='Yes' then DoorBlocked:=true else DoorBlocked:=false; s:=ExtractKeyWord(lines,'DoorMaxShiftPlug='); DoorMaxPlugShift:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'PlatformSpeed='); PlatformSpeed:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'PlatformMaxSpeed='); PlatformMaxShift:=s2r(DUE(s)); s:=DUE(ExtractKeyWord(lines,'PlatformOpenMethod=')); if s='Shift' then PlatformOpenMethod:=1 //przesuw else PlatformOpenMethod:=2; //obrót end else if (Pos('BuffCoupl.',lines)>0) or (Pos('BuffCoupl1.',lines)>0) then {zderzaki i sprzegi} begin with Couplers[0] do begin s:=DUE(ExtractKeyWord(lines,'CType=')); if s='Automatic' then CouplerType:=Automatic else if s='Screw' then CouplerType:=Screw else if s='Chain' then CouplerType:=Chain else if s='Bare' then CouplerType:=Bare else if s='Articulated' then CouplerType:=Articulated else CouplerType:=NoCoupler; s:=ExtractKeyWord(lines,'AllowedFlag='); if s<>'' then AllowedFlag:=s2i(DUE(s)); if (AllowedFlag<0) then AllowedFlag:=(-AllowedFlag) OR ctrain_depot; if (CouplerType<>NoCoupler) and (CouplerType<>Bare) and (CouplerType<>Articulated) then begin s:=ExtractKeyWord(lines,'kC='); SpringKC:=s2rE(DUE(s))*1000; s:=ExtractKeyWord(lines,'DmaxC='); DmaxC:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'FmaxC='); FmaxC:=s2rE(DUE(s))*1000; s:=ExtractKeyWord(lines,'kB='); SpringKB:=s2rE(DUE(s))*1000; s:=ExtractKeyWord(lines,'DmaxB='); DmaxB:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'FmaxB='); FmaxB:=s2rE(DUE(s))*1000; s:=ExtractKeyWord(lines,'beta='); beta:=s2r(DUE(s)); end else if (CouplerType=Bare) then {Ra: czemu masy bez ładunków?} begin SpringKC:=50*Mass+Ftmax/0.05; DmaxC:=0.05; FmaxC:=100*Mass+2*Ftmax; SpringKB:=60*Mass+Ftmax/0.05; DmaxB:=0.05; FmaxB:=50*Mass+2*Ftmax; beta:=0.3; end else if (CouplerType=Articulated) then begin SpringKC:=60*Mass+1000; DmaxC:=0.05; FmaxC:=20000000+2*Ftmax; SpringKB:=70*Mass+1000; DmaxB:=0.05; FmaxB:=4000000+2*Ftmax; beta:=0.55; end; end; if (Pos('BuffCoupl.',lines)>0) then begin Couplers[1].SpringKC:=Couplers[0].SpringKC; Couplers[1].DmaxC:=Couplers[0].DmaxC; Couplers[1].FmaxC:=Couplers[0].FmaxC; Couplers[1].SpringKB:=Couplers[0].SpringKB; Couplers[1].DmaxB:=Couplers[0].DmaxB; Couplers[1].FmaxB:=Couplers[0].FmaxB; Couplers[1].beta:=Couplers[0].beta; Couplers[1].CouplerType:=Couplers[0].CouplerType; Couplers[1].AllowedFlag:=Couplers[0].AllowedFlag; end; { CouplerTune:=(1+Mass)/100000; } end else if (Pos('BuffCoupl2.',lines)>0) then {zderzaki i sprzegi jesli sa rozne} with Couplers[1] do begin s:=DUE(ExtractKeyWord(lines,'CType=')); if s='Automatic' then CouplerType:=Automatic else if s='Screw' then CouplerType:=Screw else if s='Chain' then CouplerType:=Chain else if s='Bare' then CouplerType:=Bare else if s='Articulated' then CouplerType:=Articulated else CouplerType:=NoCoupler; s:=ExtractKeyWord(lines,'AllowedFlag='); if s<>'' then AllowedFlag:=s2i(DUE(s)); if (AllowedFlag<0) then AllowedFlag:=(-AllowedFlag) OR ctrain_depot; if (CouplerType<>NoCoupler) and (CouplerType<>Bare) and (CouplerType<>Articulated) then begin s:=ExtractKeyWord(lines,'kC='); SpringKC:=s2rE(DUE(s))*1000; s:=ExtractKeyWord(lines,'DmaxC='); DmaxC:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'FmaxC='); FmaxC:=s2rE(DUE(s))*1000; s:=ExtractKeyWord(lines,'kB='); SpringKB:=s2rE(DUE(s))*1000; s:=ExtractKeyWord(lines,'DmaxB='); DmaxB:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'FmaxB='); FmaxB:=s2rE(DUE(s))*1000; s:=ExtractKeyWord(lines,'beta='); beta:=s2r(DUE(s)); end else if (CouplerType=Bare) then begin SpringKC:=50*Mass+1000; DmaxC:=0.05; FmaxC:=20*Mass+2*Ftmax; SpringKB:=60*Mass+1000; DmaxB:=0.05; FmaxB:=10*Mass+2*Ftmax; beta:=0.3; end else if (CouplerType=Articulated) then begin SpringKC:=60*Mass+1000; DmaxC:=0.05; FmaxC:=20000000+2*Ftmax; SpringKB:=70*Mass+1000;; DmaxB:=0.05; FmaxB:=4000000+2*Ftmax; beta:=0.55; end; { CouplerTune:=(1+Mass)/100000; } end else if Pos('TurboPos:',lines)>0 then {turbo zalezne od pozycji nastawnika} begin s:=ExtractKeyWord(lines,'TurboPos='); TurboTest:=s2b(DUE(s)); end else if Pos('Cntrl.',lines)>0 then {nastawniki} begin s:=DUE(ExtractKeyWord(lines,'BrakeSystem=')); if s='Pneumatic' then BrakeSystem:=Pneumatic else if s='ElectroPneumatic' then BrakeSystem:=ElectroPneumatic else BrakeSystem:=Individual; if BrakeSystem<>Individual then begin s:=ExtractKeyWord(lines,'BCPN='); BrakeCtrlPosNo:=s2b(DUE(s)); for b:=1 to 4 do begin s:=ExtractKeyWord(lines,'BDelay'+Cut_Space(b2s(b),CutLeft)+'='); BrakeDelay[b]:=s2b(DUE(s)); end; s:=DUE(ExtractKeyWord(lines,'BrakeDelays=')); if s='GPR' then BrakeDelays:=bdelay_G+bdelay_P+bdelay_R else if s='PR' then BrakeDelays:=bdelay_P+bdelay_R else if s='GP' then BrakeDelays:=bdelay_G+bdelay_P else if s='R' then begin BrakeDelays:=bdelay_R; BrakeDelayFlag:=bdelay_R; end else if s='P' then begin BrakeDelays:=bdelay_P; BrakeDelayFlag:=bdelay_P; end else if s='G' then begin BrakeDelays:=bdelay_G; BrakeDelayFlag:=bdelay_G; end else if s='GPR+Mg' then BrakeDelays:=bdelay_G+bdelay_P+bdelay_R+bdelay_M else if s='PR+Mg' then BrakeDelays:=bdelay_P+bdelay_R+bdelay_M; s:=DUE(ExtractKeyWord(lines,'BrakeOpModes=')); if s='PN' then BrakeOpModes:=bom_PS+bom_PN else if s='PNEPMED' then BrakeOpModes:=bom_PS+bom_PN+bom_EP+bom_MED; { else if s='DPR+Mg' then begin Brakedelays:=bdelay_R; BrakeMethod:=3; end else if s='DGPR+Mg' then begin Brakedelays:=bdelay_G+bdelay_R; BrakeMethod:=3; end else if s='DGPR' then begin Brakedelays:=bdelay_G+bdelay_R; BrakeMethod:=1; end else if s='DPR' then begin Brakedelays:=bdelay_R; BrakeMethod:=1; end else if s='DGP' then begin Brakedelays:=bdelay_G; BrakeMethod:=1; end;} // else if s='GPR' then Brakedelays=bdelay_G+bdelay_R s:=DUE(ExtractKeyWord(lines,'BrakeHandle=')); if s='FV4a' then BrakeHandle:=FV4a else if s='test' then BrakeHandle:=testH else if s='D2' then BrakeHandle:=D2 else if s='MHZ_EN57' then BrakeHandle:=MHZ_EN57 else if s='M394' then BrakeHandle:=M394 else if s='Knorr' then BrakeHandle:=Knorr else if s='Westinghouse' then BrakeHandle:=West else if s='FVel6' then BrakeHandle:=FVel6 else if s='St113' then BrakeHandle:=St113; s:=DUE(ExtractKeyWord(lines,'LocBrakeHandle=')); if s='FD1' then BrakeLocHandle:=FD1 else if s='Knorr' then BrakeLocHandle:=Knorr else if s='Westinghouse' then BrakeLocHandle:=West; s:=DUE(ExtractKeyWord(lines,'MaxBPMass=')); if s<>'' then MBPM:=s2rE(s)*1000; if BrakeCtrlPosNo>0 then begin s:=DUE(ExtractKeyWord(lines,'ASB=')); if s='Manual' then ASBType:=1 else if s='Automatic' then ASBType:=2; end else begin s:=DUE(ExtractKeyWord(lines,'ASB=')); if s='Yes' then ASBType:=128; end; end; s:=DUE(ExtractKeyWord(lines,'LocalBrake=')); if s='ManualBrake' then LocalBrake:=ManualBrake else if s='PneumaticBrake' then LocalBrake:=PneumaticBrake else if s='HydraulicBrake' then LocalBrake:=HydraulicBrake else LocalBrake:=NoBrake; s:=DUE(ExtractKeyWord(lines,'ManualBrake=')); if s='Yes' then MBrake:=true else MBrake:=false; s:=DUE(ExtractKeyWord(lines,'DynamicBrake=')); if s='Passive' then DynamicBrakeType:=dbrake_passive else if s='Switch' then DynamicBrakeType:=dbrake_switch else if s='Reversal' then DynamicBrakeType:=dbrake_reversal else if s='Automatic' then DynamicBrakeType:=dbrake_automatic else DynamicBrakeType:=dbrake_none; s:=ExtractKeyWord(lines,'MCPN='); MainCtrlPosNo:=s2b(DUE(s)); s:=ExtractKeyWord(lines,'SCPN='); ScndCtrlPosNo:=s2b(DUE(s)); s:=ExtractKeyWord(lines,'SCIM='); ScndinMain:=boolean(s2b(DUE(s))); s:=DUE(ExtractKeyWord(lines,'AutoRelay=')); if s='Optional' then AutoRelayType:=2 else if s='Yes' then AutoRelayType:=1 else AutoRelayType:=0; s:=DUE(ExtractKeyWord(lines,'CoupledCtrl=')); if s='Yes' then CoupledCtrl:=true {wspolny wal} else CoupledCtrl:=false; s:=DUE(ExtractKeyWord(lines,'ScndS=')); if s='Yes' then ScndS:=true {brak pozycji rownoleglej przy niskiej nastawie PSR} else ScndS:=false; s:=ExtractKeyWord(lines,'IniCDelay='); InitialCtrlDelay:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'SCDelay='); CtrlDelay:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'SCDDelay='); if s<>'' then CtrlDownDelay:=s2r(DUE(s)) else CtrlDownDelay:=CtrlDelay; //hunter-101012: jesli nie ma SCDDelay; s:=DUE(ExtractKeyWord(lines,'FSCircuit=')); //hunter-111012: dla siodemek 303E if s='Yes' then FastSerialCircuit:=1 else FastSerialCircuit:=0; s:=ExtractKeyWord(lines,'SBD='); StopBrakeDecc:=s2r(DUE(s)); if BrakeCtrlPosNo>0 then for i:=0 to BrakeCtrlPosNo+1 do begin s:=ReadWord(fin); k:=s2iE(s); if ConversionError=0 then with BrakePressureTable[k] do begin read(fin,PipePressureVal,BrakePressureVal,FlowSpeedVal); s:=ReadWord(fin); if s='Pneumatic' then BrakeType:=Pneumatic else if s='ElectroPneumatic' then BrakeType:=ElectroPneumatic else BrakeType:=Individual; { readln(fin); } end; end; end else if Pos('Light:',lines)>0 then {zrodlo mocy dla oswietlenia} begin s:=DUE(ExtractKeyWord(lines,'Light=')); if s<>'' then begin LightPowerSource.SourceType:=PowerSourceDecode(s); PowerParamDecode(lines,'L',LightPowerSource); s:=DUE(ExtractKeyWord(lines,'AlterLight=')); if s<>'' then begin AlterLightPowerSource.SourceType:=PowerSourceDecode(s); PowerParamDecode(lines,'AlterL',AlterLightPowerSource) end else AlterLightPowerSource.SourceType:=NotDefined; end ; s:=ExtractKeyWord(lines,'Volt='); if s<>'' then NominalVoltage:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'LMaxVoltage='); if s<>'' then begin BatteryVoltage:=s2r(DUE(s)); NominalBatteryVoltage:=s2r(DUE(s)); end; //else LightPowerSource.SourceType:=NotDefined; end else if Pos('Security:',lines)>0 then begin //if (TrainType<>dt_EZT)or(Power>1) then //dla EZT tylko w silnikowym with SecuritySystem do begin s:=DUE(ExtractKeyWord(lines,'AwareSystem=')); if Pos('Active',s)>0 then SetFlag(SystemType,1); if Pos('CabSignal',s)>0 then SetFlag(SystemType,2); s:=ExtractKeyWord(lines,'AwareDelay='); if s<>'' then AwareDelay:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'AwareMinSpeed='); if s<>'' then AwareMinSpeed:=s2r(DUE(s)) else AwareMinSpeed:=0.1*Vmax; //domyślnie 10% Vmax s:=ExtractKeyWord(lines,'SoundSignalDelay='); if s<>'' then SoundSignalDelay:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'EmergencyBrakeDelay='); if s<>'' then EmergencyBrakeDelay:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'RadioStop='); if s<>'' then if Pos('Yes',s)>0 then RadioStop:=true; end end else if Pos('Clima:',lines)>0 then {zrodlo mocy dla ogrzewania itp} begin s:=DUE(ExtractKeyWord(lines,'Heating=')); if s<>'' then begin HeatingPowerSource.SourceType:=PowerSourceDecode(s); PowerParamDecode(lines,'H',HeatingPowerSource); s:=DUE(ExtractKeyWord(lines,'AlterHeating=')); if s<>'' then begin AlterHeatPowerSource.SourceType:=PowerSourceDecode(s); PowerParamDecode(lines,'AlterH',AlterHeatPowerSource) end else AlterHeatPowerSource.SourceType:=NotDefined; end else HeatingPowerSource.SourceType:=NotDefined; end else if Pos('Power:',lines)>0 then {zrodlo mocy dla silnikow trakcyjnych itp} begin s:=DUE(ExtractKeyWord(lines,'EnginePower=')); if s<>'' then begin EnginePowerSource.SourceType:=PowerSourceDecode(s); PowerParamDecode(lines,'',EnginePowerSource); if (EnginePowerSource.SourceType=Generator) and (EnginePowerSource.GeneratorEngine=WheelsDriven) then ConversionError:=-666; {perpetuum mobile?} if (Power=0) then //jeśli nie ma mocy, np. rozrządcze EZT EnginePowerSource.SourceType:=NotDefined; //to silnik nie ma zasilania end else EnginePowerSource.SourceType:=NotDefined; //if EnginePowerSource.SourceType=NotDefined then begin s:=DUE(ExtractKeyWord(lines,'SystemPower=')); if s<>'' then begin SystemPowerSource.SourceType:=PowerSourceDecode(s); PowerParamDecode(lines,'',SystemPowerSource); end else SystemPowerSource.SourceType:=NotDefined; end //else SystemPowerSource.SourceType:=InternalSource; end else if Pos('Engine:',lines)>0 then {stale parametry silnika} begin EngineType:=EngineDecode(DUE(ExtractKeyWord(lines,'EngineType='))); case EngineType of ElectricSeriesMotor: begin s:=ExtractKeyWord(lines,'Volt='); NominalVoltage:=s2r(DUE(s)); s:=DUE(ExtractKeyWord(lines,'Trans=')); Transmision.NToothW:=s2b(copy(s,Pos(':',s)+1,Length(s))); Transmision.NToothM:=s2b(copy(s,1,Pos(':',s)-1)); if s<>'' then with Transmision do if NToothM>0 then Ratio:=NToothW/NToothM else Ratio:=1; s:=ExtractKeyWord(lines,'WindingRes='); WindingRes:=s2r(DUE(s)); if WindingRes=0 then WindingRes:=0.01; s:=ExtractKeyWord(lines,'nmax='); nmax:=s2rE(DUE(s))/60.0; end; WheelsDriven: begin s:=DUE(ExtractKeyWord(lines,'Trans=')); Transmision.NToothW:=s2b(copy(s,Pos(':',s)+1,Length(s))); Transmision.NToothM:=s2b(copy(s,1,Pos(':',s)-1)); if s<>'' then with Transmision do if NToothM>0 then Ratio:=NToothW/NToothM else Ratio:=1; s:=ExtractKeyWord(lines,'Ftmax='); Ftmax:=s2rE(DUE(s)); end; Dumb: begin s:=ExtractKeyWord(lines,'Ftmax='); Ftmax:=s2rE(DUE(s)); end; DieselEngine: begin s:=DUE(ExtractKeyWord(lines,'Trans=')); Transmision.NToothW:=s2b(copy(s,Pos(':',s)+1,Length(s))); Transmision.NToothM:=s2b(copy(s,1,Pos(':',s)-1)); if s<>'' then with Transmision do if NToothM>0 then Ratio:=NToothW/NToothM else Ratio:=1; s:=ExtractKeyWord(lines,'nmin='); dizel_nmin:=s2r(DUE(s))/60.0; s:=ExtractKeyWord(lines,'nmax='); nmax:=s2rE(DUE(s))/60.0; s:=ExtractKeyWord(lines,'nmax_cutoff='); dizel_nmax_cutoff:=s2r(DUE(s))/60.0; s:=ExtractKeyWord(lines,'AIM='); dizel_AIM:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'ShuntMode='); if s<>'' then begin //dodatkowa przekładnia dla SM03 (2Ls150) ShuntModeAllow:=true; ShuntMode:=false; AnPos:=s2rE(DUE(s)); //dodatkowe przełożenie if (AnPos<1.0) then //"rozruch wysoki" ma dawać większą siłę AnPos:=1.0/AnPos; //im większa liczba, tym wolniej jedzie end; end; DieselElectric: //youBy begin s:=DUE(ExtractKeyWord(lines,'Trans=')); Transmision.NToothW:=s2b(copy(s,Pos(':',s)+1,Length(s))); Transmision.NToothM:=s2b(copy(s,1,Pos(':',s)-1)); if s<>'' then with Transmision do if NToothM>0 then Ratio:=NToothW/NToothM else Ratio:=1; s:=ExtractKeyWord(lines,'Ftmax='); Ftmax:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'Flat='); Flat:=Boolean(s2b(DUE(s))); s:=ExtractKeyWord(lines,'Vhyp='); Vhyp:=s2rE(DUE(s))/3.6; s:=ExtractKeyWord(lines,'Vadd='); Vadd:=s2rE(DUE(s))/3.6; s:=ExtractKeyWord(lines,'Cr='); PowerCorRatio:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'RelayType='); RelayType:=s2b(DUE(s)); s:=ExtractKeyWord(lines,'ShuntMode='); ShuntModeAllow:=Boolean(s2b(DUE(s))); if (ShuntModeAllow) then begin ShuntModeAllow:=true; ShuntMode:=false; AnPos:=0; ImaxHi:=2; ImaxLo:=1; end; end; ElectricInductionMotor: begin rventnmax:=1; s:=ExtractKeyWord(lines,'Volt='); NominalVoltage:=s2r(DUE(s)); s:=DUE(ExtractKeyWord(lines,'Trans=')); Transmision.NToothW:=s2b(copy(s,Pos(':',s)+1,Length(s))); Transmision.NToothM:=s2b(copy(s,1,Pos(':',s)-1)); if s<>'' then with Transmision do if NToothM>0 then Ratio:=NToothW/NToothM else Ratio:=1; s:=ExtractKeyWord(lines,'dfic='); eimc[eimc_s_dfic]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'dfmax='); eimc[eimc_s_dfmax]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'p='); eimc[eimc_s_p]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'cfu='); eimc[eimc_s_cfu]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'cim='); eimc[eimc_s_cim]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'icif='); eimc[eimc_s_icif]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'Uzmax='); eimc[eimc_f_Uzmax]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'Uzh='); eimc[eimc_f_Uzh]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'DU='); eimc[eimc_f_DU]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'I0='); eimc[eimc_f_I0]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'fcfu='); eimc[eimc_f_cfu]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'F0='); eimc[eimc_p_F0]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'a1='); eimc[eimc_p_a1]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'Pmax='); eimc[eimc_p_Pmax]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'Fh='); eimc[eimc_p_Fh]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'Ph='); eimc[eimc_p_Ph]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'Vh0='); eimc[eimc_p_Vh0]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'Vh1='); eimc[eimc_p_Vh1]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'Imax='); eimc[eimc_p_Imax]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'abed='); if DUE(s)<>'' then eimc[eimc_p_abed]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'edep='); if DUE(s)<>'' then eimc[eimc_p_eped]:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'Flat='); if DUE(s)='Yes' then Flat:=true else Flat:=false; end; else ConversionError:=-13; {not implemented yet!} end; end { Typy przelacznika 'Winger 010304 } else if Pos('Switches:',lines)>0 then begin s:=DUE(ExtractKeyWord(lines,'Pantograph=')); PantSwitchType:=s; s:=DUE(ExtractKeyWord(lines,'Converter=')); ConvSwitchType:=s; {case PantSwitchType of Continuos: begin PantSwitchType:='continuos'; end; Impulse: begin PantSwitchType:='impulse'; end; } end else if Pos('MotorParamTable:',lines)>0 then case EngineType of ElectricSeriesMotor: begin for k:=0 to ScndCtrlPosNo do begin with MotorParam[k] do read(fin, bl, mfi,mIsat, fi,Isat); if AutoRelayType=0 then MotorParam[k].AutoSwitch:=false else begin readln(fin,i); MotorParam[k].AutoSwitch:=Boolean(i); end; if bl<>k then ConversionError:=-2 end; end; //youBy DieselElectric: begin // WW_MPTRelayNo:= ScndCtrlPosNo; for k:=0 to ScndCtrlPosNo do begin with MotorParam[k] do readln(fin, bl, mfi, mIsat, fi, Isat, MPTRelay[k].Iup, MPTRelay[k].Idown); if bl<>k then ConversionError:=-2 end; end; DieselEngine: begin s:=ExtractKeyWord(lines,'minVelfullengage='); dizel_minVelfullengage:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'engageDia='); dizel_engageDia:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'engageMaxForce='); dizel_engageMaxForce:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'engagefriction='); dizel_engagefriction:=s2r(DUE(s)); for k:=0 to ScndCtrlPosNo do begin with MotorParam[k] do read(fin, bl, mIsat, fi,mfi); if AutoRelayType=0 then MotorParam[k].AutoSwitch:=false else begin readln(fin,i); MotorParam[k].AutoSwitch:=Boolean(i); end; if bl<>k then ConversionError:=-2 end; end else ConversionError:=-3; end //dwa dodatkowe parametry korekcyjne else if Pos('MotorParamTable0:',lines)>0 then begin for k:=0 to ScndCtrlPosNo do begin with MotorParam[k] do read(fin, bl, mfi,mIsat,mfi0, fi,Isat,fi0); if AutoRelayType=0 then MotorParam[k].AutoSwitch:=False else begin readln(fin,i); MotorParam[k].AutoSwitch:=Boolean(i); end; if bl<>k then ConversionError:=-2 end; end else if Pos('Circuit:',lines)>0 then begin s:=ExtractKeyWord(lines,'CircuitRes='); CircuitRes:=s2r(DUE(s)); s:=ExtractKeyWord(lines,'IminLo='); IminLo:=s2iE(DUE(s)); s:=ExtractKeyWord(lines,'IminHi='); IminHi:=s2i(DUE(s)); s:=ExtractKeyWord(lines,'ImaxLo='); ImaxLo:=s2iE(DUE(s)); s:=ExtractKeyWord(lines,'ImaxHi='); ImaxHi:=s2i(DUE(s)); Imin:=IminLo; Imax:=ImaxLo; end else if Pos('RList:',lines)>0 then begin s:=DUE(ExtractKeyWord(lines,'RVent=')); if s='Automatic' then RventType:=2 else if s='Yes' then RventType:=1 else RventType:=0; if RventType>0 then begin s:=ExtractKeyWord(lines,'RVentnmax='); RVentnmax:=s2rE(DUE(s))/60.0; s:=ExtractKeyWord(lines,'RVentCutOff='); RVentCutOff:=s2r(DUE(s)); end; RListSize:=s2b(DUE(ExtractKeyWord(lines,'Size='))); if RListSize>ResArraySize then ConversionError:=-4 else for k:=0 to RListSize do begin read(fin, RList[k].Relay, RList[k].R, RList[k].Bn, RList[k].Mn); { if AutoRelayType=0 then RList[k].AutoSwitch:=false else begin } {to sie przyda do pozycji przejsciowych} read(fin,i); RList[k].AutoSwitch:=Boolean(i); if(ScndInMain)then begin readln(fin,i); RList[k].ScndAct:=i; end else readln(fin); end; end else if Pos('DList:',lines)>0 then {dla spalinowego silnika} begin s:=ExtractKeyWord(lines,'Mmax='); dizel_Mmax:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'nMmax='); dizel_nMmax:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'Mnmax='); dizel_Mnmax:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'nmax='); dizel_nmax:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'nominalfill='); dizel_nominalfill:=s2rE(DUE(s)); s:=ExtractKeyWord(lines,'Mstand='); dizel_Mstand:=s2rE(DUE(s)); RListSize:=s2b(DUE(ExtractKeyWord(lines,'Size='))); if RListSize>ResArraySize then ConversionError:=-4 else for k:=0 to RListSize do begin readln(fin, RList[k].Relay, RList[k].R, RList[k].Mn); end; end //youBy else if (Pos('WWList:',lines)>0) then {dla spal-ele} begin RListSize:=s2b(DUE(ExtractKeyWord(lines,'Size='))); for k:=0 to RListSize do begin if not (ShuntModeAllow) then readln(fin, DEList[k].rpm, DEList[k].genpower, DEList[k].Umax, DEList[k].Imax) else begin readln(fin, DEList[k].rpm, DEList[k].genpower, DEList[k].Umax, DEList[k].Imax, SST[k].Umin, SST[k].Umax, SST[k].Pmax); SST[k].Pmin:=sqrt(sqr(SST[k].Umin)/47.6); SST[k].Pmax:=Min0R(SST[k].Pmax,sqr(SST[k].Umax)/47.6); end; end; end else if (Pos('ffList:',lines)>0) then {dla asynchronow} begin RListSize:=s2b(DUE(ExtractKeyWord(lines,'Size='))); for k:=0 to RListSize do readln(fin, DEList[k].rpm, DEList[k].genpower) end else if (Pos('LightsList:',lines)>0) then {dla asynchronow} begin LightsPosNo:=s2b(DUE(ExtractKeyWord(lines,'Size='))); LightsWrap:=('Yes')=(DUE(ExtractKeyWord(lines,'Wrap='))); LightsDefPos:=s2b(DUE(ExtractKeyWord(lines,'Default='))); for k:=1 to LightsPosNo do readln(fin, Lights[0][k], Lights[1][k]) end; end; end; {koniec filtru importu parametrow} if ConversionError=0 then OK:=true else OK:=false; end; {otwarty plik} if OK then if OKflag<>param_ok{+wheels_ok}+dimensions_ok then begin OK:=false; ConversionError:=-OKflag; {brakowalo jakiejs waznej linii z parametrami} end; if OK and (Mass<=0) then begin OK:=false; ConversionError:=-666; end; LoadChkFile:=OK; if ConversionError<>-8 then close(fin); end; {loadchkfile} END.