untoldwind / KontrolSystem2

Autopilot scripting system for KSP2
Other
54 stars 14 forks source link

Inside the VAB: get_thrust and get_isp DeltaVSituation #138

Closed PhilouDS closed 1 month ago

PhilouDS commented 3 months ago

Hello,

with ksp::oab, I have access to get_isp and get_thrust which need DeltaVSituation. Only 3 constants are available : Sealevel, Altitude or Vaccum. But, in the VAB, Altitude is treated as Vaccum. Is it possible to specify an altitude?

It will be great to have something like engine.get_thrust(DeltaVSituation.Altitude(10000) to get the thrust at 10 km.

untoldwind commented 3 months ago

Well, there seem to be a public methods to calculate ISP and thrust for different altitudes around a body. But these also modify the internal state of the underlying structure, so I am not sure if it is safe to use them.

The thrust calculation does not seem too complicated ... there is a nice helper on the engine module hat just need the atmospheric pressure and temperature (for the most part) The ISP though ... that one is a real mess, especially when it comes to the air-breathing engines that also depend on the speed of the vessel (aka mach-number).

PhilouDS commented 3 months ago

Okay. I wanted that just to calculate the true TWR at launchpad In my last craft, I get ~1.6 and when I loaded it in the launchpad, in fact, it was ~1.2. My craft wasn't very high and I don't why there is this difference so I guessed it was because I was using the thrust at sealevel.

untoldwind commented 3 months ago

There is partial support in 0.5.6.2: On Body there is now .atmosphere_pressure_kpa(altitude : float), .atmosphere_pressure(altitude : float) and .atmosphere_density(altitude : float) to get the data of the atmosphere at an altitude. On Engine there is now .calc_max_thrust_output_atm ( atmPressurekPa : float, atmTemp : float, atmDensity : float, machNumber : float ) -> float with surface level defaults for each parameters.

I ran this litte test:

use { Vessel, DeltaVSituation } from ksp::vessel
use { CONSOLE } from ksp::console
use { CONSOLE_WINDOW } from ksp::ui
use { vec3 } from ksp::math
use { sleep } from ksp::game
use { active_object_assembly_builder } from ksp::oab
use { find_body } from ksp::orbit

pub fn main_editor() -> Result<Unit, string> = {
    CONSOLE.clear()

    const builder = active_object_assembly_builder()?

    const maybe_assembly = builder.main_assembly

    const kerbin = find_body("Kerbin")?

    CONSOLE.print_line("Hub")
    if(Some(assembly) = maybe_assembly) {
        for(part in assembly.parts) {
            CONSOLE.print_line(">> " + part.part_name + " | " + part.part_title)

            if(Some(engine) = part.engine) {
                CONSOLE.print_line(engine.max_thrust_output_vac.to_fixed(2))
                CONSOLE.print_line(engine.max_thrust_output_atm.to_fixed(2))
                for(i in 0..10) {
                    const alt = 1000.0 * i
                    const pressure = kerbin.atmosphere_pressure_kpa(alt)
                    const temp = kerbin.atmosphere_temperature(alt)
                    const density = kerbin.atmosphere_density(alt)
                    const thrust = engine.calc_max_thrust_output_atm(pressure, temp, density)

                    CONSOLE.print_line($"  Alt: {alt} Pres: {pressure} Temp: {temp} Dens: {density} Thrust: {thrust} ")
                }
            }
        }
    }
}

The results looked reasonable. Only the currently selected engine mode is calculated (the internal API does not have that)

PhilouDS commented 3 months ago

Amazing. I'm looking at this right now!

PhilouDS commented 3 months ago

New question: This works well with ObjectAssemblyEngine but I'm actually working with ObjectAssemblyStageDeltaV because I need to know at which stage the engine will be active. And the return type is ObjectAssemblyEngineDeltaV.

My first attempt was to try something like that but, unfortunatly, ObjectAssemblyEngineDeltaV doesn't have part_name available.

sync fn thrust_stg (assembly: ObjectAssembly, stg: ObjectAssemblyStageDeltaV, sit: string = "vac") -> float = {
    let all_engines = assembly.parts.filter_map(fn(p) -> p.engine)
    let alt = kerbin.atmosphere_depth + 1000
    if (sit != "vac") {alt = 1000}

    const pressure = kerbin.atmosphere_pressure_kpa(alt)
    const temp = kerbin.atmosphere_temperature(alt)
    const density = kerbin.atmosphere_density(alt)
    let all_engines_with_thrust = all_engines.flat_map(fn(e) -> [[e.part_name, e.calc_max_thrust_output_atm(pressure, temp, density)]])

    let stgThrust = 0.0
    const eng = stg.active_engines
    for (e in eng) {
        for (i in 0..all_engines_with_thrust.length) {
            if (e.part_name == all_engines_with_thrust[i][0]) {
                stgThrust += all_engines_with_thrust[i][1]
                break
            }
        }
    }

    stgThrust
}
lefouvert commented 3 months ago

@PhilouDS Atmo considerations : Had done an atmo calculator I dont use anymore but it could be usefull :

sync fn atm_influence(body: ksp::orbit::Body, altitudeSealevel: float, thrustAtm: float, thrustVac: float) -> float = {
    if(!body.has_atmosphere)
        return thrustVac
    // WolframAlpha : atmoPressure = 102240.e^(-0.000165192x) with x = alt
    // I, Adrien : atmoPressure = 101325 * e^(-x/5700) with x = alt, 101325 = pressure at sealevel, and 5700 out of nowhere (now, it's wiki documented)
    // wikipedia : Barometric formula : https://en.wikipedia.org/wiki/Barometric_formula
    // considering temperature as a constant for a body (wrong, but let's say)
    // AtmoPressure = seaLevelPressure * e^((-g0 * M * (alt - altAtSeaLevel)) / (R * seaLevelTemperatureKELVIN))
    // R = universal gas constant: 8.3144598 J/(mol·K)
    // M = molar mass of Earth's air: 0.0289644 kg/mol
    // with wiki's formula, it seems the «mysterious constant» to be 8576 with base temp 20°C (293°K)
    const atmoSeaLevelPressure = 101325 // put variable when it will be available in Kontrol System
    const atmAtAlt = atmoSeaLevelPressure * exp( -clamp(altitudeSealevel, 0.0, body.atmosphere_depth) / 5700)
    return thrustAtm + ( (thrustVac - thrustAtm) * (1 - (atmAtAlt / atmoSeaLevelPressure)) )
}

It give thrust at given alt. Edit : BUT DIRECTLY AVAILABLE BY KS NOW !? WONDERFUL !!

Whitch engine will be active at whitch stage ? There you go :

pub struct Stage(vessel : Vessel, stage: int) {
    ship : Vessel = vessel
    activation_number : int = stage
    is_behaviorchange_stage : bool = vessel.parts.exists(fn(p) -> p.activation_stage == stage && (p.is_decoupler || p.is_engine))
    engines: (activation: Part[], decouple: Part[]) = (
        activation: vessel.parts // Which engines are still activated at this stage
            .filter(fn(pa) -> pa.activation_stage >= stage
                && pa.engine_module.defined
                && vessel.global_facing.vector.normalized.dot(pa.global_rotation.vector.normalized) > 0.9
                && !vessel.parts
                    .exists(fn(pd) -> pd.is_decoupler &&
                        pd.activation_stage >= stage && pd.decouple_stage <= pa.decouple_stage))
        , decouple: vessel.parts // Which engines are still activated at this stage AND will be decoupled together next
            .filter(fn(pa) -> pa.activation_stage >= stage
                && pa.engine_module.defined
                && vessel.global_facing.vector.normalized.dot(pa.global_rotation.vector.normalized) > 0.9
                && !vessel.parts
                    .exists(fn(pd) -> pd.is_decoupler &&
                        ((pd.activation_stage >= stage && pd.decouple_stage <= pa.decouple_stage)
                        || (pd.activation_stage < stage && pd.decouple_stage > pa.decouple_stage))))
    )
}

Stage(stage_you_are_looking_for).engines.activation give you which engines are running at this stage Stage(stage_you_are_looking_for).engines.decouple give you which engines will be dropped when this stage is staged. Full implementation of the stage can be found on my git. Even if their is a lot of things not fully knot'd, at least, Stage struct is fine and shouldn't move.

I'm not seeking for visitor, but you should take a look, I'm sure most of your question already have answers, even if most of my code is 'in flight oriented' and not 'VAB oriented' (or BAV, for you ^^). And please, don't look to much Ship(vessel).park(), it's heavyly in WIP state, it don't work at the time I write thoses lines. But I start to have results. It's incoming ^^. (However, ideal_exposure() work fine, and I'm a bit proud of it. Even if it still need a bit of rework for readability)

PhilouDS commented 3 months ago

@lefouvert Thanks! All of this is great but, as you said, it's useful during flight and I'm looking for a solution in the VAB. With my previous method, I found how to get thrust_output_atm by comparing the thrust at vaccum instead of the name. For ISP, no solution yet.

During flight, to know which engine is active in one given stage, I suppose you can directly use vessel.staging.parts_in_stage(n).filter_map(fn(p) -> p.engine)

untoldwind commented 3 months ago

Unluckily the vessel.staging requires the underlying SimulationObject which is (as far as I could discern) not available in VAB. But it should be possible to add a part list to the ObjectAssemblyStageDeltaV structure ... still need to do a bit of testing.

PhilouDS commented 3 months ago

Unluckily the vessel.staging requires the underlying SimulationObject which is (as far as I could discern) not available in VAB. But it should be possible to add a part list to the ObjectAssemblyStageDeltaV structure ... still need to do a bit of testing.

Thanks. I can understand if you don't want to work on this now, it's clearly not a priority!

lefouvert commented 3 months ago

@PhilouDS I know for sure you didn't even read what I suggest you :) Even if you are in VAB context, equation stay the same.

This is mostly copy/past of the code I recommended to you, with some oab adaptations :

use { CONSOLE } from ksp::console
use { active_object_assembly_builder, ObjectAssemblyPart } from ksp::oab
use { Body, Orbit, find_body } from ksp::orbit

pub const OneAtmPressure: float = 101.325 //kpa

pub type ThrustSituationConst = int

pub const ThrustSituation: (Current: ThrustSituationConst, CurrentAsOn: ThrustSituationConst, Max_Vac: ThrustSituationConst, Max_Atm: ThrustSituationConst, Min: ThrustSituationConst) = (
    Current: 2**0,
    CurrentAsOn: 2**1,
    Max_Vac: 2**2,
    Max_Atm: 2**3,
    Min: 2**4
)

/// Entry Point
pub fn main_editor() -> Result<Unit, string> = {
    // Clear the console
    CONSOLE.clear()

// const body = find_body("Kerbin").value
// for (alt in 0...71)
//     CONSOLE.print_line("Alt :" + (alt * 1000).to_string() + " pressure: " + body.atmosphere_pressure_kpa(alt * 1000).to_string())
// return Ok({})

    CONSOLE.print_line((0..80).reduce("", fn(strike, c) -> strike + "-"))

    const builder = active_object_assembly_builder()?

    CONSOLE.print_line(">>> " + builder.assemblies.length.to_string())
    const maybe_assembly = builder.main_assembly

    if(Some(assembly) = maybe_assembly) {
        // CONSOLE.print_line("a d e_def partname [part position]")
        // for(part in assembly.parts)
        //     CONSOLE.print_line(part.activation_stage.to_string() + " " + part.activation_stage.to_string() + " " + part.engine.defined.to_string() + " " + part.part_name + " " + part.relative_position.to_fixed(2))
        const maxStage = assembly.parts.reduce(0, fn(max, p) -> if(p.activation_stage > max) p.activation_stage else max)
        CONSOLE.print_line("Stage count: " + maxStage.to_string())
        for (stage in 0...maxStage) {
            const active_engines = assembly.parts.filter(fn(pa) -> pa.activation_stage >= stage
                    && pa.engine.defined
                    && !assembly.parts
                        .exists(fn(pd) -> pd.is_decoupler &&
                            pd.activation_stage >= stage && pd.decouple_stage <= pa.decouple_stage))
            const decouple_engines = assembly.parts.filter(fn(pa) -> pa.activation_stage >= stage
                    && pa.engine.defined
                    && !assembly.parts
                        .exists(fn(pd) -> pd.is_decoupler &&
                            ((pd.activation_stage >= stage && pd.decouple_stage <= pa.decouple_stage)
                            || (pd.activation_stage < stage && pd.decouple_stage > pa.decouple_stage))))
            CONSOLE.print_line("=========== STAGE " + stage.to_string() + " ===========")
            CONSOLE.print_line("thrust 10km Alt: " + thrust(active_engines, ThrustSituation.CurrentAsOn, 10000).to_string())
            // CONSOLE.print_line("thrust 0km Alt: " + thrust(active_engines, ThrustSituation.CurrentAsOn, 0000).to_string())
            // CONSOLE.print_line("thrust 70km Alt: " + thrust(active_engines, ThrustSituation.CurrentAsOn, 70000).to_string())
            CONSOLE.print_line("thrust Vacuum  : " + thrust(active_engines, ThrustSituation.Max_Vac).to_string())
            CONSOLE.print_line("thrust Sealevel: " + thrust(active_engines, ThrustSituation.Max_Atm).to_string())
            CONSOLE.print_line("isp 10km Alt: " + isp(active_engines, ThrustSituation.CurrentAsOn, 10000).to_string())
            CONSOLE.print_line("isp Vacuum  : " + isp(active_engines, ThrustSituation.Max_Vac).to_string())
            CONSOLE.print_line("isp Sealevel: " + isp(active_engines, ThrustSituation.Max_Atm).to_string())
            CONSOLE.print_line("engine list (activation): ")
            for (e in active_engines)
                CONSOLE.print_line("    " + e.part_name)
            CONSOLE.print_line("engine list (decouple)  : ")
            for (e in decouple_engines)
                CONSOLE.print_line("    " + e.part_name)
        }
    } else {
        CONSOLE.print_line(">>> no main assembly")
    }
}

pub sync fn g(body: Body, altitude: float) -> float =
    body.grav_parameter / ((body.radius + altitude)**2)

pub sync fn g0() -> float =
    g(find_body("Kerbin").value, 0.0)

pub sync fn atm_influence(body: Body, altitude: float, engine : ObjectAssemblyPart) -> float = {
    const thrustVac = engine.engine.value.max_thrust_output_vac
    const thrustAtm = engine.engine.value.max_thrust_output_atm
    thrustVac + (thrustAtm - thrustVac) * (body.atmosphere_pressure_kpa(altitude) / OneAtmPressure)
}

sync fn thrust(stageEngines : ObjectAssemblyPart[], context: ThrustSituationConst = ThrustSituation.Current, alt: float = 0.0) -> float = {
    const body = find_body("Kerbin").value
    stageEngines
        .reduce(0.0, fn(sum, p) -> {
            if (context == ThrustSituation.Current)
                sum + p.engine.value.current_thrust
            else if (context == ThrustSituation.CurrentAsOn
                || (context == ThrustSituation.Min && p.engine.value.current_engine_mode.throttle_locked))
                sum + atm_influence(body, alt, p)
            else if (context == ThrustSituation.Max_Vac)
                sum + p.engine.value.max_thrust_output_vac
            else if (context == ThrustSituation.Max_Atm)
                sum + p.engine.value.max_thrust_output_atm
            else if (context == ThrustSituation.Min)
                sum + p.engine.value.current_engine_mode.min_thrust
            else
                sum
        })
}

sync fn isp(stageEngines : ObjectAssemblyPart[], context: ThrustSituationConst = ThrustSituation.CurrentAsOn, altitude: float = 0.0) -> float = {
    const fuelFlowSum = stageEngines
        .map(fn(p) -> p.engine.value.max_fuel_flow * p.engine.value.max_thrust_output_vac / p.engine.value.current_engine_mode.max_thrust) // (fuel Flow * limiteur de poussée)
        .reduce(0.0, fn(sum, f) -> sum + f)
    const thrustSum = thrust(stageEngines, context, altitude)

    if (fuelFlowSum == 0.0)
        return 0.0
    thrustSum / (fuelFlowSum * g0())
}

It give you this (Including Isp ;P): image

The code is messy because I didn't try to make this assembly of copy/past clean, I just want see the value display, so some names can be offtopic, or, for example, body is hardcoded into thrust(), but I'm sure you are able to tidy it according to your own needs.

(Note : stage 0 is the upper stage, or, if you like to do some weird ship as much I like to do, it's the last stage when you have staged all you can)

(Caution, Launch clamp seems to be a stage 1 part finaly, stage 5, as intended, as it's clamp on stage 1. Anyway, some testings and maybe tweakings are a mandatory with this 20 minutes melted code : Main purpose is to show Isp is available without Kontrol System compute it for you, and it's possible to slice the ship assembly into activation stages without vessel.staging) Edit : Ok, I get why some part/values are not associated with their stage : in VAB, .activation_stage and .decouple_stage are the same. In flight, this assertion is (fortunately) false. More over, I had forget a dot in this range : 0...maxStage. It seems to work better, and, anyway, answer your question.

Theoretically, you can compute everything you need with thoses 3 inputs : Thrust, mass, Fuel consumption (In a unit usable as mass or weight, For example, liters/s are not usefull, except if you know the weight of a liter of propellant)

9.81 (or g0() in the code) !? -> yes, because Isp is an expression of the time your engine can give 1N of thrust with 1kg (the weight at Kerbin at sealevel, not the mass, that's why 9.81) of fuel.

PhilouDS commented 3 months ago

@PhilouDS I know for sure you didn't even read what I suggest you :) Even if you are in VAB context, equation stay the same.

@lefouvert Oh no, I did read! I always read when people answer. It's the least I can do. But you can tell that I was certainly a little tired when I read that. And I have a lot of things in mind. I don't know why I thought that some methods weren't available in the VAB. My programming skills are still limited and your stage struct confused me a little.

Sorry 🥺 And thank you for your script 🤗

PhilouDS commented 3 months ago
  • Thrust : required value. Atmo dependant, that's why body.atmosphere_pressure_kpa(altitude : float) is really cool
  • Isp : Thrust / Fuel Consumptionweight
  • BurnTime : (Initial mass - Final mass) / Fuel Consumptionmass
  • TWR : Thrust / Weight (it's in the name : Thrust Weight Ratio)
  • Dv : Isp 9,81 log10(Initial mass / Final mass)
  • any Weight = any mass * gravity acceleration (g(body, altitude) in the code)

9.81 (or g0() in the code) !? -> yes, because Isp is an expression of the time your engine can give 1N of thrust with 1kg (the weight at Kerbin at sealevel, not the mass, that's why 9.81) of fuel.

And thanks for the formula: I already worked with all of them when I did my Stage info UI. image

I use g0 = 9.80665. This value is hardCoded in KSP. I tried to use body.grav_parameter / ((body.radius + altitude)**2) a couple of months ago but I had some very weird results. And I was told I should always use 9.80665, even in space 🤔

PhilouDS commented 3 months ago

An other strange thing with KSP I noticed in my very first tests for TWR: image KSP2 seems to use the initial mass to compute the TWR and not the actual ship's mass. Very strange. (I used MicroEngineer to notice that: ME only uses numbers from KSP2 and doesn't compute the numbers itself. That's a pitty and this is why I started to create my own UI)

lefouvert commented 3 months ago

Don't worry, it happens. If you know how many mistakes I made when I'm tired... (More over, how many even when I'm not tired !!!)

I have to admit most of my code wasn't made to be read so soon, so it's not surprinzing so much code is in the shape I think it, and not in the shape it's better to communicate it.

Hû yes, this nice window, I remember it, but I was thinking, at first, it was mostly if not totaly game computed datas. So If if you have the formulas, everything should go fine :)

At the time I use it, body.grav_parameter / ((body.radius + altitude)**2) always give me a nice 9.806blablabla value for Kerbin at sealevel. I like it because it's able to give me gravity acceleration for any body, at any altitude and allow me not doing a bad thing : write manualy numbers. pub const OneAtmPressure: float = 101.325 //kpa is to my knowledge the best way when you don't have choice. And as g() is parameterizable, it allow me to have a reliable TWR on the moon, for example.

Just seeing your last post. Which mass do you use ? I use the sum of each individual part, .total_mass or .dry_mass context depending. I should take a look to the .wet_mass which I think is new. Maybe vessel.mass isn't accurate, but I don't know, I don't use it (A vessel is, in my framework, an agreggation of stages, and a stage, an aggregation of parts)

PhilouDS commented 3 months ago

Hû yes, this nice window, I remember it, but I was thinking, at first, it was mostly if not totaly game computed datas. So If if you have the formulas, everything should go fine :)

DeltaV calculations are broken in KSP2 (for the moment). I hope it will be updated soon. I prefer to compute everything myself and your code will help me to go deeper.

And as g() is parameterizable, it allow me to have a reliable TWR on the moon, for example.

That's a good point indeed.

But maybe you know the answer of this: to compute ISP, should we always use 9.81? For me, the answer is "yes" because ISP is used to compare engine's performance. but i could be mistaken.

Just seeing your last post. Which mass do you use ? I use the sum of each individual part, .total_mass or .dry_mass context depending. I should take a look to the .wet_mass which I think is new. Maybe vessel.mass isn't accurate, but I don't know, I don't use it (A vessel is, in my framework, an agreggation of stages, and a stage, an aggregation of parts)

In my UI, to compute the TWR of one given stage, I use the initial mass of this stage. Because this is the number I want. If I want to calculate the TWR during flight, I use the actual mass of the ship which is the sum of the actual mass of each part. For a tank, this is the wet mass + fuel mass.

untoldwind commented 3 months ago

In 0.5.6.3 getting more information from the DeltaV structs should be easier, i.e. the ObjectAssemblyEngineDeltaV now has a .part as well as an .engine field. Additionally I add a .parts field to StageDeltaV and ObjectAssemblyStageDeltaV.

Two test programs that seem to work in flight as well as in VAB:

use { Vessel, DeltaVSituation } from ksp::vessel
use { CONSOLE } from ksp::console
use { CONSOLE_WINDOW } from ksp::ui
use { vec3 } from ksp::math
use { sleep } from ksp::game
use { active_object_assembly_builder } from ksp::oab
use { find_body } from ksp::orbit

pub fn main_editor() -> Result<Unit, string> = {
    CONSOLE.clear()

    const builder = active_object_assembly_builder()?

    const maybe_assembly = builder.main_assembly

    const kerbin = find_body("Kerbin")?

    CONSOLE.print_line("Hub")
    if(Some(assembly) = maybe_assembly) {
        for(stage in assembly.delta_v.stages) {
            CONSOLE.print_line($"Stage {stage.stage} No Parts: {stage.parts.length}")
            for(part in stage.parts) {
                CONSOLE.print_line(">> " + part.part_name + " | " + part.part_title)
            }
        }
    }
}

pub fn main_flight(vessel: Vessel) -> Result<Unit, string> = {
    CONSOLE.clear()

    for(stage in vessel.delta_v.stages) {
        CONSOLE.print_line($"Stage {stage.stage} No Parts: {stage.parts.length}")
            for(part in stage.parts) {
                CONSOLE.print_line(">> " + part.part_name + " | " + part.part_title)
            }
    }
}

and

use { Vessel, DeltaVSituation } from ksp::vessel
use { CONSOLE } from ksp::console
use { CONSOLE_WINDOW } from ksp::ui
use { vec3 } from ksp::math
use { sleep } from ksp::game
use { active_object_assembly_builder } from ksp::oab
use { find_body } from ksp::orbit

pub fn main_editor() -> Result<Unit, string> = {
    CONSOLE.clear()

    const builder = active_object_assembly_builder()?

    const maybe_assembly = builder.main_assembly

    const kerbin = find_body("Kerbin")?

    CONSOLE.print_line("Hub")
    if(Some(assembly) = maybe_assembly) {
        for(stage in assembly.delta_v.stages) {
            CONSOLE.print_line($"Stage {stage.stage} No engines: {stage.active_engines.length}")
            for(engine in stage.active_engines) {
                CONSOLE.print_line(">> " + engine.part.part_name + " | " + engine.part.part_title)
            }
        }
    }
}

pub fn main_flight(vessel: Vessel) -> Result<Unit, string> = {
    CONSOLE.clear()

    for(stage in vessel.delta_v.stages) {
        CONSOLE.print_line($"Stage {stage.stage} No engines: {stage.active_engines.length}")
        for(engine in stage.active_engines) {
            CONSOLE.print_line(">> " + engine.part.part_name + " | " + engine.part.part_title)
        }
    }
}
PhilouDS commented 3 months ago

Thanks @untoldwind ! It seems that @lefouvert and myself are giving you lot of work 😄

lefouvert commented 3 months ago

@untoldwind Thank you !

@PhilouDS

DeltaV calculations are broken in KSP2 (for the moment).

True

and your code will help me to go deeper.

I'm happy if a can be helpfull

But maybe you know the answer of this: to compute ISP, should we always use 9.81? For me, the answer is "yes" because ISP is used to compare engine's performance. but i could be mistaken.

Yes, always 9.81. As said earlier : « 9.81 (or g0() in the code) !? -> yes, because Isp is an expression of the time your engine can give 1N of thrust with 1kg (the weight at Kerbin at sealevel, not the mass, that's why 9.81) of fuel. » It's to have a commun reference of comparison for engines efficiency. It wouldn't make sense having a «moving» reference. So on the Mun, your Isp is the same as on Kerbin, or Duna, or everywhere, and is Earth referenced (Since Kerbin is Earth referenced for many things anyway).

In my UI, to compute the TWR of one given stage, I use the initial mass of this stage. Because this is the number I want. If I want to calculate the TWR during flight, I use the actual mass of the ship which is the sum of the actual mass of each part. For a tank, this is the wet mass + fuel mass.

Maybe the mistake is here : wet_mass = dry_mass + fuel_mass = tank total_mass (Masse "mouillée", aka avec du carburant = masse sèche (sans carburant) + masse du carburant = masse totale du réservoir)

PhilouDS commented 3 months ago

Maybe the mistake is here : wet_mass = dry_mass + fuel_mass = tank total_mass

Yes, this is what I meant, sorry: dry mass + fuel mass. My point is I'm using the actual ship's mass and KSP2 uses the initial mass.

PhilouDS commented 3 months ago

On the left, the first version of my UI updated with the new method added in KS2: atmosphere_temperature, calc_max_thrust_output_atm etc. On the right, the new version using Lefouvert scripts.

image

All this time spend for not so much 😅 ASL, the v2 is better because of the calculation of the ISP.

QUESTION: Does max_thrust_output_atm take into account the thrust limiter (it seems it does) or should I multiply this by engine.thrust_limiter?

@lefouvert your p.engine.value.max_fuel_flow * p.engine.value.max_thrust_output_vac / p.engine.value.current_engine_mode.max_thrust) seems to be equal to p.engine.value.max_fuel_flow * p.engine.value.thrust_limiter

lefouvert commented 3 months ago

Yup, it is. p.engine.value.thrust_limiter wasn't available at the time I wrote this. And unavailable datas are not enought to discourage me :P

Nice datasheet tho

github-actions[bot] commented 1 month ago

This issue is stale because it has been open for 60 days with no activity.

github-actions[bot] commented 1 month ago

This issue was closed because it has been inactive for 14 days since being marked as stale.