Сообщество Engee

Двигатель постоянного тока в Engee

Автор
avatar-nikfilaretovnikfilaretov
Notebook

Создание сложных компонентов на языке физического моделирования Engee

Язык физического моделирования Engee позволяет не только разрабатывать свои компоненты но и объединять разные компоненты в единое целое. Такие компоненты называются составными.

Это как конструктор, когда есть детали (компоненты) и наша задача - соединить их в правильном порядке.

Зачем делать составные компоненты?

  • "Упаковка" множества компонентов в один (как подсистема в обычном моделировании)
  • Массивы компонентов

Пример составного компонента

В качестве примера составного компонента рассмотрим двигатель постоянного тока с внешней нагрузкой вала.

Что бы удостовериться в том, что компонент был собран правильно, возьмем эталонную реализацию на примитивах из библиотеки ненаправленных блоков:

image.png

Для тестирования будем моделировать следующий сценарий: в первые 0.1 секунды работы двигатель работает без нагрузки на вал, и достигает максимальной скорости, а затем на вале возникает нагрузка.

Создание составного компонента

Составные компоненты создаются точно также как и пользовательские компоненты при помощи языка физического моделирования Engee. Поэтому, код компонента должен содержаться в файле *.ngpc, расположенном по пути поиска Engee.

Посмотрим на код компонента из файла DCMotorComosite.ngpc:

@engeemodel DCMotorComposite begin
    
    @components begin
        p = EngeePhysicalFoundation.Electrical.Pin(), [view = ("+", "left")]
        n = EngeePhysicalFoundation.Electrical.Pin(), [view = ("-", "left")]
        r = EngeePhysicalFoundation.Mechanical.Rotational.Flange(), [view = ("R", "right")]
        c = EngeePhysicalFoundation.Mechanical.Rotational.Flange(), [view = ("C", "right")]
    end

    @parameters begin
        rotor_resistance    = 3.9, 		[unit="Ohm"]
        rotor_inductance    = 12e-6, 	[unit="H"]
        motor_inertia       = 0.01, 	[unit="g*cm^2"]
        breakaway_torque    = 0.02e-3, 	[unit="N*m"]
        coulomb_torque      = 0.02e-3, 	[unit="N*m"]
        breakaway_velocity  = 0.03347, 	[unit="rad/s"]
        back_emf_constant   = 0.072e-3*60/(2*pi), [unit="V/(rad/s)"]
        viscous_coefficient = 0.0, [unit="N*m/(rad/s)"]
    end

    @components [gui = None] begin
        rotorResistor = EngeePhysicalFoundation.Electrical.Elements.Resistor(R=default(rotor_resistance))
        rotorInductor = EngeePhysicalFoundation.Electrical.Elements.Inductor(L=default(rotor_inductance))
        motorInertia = EngeePhysicalFoundation.Mechanical.Rotational.Elements.Inertia(I=default(motor_inertia))
        friction = EngeePhysicalFoundation.Mechanical.Rotational.Elements.Friction(w_breakaway=default(breakaway_velocity),T_breakaway=default(breakaway_torque),T_coulomb=default(coulomb_torque), viscous_coefficient=default(viscous_coefficient))
        rotEMechConverter = EngeePhysicalFoundation.Electrical.Elements.RotationalConverter(k=default(back_emf_constant))
    end

    @equations begin
        connect(p, rotorResistor.p)
        connect(rotorResistor.n, rotorInductor.p)
        connect(rotorInductor.n, rotEMechConverter.p)
        connect(rotEMechConverter.n, n)
        connect(rotEMechConverter.rod_flange, friction.rod_flange, motorInertia.flange, r)
        connect(rotEMechConverter.case_flange, friction.case_flange, c)
    end

end

Обратите внимание на то, как мы создаем подкомпоненты - они содержатся в секции @components. Мы инициализируем их параметры значениями из секции @parameters

Сборка подкомпонентов в единый компонент происходит в секции @equations с помощью функции connect(). Обратим внимание, что можно указывать сразу несколько портов для соединения!

Тестирование составного компонента

Проверим результаты моделирования нашего составного компонента относительно той же модели, но на примитивах

demoroot = @__DIR__
engee.addpath(demoroot)
mdl = engee.open(joinpath(demoroot,"DCComposite.engee"))
sim_res = engee.run(mdl);

Давайте построим графики результатов симуляции:

using Plots

CustC = collect(sim_res["Cust"]);
Primitives = collect(sim_res["Prim"]);
plot(CustC.time,CustC.value, label = "Пользовательский компонент")
plot!(Primitives.time,Primitives.value, label = "Библиотека блоков")
plot!(legend=:outerbottom,legendcolumns=2)

Найдем максимальную абсолютную ошибку:

err = CustC.value .- Primitives.value;
println("Максимальная абсолютная ошибка: $(maximum(err))")
Максимальная абсолютная ошибка: 2.093656803481281e-9

Результаты моделирования фактически совпадают, а значит наш компонент работает правильно!

Выводы

Язык физического моделирования Engee - это не просто язык написания пользовательских компонентов для 1-d моделирования, но и язык для создания и описания сложных физических систем. При этом была сохранена читаемость кода, что важно для сложных систем!