akxen / nemde

Reverse engineering Australia's National Electricity Market Dispatch Engine (NEMDE)
Apache License 2.0
3 stars 4 forks source link

Ramp rates for fast-start units #1

Closed akxen closed 4 years ago

akxen commented 4 years ago

NEMDE Case ID: 20191008021

Trader dispatch targets should be constrained by SCADA ramp rates / energy offer ramp rates. For URANQ13 it's hard to tell what ramp-rate has been used to constrain dispatch. Consider the following inputs:

From TraderCollection:

{
            "@TraderID": "URANQ13",
            "@TraderType": "GENERATOR",
            "@FastStart": "1",
            "@MinLoadingMW": "80",
            "@CurrentMode": "2",
            "@WhatIfCurrentMode": "2",
            "@CurrentModeTime": "4",
            "@WhatIfCurrentModeTime": "4",
            "@T1": "6",
            "@T2": "7",
            "@T3": "39",
            "@T4": "7",
            "@SemiDispatch": "0",
            "TraderInitialConditionCollection": {
              "TraderInitialCondition": [
                {
                  "@InitialConditionID": "AGCStatus",
                  "@Value": "0"
                },
                {
                  "@InitialConditionID": "HMW",
                  "@Value": "173"
                },
                {
                  "@InitialConditionID": "InitialMW",
                  "@Value": "23.6062469482422"
                },
                {
                  "@InitialConditionID": "LMW",
                  "@Value": "79.9937515258789"
                },
                {
                  "@InitialConditionID": "SCADARampDnRate",
                  "@Value": "659.906272888184"
                },
                {
                  "@InitialConditionID": "SCADARampUpRate",
                  "@Value": "659.906272888184"
                },
                {
                  "@InitialConditionID": "WhatIfInitialMW",
                  "@Value": "45.71429"
                }
              ]
            }

From TraderPeriodCollection:

{
                "@TraderID": "URANQ13",
                "@RegionID": "NSW1",
                "@TradePriceStructureID": "20191008021",
                "TradeCollection": {
                  "Trade": {
                    "@TradeType": "ENOF",
                    "@RampUpRate": "660",
                    "@RampDnRate": "660",
                    "@MaxAvail": "166",
                    "@BandAvail1": "80",
                    "@BandAvail2": "166",
                    "@BandAvail3": "0",
                    "@BandAvail4": "0",
                    "@BandAvail5": "0",
                    "@BandAvail6": "0",
                    "@BandAvail7": "0",
                    "@BandAvail8": "0",
                    "@BandAvail9": "0",
                    "@BandAvail10": "0"
                  }
                }
              },

From TraderSolution (I am primarily focused on the physical run, hence @Intervention = "1":

        {
          "@TraderID": "URANQ13",
          "@PeriodID": "2019-10-08T05:45:00+10:00",
          "@Intervention": "1",
          "@EnergyTarget": "101.99688",
          "@R6Target": "0",
          "@R60Target": "0",
          "@R5Target": "0",
          "@R5RegTarget": "0",
          "@L6Target": "0",
          "@L60Target": "0",
          "@L5Target": "0",
          "@L5RegTarget": "0",
          "@R6Price": "0",
          "@R60Price": "0",
          "@R5Price": "0",
          "@R5RegPrice": "0",
          "@L6Price": "0",
          "@L60Price": "0",
          "@L5Price": "0",
          "@L5RegPrice": "0",
          "@R6Violation": "0",
          "@R60Violation": "0",
          "@R5Violation": "0",
          "@R5RegViolation": "0",
          "@L6Violation": "0",
          "@L60Violation": "0",
          "@L5Violation": "0",
          "@L5RegViolation": "0",
          "@FSTargetMode": "3",
          "@RampUpRate": "659.91",
          "@RampDnRate": "659.91",
          "@RampPrice": "-58.77",
          "@RampDeficit": "0"
        },

From TraderSolution (for good measure I have included results from the pricing run):

        {
          "@TraderID": "URANQ13",
          "@PeriodID": "2019-10-08T05:45:00+10:00",
          "@Intervention": "0",
          "@EnergyTarget": "101.99688",
          "@R6Target": "0",
          "@R60Target": "0",
          "@R5Target": "0",
          "@R5RegTarget": "0",
          "@L6Target": "0",
          "@L60Target": "0",
          "@L5Target": "0",
          "@L5RegTarget": "0",
          "@R6Price": "0",
          "@R60Price": "0",
          "@R5Price": "0",
          "@R5RegPrice": "0",
          "@L6Price": "0",
          "@L60Price": "0",
          "@L5Price": "0",
          "@L5RegPrice": "0",
          "@R6Violation": "0",
          "@R60Violation": "0",
          "@R5Violation": "0",
          "@R5RegViolation": "0",
          "@L6Violation": "0",
          "@L60Violation": "0",
          "@L5Violation": "0",
          "@L5RegViolation": "0",
          "@FSTargetMode": "3",
          "@RampUpRate": "659.91",
          "@RampDnRate": "659.91",
          "@RampPrice": "-93.94",
          "@RampDeficit": "0"
        },

Note how InitialMW=23.6 and the ramp-rate (given by SCADA and in the energy offer is approximately 660 MW/hr). Therefore, the unit's ramping capability over a 5min interval is 660/12=55MW, so the ramping up constraint will ensure @EnergyTarget <= 23.6 + 55 = 78.6. But note the energy target is 101.99688MW. The unit's output seems to exceed its ramping capability.

Note that this unit is initially operating on the T2 section of its fast-start inflexibility profile - it is ramping up to a min loading of 80MW. The ramp-rate over this interval is 80/7 = 11.43 MW/min = 685.7 MW/hr. But even this ramp rate is insufficient to meet the energy target (23.6 + (11.43x5) = 80.75 MW).

The unit also seems to have deviated from its fixed inflexibility profile while in T2. The unit has been in T2 for 4 mins, so it should have an output of (80/7) x 4 = 45.7142 MW, but its InitialMW is only 23.6MW. The expected MW output corresponds to the WhatIfInitialMW value, so it's not clear if this value is used instead. Even if this value is used instead this still doesn't resolve the issue. Applying the SCADA ramp rate yields a max energy target of 45.7142 + (659.91/12) = 100.7067 MW which is still below the target. Using the startup profile ramp rate yields an max energy target of 45.7142 + (685.7/12) = 102.855 MW which is now above the target. I would expect the ramp rate constraint be binding in this scenario.

akxen commented 4 years ago

After working through the above example I think I've figured out the problem: NEMDE applies the inflexibility profile T2 ramp rate while the unit is operating in T2, and then the SCADA ramp rate once it has reached min loading. The value for InitialMW also seems to correspond to the anticipated MW output along the startup profile.

The discrepancy observed above results from the unit transitioning from T2 to T3 over the dispatch interval. For the first 3mins the unit is still operating in T2, so the inflexibility profile ramp rate applies. For the last 2 mins the SCADA ramp rate applies. The max energy output target is then: 45.7142 + ((80/7)x3) + ((659.91/60)x2) = 101.9969 MW. This corresponds to the observed energy target.