uniset-algorithms 0.2
Классы | Открытые типы | Открытые члены | Открытые статические члены | Статические открытые данные | Защищенные члены | Защищенные статические члены | Защищенные данные | Друзья
Класс SEESGroup

#include <SEESGroup.h>

Граф связей класса SEESGroup:
Collaboration graph
[см. легенду]

Полный список членов класса

Классы

struct  ReservInfo

Открытые типы

typedef std::list< ReservInfoRList

Открытые члены

 SEESGroup (int num, const std::string name="")
int getNumber ()
std::string getName ()
long getP ()
long getU ()
long getF ()
bool isUdev ()
bool isFdev ()
long getReservPower ()
void step ()
void update ()
void updatePowerInfo ()
void requiredReserv (bool set)
bool isNoReserv ()
bool isReadyForLoading ()
void addGroup (SEESGroup *gr)
bool add (SEES *ses)
bool del (SEES *ses)
void clear ()
bool isProtection ()
int acceptQG (int num) throw (UniSetTypes::NameNotFound)
void releaseQG (int num) throw (UniSetTypes::NameNotFound)
bool canRun (int num) throw (UniSetTypes::NameNotFound)
SEESget (int num)
SESList getSESList ()
void setReservStatePause (int s)
void setCommandTimeout (int s)
void setReservTime (int s)
void setMaxWorkingDG (int s)
int getWorkingDG ()
void setFdev (int f_min_, int f_max_, int f_msec)
void setUdev (int u_min_, int u_max_, int U_msec)

Открытые статические члены

static void init_dlog (DebugStream &dlog)

Статические открытые данные

static DebugStream dlog

Защищенные члены

void reserv (bool set)
void checkReserv ()
bool resetReserv ()
void makeReservList ()
void checkAloneWorking ()
void updateCounters ()

Защищенные статические члены

static void update (RList &rlist, ReservInfo &ri)

Защищенные данные

UniSetTypes::uniset_mutex lstMutex
int gnum
std::string myname
int qf_locked
SESList lst
SEESleader
RList rlst
int maxWorkingDG
int countWorkingDG
UniSetTypes::uniset_mutex maxrunMutex
int reservStatePause
int reservCommandTimeout
int checkReservTime
PassiveTimer ptCheckReserv
int f_min
int f_max
int U_min
int U_max
SandClock sc_Fdev
SandClock sc_Udev
bool U_dev
bool f_dev

Друзья

std::ostream & operator<< (std::ostream &os, SEESGroup &g)
std::ostream & operator<< (std::ostream &os, SEESGroup *g)
std::ostream & print_chain (std::ostream &os, SEESGroup *g)

Подробное описание

Реализация управления группой СЭС


Методы

int SEESGroup::acceptQG ( int  num) throw (UniSetTypes::NameNotFound)

захват приоритета включения генераторного автомата

Возвращает:
Номер текущего держателя. Если захват удаётся. То возвращаемое значение будет равно num.
{
    { // lock
        UniSetTypes::uniset_mutex_lock lock(lstMutex, 5000);

        if( qf_locked != 0 )
        {
            if( qf_locked == num )
            {
                if( SEESGroup::dlog.debugging(Debug::INFO) )
                    SEESGroup::dlog[Debug::INFO] << myname << "(acceptQG): QG" << num << " ALREADY ACCEPTED..." << endl;
                return qf_locked;
            }

            if( SEESGroup::dlog.debugging(Debug::INFO) )
                SEESGroup::dlog[Debug::INFO] << myname << "(acceptQG): NOT ACCEPT QG" << num << " qf locked..." << endl;
            return qf_locked;
        }

        for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
        {
            SEES* s(*it);
            if( s->isHaveQGLock() )
            {
                if( (*it)->getNumber() == num )
                {
                    if( SEESGroup::dlog.debugging(Debug::INFO) )
                        SEESGroup::dlog[Debug::INFO] << myname << "(acceptQG): REPEAT ACCEPT QG" << num << endl;
                    qf_locked = num;
                    return qf_locked;
                }

                if( SEESGroup::dlog.debugging(Debug::INFO) )
                    SEESGroup::dlog[Debug::INFO] << myname << "(acceptQG): NOT ACCEPT QG" << num
                        << " but blocked ses" << (*it)->getNumber() << endl;
                s->setQGLock(true);
                qf_locked = (*it)->getNumber();
                return qf_locked;
            }
        }
    }

    ostringstream err;
    err <<  myname << "(acceptQG): Not found ses" + num;
    throw NameNotFound(err.str());
}
void SEESGroup::checkAloneWorking ( ) [protected]

обновление информации о том "один ли ДГ на шинах"

Перекрестные ссылки lst.

{
  { // lock
        UniSetTypes::uniset_mutex_lock lock(lstMutex, 4000);
        int count = getWorkingDG();
        if( count > 0 )
        {
            for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
            {
                if( (*it)->isOnMode() )
                {
                    if( count == 1 )
                        (*it)->setAloneWorking(true);
                    else
                        (*it)->setAloneWorking(false);
                }
                else
                    (*it)->setAloneWorking(false);
            }
        }
        else
        {
            for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
                (*it)->setAloneWorking(true);
        }
  }// unlock
}
void SEESGroup::checkReserv ( ) [protected]

проверка необходимости запуска/остановки резерва

Перекрестные ссылки leader, myname, reserv(), resetReserv() и rlst.

{
    UniSetTypes::uniset_mutex_lock lock(lstMutex, 5000);
    bool needCheck = false;

    if( !leader )
    {
        if( SEESGroup::dlog.debugging(Debug::LEVEL4) )
            SEESGroup::dlog[Debug::LEVEL4] << myname << "(checkReserv): ignore.. no leader.." << endl;
        return;
    }

    if( leader->isReservOnNeeded() )
    {
        if( SEESGroup::dlog.debugging(Debug::LEVEL4) )
            SEESGroup::dlog[Debug::LEVEL4] << myname << "(checkReserv): needON for "
                << leader->getName() << endl;

        reserv(true);
        needCheck = true;
    }
    else if( leader->isReservOffNeeded() )
    {
        if( SEESGroup::dlog.debugging(Debug::LEVEL4) )
            SEESGroup::dlog[Debug::LEVEL4] << myname << "(checkReserv): needOFF for "
                << leader->getName() << endl;

        reserv(false);
        needCheck = true;
    }
    else
    {
        // Сбрасываем все таймеры и тригеры
        // т.к. резерв никому не требуется
        for( RList::iterator it=rlst.begin(); it!=rlst.end(); ++it )
        {
            it->ptPause.setTiming(0);
            it->trChangeState.hi(true);
            it->waitRunning = false;
            it->waitStopping = false;
        }
        
        resetReserv();
    }

    if( !needCheck )
        ptCheckReserv.setTiming(UniSetTimer::WaitUpTime);
}
long SEESGroup::getF ( )

частота

Перекрестные ссылки lst.

Используется в UnionGroups::updateF() и updatePowerInfo().

{
    // при параллельном включении:
    // частоты одинаковые
    { // lock
        UniSetTypes::uniset_mutex_lock lock(lstMutex, 3000);
        for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
        {
            if( (*it)->getF() > 0 )
                return (*it)->getF();
        }
    } // unlock

    return 0;
}
long SEESGroup::getP ( )

суммарная мощность

Перекрестные ссылки lst.

Используется в UnionGroups::updateP().

{
    // при параллельном включении:
    // мощности складываются..
    long P=0;
    { // lock 
        UniSetTypes::uniset_mutex_lock lock(lstMutex, 3000);
        for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
            P += (*it)->getP();
    } // unlock

    return P;
}
long SEESGroup::getReservPower ( )

резерв мощности

Перекрестные ссылки lst.

Используется в UnionGroups::updateReservPower().

{
    long Pres=0;

    { // lock
        UniSetTypes::uniset_mutex_lock lock(lstMutex, 3000);    
        for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
            Pres += (*it)->getReservPower();
    } // unlock

    return Pres;
}
long SEESGroup::getU ( )

напряжение

Перекрестные ссылки lst.

Используется в updatePowerInfo() и UnionGroups::updateU().

{
    // при параллельном включении:
    // напряжения одинаковые
    { // lock
        UniSetTypes::uniset_mutex_lock lock(lstMutex, 3000);
        for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
        {
            if( (*it)->getU() > 0 )
                return (*it)->getU();
        }
    } // unlock

    return 0;
}
bool SEESGroup::isFdev ( )

отклонение частоты от нормы

Перекрестные ссылки f_dev.

Используется в UnionGroups::updateFdev().

{
    return f_dev;
}
bool SEESGroup::isProtection ( )

Есть ли хоть одна сработавшая защита

Перекрестные ссылки lst.

{
    UniSetTypes::uniset_mutex_lock lock(lstMutex, 4000);
    for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
    {
        if( (*it)->isProtection() )
            return true;
    }

    return false;
}
bool SEESGroup::isReadyForLoading ( )

готова ли группа к приёму нагрузки

Перекрестные ссылки lst.

Используется в UnionGroups::updateReadyForLoading().

{
    // если есть хоть один работющий ДГ и он не перегружен (не требует резерва), то СЭС готова.
    UniSetTypes::uniset_mutex_lock lock(lstMutex, 5000);
    for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
    {
        if( (*it)->isOnMode() && !(*it)->isReservOnNeeded() )
            return true;
    }

    return false;
}
bool SEESGroup::isUdev ( )

отклонение напряжения от нормы

Перекрестные ссылки U_dev.

Используется в UnionGroups::updateUdev().

{
    return U_dev;
}
void SEESGroup::makeReservList ( ) [protected]

обновление списка резервных ДГ

Перекрестные ссылки SEES::isAutoControl(), SEES::isOnMode(), leader, lst, myname и rlst.

{
    UniSetTypes::uniset_mutex_lock lock(lstMutex, 5000);

    // проходим по списку СЭС в группе
    // определяем главный ДГ (он должен быть один)
    // и какие есть резервные ДГ
    SEES* main = 0;
    RList rlist;

    // Т.к. самым приоритетным считается ДГ с наименьшим заданным приоритетом,
    // то строим список резервных так: делаем map, сортируем по возрастанию приоритета
    // и строим уже список резервных
    // в map - добавляем только те ДГ, которые находятся в режиме "авто"
    typedef std::map<int,SEES*> PriorityMap;
    PriorityMap prmap;
    
    for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
    {
        SEES* ses(*it);

        if( ses->isAutoControl() && ses->getPriority()>0 )
            prmap[ses->getPriority()] = ses;
        else
            ses->setLeader(false); // просто на всякий сбрасываем флаг
            
        // если ГДГ не в режиме автомат, сбрасываем команды управления резервом
        if( !ses->isAutoControl() )
            ses->resetReservCommand();
    }

    // формируем список резервных на основе "карты приоритетов"
    if( !prmap.empty() )
    {
        PriorityMap::iterator it=prmap.begin();
        // первый в списке, это самый приоритетный
        main = it->second;
        it++;
        // остальные добавляем в список в соответсвии с приоритетом
        while( it!=prmap.end() )
        {
            rlist.push_back(it->second);
            it++;
        }
    }

    // -------------------
    // Есть особый случай:
    // Допустим, что НЕ приоритетный дизель, до перевода в "автомат"
    // был в ручную запущен. А переключателем "приоритета пуска"
    // выставлен приоритетным другой дизель. То после перевода обоих ДГ
    // в режим "автомат" будет противоречивое состояние:
    // Тот дизель который должен быть основным (и по идее начать автоматически запускаться)
    // не запущен, а тот который должен быть резервным (и должен быть остановлен),
    // оказывается запущенным (уже на шинах).
    // Для решения этого вопроса, здесь реализована следующая логика:
    // Если найденный "потенциальный" лидер, не запущен, то мы смотрим,
    // нет ли среди списка резервных уже запущенного. Если есть, то находим,
    // среди запущенных (резервных), ДГ с наименьшим приоритетом  и делаем его лидером.
    // А нашего "потенциального" лидера (если был до этого найден),
    // переводим в список резервных.
    if( !main || (main && !main->isOnMode()) )
    {
        RList::iterator rit = rlist.end();
        for( RList::iterator it=rlist.begin(); it!=rlist.end(); ++it )
        {
            if( !it->ses->isOnMode() )
                continue;

            long prior = it->ses->getPriority();
            if( rit == rlist.end() || ( prior>0 && prior < rit->ses->getPriority() ))
                rit = it;
        }

        // если нашли среди резервных "запущенный"
        if( rit != rlist.end() )
        {
            if( main )
            {
                // сперва добавляем "бывшего" лидера в список резервных
                ReservInfo ri(main);
                rlist.push_back(ri);
            }

            // запоминаем нового лидера
            main = rit->ses;
            // удаляем его из списка резервных
            rlist.erase(rit);
        }
    }
    
    // -------------------
    if( !main )
    {
        // Если не нашли (явного) приоритетного лидера (например у всех одинаковый приоритет)
        // а список резервных не пустой
        // то берём из резервных с наименьшим номером
        // и делаем его лидером (удалив из списка резервных)
        RList::iterator rit = rlist.end();
        if( !rlist.empty() )
        {
            for( RList::iterator it=rlist.begin(); it!=rlist.end(); ++it )
            {
                long num = it->ses->getNumber();
                if( rit == rlist.end() || num < rit->ses->getNumber() )
                    rit = it;
            }

            if( rit != rlist.end() )
            {
                main = rit->ses;
                rlist.erase(rit);
            }
        }
    }

    // ------------------
    if( main )
    {
        // чтобы сохранить работу внутренних таймеров структуры ReservInfo 
        // надо в новом списке обновить информацию взяв из старого
        for( RList::iterator it=rlst.begin(); it!=rlst.end(); ++it )
            update( rlist, (*it) );

        leader  = main;
        rlst    = rlist;
        if( SEESGroup::dlog.debugging(Debug::LEVEL4) )
        {
            SEESGroup::dlog[Debug::LEVEL4] << myname << "(makeReservList): For leader='ses" << main->getNumber()
            << "' reserv(" << rlist.size() << "): [";
            for( RList::iterator it=rlst.begin(); it!=rlst.end(); ++it )
               SEESGroup::dlog(Debug::LEVEL4) << " ses" << it->ses->getNumber(); // << ")" << it->ses->getName();
            SEESGroup::dlog(Debug::LEVEL4) <<  " ]" << endl;
        }

        // выставляем у всех признак, что они в резерве (не лидеры)
        for( RList::iterator it=rlst.begin(); it!=rlst.end(); ++it )
        {
            try
            {
                it->ses->setLeader(false);
            }
            catch(...){}
        }
        // и выставляем режим у "ведущего"
        leader->setLeader(true);
    }
    else
    {
        SEESGroup::dlog[Debug::LEVEL4] << myname << "(makeReservList): LEADER not found..." << endl;
        leader = 0;
        rlst.clear();
    }
}
void SEESGroup::releaseQG ( int  num) throw (UniSetTypes::NameNotFound)

освобождение приоритета включения генераторного автомата Проверка можно ли запускать указанный СЭС например ограничение по максимльному разрешенному количеству одновременно работющих ДГ на шинах

{
    { // lock
        UniSetTypes::uniset_mutex_lock lock(lstMutex, 4000);
        for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
        {
            SEES* s(*it);
            if( s->getNumber() == num )
            {
                if( s->isHaveQGLock() )
                    SEESGroup::dlog[Debug::INFO] << myname << "(releaseQG): RELEASE QG" << num << endl;

                s->setQGLock(false);
                qf_locked = 0;
                return;
            }
        }
    }

    ostringstream err;
    err <<  myname << "(acceptQG): Not found ses" + num;
    throw NameNotFound(err.str());
}
void SEESGroup::requiredReserv ( bool  set)

выставление признака требуется резерв

Перекрестные ссылки lst.

{
    { // lock
        UniSetTypes::uniset_mutex_lock lock(lstMutex, 3000);
        for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
            (*it)->requiredReserv(set);
    } // unlock
}
void SEESGroup::reserv ( bool  set) [protected]

функция запуска или остановки резерва

Перекрестные ссылки SEES::isProtection(), myname, rlst, SEESGroup::ReservInfo::waitRunning и SEESGroup::ReservInfo::waitStopping.

Используется в checkReserv().

{
    // UniSetTypes::uniset_mutex_lock lock(lstMutex, 5000);
    if( SEESGroup::dlog.debugging(Debug::LEVEL4) )
    {
        SEESGroup::dlog[Debug::LEVEL4] << myname << "(reserv):"
                    << " set=" << set
                    << " rlist=" << rlst.size() << endl;
    }
    
    if( rlst.empty() )
    {
        SEESGroup::dlog[Debug::LEVEL4] << myname
            << "(reserv): rlst=0 RESERV NOT FOUND" << endl;
        
        ptCheckReserv.setTiming(UniSetTimer::WaitUpTime);
        return;
    }

    // Проходим по списку резервных 
    // и ищем кто готов запускатся..
    // Т.к. список выстроен в соответсвии с приоритетом
    // то можно остановиться на первом подходящем
    
    // Если нам нужно запускать ищем в прямом порядке,
    // если останавливать, то в обратном.
    typedef list<ReservInfo*> TMPList;
    TMPList tmplist;
    if( set )
    {
        for( RList::iterator it=rlst.begin(); it!=rlst.end(); ++it )
            tmplist.push_back( &(*it) );
    }
    else
    {
        for( RList::iterator it=rlst.begin(); it!=rlst.end(); ++it )
            tmplist.push_front( &(*it) );
    }

    ReservInfo* rses = 0;
    for( TMPList::iterator it=tmplist.begin(); it!=tmplist.end(); ++it )
    {
        ReservInfo* ri(*it);
        // Ловим момент, если резервный только что, запустился/остановился 
        // и засекаем таймер на "паузу"
        // необходимую для прихода системы в устойчивое состояние
        // после пуска/остановки резерва 
        // (например распределение нагрузки и т.п.)
        // а то может начать запускатся следующий резервный
        // если распределитель ещё не успел "поработать"
        // и основной(leader) остался загружен
        // несмотря на то, что уже запустился резервный
        if( set && ri->trChangeState.hi(ri->ses->getOMode()==mON) )
        {
            ri->ptPause.setTiming(reservStatePause);
            ri->waitRunning = false;
            ri->waitStopping = false;
        }
        else if( !set && ri->trChangeState.hi(ri->ses->getOMode()==mOFF) )
        {
            ri->ptPause.setTiming(reservStatePause);
            ri->waitRunning = false;
            ri->waitStopping = false;
        }

        // ничего не делаем, пока резервный ses исполняет команду
        // либо он её выполнит, либо timeout, либо у него сработает защита
        if( (set && ri->waitRunning) || (!set && ri->waitStopping) )
        {
            if( !ri->ptPause.checkTime() && !ri->ses->isProtection() )
            {
                if( SEESGroup::dlog.debugging(Debug::LEVEL4) )
                {
                    int wmsec = ri->ptPause.getInterval() - ri->ptPause.getCurrent();
                    SEESGroup::dlog[Debug::LEVEL4] << myname << "(reserv):"
                        << " IGNORE. Wait processing command for ses" 
                        << ri->ses->getNumber()
                        << " (sec=" << wmsec/1000 << " msec=" << wmsec%1000 << ")"
                        << endl;
                }
                ptCheckReserv.setTiming(checkReservTime);
                return;
            }

            ri->waitRunning = false;
            ri->waitStopping = false;
            ri->ptPause.setTiming(0);
        }

        // Если пауза ещё не прошла, ждём...
        // либо признак нужности/ненужности резерва
        // снимется у leader, либо мы начнём 
        // запускатся/останавливать следующий в списке
        if( !ri->ptPause.checkTime() && !ri->waitRunning && !ri->waitStopping )
        {
            if( SEESGroup::dlog.debugging(Debug::LEVEL4) )
            {
                int wmsec = ri->ptPause.getInterval() - ri->ptPause.getCurrent();
                SEESGroup::dlog[Debug::LEVEL4] << myname << "(reserv):"
                    << " IGNORE. Wait state pause for ses" 
                    << ri->ses->getNumber()
                    << " (sec=" << wmsec/1000 << " msec=" << wmsec%1000 << ")"
                    << endl;
            }
            ptCheckReserv.setTiming(checkReservTime);
            return;
        }

        // Эти условия должны проверятся ОБЯЗАТЕЛЬНО после ptStatePause
        // т.к. canReservRunning или canReservStopping вернут false
        // как только, резерв запустится/остановится.
        // а нам ведь надо ещё и паузу выждать,
        // прежде чем пытатся запускать/останавливать
        // следующий резервный в списке..
        if( set && !ri->ses->canReservRunning() ) // требуется запуск, а не может
            continue;
        
        if( !set && !ri->ses->canReservStopping() ) // требуется остановка, а не может
            continue;

        rses = ri; 
        break;
    }

    if( !rses )
    {
        SEESGroup::dlog[Debug::LEVEL4] << myname << "(reserv):"
            << " FREE RESERV NOT FOUND" << endl;
        ptCheckReserv.setTiming(UniSetTimer::WaitUpTime);
        return;
    }

    if( set )
    {
        if( SEESGroup::dlog.debugging(Debug::LEVEL4) )
        {
            SEESGroup::dlog[Debug::LEVEL4] << myname << "(reserv):"
                << " SELECT RUN ses" << rses->ses->getNumber() << endl;
        }
        rses->ses->onReservCommand();
        rses->waitRunning = true;
        rses->waitStopping = false;
    }
    else
    {
        if( SEESGroup::dlog.debugging(Debug::LEVEL4) )
        {
            SEESGroup::dlog[Debug::LEVEL4] << myname << "(reserv):"
                << " SELECT STOP ses" << rses->ses->getNumber() << endl;
        }
        rses->ses->offReservCommand();
        rses->waitRunning = false;
        rses->waitStopping = true;
    }

    ptCheckReserv.setTiming(checkReservTime);
    rses->trChangeState.hi(false);
    rses->ptPause.setTiming(reservCommandTimeout);
}
bool SEESGroup::resetReserv ( ) [protected]

сброс команд управления резерва

Перекрестные ссылки lst, myname и rlst.

Используется в checkReserv().

{
//  SEESGroup::dlog[Debug::LEVEL4] << myname << "(resetReserv): ..." << endl;
    for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
    {
        // если есть хоть один СЭС требущий резерв,
        // то сбрасывать команды нельзя...
        if( (*it)->isReservOnNeeded() || (*it)->isReservOffNeeded() )
            return false;
    }

    // сбрасываем команды
    for( RList::iterator it=rlst.begin(); it!=rlst.end(); ++it )
    {
        SEESGroup::dlog[Debug::LEVEL4] << myname << "(resetReserv): сбрасываем команды резерва для ses" << it->ses->getNumber() << endl;
        it->ses->resetReservCommand();
    }

    return true;
}
void SEESGroup::update ( RList &  rlist,
ReservInfo ri 
) [static, protected]

функция копирующая в список rlst, информацию из ri, если там есть такой ДГ

{
    //UniSetTypes::uniset_mutex_lock lock(lstMutex, 5000);
    for( RList::iterator it=rlist.begin(); it!=rlist.end(); ++it )
    {
        if( it->ses->getNumber() == ri.ses->getNumber() )
        {
            (*it) = ri;
            return;
        }
    }  
}
void SEESGroup::updateCounters ( ) [protected]

Обновление различных счётчиков

Перекрестные ссылки countWorkingDG и lst.

{
    int count = 0;
    { // lock
        UniSetTypes::uniset_mutex_lock lock(lstMutex, 4000);
        for( SESList::iterator it=lst.begin(); it!=lst.end(); ++it )
        {
            if( (*it)->isOnMode() )
                count++;
        }
    }

    // Обновляем информацию о текущем количестве работающих ДГ
    {
        uniset_mutex_lock l(maxrunMutex,200);
        countWorkingDG = count;
    }
}
void SEESGroup::updatePowerInfo ( )

Обновление расчётных параметров сети

Перекрестные ссылки getF(), getU(), sc_Fdev и sc_Udev.

{
    bool u_res = false;
    // Фомирование сигнала по отклонению напряжения
    if( U_min > 0 )
    {
        long u = getU();
        if( u > 0 )
        {
            if( u < U_min || u > U_max  )
                u_res = true;
        }
    }

    // устанавливаем (или отключаем) таймер
    sc_Udev.rotate(u_res);

    bool f_res = false;
    // Фомирование сигнала по отклонению напряжения
    if( f_min > 0 )
    {
        long f = getF();
        if( f > 0 )
        {
            if( f < f_min || f > f_max  )
                f_res = true;
        }
    }

    // устанавливаем (или отключаем) таймер
    sc_Fdev.rotate(f_res);
}

Данные класса

int SEESGroup::countWorkingDG [protected]

текущее количество работающих ДГ

Используется в updateCounters().

bool SEESGroup::f_dev [protected]

флаг отклонение частоты от нормы

Используется в isFdev().

int SEESGroup::gnum [protected]

номер данной группы

SEES* SEESGroup::leader [protected]

указатель на "ведущий" ДГ в группе

Используется в checkReserv() и makeReservList().

SESList SEESGroup::lst [protected]

номер СЭС заблокировавшей включение автомата список СЭС в группе

Используется в checkAloneWorking(), getF(), getP(), getReservPower(), getU(), isProtection(), isReadyForLoading(), makeReservList(), requiredReserv(), resetReserv() и updateCounters().

int SEESGroup::maxWorkingDG [protected]

максимальное разрешённое количество одновременно работающих ДГ

std::string SEESGroup::myname [protected]

исключительно для логов

Используется в checkReserv(), makeReservList(), reserv() и resetReserv().

RList SEESGroup::rlst [protected]

список доступных резервных ДГ

Используется в checkReserv(), makeReservList(), reserv() и resetReserv().

SandClock SEESGroup::sc_Fdev [protected]

специальная задержка на срабатывание по сигналу "отклонение частоты"

Используется в updatePowerInfo().

SandClock SEESGroup::sc_Udev [protected]

специальная задержка на срабатывание по сигналу "отклонение напряжения"

Используется в updatePowerInfo().

bool SEESGroup::U_dev [protected]

флаг отклонение напряжения от нормы

Используется в isUdev().


Объявления и описания членов классов находятся в файлах: