如何在 C++ 中实现传递函数的控制系统块?

发布于 2024-10-09 19:56:18 字数 564 浏览 0 评论 0原文

我想定义一个控制系统块,如下所示:

class ControlSystemBlock
{
 public:
  ControlSystemBlock()
  {
   m_dbTimeStep = 0.001; // time between two consequential inputs
  }

  // this method can be called anytime,
  // but the object will assume
  // that it was called
  // after m_dbTimeStep before the last call
  void LoadNewInput(double dbInputValue);

  double GetCurrentOutput();
  // ...
 private:
  double m_dbTimeStep;
  // ...
};

系统将接收输入,并根据这些输入和用户定义的传递函数,其输出值将及时改变。

例如,假设我想实现传递函数 H(s) = 1 / (s + 2)。我该怎么做?有什么算法吗?

I want to define a control system block like:

class ControlSystemBlock
{
 public:
  ControlSystemBlock()
  {
   m_dbTimeStep = 0.001; // time between two consequential inputs
  }

  // this method can be called anytime,
  // but the object will assume
  // that it was called
  // after m_dbTimeStep before the last call
  void LoadNewInput(double dbInputValue);

  double GetCurrentOutput();
  // ...
 private:
  double m_dbTimeStep;
  // ...
};

The system will receive inputs, and according to these inputs and user defined transfer-function in it, its output value will change in time.

For instance, assume that I want to implement the transfer function H(s) = 1 / (s + 2). How do I do it? Is there any algorithm for that?

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

一枫情书 2024-10-16 19:56:18

你觉得我的代码怎么样:

ControlSystemBlock.h

#ifndef CONTROLSYSTEMBLOCK_H
#define CONTROLSYSTEMBLOCK_H

#include <vector>
#include <deque>
#include "Polynomial.h"
#include "PolynomialFraction.h"

class ControlSystemBlock
{
    public:
        enum SIGNAL_TYPE
        {
            ST_DISCRETE     = 1,
            ST_CONTINUOUS   = 2
        };

        ControlSystemBlock( long double dbSamplingPeriod = 0.001);
        ControlSystemBlock( const std::vector<long double> & NominatorCoefficients,
                            const std::vector<long double> & DenominatorCoefficients,
                            SIGNAL_TYPE SignalType = SIGNAL_TYPE::ST_CONTINUOUS,
                            long double dbSamplingPeriod = 0.001);
        ControlSystemBlock( const Polynomial<long double> & NominatorPolynomial,
                            const Polynomial<long double> & DenominatorPolynomial,
                            SIGNAL_TYPE SignalType = SIGNAL_TYPE::ST_CONTINUOUS,
                            long double dbSamplingPeriod = 0.001);
        ControlSystemBlock( const PolynomialFraction<long double> & TransferFunction,
                            SIGNAL_TYPE SignalType = SIGNAL_TYPE::ST_CONTINUOUS,
                            long double dbSamplingPeriod = 0.001);

        // Sends a new input to the system block
        // Assuming that this input is sent just after m_dbSamplingPeriod seconds after the last input
        // Returns the the new output value
        long double SendInput(long double dbInput);
        long double GetOutput() const;

    protected:
        long double m_dbSamplingPeriod;
        std::deque<long double> m_InputMemory;
        std::deque<long double> m_OutputMemory;
        void SetTransferFunction(const PolynomialFraction<long double> & TransferFunction, SIGNAL_TYPE SignalType);
        PolynomialFraction<long double> m_TransferFunction;

    private:
        PolynomialFraction<long double> ContinuousTimeToDiscreteTime(const PolynomialFraction<long double> & ContinuousTimeTransferFunction);
        PolynomialFraction<long double> ContinuousTimeToDiscreteTime(const Polynomial<long double> & NominatorPolynomial,
                                                                     const Polynomial<long double> & DenominatorPolynomial);
        PolynomialFraction<long double> ContinuousTimeToDiscreteTime(const std::vector<long double> & NominatorCoefficients,
                                                                     const std::vector<long double> & DenominatorCoefficients);
        void ShiftMemoryRegisters(long double dbNewInput);
};

#endif

ControlSystemBlock.cpp

#include "ControlSystemBlock.h"

ControlSystemBlock::ControlSystemBlock( long double dbSamplingPeriod /*= 0.001*/)
{
    m_dbSamplingPeriod = dbSamplingPeriod;
    std::vector<long double> Coefficients;
    Coefficients.push_back(1.0);
    PolynomialFraction<long double> TransferFunction(Coefficients, Coefficients);
    SetTransferFunction(TransferFunction, SIGNAL_TYPE::ST_DISCRETE);
}

ControlSystemBlock::ControlSystemBlock( const std::vector<long double> & NominatorCoefficients,
                                        const std::vector<long double> & DenominatorCoefficients,
                                        SIGNAL_TYPE SignalType /*= SIGNAL_TYPE::ST_CONTINUOUS*/,
                                        long double dbSamplingPeriod /*= 0.001*/)
{
    m_dbSamplingPeriod = dbSamplingPeriod;
    PolynomialFraction<long double> TransferFunction = PolynomialFraction<long double>(NominatorCoefficients, DenominatorCoefficients);
    SetTransferFunction(TransferFunction, SignalType);
}

ControlSystemBlock::ControlSystemBlock( const Polynomial<long double> & NominatorPolynomial,
                                        const Polynomial<long double> & DenominatorPolynomial,
                                        SIGNAL_TYPE SignalType /*= SIGNAL_TYPE::ST_CONTINUOUS*/,
                                        long double dbSamplingPeriod /*= 0.001*/ )
{
    m_dbSamplingPeriod = dbSamplingPeriod;
    PolynomialFraction<long double> TransferFunction = PolynomialFraction<long double>(NominatorPolynomial, DenominatorPolynomial);
    SetTransferFunction(TransferFunction, SignalType);
}

ControlSystemBlock::ControlSystemBlock( const PolynomialFraction<long double> & TransferFunction,
                                        ControlSystemBlock::SIGNAL_TYPE SignalType /*= SIGNAL_TYPE::ST_CONTINUOUS*/,
                                        long double dbSamplingPeriod /*= 0.001*/)
{
    m_dbSamplingPeriod = dbSamplingPeriod;
    if (SignalType == SIGNAL_TYPE::ST_CONTINUOUS)
    SetTransferFunction(TransferFunction, SignalType);
}

long double ControlSystemBlock::SendInput(long double dbInput)
{
    ShiftMemoryRegisters(dbInput);
    long double dbSumX = 0.0, dbSumY = 0.0;
    for (uint64_t i=0; i<m_TransferFunction.GetNominatorDegree()+1; i++)
    {
        dbSumX += m_TransferFunction.GetNominator().GetCoefficientAt(i) * m_InputMemory.at(i);
    }
    for (uint64_t i=1; i<m_TransferFunction.GetDenominatorDegree()+1; i++)
    {
        dbSumY += m_TransferFunction.GetDenominator().GetCoefficientAt(i) * m_OutputMemory.at(i);
    }
    return m_OutputMemory.at(0) = (dbSumX - dbSumY) / m_TransferFunction.GetDenominator().GetCoefficientAt(0);
}

long double ControlSystemBlock::GetOutput() const
{
    return m_OutputMemory.at(0);
}

PolynomialFraction<long double> ControlSystemBlock::ContinuousTimeToDiscreteTime(const PolynomialFraction<long double> & ContinuousTimeTransferFunction)
{
    // Generate an "s" term in terms of "z^(-1)" terms
    std::vector<long double> nom, den;
    nom.push_back(1);
    nom.push_back(-1);
    den.push_back(1);
    den.push_back(1);
    PolynomialFraction<long double> STerm(nom, den);
    STerm *= static_cast<long double>(2) / m_dbSamplingPeriod;
    // Define nominator and denominator terms of the discrete time transfer function separately
    nom.clear();
    den.clear();
    nom.push_back(0);
    nom.push_back(1);
    PolynomialFraction<long double> NominatorOfDiscreteTimeTransferFunction(nom, den);
    PolynomialFraction<long double> DenominatorOfDiscreteTimeTransferFunction(nom, den);
    // Generate the nominator and denominator terms of the resulting discrete time transfer function
    for (uint64_t i=0; i<ContinuousTimeTransferFunction.GetNominatorDegree()+1; i++)
    {
        NominatorOfDiscreteTimeTransferFunction += STerm.GetPower(i) * ContinuousTimeTransferFunction.GetNominator().GetCoefficientAt(i);
    }
    for (uint64_t i=0; i<ContinuousTimeTransferFunction.GetDenominatorDegree()+1; i++)
    {
        NominatorOfDiscreteTimeTransferFunction += STerm.GetPower(i) * ContinuousTimeTransferFunction.GetDenominator().GetCoefficientAt(i);
    }
    return NominatorOfDiscreteTimeTransferFunction / DenominatorOfDiscreteTimeTransferFunction;
}

PolynomialFraction<long double> ControlSystemBlock::ContinuousTimeToDiscreteTime(const Polynomial<long double> & NominatorPolynomial,
                                                                                 const Polynomial<long double> & DenominatorPolynomial)
{
    PolynomialFraction<long double> ContinuousTimeTransferFunction(NominatorPolynomial, DenominatorPolynomial);
    return ContinuousTimeToDiscreteTime(ContinuousTimeTransferFunction);
}

PolynomialFraction<long double> ControlSystemBlock::ContinuousTimeToDiscreteTime(const std::vector<long double> & NominatorCoefficients,
                                                                                 const std::vector<long double> & DenominatorCoefficients)
{
    PolynomialFraction<long double> ContinuousTimeTransferFunction(NominatorCoefficients, DenominatorCoefficients);
    return ContinuousTimeToDiscreteTime(ContinuousTimeTransferFunction);
}

void ControlSystemBlock::SetTransferFunction( const PolynomialFraction<long double> & TransferFunction, SIGNAL_TYPE SignalType)
{
    if (SignalType == SIGNAL_TYPE::ST_CONTINUOUS)
    {
        m_TransferFunction = ContinuousTimeToDiscreteTime(TransferFunction);
    }
    else
    {
        m_TransferFunction = TransferFunction;
    }
    m_InputMemory.resize(m_TransferFunction.GetNominatorDegree() + 1, 0.0);
    m_OutputMemory.resize(m_TransferFunction.GetDenominatorDegree() + 1, 0.0);
}

void ControlSystemBlock::ShiftMemoryRegisters(long double dbNewInput)
{
    m_InputMemory.push_back(dbNewInput);
    m_InputMemory.pop_front();
    m_OutputMemory.push_back(0.0);
    m_OutputMemory.pop_front();
}

我刚刚完成它。
我很快就会测试一下。

What do you think of my code:

ControlSystemBlock.h

#ifndef CONTROLSYSTEMBLOCK_H
#define CONTROLSYSTEMBLOCK_H

#include <vector>
#include <deque>
#include "Polynomial.h"
#include "PolynomialFraction.h"

class ControlSystemBlock
{
    public:
        enum SIGNAL_TYPE
        {
            ST_DISCRETE     = 1,
            ST_CONTINUOUS   = 2
        };

        ControlSystemBlock( long double dbSamplingPeriod = 0.001);
        ControlSystemBlock( const std::vector<long double> & NominatorCoefficients,
                            const std::vector<long double> & DenominatorCoefficients,
                            SIGNAL_TYPE SignalType = SIGNAL_TYPE::ST_CONTINUOUS,
                            long double dbSamplingPeriod = 0.001);
        ControlSystemBlock( const Polynomial<long double> & NominatorPolynomial,
                            const Polynomial<long double> & DenominatorPolynomial,
                            SIGNAL_TYPE SignalType = SIGNAL_TYPE::ST_CONTINUOUS,
                            long double dbSamplingPeriod = 0.001);
        ControlSystemBlock( const PolynomialFraction<long double> & TransferFunction,
                            SIGNAL_TYPE SignalType = SIGNAL_TYPE::ST_CONTINUOUS,
                            long double dbSamplingPeriod = 0.001);

        // Sends a new input to the system block
        // Assuming that this input is sent just after m_dbSamplingPeriod seconds after the last input
        // Returns the the new output value
        long double SendInput(long double dbInput);
        long double GetOutput() const;

    protected:
        long double m_dbSamplingPeriod;
        std::deque<long double> m_InputMemory;
        std::deque<long double> m_OutputMemory;
        void SetTransferFunction(const PolynomialFraction<long double> & TransferFunction, SIGNAL_TYPE SignalType);
        PolynomialFraction<long double> m_TransferFunction;

    private:
        PolynomialFraction<long double> ContinuousTimeToDiscreteTime(const PolynomialFraction<long double> & ContinuousTimeTransferFunction);
        PolynomialFraction<long double> ContinuousTimeToDiscreteTime(const Polynomial<long double> & NominatorPolynomial,
                                                                     const Polynomial<long double> & DenominatorPolynomial);
        PolynomialFraction<long double> ContinuousTimeToDiscreteTime(const std::vector<long double> & NominatorCoefficients,
                                                                     const std::vector<long double> & DenominatorCoefficients);
        void ShiftMemoryRegisters(long double dbNewInput);
};

#endif

ControlSystemBlock.cpp

#include "ControlSystemBlock.h"

ControlSystemBlock::ControlSystemBlock( long double dbSamplingPeriod /*= 0.001*/)
{
    m_dbSamplingPeriod = dbSamplingPeriod;
    std::vector<long double> Coefficients;
    Coefficients.push_back(1.0);
    PolynomialFraction<long double> TransferFunction(Coefficients, Coefficients);
    SetTransferFunction(TransferFunction, SIGNAL_TYPE::ST_DISCRETE);
}

ControlSystemBlock::ControlSystemBlock( const std::vector<long double> & NominatorCoefficients,
                                        const std::vector<long double> & DenominatorCoefficients,
                                        SIGNAL_TYPE SignalType /*= SIGNAL_TYPE::ST_CONTINUOUS*/,
                                        long double dbSamplingPeriod /*= 0.001*/)
{
    m_dbSamplingPeriod = dbSamplingPeriod;
    PolynomialFraction<long double> TransferFunction = PolynomialFraction<long double>(NominatorCoefficients, DenominatorCoefficients);
    SetTransferFunction(TransferFunction, SignalType);
}

ControlSystemBlock::ControlSystemBlock( const Polynomial<long double> & NominatorPolynomial,
                                        const Polynomial<long double> & DenominatorPolynomial,
                                        SIGNAL_TYPE SignalType /*= SIGNAL_TYPE::ST_CONTINUOUS*/,
                                        long double dbSamplingPeriod /*= 0.001*/ )
{
    m_dbSamplingPeriod = dbSamplingPeriod;
    PolynomialFraction<long double> TransferFunction = PolynomialFraction<long double>(NominatorPolynomial, DenominatorPolynomial);
    SetTransferFunction(TransferFunction, SignalType);
}

ControlSystemBlock::ControlSystemBlock( const PolynomialFraction<long double> & TransferFunction,
                                        ControlSystemBlock::SIGNAL_TYPE SignalType /*= SIGNAL_TYPE::ST_CONTINUOUS*/,
                                        long double dbSamplingPeriod /*= 0.001*/)
{
    m_dbSamplingPeriod = dbSamplingPeriod;
    if (SignalType == SIGNAL_TYPE::ST_CONTINUOUS)
    SetTransferFunction(TransferFunction, SignalType);
}

long double ControlSystemBlock::SendInput(long double dbInput)
{
    ShiftMemoryRegisters(dbInput);
    long double dbSumX = 0.0, dbSumY = 0.0;
    for (uint64_t i=0; i<m_TransferFunction.GetNominatorDegree()+1; i++)
    {
        dbSumX += m_TransferFunction.GetNominator().GetCoefficientAt(i) * m_InputMemory.at(i);
    }
    for (uint64_t i=1; i<m_TransferFunction.GetDenominatorDegree()+1; i++)
    {
        dbSumY += m_TransferFunction.GetDenominator().GetCoefficientAt(i) * m_OutputMemory.at(i);
    }
    return m_OutputMemory.at(0) = (dbSumX - dbSumY) / m_TransferFunction.GetDenominator().GetCoefficientAt(0);
}

long double ControlSystemBlock::GetOutput() const
{
    return m_OutputMemory.at(0);
}

PolynomialFraction<long double> ControlSystemBlock::ContinuousTimeToDiscreteTime(const PolynomialFraction<long double> & ContinuousTimeTransferFunction)
{
    // Generate an "s" term in terms of "z^(-1)" terms
    std::vector<long double> nom, den;
    nom.push_back(1);
    nom.push_back(-1);
    den.push_back(1);
    den.push_back(1);
    PolynomialFraction<long double> STerm(nom, den);
    STerm *= static_cast<long double>(2) / m_dbSamplingPeriod;
    // Define nominator and denominator terms of the discrete time transfer function separately
    nom.clear();
    den.clear();
    nom.push_back(0);
    nom.push_back(1);
    PolynomialFraction<long double> NominatorOfDiscreteTimeTransferFunction(nom, den);
    PolynomialFraction<long double> DenominatorOfDiscreteTimeTransferFunction(nom, den);
    // Generate the nominator and denominator terms of the resulting discrete time transfer function
    for (uint64_t i=0; i<ContinuousTimeTransferFunction.GetNominatorDegree()+1; i++)
    {
        NominatorOfDiscreteTimeTransferFunction += STerm.GetPower(i) * ContinuousTimeTransferFunction.GetNominator().GetCoefficientAt(i);
    }
    for (uint64_t i=0; i<ContinuousTimeTransferFunction.GetDenominatorDegree()+1; i++)
    {
        NominatorOfDiscreteTimeTransferFunction += STerm.GetPower(i) * ContinuousTimeTransferFunction.GetDenominator().GetCoefficientAt(i);
    }
    return NominatorOfDiscreteTimeTransferFunction / DenominatorOfDiscreteTimeTransferFunction;
}

PolynomialFraction<long double> ControlSystemBlock::ContinuousTimeToDiscreteTime(const Polynomial<long double> & NominatorPolynomial,
                                                                                 const Polynomial<long double> & DenominatorPolynomial)
{
    PolynomialFraction<long double> ContinuousTimeTransferFunction(NominatorPolynomial, DenominatorPolynomial);
    return ContinuousTimeToDiscreteTime(ContinuousTimeTransferFunction);
}

PolynomialFraction<long double> ControlSystemBlock::ContinuousTimeToDiscreteTime(const std::vector<long double> & NominatorCoefficients,
                                                                                 const std::vector<long double> & DenominatorCoefficients)
{
    PolynomialFraction<long double> ContinuousTimeTransferFunction(NominatorCoefficients, DenominatorCoefficients);
    return ContinuousTimeToDiscreteTime(ContinuousTimeTransferFunction);
}

void ControlSystemBlock::SetTransferFunction( const PolynomialFraction<long double> & TransferFunction, SIGNAL_TYPE SignalType)
{
    if (SignalType == SIGNAL_TYPE::ST_CONTINUOUS)
    {
        m_TransferFunction = ContinuousTimeToDiscreteTime(TransferFunction);
    }
    else
    {
        m_TransferFunction = TransferFunction;
    }
    m_InputMemory.resize(m_TransferFunction.GetNominatorDegree() + 1, 0.0);
    m_OutputMemory.resize(m_TransferFunction.GetDenominatorDegree() + 1, 0.0);
}

void ControlSystemBlock::ShiftMemoryRegisters(long double dbNewInput)
{
    m_InputMemory.push_back(dbNewInput);
    m_InputMemory.pop_front();
    m_OutputMemory.push_back(0.0);
    m_OutputMemory.pop_front();
}

I have just finished it.
I going to test it soon.

各自安好 2024-10-16 19:56:18

让系统接受一个函数(即 C++0x 中的 std::function 或 Boost 中的等效函数)接受一个 double 值并返回一个 double 值,并使用该函数进行实际计算。

然后,用户可以提供任意函数或函子(重载operator()的类)来执行您想要的转换函数。

或者,使您的函数需要任意转换模板函数,并按值传递函子/函数指针,就像 STL 算法所做的那样。

Make the system accept a function (i.e. std::function in C++0x, or the equivalents in Boost) taking a double and returning a double, and use that function to do the actual calculation.

The user can then supply any arbitrary function or functor (a class overloading operator()) in order to do the transformation function you want.

Alternately, make your functions requiring the arbitrary transformation template functions and pass the functor/function pointer in by value, like the STL algorithms do.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文