Kontaktné údaje
- info@ipesoft.com
- +421 907 703 854
- Obchodná 9076/3D
010 08 Žilina
Slovensko
© Copyright IPESOFT 2023
Pred pár dňami prišiel za mnou kolega. Že či by som mu neporadil: „Potrebujem sumovať, respektíve integrovať spotrebu energie – ale tak, že na začiatku každej pracovnej zmeny sa to číslo vynuluje. Takže graf toho bude pripomínať zuby píly – bude rásť, rásť a potom na hrane pracovnej zmeny pôjde znovu na nulu. Viem to urobiť nejak elegantne – najlepšie priamo v archíve a bez nutnosti počítania niekde v ESL skripte?“.
Pokiaľ by zadanie znelo tak, že chce integrál za 8-hodinovú pracovnú zmenu, nebolo by nutné nič vymýšľať. Jednoducho by sa nakonfiguroval štatistický archív , ktorý by počítal integrál z primárneho archívu:
Ako vidieť na obrázku vyššie, takýto archív by sa automaticky prepočítal každú minútu. Ale požiadavky kolegu boli iné – integrácia má prebiehať priebežne a užívateľovi sa majú zobrazovať aj medzivýsledky a nielen jedno číslo na konci periódy (8-hodinovej pracovnej zmeny).
Takže štatistický archív nebude to pravé orechové. Cestou k riešeniu bude zrejme použiť vypočítaný archív a dať mu požadované vlastnosti.
Aby som mohol príklad ladiť, vytvoril som si linku, stanicu so zapnutou simuláciou a periódou pollingu 2 sekundy a meraný bod M.MySimulPower. Tento meraný bod bude meniť hodnotu podľa časových parametrov stanice, t.j. cca každé 2 sekundy (pričom hodnoty budú mať sínusový priebeh s amplitúdou rešpektujúcou nastavenie limitov LL a HL na meranom bode). Následne som vytvoril primárny archív H.MySimulPower, ktorý archivuje tento meraný bod:
Potom som sa pustil do tvorby vypočítaného archívu. Princíp integrácie je jednoduchý. Integrál (resp. suma) sa skladá zo súčtov Hodnota * DeltaT, kde DeltaT je veľkosť časového intervalu, počas ktorého bola hodnota platná. Prvá verzia vypočítaného archívu vyzerala takto:
Riadok
_prevVal := %ARC_GetValue(H.MySimulPowerIntegral, @EvalTime - 0.001, @FALSE)
zistí predchádzajúcu hodnotu integrálu.
Čas je špecifikovaný ako čas výpočtu (reprezentovaný konštantou @EvalTime) zmenšený o 1 ms, čo je základná časová jednotka podporovaná systémom D2000). Parameter @FALSE hovorí, že ak pre požadovaný čas nie je k dispozícii hodnota, použije sa najbližšia staršia.
Riadok
_prevTime:= _prevVal\TIM
priradí do premennej _prevTime časovú značku predchádzajúcej hodnoty integrálu.
No a nakoniec riadok
_prevVal + (@EvalTime - _prevTime) * H.MySimulPower
v sekcii FINALLY vykoná integráciu – k predchádzajúcej hodnote integrálu pričíta aktuálnu hodnotu integrovanej veličiny H.MySimulPower vynásobenú veľkosťou časového intervalu (aktuálny čas mínus čas poslednej naintegrovanej hodnoty).
Takýto integrál ale nespĺňa požiadavky zadania, pretože stále rastie. Takže ako implementovať požadované vynulovanie na začiatku ďalšej zmeny?
Pre zrýchlenie ladenia nebudeme nulovať po 8 hodinách ale po naše pracovné zmeny budú 15 sekundové. Niekomu by takáto pracovná zmena vyhovovala aj v skutočnom živote :-)
Ako na to? Najskôr si vytvoríme pomocný archívny objekt H.MyPeriodicTrigger, ktorý bude mať požadovanú periódu (15 sekúnd). Tento použijeme na vybudenie výpočtu na hrane pracovnej zmeny. Tento 15-sekundový archív môže archivovať hocičo – konkrétne sme použili systémový objekt Day, ktorý sa mení raz denne a udáva aktuálny deň v mesiaci.
Niektorí čitatelia môžu namietnuť, že takto si zbytočne zaplníme archívnu databázu – každých 15 sekúnd archivovať tú istú hodnotu? Táto námietka môže byť platná v iných systémoch ale nie v D2000. Vďaka zmenovému spôsobu ukladania periodických dát v archívnej databáze D2000 sa každý deň uloží iba jediná hodnota.
Dôležité je aj nastavenie časových parametrov – dĺžka pracovnej zmeny (15 sekúnd) a ukladanie času konca intervalu.
Ako sa zmení vypočítaný archív? Odpoveď je na nasledujúcom obrázku:
Jednak do výpočtu potrebujeme zahrnúť trigger H.MyPeriodicTrigger (hoci hodnotu tohto objektu vôbec nepoužijeme, ale vybudí nám výpočet). To robí riadok
_prevVal := H.MyPeriodicTrigger
Ďalší riadok (ktorý ostal bez zmeny) túto hodnotu prepíše predchádzajúcou hodnotou integrálu.
_prevVal := %ARC_GetValue(H.MySimulPowerIntegral, @EvalTime - 0.001, @FALSE)
Ďalej pribudli riadky implementujúce resetovanie. Ak je čas predchádzajúcej hodnoty integrálu násobok periódy, tak sa výsledok vynuluje (lebo počítame prvú hodnotu v novej pracovnej zmene). Inak sa nič nestane, teda použije sa predchádzajúca hodnota (pokračujeme v integrovaní).
IF %ModTime(_prevTime, 15) = 0 THEN
_prevVal := 0
ENDIF
Posledný riadok implementujúci integráciu zostal bez zmeny.
Je tento predpis už finálny, alebo mu do dokonalosti ešte niečo chýba? Napadajú ma dve možné vylepšenia:
Záver
Popisovaný vypočítaný archív demonštruje silu archívneho subsystému aplikačného servera D2000 jednoducho realizovať užívateľské výpočty – iba prostredníctvom archívu, bez použitia akýchkoľvek externých prostriedkov.
Keď som sa na veľtrhu Ampér 2019 rozprával s technikmi renomovaného rakúskeho dodávateľa PLC a riadiacich systémov a pýtal som sa ich, ako by realizovali funkčnosť “vypočítaných archívov”, tak rozprávali o externom skripte napísanom v Pythone, ktorý by periodicky načítaval dáta primárnych archívnych objektov, počítal a výsledky posielal do archívu.
Iný, tentokrát americký výrobca SCADA systémov, používa periodicky spúšťané externé programy v jazyku C, ktoré robia niečo podobné ako Python skripty.
Niektoré nevýhody týchto prístupov sú zjavné na prvý pohľad – namiesto jednoduchej konfigurácie v natívnom prostredí SCADA systému (používajúcej rovnakú syntax ako vypočítané body či ESL skripty) musí aplikačný programátor používať iné jazyky (Python, C) a venovať úsilie nielen napísaniu samotného výpočtu, ale aj získaniu dát a zapísaniu výsledkov.
Ďalšie nevýhody sú možno viac skryté. Externé výpočty treba pri upgradoch, zmenách verzie a prípadne pri migráciách na inú platformu udržovať a prípadne rekompilovať (kvôli zmenám v API alebo kvôli linkovaniu aktuálnej API knižnice). Zdrojové kódy je potrebné niekde udržovať a spravovať. V redundantných systémoch je potrebné distribuovať aktuálne verzie externých skriptov alebo binárok na dva či viaceré servery a riešiť, kde sú najnovšie zdrojové kódy.
Vyčlenenie výpočtov mimo SCADA systém navyše spôsobí stratu väzieb medzi zdrojovými a vypočítanými archívnymi objektami. Jedna z kľúčových vlastností systému D2000 nazývaná referenčná integrita je založená na udržovaní si informácií o väzbách medzi všetkými objektami v systéme. O každom objekte je neustále dostupná informácia, ktoré iné objekty používa a ktoré objekty používajú jeho. Nemôže tak dôjsť k zrušeniu ešte používaného objektu. Zároveň je referenčná integrita neoceniteľná pomôcka pri ladení a hľadaní chýb (dáva odpovede na otázky typu “ako a odkiaľ sa sem tá hodnota dostala”) a pri budovaní a najmä udržovaní riešení s rozsahom desaťtisíce až stotisíce objektov.
Dnešným príkladom z praxe som chcel demonštrovať, ako sa v D2000 dajú relatívne jednoducho riešiť netriviálne problémy – s použitím zabudovanej funkcionality vypočítaných archívov a bez nutnosti uchyľovať sa k barličkám typu externých programov.
2.5.2019, Ing. Peter Humaj, www.ipesoft.com