diff --git a/AutomaticControl/AutomaticControl.sln b/AutomaticControl/AutomaticControl.sln
new file mode 100644
index 0000000..f6f2c47
--- /dev/null
+++ b/AutomaticControl/AutomaticControl.sln
@@ -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
diff --git a/AutomaticControl/AutomaticController/AutomaticController.csproj b/AutomaticControl/AutomaticController/AutomaticController.csproj
new file mode 100644
index 0000000..132c02c
--- /dev/null
+++ b/AutomaticControl/AutomaticController/AutomaticController.csproj
@@ -0,0 +1,9 @@
+
+
+
+ net6.0
+ enable
+ enable
+
+
+
diff --git a/AutomaticControl/AutomaticController/IAutomaticController.cs b/AutomaticControl/AutomaticController/IAutomaticController.cs
new file mode 100644
index 0000000..c6070ad
--- /dev/null
+++ b/AutomaticControl/AutomaticController/IAutomaticController.cs
@@ -0,0 +1,7 @@
+namespace AutomaticController
+{
+ public interface IAutomaticController
+ {
+ double Compute(double setpoint, double processVariable);
+ }
+}
diff --git a/AutomaticControl/AutomaticController/PIDController.cs b/AutomaticControl/AutomaticController/PIDController.cs
new file mode 100644
index 0000000..f0069d5
--- /dev/null
+++ b/AutomaticControl/AutomaticController/PIDController.cs
@@ -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;
+ }
+ }
+}
diff --git a/AutomaticControl/Simulator/App.xaml b/AutomaticControl/Simulator/App.xaml
new file mode 100644
index 0000000..1db1fee
--- /dev/null
+++ b/AutomaticControl/Simulator/App.xaml
@@ -0,0 +1,9 @@
+
+
+
+
+
diff --git a/AutomaticControl/Simulator/App.xaml.cs b/AutomaticControl/Simulator/App.xaml.cs
new file mode 100644
index 0000000..2bf6c35
--- /dev/null
+++ b/AutomaticControl/Simulator/App.xaml.cs
@@ -0,0 +1,14 @@
+using System.Configuration;
+using System.Data;
+using System.Windows;
+
+namespace Simulator
+{
+ ///
+ /// Interaction logic for App.xaml
+ ///
+ public partial class App : Application
+ {
+ }
+
+}
diff --git a/AutomaticControl/Simulator/AssemblyInfo.cs b/AutomaticControl/Simulator/AssemblyInfo.cs
new file mode 100644
index 0000000..b0ec827
--- /dev/null
+++ b/AutomaticControl/Simulator/AssemblyInfo.cs
@@ -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)
+)]
diff --git a/AutomaticControl/Simulator/MainWindow.xaml b/AutomaticControl/Simulator/MainWindow.xaml
new file mode 100644
index 0000000..b70ccdd
--- /dev/null
+++ b/AutomaticControl/Simulator/MainWindow.xaml
@@ -0,0 +1,14 @@
+
+
+
+
diff --git a/AutomaticControl/Simulator/MainWindow.xaml.cs b/AutomaticControl/Simulator/MainWindow.xaml.cs
new file mode 100644
index 0000000..18555d0
--- /dev/null
+++ b/AutomaticControl/Simulator/MainWindow.xaml.cs
@@ -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
+{
+ ///
+ /// Interaction logic for MainWindow.xaml
+ ///
+ public partial class MainWindow : Window
+ {
+ public MainWindow()
+ {
+ InitializeComponent();
+ }
+ }
+}
\ No newline at end of file
diff --git a/AutomaticControl/Simulator/Models/FixedPIDSetpointModel.cs b/AutomaticControl/Simulator/Models/FixedPIDSetpointModel.cs
new file mode 100644
index 0000000..c2ac034
--- /dev/null
+++ b/AutomaticControl/Simulator/Models/FixedPIDSetpointModel.cs
@@ -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; }
+ }
+}
diff --git a/AutomaticControl/Simulator/Simulator.csproj b/AutomaticControl/Simulator/Simulator.csproj
new file mode 100644
index 0000000..c79c89d
--- /dev/null
+++ b/AutomaticControl/Simulator/Simulator.csproj
@@ -0,0 +1,20 @@
+
+
+
+ WinExe
+ net6.0-windows
+ enable
+ enable
+ true
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AutomaticControl/Simulator/ViewModels/FixedSetpointPIDViewModel.cs b/AutomaticControl/Simulator/ViewModels/FixedSetpointPIDViewModel.cs
new file mode 100644
index 0000000..61dbd94
--- /dev/null
+++ b/AutomaticControl/Simulator/ViewModels/FixedSetpointPIDViewModel.cs
@@ -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 _processHistory;
+ [ObservableProperty]
+ private ObservableCollection _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();
+ SetpointHistory = new ObservableCollection();
+ Series = new SeriesCollection()
+ {
+ new LineSeries()
+ {
+ Title = "Actual",
+ Values = new ChartValues()
+ },
+ new LineSeries()
+ {
+ Title = "Setpoint",
+ Values = new ChartValues()
+ },
+ };
+#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);
+ }
+ }
+}
diff --git a/AutomaticControl/Simulator/Views/FixedSetpointPIDView.xaml b/AutomaticControl/Simulator/Views/FixedSetpointPIDView.xaml
new file mode 100644
index 0000000..b683a4b
--- /dev/null
+++ b/AutomaticControl/Simulator/Views/FixedSetpointPIDView.xaml
@@ -0,0 +1,41 @@
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
+
diff --git a/AutomaticControl/Simulator/Views/FixedSetpointPIDView.xaml.cs b/AutomaticControl/Simulator/Views/FixedSetpointPIDView.xaml.cs
new file mode 100644
index 0000000..943be8f
--- /dev/null
+++ b/AutomaticControl/Simulator/Views/FixedSetpointPIDView.xaml.cs
@@ -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
+{
+ ///
+ /// FixedSetpointPIDView.xaml에 대한 상호 작용 논리
+ ///
+ public partial class FixedSetpointPIDView : Page
+ {
+ public FixedSetpointPIDView()
+ {
+ InitializeComponent();
+ }
+ }
+}