Open Looky1173 opened 2 years ago
Property | Value |
---|---|
Posted by | Wesley Johnson (trackcreworts) |
Date posted | Sat, 10 Sep 2022 04:05:56 GMT |
I missed putting this in the bug report. From my code:
// verify_and_correct model
// max steam vrs max speed damper_factor_manual = boiler_steam_output_max / MPH60; // a factor for damper control that will vary with speed.
blower_steam_usage_factor = (0.04f 2.20462f / 255) boiler_steam_output_max / boiler_pressure_max; // kg/sec/psi/control_step
// draft_air multipliers, guess work for now // natural draft can support 20% of full burn fire_draft_multiplier = (fire_mass_ideal 0.2f) / grate_burn_rate_max; // background burn rate // exhaust, by itself, supplies air for 85% of full burn exhaust_draft_multiplier = (fire_mass_ideal 0.85f) / boiler_steam_output_max; // blower can support 40% of full burn blower_draft_multiplier = (fire_mass_ideal 0.4f / 255) / (blower_steam_usage_factor boiler_pressure_max); // control 0..255
note: I expect at full steam, the firebox will suffer from excess air. I expect that because the stack and flues will be designed for efficient operation at a nomimal steam usage less than the maximum. The fireman will be expected to close the dampers somewhat.
Imported from https://bugs.launchpad.net/bugs/1989236
In every comment, the DamperFactorManual is said to be for manual damper control. At the point of use, it is used by the AI, and not the manual damper control. The test is reversed, or something more complicated,
File: MSTSSteamLocomotive.cs
float DamperFactorManual = 1.0f; // factor to control draft through fire when locomotive is running in Manual mode
DamperFactorManual = TheoreticalMaxSteamOutputLBpS / SpeedEquivMpS; // Calculate a factor for damper control that will vary with speed.
// ORTS ERROR: or at least this is terribly confusing given the previous comments.
// Damper - to determine smoke color float SmokeColorDamper = 0.0f; if (FiringIsManual) { SmokeColorDamper = DamperBurnEffect; // set to the damper burn effect as set for manual firing } else { SmokeColorDamper = absSpeedMpS * DamperFactorManual; // Damper value for manual firing - related to increased speed, and airflow through fire }
Note: my code is replacing the ORTS damper controls with something entirely new, with more control, and more refined simulation. Not entirely ready yet, as I have these details to figure out.
My code: // ---- Damper Model // factor to control draft through fire when locomotive is running in Manual mode float damper_factor_manual = 1.0f; // kg/meter/sec // DamperFactorManual lb/meter/sec float fire_draft_multiplier; // kg / kg/sec // multiply by fuel_burn_rate float exhaust_draft_multiplier; // kg / kg/sec // multiply by cylinder_steam_usage
// ---- Damper in engine unit // Damper byte damper_control; // 0..255 float draft_air; // 1.0 = air to burn 1kg float DamperBurnEffect; // Effect of the Damper control
// Draft caused by fire. Do not ever let it be 0. draft_air = model->fire_draft_multiplier fuel_burn_rate_eff; // Draft caused by exhaust steam. draft_air += model->exhaust_draft_multiplier cylinder_steam_usage;
// Damper - need to be calculated in AI fireman case too, to determine smoke color if (absSpeedMpS < 1.0f) // locomotive is stationary then damper will have no effect { // This is not necessary. DamperBurnEffect = 0.0f; } else { // Damper value for manual firing - related to damper setting and increased speed DamperBurnEffect = damper_control (1.0/255) absSpeedMpS model->damper_factor_manual; } draft_air = damper_control * (1.0/255);
// Manual fireman // Test to see if blower has been manually activated. if( blower_control > 0 ) { fire_control_status |= SF_blower; // turn blower on if being used blower_steam_usage = model->blower_steam_usage_factor boiler_pressure blower_control; BlowerBurnEffect = model->blower_multiplier blower_steam_usage; draft_air += model->blower_draft_multiplier blower_steam_usage; }
// AI fireman draft_air = fire_mass; // perfect damper control ?? FIXME
// The draft_air is measured as the amount of fire that can be supported, so it is measured the same as fire mass. float fire_supported = fire_mass; float fire_mass_unburned = 0; float excess_air = 0; draft_air += (fire_mass 0.01f) + 0.1; // damper leakage, and so draft_air is never 0. if( draft_air > fire_mass ) { // Excess air excess_air = draft_air - fire_mass; // Excess air cools the fire, the boiler, and the superheater. // The amount of air that would be ideal for the fire is same value as fire_mass. // All the draft_air going through the firebox has to be heated too. float excess_air_frac = fire_mass / draft_air; float source_temp = C_to_K(environment_temperature); superheater_temperature = ((superheater_temperature - source_temp) excess_air_frac) + source_temp; // specific heat of air = 1.006 kj/kg K // specific heat of water = 4.22 kj/kg K at 300 K float draft_heat_loss = excess_air (boiler_water_temp_K - source_temp) (1.006 / 4.22) / boiler_water_mass; boiler_output_heat_rate += draft_heat_loss; boiler_heat -= draft_heat_loss tick_secs; // Reduce boiler Heat to reflect heat lost by excess air. }else{ // Insufficient air // Can only support draft_air amount of fire. fire_supported = draft_air; fire_mass_unburned = fire_mass - draft_air; // creates smoke } fire_burn_rate_inst = fire_supported / model->fire_mass_ideal;
I have not yet tied the draft_air and fire_mass_unburned to the smoke, as that requires rewriting the smoke generation for my graphics files and environment.