pid controller

main
syneffort 12 months ago
parent 37cb3cb01e
commit c78e98e11d
  1. 31
      AutomaticControl/AutomaticControl.sln
  2. 9
      AutomaticControl/AutomaticController/AutomaticController.csproj
  3. 7
      AutomaticControl/AutomaticController/IAutomaticController.cs
  4. 41
      AutomaticControl/AutomaticController/PIDController.cs
  5. 9
      AutomaticControl/Simulator/App.xaml
  6. 14
      AutomaticControl/Simulator/App.xaml.cs
  7. 10
      AutomaticControl/Simulator/AssemblyInfo.cs
  8. 14
      AutomaticControl/Simulator/MainWindow.xaml
  9. 24
      AutomaticControl/Simulator/MainWindow.xaml.cs
  10. 16
      AutomaticControl/Simulator/Models/FixedPIDSetpointModel.cs
  11. 20
      AutomaticControl/Simulator/Simulator.csproj
  12. 104
      AutomaticControl/Simulator/ViewModels/FixedSetpointPIDViewModel.cs
  13. 41
      AutomaticControl/Simulator/Views/FixedSetpointPIDView.xaml
  14. 28
      AutomaticControl/Simulator/Views/FixedSetpointPIDView.xaml.cs

@ -0,0 +1,31 @@

Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.9.34728.123
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "AutomaticController", "AutomaticController\AutomaticController.csproj", "{F16FE10F-A3FA-4566-8DE9-B42708CE7BC9}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "Simulator", "Simulator\Simulator.csproj", "{539BBF00-E7DD-42E2-987C-8756642A4EA2}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{F16FE10F-A3FA-4566-8DE9-B42708CE7BC9}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{F16FE10F-A3FA-4566-8DE9-B42708CE7BC9}.Debug|Any CPU.Build.0 = Debug|Any CPU
{F16FE10F-A3FA-4566-8DE9-B42708CE7BC9}.Release|Any CPU.ActiveCfg = Release|Any CPU
{F16FE10F-A3FA-4566-8DE9-B42708CE7BC9}.Release|Any CPU.Build.0 = Release|Any CPU
{539BBF00-E7DD-42E2-987C-8756642A4EA2}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{539BBF00-E7DD-42E2-987C-8756642A4EA2}.Debug|Any CPU.Build.0 = Debug|Any CPU
{539BBF00-E7DD-42E2-987C-8756642A4EA2}.Release|Any CPU.ActiveCfg = Release|Any CPU
{539BBF00-E7DD-42E2-987C-8756642A4EA2}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {5A0745B4-0117-4796-93E9-B17323D15F92}
EndGlobalSection
EndGlobal

@ -0,0 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net6.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

@ -0,0 +1,7 @@
namespace AutomaticController
{
public interface IAutomaticController
{
double Compute(double setpoint, double processVariable);
}
}

@ -0,0 +1,41 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace AutomaticController
{
public class PIDController : IAutomaticController
{
public double Kp { get; set; }
public double Ki { get; set; }
public double Kd { get; set; }
private double _prevError;
private double _integralError;
public PIDController(double kp, double ki, double kd)
{
Kp = kp;
Ki = ki;
Kd = kd;
_prevError = 0;
_integralError = 0;
}
public double Compute(double setpoint, double processVariable)
{
double error = setpoint - processVariable;
_integralError += error;
double derivative = error - _prevError;
double output = Kp * error + Ki * _integralError + Kd * derivative;
_prevError = error;
return output;
}
}
}

@ -0,0 +1,9 @@
<Application x:Class="Simulator.App"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:local="clr-namespace:Simulator"
StartupUri="MainWindow.xaml">
<Application.Resources>
</Application.Resources>
</Application>

@ -0,0 +1,14 @@
using System.Configuration;
using System.Data;
using System.Windows;
namespace Simulator
{
/// <summary>
/// Interaction logic for App.xaml
/// </summary>
public partial class App : Application
{
}
}

@ -0,0 +1,10 @@
using System.Windows;
[assembly: ThemeInfo(
ResourceDictionaryLocation.None, //where theme specific resource dictionaries are located
//(used if a resource is not found in the page,
// or application resource dictionaries)
ResourceDictionaryLocation.SourceAssembly //where the generic resource dictionary is located
//(used if a resource is not found in the page,
// app, or any theme specific resource dictionaries)
)]

@ -0,0 +1,14 @@
<Window x:Class="Simulator.MainWindow"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Simulator"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
Title="MainWindow"
Width="800"
Height="450"
mc:Ignorable="d">
<Frame NavigationUIVisibility="Hidden"
Source="/Views/FixedSetpointPIDView.xaml">
</Frame>
</Window>

@ -0,0 +1,24 @@
using System.Text;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Simulator
{
/// <summary>
/// Interaction logic for MainWindow.xaml
/// </summary>
public partial class MainWindow : Window
{
public MainWindow()
{
InitializeComponent();
}
}
}

@ -0,0 +1,16 @@
using AutomaticController;
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Simulator.Models
{
internal class FixedPIDSetpointModel
{
public double Setpoint { get; set; }
public PIDController Controller { get; set; }
}
}

@ -0,0 +1,20 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>WinExe</OutputType>
<TargetFramework>net6.0-windows</TargetFramework>
<Nullable>enable</Nullable>
<ImplicitUsings>enable</ImplicitUsings>
<UseWPF>true</UseWPF>
</PropertyGroup>
<ItemGroup>
<PackageReference Include="CommunityToolkit.Mvvm" Version="8.2.2" />
<PackageReference Include="LiveCharts.Wpf.NetCore3" Version="0.9.8" />
</ItemGroup>
<ItemGroup>
<ProjectReference Include="..\AutomaticController\AutomaticController.csproj" />
</ItemGroup>
</Project>

@ -0,0 +1,104 @@
using AutomaticController;
using CommunityToolkit.Mvvm.ComponentModel;
using CommunityToolkit.Mvvm.Input;
using LiveCharts;
using LiveCharts.Wpf;
using Simulator.Models;
using System;
using System.Collections.Generic;
using System.Collections.ObjectModel;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
namespace Simulator.ViewModels
{
internal partial class FixedSetpointPIDViewModel : ObservableObject
{
[ObservableProperty]
private FixedPIDSetpointModel _setpointModel;
[ObservableProperty]
private ObservableCollection<double> _processHistory;
[ObservableProperty]
private ObservableCollection<double> _setpointHistory;
[ObservableProperty]
private SeriesCollection _series;
[ObservableProperty]
private double _kp;
[ObservableProperty]
private double _ki;
[ObservableProperty]
private double _kd;
public FixedSetpointPIDViewModel()
{
Kp = 0.5;
Ki = 0.1;
Kd = 0.2;
SetpointModel = new FixedPIDSetpointModel()
{
Setpoint = 50,
Controller = new PIDController(Kp, Kd, Ki)
};
ProcessHistory = new ObservableCollection<double>();
SetpointHistory = new ObservableCollection<double>();
Series = new SeriesCollection()
{
new LineSeries()
{
Title = "Actual",
Values = new ChartValues<double>()
},
new LineSeries()
{
Title = "Setpoint",
Values = new ChartValues<double>()
},
};
#if DEBUG
Simulate();
#endif
}
[RelayCommand]
public void Simulate()
{
SetpointModel.Controller.Kp = Kp;
SetpointModel.Controller.Ki = Ki;
SetpointModel.Controller.Kd = Kd;
ProcessHistory.Clear();
SetpointHistory.Clear();
Series[0].Values.Clear();
Series[1].Values.Clear();
InsertData(SetpointModel.Setpoint, 0d);
for (int i = 0; i < 100; i++)
{
double current = ProcessHistory.LastOrDefault();
double output = SetpointModel.Controller.Compute(SetpointModel.Setpoint, current);
double actual = current + output;
InsertData(SetpointModel.Setpoint, actual);
}
}
private void InsertData(double setpoint, double actual)
{
Series[1].Values.Add(setpoint);
Series[0].Values.Add(actual);
SetpointHistory.Add(SetpointModel.Setpoint);
ProcessHistory.Add(actual);
}
}
}

@ -0,0 +1,41 @@
<Page x:Class="Simulator.Views.FixedSetpointPIDView"
xmlns="http://schemas.microsoft.com/winfx/2006/xaml/presentation"
xmlns:x="http://schemas.microsoft.com/winfx/2006/xaml"
xmlns:d="http://schemas.microsoft.com/expression/blend/2008"
xmlns:local="clr-namespace:Simulator.Views"
xmlns:lvc="clr-namespace:LiveCharts.Wpf;assembly=LiveCharts.Wpf"
xmlns:mc="http://schemas.openxmlformats.org/markup-compatibility/2006"
xmlns:viewModels="clr-namespace:Simulator.ViewModels"
Title="FixedSetpointPIDView"
d:DesignHeight="450"
d:DesignWidth="800"
mc:Ignorable="d">
<Page.DataContext>
<viewModels:FixedSetpointPIDViewModel />
</Page.DataContext>
<Grid>
<Grid.RowDefinitions>
<RowDefinition Height="*" />
<RowDefinition Height="Auto" />
</Grid.RowDefinitions>
<lvc:CartesianChart LegendLocation="Bottom" Series="{Binding Series}" />
<StackPanel Grid.Row="1" Orientation="Horizontal">
<Label Content="Kp" />
<TextBox Width="50"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
Text="{Binding Kp}" />
<Label Content="Ki" />
<TextBox Width="50"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
Text="{Binding Ki}" />
<Label Content="Kd" />
<TextBox Width="50"
HorizontalContentAlignment="Center" VerticalContentAlignment="Center"
Text="{Binding Kd}" />
<Button Command="{Binding SimulateCommand}" Content="Simulate" Margin="20 0 0 0" />
</StackPanel>
</Grid>
</Page>

@ -0,0 +1,28 @@
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
using System.Threading.Tasks;
using System.Windows;
using System.Windows.Controls;
using System.Windows.Data;
using System.Windows.Documents;
using System.Windows.Input;
using System.Windows.Media;
using System.Windows.Media.Imaging;
using System.Windows.Navigation;
using System.Windows.Shapes;
namespace Simulator.Views
{
/// <summary>
/// FixedSetpointPIDView.xaml에 대한 상호 작용 논리
/// </summary>
public partial class FixedSetpointPIDView : Page
{
public FixedSetpointPIDView()
{
InitializeComponent();
}
}
}
Loading…
Cancel
Save