ladime a ladime
This commit is contained in:
@@ -9,4 +9,6 @@ alwaysApply: false
|
|||||||
- U **`DROP FUNCTION`** (včetně schématu, např. `ems.fn_pv_forecast_delta_profile`) **nemusíme** uvádět signaturu argumentů, pokud platí předpoklad: **v DB existuje jen jedna funkce tohoto plného jména** (žádný jiný overload se stejným jménem).
|
- U **`DROP FUNCTION`** (včetně schématu, např. `ems.fn_pv_forecast_delta_profile`) **nemusíme** uvádět signaturu argumentů, pokud platí předpoklad: **v DB existuje jen jedna funkce tohoto plného jména** (žádný jiný overload se stejným jménem).
|
||||||
- Stejně u **`COMMENT ON FUNCTION`** používej **`COMMENT ON FUNCTION ems.nazev_funkce IS '...'`** bez seznamu typů argumentů — za stejného předpokladu jedné funkce na jméno.
|
- Stejně u **`COMMENT ON FUNCTION`** používej **`COMMENT ON FUNCTION ems.nazev_funkce IS '...'`** bez seznamu typů argumentů — za stejného předpokladu jedné funkce na jméno.
|
||||||
|
|
||||||
**Důsledek:** při zavádění overloadů se stejným názvem je nutné signatury zase explicitně rozlišit, nebo přejmenovat / sloučit funkce tak, aby jméno bylo jednoznačné.
|
**Chyba při migraci je v pořádku:** pokud v DB existují **dvě (nebo víc) funkcí stejného jména** (overloady), `DROP FUNCTION` / `COMMENT ON FUNCTION` **bez** seznamu typů může Postgres **zamítnout jako nejednoznačné** — to je žádoucí: hned se detekuje **nechtěný stav**, který se má opravit **odstraněním jedné z funkcí** (nebo přejmenováním), ne obcházením přes dlouhou signaturu v migraci.
|
||||||
|
|
||||||
|
**Když overload záměrně chceme:** jednoznačná jména nebo v daném skriptu dočasně uvést signaturu — v tomto projektu je default „jedna funkce na jméno“.
|
||||||
|
|||||||
1
.idea/data_source_mapping.xml
generated
1
.idea/data_source_mapping.xml
generated
@@ -4,6 +4,7 @@
|
|||||||
<file url="file://$PROJECT_DIR$/../ems-cursor-db-pracovni/debug-forecast.sql" value="26ebef46-ff23-475b-8adc-082723263a02" />
|
<file url="file://$PROJECT_DIR$/../ems-cursor-db-pracovni/debug-forecast.sql" value="26ebef46-ff23-475b-8adc-082723263a02" />
|
||||||
<file url="file://$PROJECT_DIR$/../ems-cursor-db-pracovni/porovnani-view-status.sql" value="26ebef46-ff23-475b-8adc-082723263a02" />
|
<file url="file://$PROJECT_DIR$/../ems-cursor-db-pracovni/porovnani-view-status.sql" value="26ebef46-ff23-475b-8adc-082723263a02" />
|
||||||
<file url="file://$PROJECT_DIR$/db/migration/V009__postgrest_roles.sql" value="26ebef46-ff23-475b-8adc-082723263a02" />
|
<file url="file://$PROJECT_DIR$/db/migration/V009__postgrest_roles.sql" value="26ebef46-ff23-475b-8adc-082723263a02" />
|
||||||
|
<file url="file://$PROJECT_DIR$/db/routines/R__079_fn_forecast_pv_slots_range_corrected.sql" value="26ebef46-ff23-475b-8adc-082723263a02" />
|
||||||
<file url="file://$PROJECT_DIR$/db/views/R__072_z_postgrest_ems_anon_grants.sql" value="26ebef46-ff23-475b-8adc-082723263a02" />
|
<file url="file://$PROJECT_DIR$/db/views/R__072_z_postgrest_ems_anon_grants.sql" value="26ebef46-ff23-475b-8adc-082723263a02" />
|
||||||
<file url="file://$PROJECT_DIR$/scripts/analysis/ote_arbitrage_proxy.sql" value="26ebef46-ff23-475b-8adc-082723263a02" />
|
<file url="file://$PROJECT_DIR$/scripts/analysis/ote_arbitrage_proxy.sql" value="26ebef46-ff23-475b-8adc-082723263a02" />
|
||||||
</component>
|
</component>
|
||||||
|
|||||||
@@ -560,24 +560,6 @@ async def get_site_forecast_pv_slots_range_corrected(
|
|||||||
le=10_000,
|
le=10_000,
|
||||||
description="Ignorovat sloty s nízkou výrobou (W) při odhadu profilu",
|
description="Ignorovat sloty s nízkou výrobou (W) při odhadu profilu",
|
||||||
),
|
),
|
||||||
top_n_days: int | None = Query(
|
|
||||||
None,
|
|
||||||
ge=1,
|
|
||||||
le=120,
|
|
||||||
description="Jen N nejlepších kalendářních dní (podle clear-ish skóre) pro delta profil; ostatní dny ztlumené",
|
|
||||||
),
|
|
||||||
non_top_day_factor: float | None = Query(
|
|
||||||
None,
|
|
||||||
ge=0.0,
|
|
||||||
le=1.0,
|
|
||||||
description="Násobek váhy pro dny mimo top N (default 0.02)",
|
|
||||||
),
|
|
||||||
day_weight_gamma: float | None = Query(
|
|
||||||
None,
|
|
||||||
ge=0.25,
|
|
||||||
le=8.0,
|
|
||||||
description="Exponent na denní váhu (>1 silněji preferuje jen velmi 'clear' dny)",
|
|
||||||
),
|
|
||||||
) -> dict[str, list[dict[str, Any]]]:
|
) -> dict[str, list[dict[str, Any]]]:
|
||||||
if to_ts <= from_ts:
|
if to_ts <= from_ts:
|
||||||
raise HTTPException(status_code=422, detail="'to' must be after 'from'")
|
raise HTTPException(status_code=422, detail="'to' must be after 'from'")
|
||||||
@@ -589,8 +571,6 @@ async def get_site_forecast_pv_slots_range_corrected(
|
|||||||
now = datetime.now(tz=timezone.utc)
|
now = datetime.now(tz=timezone.utc)
|
||||||
delta_to = delta_to_ts or now
|
delta_to = delta_to_ts or now
|
||||||
delta_from = delta_from_ts or (delta_to - timedelta(days=60))
|
delta_from = delta_from_ts or (delta_to - timedelta(days=60))
|
||||||
ntf = 0.02 if non_top_day_factor is None else float(non_top_day_factor)
|
|
||||||
dg = 1.0 if day_weight_gamma is None else float(day_weight_gamma)
|
|
||||||
async with db.acquire() as conn:
|
async with db.acquire() as conn:
|
||||||
site_ok = await conn.fetchval(
|
site_ok = await conn.fetchval(
|
||||||
"SELECT EXISTS(SELECT 1 FROM ems.site WHERE id = $1)", site_id
|
"SELECT EXISTS(SELECT 1 FROM ems.site WHERE id = $1)", site_id
|
||||||
@@ -607,10 +587,7 @@ async def get_site_forecast_pv_slots_range_corrected(
|
|||||||
$4::timestamptz,
|
$4::timestamptz,
|
||||||
$5::timestamptz,
|
$5::timestamptz,
|
||||||
$6::numeric,
|
$6::numeric,
|
||||||
$7::int,
|
$7::int
|
||||||
$8::int,
|
|
||||||
$9::numeric,
|
|
||||||
$10::numeric
|
|
||||||
)
|
)
|
||||||
""",
|
""",
|
||||||
site_id,
|
site_id,
|
||||||
@@ -620,9 +597,6 @@ async def get_site_forecast_pv_slots_range_corrected(
|
|||||||
delta_to,
|
delta_to,
|
||||||
half_life_days,
|
half_life_days,
|
||||||
threshold_w,
|
threshold_w,
|
||||||
top_n_days,
|
|
||||||
ntf,
|
|
||||||
dg,
|
|
||||||
)
|
)
|
||||||
slots = raw if isinstance(raw, list) else []
|
slots = raw if isinstance(raw, list) else []
|
||||||
if not isinstance(slots, list):
|
if not isinstance(slots, list):
|
||||||
|
|||||||
@@ -24,13 +24,11 @@ as $fn$
|
|||||||
from ems.site s
|
from ems.site s
|
||||||
where s.id = p_site_id
|
where s.id = p_site_id
|
||||||
),
|
),
|
||||||
-- Cutoff z analýzy DB (EMS Postgres): u site_id=2 (`home-01`) začíná být
|
-- Cutoff: učení delty jen od začátku kalendářního dne 2026-04-12 (Europe/Prague).
|
||||||
-- `forecast_accuracy.actual_power_w` spolehlivě vyplněné pro celé kalendářní dny
|
-- (UTC okamžik odpovídá DST v dubnu: půlnoc v Praze = předchozí den 22:00 UTC.)
|
||||||
-- od 2026-04-11 (Europe/Prague). Před tímto datem se v `forecast_accuracy` objevují
|
-- Před tím mohou být v `forecast_accuracy` nekonzistentní historická data (telemetrie signed/unsigned).
|
||||||
-- ustřelené hodnoty (abs(error_w) ~ 65k) způsobené historickým bugem v telemetrii
|
|
||||||
-- (signed/unsigned). Cutoff je fixní záměrně, aby se delta profil neučil z nekonzistentní historie.
|
|
||||||
cutoff as (
|
cutoff as (
|
||||||
select timestamptz '2026-04-10T22:00:00Z' as min_ts
|
select timestamptz '2026-04-11T22:00:00Z' as min_ts
|
||||||
),
|
),
|
||||||
bounds as (
|
bounds as (
|
||||||
select
|
select
|
||||||
@@ -229,4 +227,4 @@ as $fn$
|
|||||||
$fn$;
|
$fn$;
|
||||||
|
|
||||||
comment on function ems.fn_pv_forecast_delta_profile is
|
comment on function ems.fn_pv_forecast_delta_profile is
|
||||||
'Aditivní delta profil chyby PV forecastu po 15min slotu dne (96 slotů). Zdroj: forecast_accuracy, vážení exp(-age/half_life_days) * day_weight (clear-ish dny) * volitelně top_n_days (jen N nejlepších kalendářních dní podle w_energy*w_smooth, ostatní ztlumené) * power(day_weight, day_weight_gamma). Vrací JSON {deltas:[{slot_of_day, delta_w, sample_count}], ...}. Cutoff dat od 2026-04-11 Europe/Prague.';
|
'Aditivní delta profil chyby PV forecastu po 15min slotu dne (96 slotů). Zdroj: forecast_accuracy, vážení exp(-age/half_life_days) * day_weight (clear-ish dny) * volitelně top_n_days (jen N nejlepších kalendářních dní podle w_energy*w_smooth, ostatní ztlumené) * power(day_weight, day_weight_gamma). Vrací JSON {deltas:[{slot_of_day, delta_w, sample_count}], ...}. Cutoff dat od 2026-04-12 Europe/Prague.';
|
||||||
|
|||||||
@@ -12,10 +12,7 @@ create or replace function ems.fn_forecast_pv_slots_range_corrected(
|
|||||||
p_delta_data_from timestamptz,
|
p_delta_data_from timestamptz,
|
||||||
p_delta_data_to timestamptz default now(),
|
p_delta_data_to timestamptz default now(),
|
||||||
p_half_life_days numeric default 14,
|
p_half_life_days numeric default 14,
|
||||||
p_threshold_w int default 150,
|
p_threshold_w int default 150
|
||||||
p_top_n_days int default null,
|
|
||||||
p_non_top_day_factor numeric default 0.02,
|
|
||||||
p_day_weight_gamma numeric default 1.0
|
|
||||||
)
|
)
|
||||||
returns jsonb
|
returns jsonb
|
||||||
language sql
|
language sql
|
||||||
@@ -72,10 +69,7 @@ as $fn$
|
|||||||
p_delta_data_from,
|
p_delta_data_from,
|
||||||
p_delta_data_to,
|
p_delta_data_to,
|
||||||
p_half_life_days,
|
p_half_life_days,
|
||||||
p_threshold_w,
|
p_threshold_w
|
||||||
p_top_n_days,
|
|
||||||
p_non_top_day_factor,
|
|
||||||
p_day_weight_gamma
|
|
||||||
) as j
|
) as j
|
||||||
),
|
),
|
||||||
deltas as (
|
deltas as (
|
||||||
@@ -128,4 +122,4 @@ as $fn$
|
|||||||
$fn$;
|
$fn$;
|
||||||
|
|
||||||
comment on function ems.fn_forecast_pv_slots_range_corrected is
|
comment on function ems.fn_forecast_pv_slots_range_corrected is
|
||||||
'JSON pole {interval_start, pv_forecast_total_w, pv_forecast_corrected_w, slot_of_day} po 15 min pro [p_from, p_to). Korekce je aditivní delta profil z fn_pv_forecast_delta_profile (top_n_days / non_top_day_factor / day_weight_gamma). Horizont je omezený na max. 60 dní.';
|
'JSON pole {interval_start, pv_forecast_total_w, pv_forecast_corrected_w, slot_of_day} po 15 min pro [p_from, p_to). Korekce je aditivní delta profil z fn_pv_forecast_delta_profile (parametry delty = defaulty v té funkci). Horizont je omezený na max. 60 dní.';
|
||||||
|
|||||||
@@ -18,7 +18,7 @@ Shrnutí otevřených bodů z `docs/06-open-questions.md`, checklistů v modulec
|
|||||||
| **Telemetry – výroba FVE:** Registry 672/673/667 jsou **signed** W; `pv_power_w` = max(0,pv1)+max(0,pv2)+max(0,gen) (dashboard); sloupce pv1/pv2/gen ukládají signed pro audit. |
|
| **Telemetry – výroba FVE:** Registry 672/673/667 jsou **signed** W; `pv_power_w` = max(0,pv1)+max(0,pv2)+max(0,gen) (dashboard); sloupce pv1/pv2/gen ukládají signed pro audit. |
|
||||||
| **Ekonomika baterie:** snížení `reserve_soc_percent` na 10 % a `degradation_cost_czk_kwh` na 0.1500 (migrace `V026__battery_economics_tuning.sql`), úpravy objective pro ekonomicky konzistentnější nabíjení/vybíjení. |
|
| **Ekonomika baterie:** snížení `reserve_soc_percent` na 10 % a `degradation_cost_czk_kwh` na 0.1500 (migrace `V026__battery_economics_tuning.sql`), úpravy objective pro ekonomicky konzistentnější nabíjení/vybíjení. |
|
||||||
| **Planning UI operátor akce:** trvale viditelné akce import/forecast/init plan, volba data OTE (dnes/zítra), zobrazení `pv_scarcity_factor` ve stavu plánu. |
|
| **Planning UI operátor akce:** trvale viditelné akce import/forecast/init plan, volba data OTE (dnes/zítra), zobrazení `pv_scarcity_factor` ve stavu plánu. |
|
||||||
| **PV delta profil – cutoff historie:** po analýze `ems.forecast_accuracy` pro `home-01` je minimální spolehlivý začátek učení **2026-04-11 (Europe/Prague)** (UTC `2026-04-10T22:00:00Z`); cutoff je zafixovaný v `db/routines/R__078_fn_pv_forecast_delta_profile.sql` (ignoruje starší data i při širším `p_data_from`). |
|
| **PV delta profil – cutoff historie:** minimální začátek učení delty je **2026-04-12 (Europe/Prague)** (UTC `2026-04-11T22:00:00Z`); cutoff je zafixovaný v `db/routines/R__078_fn_pv_forecast_delta_profile.sql` (ignoruje starší data i při širším `p_data_from`). |
|
||||||
|
|
||||||
---
|
---
|
||||||
|
|
||||||
|
|||||||
@@ -129,12 +129,6 @@ export type ForecastPvSlotsCorrectedParams = {
|
|||||||
delta_to?: string
|
delta_to?: string
|
||||||
half_life_days?: number
|
half_life_days?: number
|
||||||
threshold_w?: number
|
threshold_w?: number
|
||||||
/** Jen N nejlepších kalendářních dní pro výpočet delta profilu (backend → fn_pv_forecast_delta_profile). */
|
|
||||||
top_n_days?: number
|
|
||||||
/** Násobek váhy pro dny mimo top N (0–1, default na serveru 0.02). */
|
|
||||||
non_top_day_factor?: number
|
|
||||||
/** Exponent na denní váhu (default 1 = beze změny oproti předchozímu chování bez top_n). */
|
|
||||||
day_weight_gamma?: number
|
|
||||||
}
|
}
|
||||||
|
|
||||||
export async function getForecastPvSlotsRangeCorrected(
|
export async function getForecastPvSlotsRangeCorrected(
|
||||||
|
|||||||
Reference in New Issue
Block a user