Как реализовать блок системы управления передаточной функцией в C ++? - PullRequest
1 голос
/ 28 декабря 2010

Я хочу определить блок системы управления, например:

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). Как мне это сделать? Есть ли алгоритм для этого?

Ответы [ 2 ]

3 голосов
/ 05 января 2011

Что вы думаете о моем коде:

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();
}

Я только что закончил.
Я собираюсь проверить это в ближайшее время.

0 голосов
/ 28 декабря 2010

Заставьте систему принять функцию (т.е. std::function в C ++ 0x или эквивалентах в Boost), принимающую double и возвращающую double, и используйте эту функцию для выполнения фактических вычислений.

Затем пользователь может предоставить любую произвольную функцию или функтор (перегрузка класса operator()) для выполнения требуемой функции преобразования.

Альтернативно, сделайте ваши функции требующими произвольных функций шаблона преобразования и передайте указатель функтора / функции по значению, как это делают алгоритмы STL.

...