• 温控PID自测验程序


    #pragma once
    #ifndef _PID_H_
    #define _PID_H_
    #include <vector> 
    #include <map>
    using namespace std;
    
    struct kpid { float kp, ki, kd; long i; };
    struct eval
    {
        float minrate;
        float maxrate;
        float avgrate;
        float avgcalc;
        float maxhold;
        float minhold;
        float avghold;
        float varhold;
        float countif;//平稳时间
        float gradual;
    };
    struct score { kpid pid; eval _eval[2]; };
    typedef vector<score> scoretable;
    typedef vector<scoretable> favortable; 
    class cmd
    {
    public:
        virtual void setpid(const kpid& k)const {
            printf("-------------------------cmdpid:%.2f,%.2f,%.2f
    ", k.kp, k.ki, k.kd);
        }
        virtual void settarget(float t)const{
            printf("-------------------------cmdtarget:%.2f
    ",t);
        }
        virtual void report(const scoretable& table)const
        {
            FILE* file;
            if (0 == fopen_s(&file, "pid.table.txt", "a"))
            { 
                for (scoretable::const_iterator it = table.begin(); it != table.end(); ++it)
                {
                    const score& score = *it;
                    output(score, file);
                }
            }
            fclose(file);
        }
        virtual void report(const favortable& table)const
        { 
            printf("*************************print
    ");
            FILE* file;
            if (0 == fopen_s(&file, "pid.score.txt", "a"))
            {
                favortable::const_iterator it = table.begin();
                for (; it != table.end(); ++it)
                {
                    const scoretable& table = *it; 
                    for (scoretable::const_iterator it = table.begin(); it != table.end(); ++it)
                    {
                        const score& score = *it;
                        output(score, file);
                    }
                    fprintf_s(file, "
    ");
                } 
            }
            fclose(file);
        }
        virtual void trace(const score& score)const
        {
            FILE* file;
            if (0 == fopen_s(&file, "pid.trace.txt", "a"))
            {
                output(score, file);
            }
            fclose(file);
        }
    private:
        void output(const score& score ,FILE* file)const
        {
            fprintf_s(file, "PID %5.2f %5.2f %5.2f : ", score.pid.kp, score.pid.ki, score.pid.kd);
            for (int i = 0; i < 2; ++i) {
                fprintf_s(file, "[%c] avg:%.2f/%.2f min:%.2f max:%.2f T:%.2f  [T:%.2f (%.2f ~ %.2f) avg:%.2f]."
                    , "+-"[i] 
                    , score._eval[i].avgrate
                    , score._eval[i].avgcalc
                    , score._eval[i].minrate
                    , score._eval[i].maxrate
                    , score._eval[i].gradual
                    , score._eval[i].countif
                    , score._eval[i].minhold
                    , score._eval[i].maxhold
                    , score._eval[i].avghold);
            }
            fprintf_s(file, "
    ");
        }
    };
    class pid
    {   
        template<class T ,class H>
        struct Template{     
            T val;
            vector<H*> list[2];
            ~Template() {  
                for (int i = 0; i < 2; ++i)
                    for (; !list[i].empty(); list[i].pop_back())
                        delete list[i].back();
            }
        };
        enum tendecy { eupper = 0, elower = 1, efirst,equiet,etail,eidle};
        struct data { float targetvalue; enum tendecy tendecy;  int duration; };
        struct temp { float temperature, interval; 
        temp(float t,float i):temperature(t),interval(i){}
        }; 
        typedef Template<data, temp> segment;
        typedef Template<kpid, segment> piddata;
        typedef vector<piddata *> pidsort;
    public: 
        class policy
        { 
        public:
            policy(const kpid pid = { 1.0,0.0,0.0,0})
                : _target{ 95,50,95,50,95,50 }
                , _pid(pid),i(0),k(0)
                , entry(3)
            {}
            virtual const kpid& trimpid(const favortable&);
            virtual float target()const;
            virtual bool segment();
            virtual bool oncepid();
            virtual int count() { return 20; }
        protected:
            kpid _pid;
            float _target[6];
            unsigned int i,k;
            map<float, int> _score;
            const int entry;
        };
    public:
        explicit pid(cmd*);
        virtual ~pid();
        void apply(policy*);
        void init(); 
        void fini();  
        void input(float temperature, float interval); 
    private:
        void sort();
        void score(); 
        void eval(const segment * _segment,struct eval&);
        
        void incr(temp *);
        void quiet(temp *);
        void decr(temp *);
        void first(float t);
        void tail(); 
        void stage();
        void ctrl();  
        void newpid(const kpid&);
        void newtarget(float target);
        void endtarget();
        void endpid();
        void newapply();
        void endapply(); 
    private: 
        segment * _segment;
        piddata * _piddata;
        pidsort * _pidsort;
    private:
        enum tendecy _state;
    private: 
        scoretable _scoretable;
        favortable _favortable;
        cmd* _cmd;
        policy* _policy;
        vector<policy*> _policylist;
    };
    #endif
    
    
    
    #include "pid.h"
    #include <assert.h>
    #include <algorithm>
    #include <limits>
     
    class defaultpolicy :public pid::policy
    {
    public:
        const kpid& trimpid(const favortable& t)
        {
            switch (k)
            {
            case 0:
                if (_pid.kp < 2.0f)
                {
                    _pid.kp += 0.01;
                    break;
                }
                else 
                {
                    _pid.i = k = 1;
                } 
            case 1:
                if (_pid.ki < 1.2f)
                {
                    _pid.ki += 0.001;
                    break;
                }
                else
                {
                    _pid.i = k = 2;
                } 
            case 2:
                if (_pid.kd < 1.2f)
                {
                    _pid.kd += 0.001;
                    break;
                }
                else
                {
                    _pid.i = k = 3;
                } 
            default:
                break;
            }  
            return _pid;
        }
    };
    const kpid& pid::policy::trimpid(const favortable& t)
    {
        if ( k < t.size())
        {
            const scoretable& _table = t[k];  
    
            struct kpid pid;
            struct eval val = {0};
            if (!_table.empty())
            {
                pid = _table[0].pid;
                val = _table[0]._eval[0];
            }
            else
                pid = _pid;
            switch (k)
            {
            case 0: 
                _pid.kp += pid.kp >= _pid.kp ? +0.005f : -0.005f;  
                if (++_score[_pid.kp] > entry)
                {
                    _pid.i = k = 1;
                    _score.clear();
                }
                if (val.gradual < 50)
                {
                    break;
                } 
            case 1:
                _pid.ki += pid.ki >= _pid.ki ? +0.001f : -0.001f; 
                if (++_score[_pid.ki] > entry)
                {
                    _pid.i = k = 2;
                    _score.clear();
                }
            break;
            case 2:
                _pid.kd += pid.kd >= _pid.kd ? +0.001f : -0.001f; 
                if (++_score[_pid.kd] > entry)
                {
                    _pid.i = k = 3;
                    _score.clear();
                }
            break;
            default:
                break;
            }
        } 
        return _pid;
    }
    bool pid::policy::oncepid()
    {
        return k < 3;
    }
    float pid::policy::target()const
    {  
        return _target[i% _countof(_target)];
    }
    bool pid::policy::segment()
    {
        return 0 == (++i % _countof(_target));
    }
    
    pid::pid(cmd* c) 
        : _state(eidle)
        , _cmd(c)
        , _policy(new defaultpolicy())
    { 
        assert(c);
        apply(_policy);
    }
    void pid::apply(policy* p)
    {
        _policylist.push_back(p);
        _policy = p;
    }
    void pid::init()
    {  
        _favortable.resize(3);
        _pidsort = new pidsort();
        newpid(_policy->trimpid(_favortable));
        newtarget(_policy->target());
    }
    void pid::fini()
    {
        endtarget();
        endpid();
        score();
        sort();
        _cmd->trace(_scoretable.back()); 
        std::sort(_scoretable.begin(), _scoretable.end(),[](auto a, auto b){return a._eval[0].avgrate > b._eval[0].avgrate; });
        _cmd->report(_scoretable);
        _cmd->report(_favortable); 
        _favortable.clear(); 
        while (!_pidsort->empty())
        {
            delete _pidsort->back();
            _pidsort->pop_back();
        } 
        delete _pidsort;
        while (!_policylist.empty())
        {
            delete _policylist.back();
            _policylist.pop_back();
        } 
    }
    pid::~pid()
    { 
        delete _cmd; 
    }
    void pid::newapply()
    {
        _policy = _policylist.back();
    }
    void pid::endapply()
    { 
        std::rotate(_policylist.begin(), _policylist.begin() + 1, _policylist.end());
    }
    void pid::newpid(const kpid& k)
    {
        _cmd->setpid(k);
        _piddata = new piddata();
        _piddata->val = k;
    }
    void pid::newtarget(float target)
    {
        _cmd->settarget(target);
        _segment = new segment();
        _segment->val.targetvalue = target;
        _state = efirst;
    } 
    void pid::ctrl()
    {
        endtarget(); 
        if (_policy->segment())
        {
            endpid();
            score();
            sort(); 
            _cmd->trace(_scoretable.back());
            if (_policy->oncepid())
            {
                endapply();
                newapply();
            }  
            newpid(_policy->trimpid(_favortable));
        }
        newtarget(_policy->target()); 
    }
    void pid::stage()
    {
        _segment->val.duration = 0; 
        _state = equiet;
    }
    void pid::quiet(temp * t)
    {
        _segment->list[1].push_back(t);
        _segment->val.duration++; 
    }
    void pid::incr(temp * t)
    {
        _segment->list[0].push_back(t);
    }
    void pid::decr(temp * t)
    {
        _segment->list[0].push_back(t);
    }
    void pid::endpid()
    {
        _pidsort->push_back(_piddata);
    }
    void pid::endtarget()
    {
        _piddata->list[_segment->val.tendecy].push_back(_segment);
    }
    void pid::first(float t)
    {
        _state = _segment->val.targetvalue > t ? eupper : elower;
        _segment->val.tendecy = _state;
    }
    void pid::tail()
    { 
        _state = etail;
    } 
    void pid::input(float t, float i)
    {
        assert(_segment); 
        for(;;)
            switch (_state)
            { 
            case efirst:
                first(t);
                break;
            case eupper:
                incr(new temp(t,i));
                if (_segment->val.targetvalue < t)
                { 
                    stage();
                    break;
                } 
                return;
            case elower:
                decr(new temp(t, i));
                if (_segment->val.targetvalue > t)
                { 
                    stage();
                    break;
                } 
                return;
            case equiet:
                quiet(new temp(t, i));
                if (_segment->val.duration > _policy->count())
                {
                    tail();
                    break;
                } 
                return;
            case etail: 
                ctrl();
                return;
            case eidle: 
                return;
            }
    }
    void pid::eval(const segment * _segment, struct eval& _eval)
    {
        int i;
        auto v = _segment->list;
        switch (_segment->val.tendecy)
        {
        case eupper:
        case elower:
            struct cnt
            {
                cnt(float t, float& q, bool b = true)
                    : target(t)
                    , quiet(q)
                    , cmpval(b)
                {
                    quiet = 0.f;
                }
                bool operator()(const struct temp* a)
                {
                    bool b = a->temperature > target + 0.5
                        || a->temperature < target - 0.5;
                    if (cmpval == b)
                    {
                        quiet += a->interval;
                        return true;
                    }
                    else
                        return false;
                }
                float &quiet;
                float target;
                bool cmpval;
            };
            i = 0;
            if (!v[i].empty())
            {
                _eval.minrate = FLT_MAX;
                _eval.maxrate = FLT_MIN;
                _eval.avgrate = .0f;
                auto it = v[i].begin();
                float _t = (*it)->temperature;
                while (++it != v[i].end())
                {
                    float r = ((*it)->temperature - _t) / (*it)->interval;
                    _t = (*it)->temperature;
                    if (r > _eval.maxrate)
                        _eval.maxrate = r;
                    if (r < _eval.minrate)
                        _eval.minrate = r;
                    _eval.avgrate += r;
                } 
                _eval.avgrate /= v[i].size();
                std::count_if(v[i].begin(), v[i].end(), cnt(_segment->val.targetvalue, _eval.gradual, false));
                /**/
                float cost = 0.f;
                it = v[i].begin();
                while (++it != v[i].end())
                    cost += (*it)->interval; 
                _eval.avgcalc = (v[i].back()->temperature - v[i].front()->temperature) / cost;
            }
            i = 1;
            if (!v[i].empty())
            {
                struct cmp {
                    bool operator()(const struct temp* a, const struct temp* b) {
                        return a->temperature > b->temperature;
                    }
                };
                auto it = v[i].begin();
                auto minmax = std::minmax_element(it + 1, v[i].end(), cmp());
                _eval.maxhold = (*minmax.first)->temperature - _segment->val.targetvalue;
                _eval.minhold = (*minmax.second)->temperature - _segment->val.targetvalue;
                std::count_if(v[i].begin(), v[i].end(), cnt(_segment->val.targetvalue, _eval.countif, true));
                /**/
                float temp = 0.f;
                for (; it != v[i].end(); ++it)
                    temp +=abs((*it)->temperature - _segment->val.targetvalue);
                _eval.avghold = temp / v[i].size(); 
                _eval.varhold = 0.f;
            }
            break;
        }
    }
    void pid::score()
    {
        struct score _score;
        struct eval _eval;
        _score.pid = _piddata->val;
        for (int i = 0; i < 2; ++i)
        {
            _score._eval[i].maxrate = FLT_MIN;
            _score._eval[i].minrate = FLT_MAX;
            _score._eval[i].gradual = FLT_MIN;
            _score._eval[i].maxhold = FLT_MIN;
            _score._eval[i].minhold = FLT_MAX;
            _score._eval[i].varhold = FLT_MIN;
            _score._eval[i].countif = FLT_MIN;
            _score._eval[i].avghold = 0.f;
            _score._eval[i].avgcalc = 0.f;
            _score._eval[i].avgrate = 0.f;
            for (int j = 0; j < _piddata->list[i].size(); ++j)
            {
                eval(_piddata->list[i][j], _eval);
    
                if (_eval.maxrate > _score._eval[i].maxrate)
                    _score._eval[i].maxrate = _eval.maxrate;
                if (_eval.minrate < _score._eval[i].minrate)
                    _score._eval[i].minrate = _eval.minrate; 
                if (_eval.gradual > _score._eval[i].gradual)
                    _score._eval[i].gradual = _eval.gradual;
    
                if (_eval.maxhold > _score._eval[i].maxhold)
                    _score._eval[i].maxhold = _eval.maxhold; 
                if (_eval.minhold < _score._eval[i].minhold)
                    _score._eval[i].minhold = _eval.minhold; 
                
                if (_eval.varhold > _score._eval[i].varhold)
                    _score._eval[i].varhold = _eval.varhold;
                if (_eval.countif > _score._eval[i].countif)
                    _score._eval[i].countif = _eval.countif;
    
                _score._eval[i].avgrate += _eval.avgrate;
                _score._eval[i].avgcalc += _eval.avgcalc;
    
                _score._eval[i].avghold += _eval.avghold;
            }
            _score._eval[i].avgcalc /= _piddata->list[i].size();
            _score._eval[i].avgrate /= _piddata->list[i].size();
            _score._eval[i].avghold /= _piddata->list[i].size();
        }
        _scoretable.push_back(_score);
    }
    void pid::sort()
    {
        struct cmp 
        {
            cmp(int t=0) {}
            bool operator()(const struct score& a, const struct score& b) const 
            {
                switch (t)
                {
                case 0:
                    return a._eval[0].avgrate > b._eval[0].avgrate;
                case 1:
                    return (a._eval[0].maxhold - a._eval[0].minhold) > (b._eval[0].maxhold - b._eval[0].minhold);
                case 2:
                    return (a._eval[0].maxrate - a._eval[0].minrate) < (b._eval[0].maxrate - b._eval[0].minrate);
                default:
                    return a._eval[0].maxrate > b._eval[0].maxrate;
                }
            }
            int t;
        };  
        int topnum = _scoretable.end() - _scoretable.begin();
        topnum = min(topnum, 9);
        for (size_t i = 0; i < _favortable.size(); ++i)
        { 
            _favortable[i].resize(topnum);
            std::partial_sort_copy(_scoretable.begin(), _scoretable.end()
                , _favortable[i].begin(), _favortable[i].end(), cmp(i));
        }
    }
  • 相关阅读:
    17、springcloud整合lettuce使用redis
    16、springcloud整合Swagger2构建Restful服务的APIs
    15、Feign整合断路器监控Hystrix Dashboard
    14、Ribbon整合断路器监控Hystrix Dashboard
    13、如何使用断路器监控Hystrix Dashboard
    12、Feign整合断路器Hystrix
    wince中对ini文件的操作
    winform应用程序更新 带进度条
    wince隐藏任务栏
    一文学会JVM性能优化
  • 原文地址:https://www.cnblogs.com/xuyouzhu/p/10829847.html
Copyright © 2020-2023  润新知