├── L01 ├── L01_Assignment_installMATLAB.mlx ├── L01_Lesson_courseIntroduction.mlx └── L01_TCLab_beginMATLAB.mlx ├── L02 ├── L02_Assignment_simulateInfection.mlx ├── L02_Lesson_simulateDynamics.mlx └── L02_TCLab_stepTestSimulation.mlx ├── L03 ├── L03_Assignment_deriveBalanceEquations.mlx ├── L03_Lesson_physicsBasedDynamicModeling.mlx └── L03_TCLab_convectiveHeatTransfer.mlx ├── L04 ├── L4_Assignment_tankBlending.mlx ├── L4_Lesson_balanceEquations.mlx └── L4_TCLab_radiativeHeatTransfer.mlx ├── L05 ├── L05_Assignment_linearSimulation.mlx ├── L05_Lesson_LinearizationofDifferentialEquations.mlx └── L05_TCLab_linearizeEnergyBalance.mlx ├── L06 ├── L06_Assignment_graphicalFOPDTFit.mlx ├── L06_Lesson_FirstOrderPlusDeadTime.mlx └── L06_TCLab_graphicalFOPDTFit.mlx ├── L07 ├── L07_Assignment_parameterRegression.mlx ├── L07_Lesson_OptimizeModelParameterFit_optimizeBlock.mlx └── L07_TCab_fitFOPDT.mlx ├── L10 ├── L10_Assignment_controlDesign.mlx ├── L10_Lesson_ControlDesign.mlx └── L10_TCLab_controllerDesign.mlx ├── L11 ├── L11_Assignment_controlWaterTankLevel.mlx ├── L11_Lesson_ProportionalOnlyControl.mlx └── L11_TCLab_pOnlyControl.mlx ├── L12 ├── L12_Assignment_autoCruiseControl.mlx ├── L12_Lesson_ProportionalIntegralPIControl.mlx └── L12_TCLab_PIControl.mlx ├── L13 ├── L13_Assignemnt_blendingControl.mlx ├── L13_Lesson_ProportionalIntegralDerivative.mlx └── L13_TCLab_PIDControl.mlx ├── L14 ├── L14_Lesson_Assignment_levelControl.mlx ├── L14_TCLab_PITuning.mlx ├── L14_TCLab_simulinkPITuning.mlx ├── Simulink │ ├── Step_Response.csv │ ├── arduino_lab1.m │ ├── arduino_lab2.m │ ├── arduino_ode.m │ ├── arduino_pi.slx │ ├── arduino_pi_R2014a.slx │ ├── arduino_sim.m │ ├── msfun_realtime_elapsed.m │ ├── msfun_realtime_pacer.m │ ├── realtime_pacer_lib.mdl │ ├── slblocks.m │ └── tclab.m └── slprj │ ├── modeladvisor │ └── UpgradeAdv_ │ │ └── arduino_pi │ │ └── ModelAdvisorData │ └── sl_proj.tmw ├── L15 ├── L15_Lesson-Assignment_temperatureControlCSTR.mlx ├── L15_Lesson_Assignment_temperatureControlCSTR.mlx ├── L15_TCLab_PIDTuning.mlx ├── L15_TCLab_simulinkPIDTuning.mlx └── Simulink │ ├── Step_Response.csv │ ├── arduino_lab1.m │ ├── arduino_lab2.m │ ├── arduino_ode.m │ ├── arduino_pid.slx │ ├── arduino_pid_R2014a.slx │ ├── arduino_sim.m │ ├── msfun_realtime_elapsed.m │ ├── msfun_realtime_pacer.m │ ├── realtime_pacer_lib.mdl │ ├── slblocks.m │ └── tclab.m ├── L16 ├── L16_Lesson-Assignment_maintainGlucose.mlx ├── L16_Lesson_Assignment_maintainGlucose.mlx └── L16_TCLab_PIDFeedforward.mlx ├── L17 ├── L17_Assignment_valveDesign.mlx ├── L17_Lesson_ValveDesignForFlowControl.mlx └── L17_TCLab_TCLabActuator.mlx ├── L18 ├── L18_Assignment_sensorDesign.mlx ├── L18_Lesson_SensorsAndDataAcquisition.mlx └── L18_TCLab_TemperatureSensor.mlx ├── L21 ├── Arduino_lab_rubric.pdf ├── L21_TCLabProject_singleTemperatureModeling.mlx └── L21_TCLabProject_twoTemperatureModeling.mlx ├── L22 ├── L22_TCLabProject_singleParameterRegression.mlx ├── L22_TCLabProject_twoParameterRegression.mlx ├── Step_Response.csv └── twoHeaterResponse.csv ├── L23 ├── L23_TCLabProject_createPID.mlx ├── L23_TCLabProject_interactingPIDControl.mlx └── SIMULINK │ ├── arduino_lab.slx │ ├── arduino_lab1.m │ ├── arduino_lab2.m │ ├── arduino_lab_R2011a.mdl │ ├── arduino_lab_R2014a.slx │ ├── arduino_lab_R2016a.slx │ ├── arduino_ode.m │ ├── arduino_sim.m │ ├── msfun_realtime_elapsed.m │ ├── msfun_realtime_pacer.m │ ├── realtime_pacer_lib.mdl │ ├── slblocks.m │ └── tclab.m ├── L24 ├── L24_Assignment_laplaceApplications.mlx ├── L24_Lesson_LaplaceTransform.mlx └── L24_TCLab_impulseResponse.mlx ├── L25 ├── L25_Assignment_blockDiagrams.mlx ├── L25_Lesson_transferFunctions.mlx └── L25_TCLab_blockDiagram.mlx ├── L26 ├── L26_Assignment_stateSpaceStirredReactor.mlx ├── L26_Lesson_StateSpaceModels.mlx ├── L26_TCLab_stateSpaceModels.mlx └── Step_Response.csv ├── L27 ├── L27_Assignment_secondOrderEstimation.mlx ├── L27_Lesson_SecondOrderSystemsWithGraphicalFit.mlx ├── L27_TCLab_OnOffControl.mlx ├── L27_TCLab_simulinkOnOffControl.mlx └── Simulink │ ├── On_Off_Control.PNG │ ├── On_Off_Control.slx │ ├── arduino_lab.m │ ├── msfun_realtime_elapsed.m │ ├── msfun_realtime_pacer.m │ ├── realtime_pacer_lib.mdl │ ├── slblocks.m │ └── tclab.m ├── L28 ├── L28_Assignment_secondOrderFit.mlx ├── L28_Lesson_SecondOrderOptimization.mlx └── L28_TCLab_SecondOrderRegression.mlx ├── L29 ├── L29_Assignment_distillationControl.mlx ├── L29_Lesson_SimulationofFOPDTSOPDTandHigherOrderSystems.mlx └── L29_TClab_higherOrderRegression.mlx ├── L30 ├── L30_Assignment_controllerStability.mlx ├── L30_Lesson_StabilityAnalysis.mlx └── L30_TCLab_pOnlyStability.mlx ├── L31 ├── L31_Assignment_cascadeFFControlDesign.mlx ├── L31_Lesson_CascadeAndFeedforwardControl.mlx └── L31_TCLab_cascadeControl.mlx ├── L34 └── L34_Lesson_controlProjectIntroduction.mlx ├── L35 └── L35_Lesson_optimizationIntroduction.mlx ├── L36 └── L36_Lesson_LinearProgramming.mlx ├── L37 └── L37_Lesson_SchedulingOptimization.mlx ├── L38 └── L38_Lesson_NonlinearProgramming.mlx ├── L39 └── L39_Lesson_MachineLearningClassification.mlx ├── L40 ├── L40_Lesson_ModelPredictiveControl.mlx ├── apm │ ├── apm.m │ ├── apm_app.m │ ├── apm_details.m │ ├── apm_get.m │ ├── apm_info.m │ ├── apm_linear.m │ ├── apm_linprog.m │ ├── apm_load.m │ ├── apm_lti.m │ ├── apm_meas.m │ ├── apm_option.m │ ├── apm_quadprog.m │ ├── apm_sol.m │ ├── apm_solve.m │ ├── apm_tag.m │ ├── apm_web.m │ ├── apm_web_root.m │ ├── apm_web_var.m │ ├── csv_data.m │ ├── csv_element.m │ ├── csv_load.m │ ├── csv_lookup.m │ ├── parse.m │ ├── t0_load.m │ └── urlread_apm.m ├── pendulum.apm ├── pendulum.csv └── solution_crane_pendulum.csv ├── LICENSE ├── README.md ├── data.txt ├── images ├── apm.png ├── github.png ├── hammond.jpg ├── hedengren.jpg ├── matlab.png ├── pdc_overview.png ├── tclab.png ├── webinar.png └── youtube.png └── tclab.m /L01/L01_Assignment_installMATLAB.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L01/L01_Assignment_installMATLAB.mlx -------------------------------------------------------------------------------- /L01/L01_Lesson_courseIntroduction.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L01/L01_Lesson_courseIntroduction.mlx -------------------------------------------------------------------------------- /L01/L01_TCLab_beginMATLAB.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L01/L01_TCLab_beginMATLAB.mlx -------------------------------------------------------------------------------- /L02/L02_Assignment_simulateInfection.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L02/L02_Assignment_simulateInfection.mlx -------------------------------------------------------------------------------- /L02/L02_Lesson_simulateDynamics.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L02/L02_Lesson_simulateDynamics.mlx -------------------------------------------------------------------------------- /L02/L02_TCLab_stepTestSimulation.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L02/L02_TCLab_stepTestSimulation.mlx -------------------------------------------------------------------------------- /L03/L03_Assignment_deriveBalanceEquations.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L03/L03_Assignment_deriveBalanceEquations.mlx -------------------------------------------------------------------------------- /L03/L03_Lesson_physicsBasedDynamicModeling.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L03/L03_Lesson_physicsBasedDynamicModeling.mlx -------------------------------------------------------------------------------- /L03/L03_TCLab_convectiveHeatTransfer.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L03/L03_TCLab_convectiveHeatTransfer.mlx -------------------------------------------------------------------------------- /L04/L4_Assignment_tankBlending.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L04/L4_Assignment_tankBlending.mlx -------------------------------------------------------------------------------- /L04/L4_Lesson_balanceEquations.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L04/L4_Lesson_balanceEquations.mlx -------------------------------------------------------------------------------- /L04/L4_TCLab_radiativeHeatTransfer.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L04/L4_TCLab_radiativeHeatTransfer.mlx -------------------------------------------------------------------------------- /L05/L05_Assignment_linearSimulation.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L05/L05_Assignment_linearSimulation.mlx -------------------------------------------------------------------------------- /L05/L05_Lesson_LinearizationofDifferentialEquations.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L05/L05_Lesson_LinearizationofDifferentialEquations.mlx -------------------------------------------------------------------------------- /L05/L05_TCLab_linearizeEnergyBalance.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L05/L05_TCLab_linearizeEnergyBalance.mlx -------------------------------------------------------------------------------- /L06/L06_Assignment_graphicalFOPDTFit.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L06/L06_Assignment_graphicalFOPDTFit.mlx -------------------------------------------------------------------------------- /L06/L06_Lesson_FirstOrderPlusDeadTime.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L06/L06_Lesson_FirstOrderPlusDeadTime.mlx -------------------------------------------------------------------------------- /L06/L06_TCLab_graphicalFOPDTFit.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L06/L06_TCLab_graphicalFOPDTFit.mlx -------------------------------------------------------------------------------- /L07/L07_Assignment_parameterRegression.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L07/L07_Assignment_parameterRegression.mlx -------------------------------------------------------------------------------- /L07/L07_Lesson_OptimizeModelParameterFit_optimizeBlock.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L07/L07_Lesson_OptimizeModelParameterFit_optimizeBlock.mlx -------------------------------------------------------------------------------- /L07/L07_TCab_fitFOPDT.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L07/L07_TCab_fitFOPDT.mlx -------------------------------------------------------------------------------- /L10/L10_Assignment_controlDesign.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L10/L10_Assignment_controlDesign.mlx -------------------------------------------------------------------------------- /L10/L10_Lesson_ControlDesign.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L10/L10_Lesson_ControlDesign.mlx -------------------------------------------------------------------------------- /L10/L10_TCLab_controllerDesign.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L10/L10_TCLab_controllerDesign.mlx -------------------------------------------------------------------------------- /L11/L11_Assignment_controlWaterTankLevel.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L11/L11_Assignment_controlWaterTankLevel.mlx -------------------------------------------------------------------------------- /L11/L11_Lesson_ProportionalOnlyControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L11/L11_Lesson_ProportionalOnlyControl.mlx -------------------------------------------------------------------------------- /L11/L11_TCLab_pOnlyControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L11/L11_TCLab_pOnlyControl.mlx -------------------------------------------------------------------------------- /L12/L12_Assignment_autoCruiseControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L12/L12_Assignment_autoCruiseControl.mlx -------------------------------------------------------------------------------- /L12/L12_Lesson_ProportionalIntegralPIControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L12/L12_Lesson_ProportionalIntegralPIControl.mlx -------------------------------------------------------------------------------- /L12/L12_TCLab_PIControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L12/L12_TCLab_PIControl.mlx -------------------------------------------------------------------------------- /L13/L13_Assignemnt_blendingControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L13/L13_Assignemnt_blendingControl.mlx -------------------------------------------------------------------------------- /L13/L13_Lesson_ProportionalIntegralDerivative.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L13/L13_Lesson_ProportionalIntegralDerivative.mlx -------------------------------------------------------------------------------- /L13/L13_TCLab_PIDControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L13/L13_TCLab_PIDControl.mlx -------------------------------------------------------------------------------- /L14/L14_Lesson_Assignment_levelControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L14/L14_Lesson_Assignment_levelControl.mlx -------------------------------------------------------------------------------- /L14/L14_TCLab_PITuning.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L14/L14_TCLab_PITuning.mlx -------------------------------------------------------------------------------- /L14/L14_TCLab_simulinkPITuning.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L14/L14_TCLab_simulinkPITuning.mlx -------------------------------------------------------------------------------- /L14/Simulink/Step_Response.csv: -------------------------------------------------------------------------------- 1 | 0,24.7800586510264,0 2 | 1.0099191,24.8289345063539,80 3 | 2.0092256,25.0244379276637,80 4 | 3.007527,24.9266862170088,80 5 | 4.0005121,25.1221896383187,80 6 | 5.0099991,24.8778103616813,80 7 | 6.0121858,24.8778103616813,80 8 | 7.005106,25.1710654936462,80 9 | 8.0143021,25.0244379276637,80 10 | 9.0041464,25.2688172043011,80 11 | 10.0117586,25.5131964809384,80 12 | 11.0046488,25.5620723362659,80 13 | 12.009741,25.8064516129032,80 14 | 13.00164,26.0019550342131,80 15 | 14.0067389,26.099706744868,80 16 | 15.01441,26.3929618768329,80 17 | 16.0056644,26.4418377321603,80 18 | 17.0037862,26.5884652981427,80 19 | 18.0047027,26.6862170087977,80 20 | 19.0002928,26.8817204301075,80 21 | 20.0087723,27.1749755620723,80 22 | 21.0132224,27.4193548387097,80 23 | 22.0085158,27.761485826002,80 24 | 23.0045447,27.9569892473118,80 25 | 24.0105019,28.2502443792766,80 26 | 25.001954,28.6412512218964,80 27 | 26.0077609,28.7390029325513,80 28 | 27.0026242,29.1300097751711,80 29 | 28.0062554,29.4721407624634,80 30 | 29.0126497,29.6676441837732,80 31 | 30.0028389,29.9120234604106,80 32 | 31.00966,30.058651026393,80 33 | 32.0000579,30.5474095796676,80 34 | 33.0069966,30.8895405669599,80 35 | 34.0104632,31.2805474095797,80 36 | 35.0017162,31.3294232649071,80 37 | 36.010746,31.6715542521994,80 38 | 37.0036075,32.0625610948192,80 39 | 38.0076519,32.2091886608016,80 40 | 39.0127609,32.4046920821114,80 41 | 40.0043646,32.7468230694037,80 42 | 41.0118477,32.8934506353861,80 43 | 42.0135748,33.1378299120235,80 44 | 43.0001349,33.6265884652981,80 45 | 44.0034835,33.9687194525904,80 46 | 45.0020722,34.1642228739003,80 47 | 46.0094154,34.5063538611926,80 48 | 47.0017713,34.7507331378299,80 49 | 48.0007385,34.8484848484848,80 50 | 49.0065432,35.5327468230694,80 51 | 50.0120216,35.7282502443793,80 52 | 51.0000604,35.9726295210166,80 53 | 52.0068502,36.2658846529814,80 54 | 53.0090295,36.2658846529814,80 55 | 54.0012779,36.9012707722385,80 56 | 55.0072776,36.8523949169111,80 57 | 56.0132462,37.3411534701857,80 58 | 57.0035673,37.781036168133,80 59 | 58.0004312,37.5855327468231,80 60 | 59.0031547,38.1720430107527,80 61 | 60.0057683,38.3675464320626,80 62 | 61.0135268,38.5630498533724,80 63 | 62.00263,39.0518084066471,80 64 | 63.0106975,39.1495601173021,80 65 | 64.0019344,39.5405669599218,80 66 | 65.0069374,39.8338220918866,80 67 | 66.0094822,39.8338220918866,80 68 | 67.0105843,40.2737047898338,80 69 | 68.0145263,40.7135874877811,80 70 | 69.0055811,40.811339198436,80 71 | 70.0127384,41.3000977517107,80 72 | 71.0075215,41.6422287390029,80 73 | 72.0004063,41.544477028348,80 74 | 73.0083117,42.0332355816227,80 75 | 74.0002869,42.5219941348974,80 76 | 75.0105919,42.4731182795699,80 77 | 76.0007936,42.6686217008798,80 78 | 77.0103865,42.9130009775171,80 79 | 78.0107458,43.0596285434995,80 80 | 79.0018054,43.5483870967742,80 81 | 80.0146505,43.7438905180841,80 82 | 81.0118292,43.9882697947214,80 83 | 82.0102586,44.1837732160313,80 84 | 83.0025126,44.5259042033236,80 85 | 84.0073525,44.6236559139785,80 86 | 85.0102119,44.8680351906158,80 87 | 86.0011796,45.2101661779081,80 88 | 87.0149138,45.1612903225806,80 89 | 88.0071246,45.5522971652004,80 90 | 89.0126737,45.8944281524927,80 91 | 90.0055599,46.0410557184751,80 92 | 91.0015084,46.236559139785,80 93 | 92.0084462,46.3831867057674,80 94 | 93.0080614,46.5298142717498,80 95 | 94.0124014,46.871945259042,80 96 | 95.0066402,46.8230694037146,80 97 | 96.0038045,47.1163245356794,80 98 | 97.0132574,47.3118279569892,80 99 | 98.0056581,47.4095796676442,80 100 | 99.0005833,48.0938416422287,80 101 | 100.0066743,48.1915933528837,80 102 | 101.0075764,48.1427174975562,80 103 | 102.0126281,48.6803519061584,80 104 | 103.0008051,48.7292277614859,80 105 | 104.0096817,48.8758553274682,80 106 | 105.0069706,49.1202346041056,80 107 | 106.0128398,49.6089931573803,80 108 | 107.0007818,49.7067448680352,80 109 | 108.0056995,49.8044965786901,80 110 | 109.0135042,49.9511241446725,80 111 | 110.0125946,50.1955034213099,80 112 | 111.0141096,50.2932551319648,80 113 | 112.0151626,50.5376344086022,80 114 | 113.0041143,50.6842619745846,80 115 | 114.0058846,50.9286412512219,80 116 | 115.0097923,51.3196480938416,80 117 | 116.0108258,51.3196480938416,80 118 | 117.0056492,51.564027370479,80 119 | 118.0118994,51.6617790811339,80 120 | 119.0101205,51.8084066471163,80 121 | 120.0076196,51.8572825024438,80 122 | 121.013191,52.0527859237536,80 123 | 122.0090783,52.297165200391,80 124 | 123.0047697,52.7859237536657,80 125 | 124.0015961,52.8347996089932,80 126 | 125.0107126,52.8836754643206,80 127 | 126.0074116,52.9325513196481,80 128 | 127.0146329,53.1769305962854,80 129 | 128.0115599,53.3724340175953,80 130 | 129.0056858,53.8123167155425,80 131 | 130.0085896,54.0078201368524,80 132 | 131.0149487,54.0078201368524,80 133 | 132.0076475,54.0566959921799,80 134 | 133.0067914,54.2033235581622,80 135 | 134.0016461,54.5454545454546,80 136 | 135.0114565,54.7898338220919,80 137 | 136.0006358,54.9853372434018,80 138 | 137.0146864,55.1319648093842,80 139 | 138.0070191,55.1319648093842,80 140 | 139.0117475,55.425219941349,80 141 | 140.0014729,55.4740957966764,80 142 | 141.000048,55.327468230694,80 143 | 142.0001314,55.5718475073313,80 144 | 143.0009931,55.8162267839687,80 145 | 144.0061286,56.0117302052786,80 146 | 145.0116023,56.3049853372434,80 147 | 146.0055083,56.4027370478983,80 148 | 147.0020442,56.4516129032258,80 149 | 148.0015412,56.6471163245357,80 150 | 149.0006316,56.5004887585533,80 151 | 150.0036724,56.8426197458455,80 152 | 151.0028417,56.989247311828,80 153 | 152.014761,56.891495601173,80 154 | 153.0108122,57.1847507331378,80 155 | 154.0117184,57.2825024437928,80 156 | 155.0024276,57.4291300097752,80 157 | 156.0136639,57.4780058651026,80 158 | 157.0076659,57.5757575757576,80 159 | 158.0099706,57.9667644183773,80 160 | 159.0087255,57.7712609970674,80 161 | 160.0038798,58.1622678396872,80 162 | 161.0039069,58.4066471163245,80 163 | 162.0079985,58.455522971652,80 164 | 163.0074557,58.3088954056696,80 165 | 164.0005954,58.5532746823069,80 166 | 165.0077503,58.6999022482893,80 167 | 166.0104794,59.0420332355816,80 168 | 167.0036831,58.8954056695992,80 169 | 168.0114316,59.0420332355816,80 170 | 169.0100593,59.2375366568915,80 171 | 170.0067591,59.2375366568915,80 172 | 171.0056242,59.3841642228739,80 173 | 172.0137428,59.4330400782014,80 174 | 173.0141934,59.7262952101661,80 175 | 174.0111057,59.7262952101662,80 176 | 175.0087494,60.019550342131,80 177 | 176.0126424,60.019550342131,80 178 | 177.0145453,60.0684261974584,80 179 | 178.0146644,60.1173020527859,80 180 | 179.0048722,60.2639296187683,80 181 | 180.0085345,59.9706744868035,80 182 | 181.0057983,60.3128054740958,80 183 | 182.011767,60.5083088954057,80 184 | 183.0056913,60.6549364613881,80 185 | 184.00014,60.752688172043,80 186 | 185.00228,60.8015640273705,80 187 | 186.0119505,60.5571847507331,80 188 | 187.01382,60.850439882698,80 189 | 188.012347,60.654936461388,80 190 | 189.0144552,60.7038123167155,80 191 | 190.0097427,61.1925708699902,80 192 | 191.0096891,61.0948191593353,80 193 | 192.0017751,61.4369501466275,80 194 | 193.0028478,61.4369501466275,80 195 | 194.0000432,61.5347018572825,80 196 | 195.0075741,61.6813294232649,80 197 | 196.0035049,61.6324535679375,80 198 | 197.0105941,61.8279569892473,80 199 | 198.0019948,61.7790811339198,80 200 | 199.0025988,61.8768328445748,80 201 | 200.0056496,61.7790811339198,80 202 | 201.0126747,62.0234604105572,80 203 | 202.0015874,61.9745845552297,80 204 | 203.0055714,62.218963831867,80 205 | 204.007267,62.1212121212121,80 206 | 205.0087646,62.0723362658846,80 207 | 206.0097612,62.316715542522,80 208 | 207.0099102,62.2678396871945,80 209 | 208.0009536,62.5122189638319,80 210 | 209.0025124,62.7077223851417,80 211 | 210.0035422,62.7077223851417,80 212 | 211.0052607,62.7565982404692,80 213 | 212.0074642,62.6099706744868,80 214 | 213.0045475,63.049853372434,80 215 | 214.0052461,63.0009775171065,80 216 | 215.0087726,63.049853372434,80 217 | 216.0030315,63.2942326490713,80 218 | 217.0054419,63.2942326490713,80 219 | 218.0056111,63.3919843597263,80 220 | 219.0138106,63.3431085043988,80 221 | 220.0066227,63.5386119257087,80 222 | 221.0116896,63.5874877810361,80 223 | 222.0106375,63.880742913001,80 224 | 223.0076985,63.6852394916911,80 225 | 224.006618,63.7341153470186,80 226 | 225.0068444,63.5874877810361,80 227 | 226.0126915,63.5874877810362,80 228 | 227.0008197,63.7341153470186,80 229 | 228.0060326,63.782991202346,80 230 | 229.0119285,64.1251221896383,80 231 | 230.0151312,63.880742913001,80 232 | 231.001882,63.7341153470186,80 233 | 232.0119541,64.0762463343108,80 234 | 233.0017919,64.3695014662756,80 235 | 234.0059719,64.3695014662757,80 236 | 235.0098728,64.5650048875855,80 237 | 236.0099399,64.5650048875855,80 238 | 237.0058743,64.5650048875855,80 239 | 238.0006932,64.5650048875855,80 240 | 239.0063161,64.5650048875855,80 241 | 240.0027341,64.613880742913,80 242 | 241.001934,64.8093841642229,80 243 | 242.0055472,64.8093841642229,80 244 | 243.0046569,64.9071358748778,80 245 | 244.0010438,64.9071358748778,80 246 | 245.0147568,64.7605083088954,80 247 | 246.0011172,65.1515151515151,80 248 | 247.0045973,65.1026392961877,80 249 | 248.0076803,65.2981427174975,80 250 | 249.0140263,65.3958944281525,80 251 | 250.0018415,65.5425219941349,80 252 | 251.0038222,65.44477028348,80 253 | 252.0064681,65.347018572825,80 254 | 253.0143714,65.5913978494624,80 255 | 254.0082794,65.5425219941349,80 256 | 255.0133456,65.5913978494624,80 257 | 256.013538,65.6891495601173,80 258 | 257.004496,65.7380254154447,80 259 | 258.0133525,65.7380254154448,80 260 | 259.0046842,65.9824046920821,80 261 | 260.0020309,65.9824046920821,80 262 | 261.0081493,65.7869012707722,80 263 | 262.0145668,65.9824046920821,80 264 | 263.0045722,66.0312805474096,80 265 | 264.0106451,66.080156402737,80 266 | 265.010756,65.9335288367546,80 267 | 266.0032864,66.2267839687194,80 268 | 267.0006123,66.177908113392,80 269 | 268.004752,66.0312805474096,80 270 | 269.010999,66.177908113392,80 271 | 270.0015549,66.3734115347018,80 272 | 271.0016618,66.6666666666667,80 273 | 272.0039267,66.4711632453568,80 274 | 273.0043604,66.2267839687194,80 275 | 274.0026574,66.1290322580645,80 276 | 275.0063944,66.4222873900293,80 277 | 276.0117742,66.8132942326491,80 278 | 277.0118435,66.4711632453568,80 279 | 278.0086492,66.6666666666667,80 280 | 279.010021,66.7644183773216,80 281 | 280.0072898,66.6666666666667,80 282 | 281.0127158,66.2267839687194,80 283 | 282.0053496,66.6177908113392,80 284 | 283.0074836,66.6666666666667,80 285 | 284.0037084,66.7155425219941,80 286 | 285.0049401,66.7644183773216,80 287 | 286.0045328,66.4711632453568,80 288 | 287.0068945,66.7644183773216,80 289 | 288.0086785,66.911045943304,80 290 | 289.0017441,66.8132942326491,80 291 | 290.0025357,66.9599217986315,80 292 | 291.0016527,67.1554252199413,80 293 | 292.0009305,67.008797653959,80 294 | 293.0009034,67.0576735092864,80 295 | 294.0036662,66.8621700879765,80 296 | 295.013523,67.0576735092864,80 297 | 296.0140252,66.6666666666667,80 298 | 297.0150027,67.008797653959,80 299 | 298.0015613,67.3998044965787,80 300 | 299.0025106,67.4486803519062,80 301 | 300.0128142,67.2043010752688,80 302 | 301.0027112,67.2043010752688,80 303 | 302.0049663,67.4975562072337,80 304 | 303.0035805,67.3509286412512,80 305 | 304.0034397,67.4975562072336,80 306 | 305.013515,67.4486803519062,80 307 | 306.0007355,67.1065493646139,80 308 | 307.0000485,67.5464320625611,80 309 | 308.010749,67.2043010752688,80 310 | 309.011163,67.4486803519062,80 311 | 310.0016419,67.6930596285435,80 312 | 311.0089662,67.4975562072337,80 313 | 312.000224,67.4486803519062,80 314 | 313.0088976,67.4975562072336,80 315 | 314.0112513,67.4975562072337,80 316 | 315.0144379,67.5464320625611,80 317 | 316.0055413,67.4486803519062,80 318 | 317.0074681,67.644183773216,80 319 | 318.0114636,67.4486803519062,80 320 | 319.0055704,67.644183773216,80 321 | 320.0112201,67.3998044965787,80 322 | 321.0019069,67.644183773216,80 323 | 322.0065995,67.8885630498534,80 324 | 323.0097281,67.644183773216,80 325 | 324.0015741,67.6930596285435,80 326 | 325.0052765,67.644183773216,80 327 | 326.0112558,67.7908113391984,80 328 | 327.0148541,67.8885630498534,80 329 | 328.0136764,67.8885630498534,80 330 | 329.0127334,67.7908113391984,80 331 | 330.0144682,67.644183773216,80 332 | 331.0134967,67.7908113391984,80 333 | 332.0134613,67.8396871945259,80 334 | 333.0034496,67.9374389051808,80 335 | 334.0030431,68.0840664711633,80 336 | 335.0018473,68.0840664711633,80 337 | 336.0027507,67.9863147605083,80 338 | 337.0043844,68.0840664711633,80 339 | 338.002937,68.1818181818182,80 340 | 339.0067457,67.9374389051808,80 341 | 340.006691,68.2795698924731,80 342 | 341.0045274,68.1329423264907,80 343 | 342.0144702,67.9863147605083,80 344 | 343.0005206,68.3284457478006,80 345 | 344.0125919,68.3284457478006,80 346 | 345.0146781,68.2306940371457,80 347 | 346.0141889,68.1329423264907,80 348 | 347.0137456,68.1818181818182,80 349 | 348.0126489,68.3284457478006,80 350 | 349.0059995,68.3284457478006,80 351 | 350.0016949,68.3773216031281,80 352 | 351.0140671,68.3773216031281,80 353 | 352.0023174,68.475073313783,80 354 | 353.0027717,68.2795698924731,80 355 | 354.011589,68.2795698924731,80 356 | 355.0000636,68.1818181818182,80 357 | 356.0093174,68.2306940371457,80 358 | 357.0093056,68.1818181818182,80 359 | 358.0080673,68.4261974584555,80 360 | 359.0147675,68.4261974584555,80 361 | 360.0050178,68.0840664711633,80 362 | 361.0066613,68.1329423264907,80 363 | 362.0115153,68.3284457478006,80 364 | 363.0119444,68.2306940371457,80 365 | 364.0028446,68.3284457478006,80 366 | 365.0124219,68.475073313783,80 367 | 366.0046449,68.572825024438,80 368 | 367.0123307,68.4261974584555,80 369 | 368.0023483,68.6217008797654,80 370 | 369.0054312,68.4261974584555,80 371 | 370.0013416,68.5728250244379,80 372 | 371.0119744,68.3284457478006,80 373 | 372.0054783,68.6217008797654,80 374 | 373.0107668,68.572825024438,80 375 | 374.0075983,68.4261974584555,80 376 | 375.0084924,68.4261974584555,80 377 | 376.0024385,68.5728250244379,80 378 | 377.0000412,68.6705767350929,80 379 | 378.0085999,68.475073313783,80 380 | 379.0016671,68.6705767350929,80 381 | 380.009011,68.6705767350929,80 382 | 381.0108832,68.5239491691105,80 383 | 382.0033503,68.6705767350929,80 384 | 383.0084188,68.8172043010753,80 385 | 384.0127811,68.4261974584555,80 386 | 385.0020782,68.4261974584555,80 387 | 386.0026668,68.8172043010753,80 388 | 387.010637,68.8172043010753,80 389 | 388.0045442,68.5728250244379,80 390 | 389.0074363,68.7194525904203,80 391 | 390.011452,68.8660801564028,80 392 | 391.0059795,69.0127077223851,80 393 | 392.0149701,68.8660801564028,80 394 | 393.0000514,68.8660801564027,80 395 | 394.0100546,68.9149560117302,80 396 | 395.0103862,68.9638318670577,80 397 | 396.0081989,68.9149560117302,80 398 | 397.0125481,68.7194525904203,80 399 | 398.0142729,68.8660801564028,80 400 | 399.0004677,69.0127077223851,80 401 | 400.0108114,69.0615835777126,80 402 | 401.0025592,69.0127077223851,80 403 | 402.0061012,68.9638318670577,80 404 | 403.015055,68.9638318670577,80 405 | 404.0077603,68.9638318670577,80 406 | 405.0127874,69.208211143695,80 407 | 406.0146995,69.30596285435,80 408 | 407.0044247,69.3548387096774,80 409 | 408.0000503,69.3548387096775,80 410 | 409.0104327,69.2570869990225,80 411 | 410.0055755,69.2570869990225,80 412 | 411.0115091,69.0127077223852,80 413 | 412.0124191,69.0127077223851,80 414 | 413.0071895,69.0127077223851,80 415 | 414.0141185,69.3548387096775,80 416 | 415.0064458,69.2570869990225,80 417 | 416.0017231,69.3548387096774,80 418 | 417.0087934,69.1104594330401,80 419 | 418.0000549,69.4037145650049,80 420 | 419.013401,69.4525904203324,80 421 | 420.0064805,69.2570869990225,80 422 | 421.0113656,69.5014662756598,80 423 | 422.0037896,69.4037145650049,80 424 | 423.0086053,69.3548387096775,80 425 | 424.0124672,69.208211143695,80 426 | 425.0053233,69.5014662756598,80 427 | 426.0112354,69.3548387096775,80 428 | 427.0089362,69.3548387096775,80 429 | 428.0108645,69.5992179863148,80 430 | 429.0064704,69.4525904203324,80 431 | 430.0126553,69.5014662756598,80 432 | 431.0028453,69.4525904203324,80 433 | 432.0107047,69.5014662756598,80 434 | 433.0085041,69.5014662756598,80 435 | 434.0023942,69.30596285435,80 436 | 435.0083285,69.5992179863148,80 437 | 436.0095289,69.6480938416423,80 438 | 437.0087928,69.5992179863148,80 439 | 438.0042599,69.7458455522972,80 440 | 439.002585,69.5992179863148,80 441 | 440.0112023,69.5992179863148,80 442 | 441.0074976,69.5992179863148,80 443 | 442.0107948,69.9413489736071,80 444 | 443.0076652,69.8435972629521,80 445 | 444.0023028,69.7947214076246,80 446 | 445.0118893,69.5503421309873,80 447 | 446.0151137,69.6480938416422,80 448 | 447.0083086,69.7947214076246,80 449 | 448.0115333,70.039100684262,80 450 | 449.0146449,69.7947214076247,80 451 | 450.0049252,69.8435972629521,80 452 | 451.0106016,70.039100684262,80 453 | 452.0008216,69.8435972629521,80 454 | 453.0047882,69.8924731182796,80 455 | 454.0043311,69.7458455522972,80 456 | 455.0110263,69.8435972629521,80 457 | 456.0085956,69.8435972629521,80 458 | 457.011811,69.7947214076246,80 459 | 458.0138078,69.7947214076246,80 460 | 459.0141548,69.9902248289345,80 461 | 460.0118718,70.039100684262,80 462 | 461.0036768,69.7458455522972,80 463 | 462.0105488,70.1368523949169,80 464 | 463.015185,69.6969696969697,80 465 | 464.0082825,69.5503421309873,80 466 | 465.0007698,69.5503421309873,80 467 | 466.0118721,69.9902248289345,80 468 | 467.0051126,69.5014662756598,80 469 | 468.0067529,69.4525904203324,80 470 | 469.0137506,69.5992179863147,80 471 | 470.0095426,69.6969696969697,80 472 | 471.007292,69.941348973607,80 473 | 472.0151144,69.5992179863148,80 474 | 473.0150334,69.8924731182796,80 475 | 474.0018495,69.6969696969697,80 476 | 475.0068088,69.9902248289345,80 477 | 476.0118635,70.039100684262,80 478 | 477.011564,70.0879765395894,80 479 | 478.0048029,69.8924731182796,80 480 | 479.0107067,69.8435972629521,80 481 | 480.0027025,70.039100684262,80 482 | 481.0039329,70.2346041055719,80 483 | 482.0097794,69.7947214076246,80 484 | 483.0028798,69.9413489736071,80 485 | 484.010554,70.2346041055719,80 486 | 485.0020699,70.2346041055718,80 487 | 486.0003797,70.1857282502444,80 488 | 487.0019048,70.1368523949169,80 489 | 488.0028778,70.4301075268817,80 490 | 489.0038265,70.3323558162268,80 491 | 490.0007176,70.3323558162268,80 492 | 491.0135326,70.1857282502444,80 493 | 492.0024801,70.4301075268817,80 494 | 493.0136949,70.1368523949169,80 495 | 494.0096661,70.1857282502444,80 496 | 495.0120083,69.8924731182796,80 497 | 496.001974,69.941348973607,80 498 | 497.0104495,70.1368523949169,80 499 | 498.0056776,70.2346041055719,80 500 | 499.0095906,70.0879765395894,80 501 | 500.014153,69.9902248289345,80 502 | 501.0063272,69.9902248289345,80 503 | 502.0128329,70.039100684262,80 504 | 503.0058794,69.941348973607,80 505 | 504.0016095,70.0879765395894,80 506 | 505.01144,70.2346041055719,80 507 | 506.0046192,70.039100684262,80 508 | 507.0098904,70.2346041055719,80 509 | 508.0021546,70.3323558162268,80 510 | 509.0136803,70.2346041055718,80 511 | 510.009968,70.2346041055719,80 512 | 511.0037902,70.2834799608993,80 513 | 512.0079354,70.4301075268817,80 514 | 513.0098059,70.3323558162268,80 515 | 514.001731,70.2834799608993,80 516 | 515.0117656,70.3323558162268,80 517 | 516.0136567,70.0879765395894,80 518 | 517.0114664,70.2834799608993,80 519 | 518.0053605,70.2834799608993,80 520 | 519.0097101,70.1368523949169,80 521 | 520.0026831,70.3323558162268,80 522 | 521.0096219,70.2834799608993,80 523 | 522.0066632,70.2834799608993,80 524 | 523.00691,70.1368523949169,80 525 | 524.0114686,70.3323558162268,80 526 | 525.0058153,70.2346041055718,80 527 | 526.0144288,70.5278592375367,80 528 | 527.0008479,70.4301075268817,80 529 | 528.0034156,70.1857282502444,80 530 | 529.0035734,70.3323558162268,80 531 | 530.002375,70.4789833822092,80 532 | 531.0043967,70.6256109481916,80 533 | 532.013895,70.3323558162268,80 534 | 533.0023103,70.3812316715543,80 535 | 534.0000447,70.4789833822092,80 536 | 535.0127741,70.2834799608993,80 537 | 536.0130721,70.3323558162268,80 538 | 537.0025644,70.3323558162268,80 539 | 538.0108916,70.2834799608993,80 540 | 539.0103784,70.5767350928641,80 541 | 540.0084717,70.5767350928641,80 542 | 541.0074407,70.6744868035191,80 543 | 542.0094364,70.4789833822092,80 544 | 543.0004183,70.6256109481916,80 545 | 544.0002598,70.7233626588465,80 546 | 545.0021414,70.772238514174,80 547 | 546.0041361,70.7233626588466,80 548 | 547.005765,70.4789833822092,80 549 | 548.0086629,70.5767350928641,80 550 | 549.0053374,70.6256109481916,80 551 | 550.0077302,70.2346041055719,80 552 | 551.0130911,70.039100684262,80 553 | 552.0139667,69.6969696969697,80 554 | 553.0058025,69.4037145650049,80 555 | 554.0067693,68.9149560117302,80 556 | 555.0077751,68.7194525904203,80 557 | 556.0138052,68.5239491691105,80 558 | 557.0097775,68.2795698924731,80 559 | 558.0096281,67.4975562072336,80 560 | 559.0047926,66.911045943304,80 561 | 560.0048111,66.7155425219941,80 562 | 561.0107019,66.6177908113392,80 563 | 562.0036019,66.0312805474096,80 564 | 563.0003259,66.080156402737,80 565 | 564.0006216,66.1290322580645,80 566 | 565.0025287,66.0312805474096,80 567 | 566.0074869,65.6402737047898,80 568 | 567.008463,65.6891495601173,80 569 | 568.0077793,65.44477028348,80 570 | 569.0054493,65.347018572825,80 571 | 570.0074937,65.347018572825,80 572 | 571.0000437,65.44477028348,80 573 | 572.0024933,65.2003910068426,80 574 | 573.0084582,64.7605083088954,80 575 | 574.001567,64.6627565982405,80 576 | 575.0147185,64.5650048875855,80 577 | 576.0052427,64.4672531769306,80 578 | 577.0056622,64.3206256109482,80 579 | 578.013603,64.0273704789834,80 580 | 579.0045873,63.880742913001,80 581 | 580.0131687,63.4897360703812,80 582 | 581.0046724,63.4408602150538,80 583 | 582.0094573,63.1476050830889,80 584 | 583.0057306,62.8543499511241,80 585 | 584.0055299,62.4633431085044,80 586 | 585.0106546,62.3655913978494,80 587 | 586.0055877,62.1212121212121,80 588 | 587.005086,61.7790811339199,80 589 | 588.0047653,61.6324535679374,80 590 | 589.0017011,61.4369501466276,80 591 | 590.0096894,61.0948191593353,80 592 | 591.0003612,61.3391984359726,80 593 | 592.0012874,61.0948191593353,80 594 | 593.0008926,60.9970674486803,80 595 | 594.0007349,60.5571847507331,80 596 | 595.0000785,60.4594330400782,80 597 | 596.003727,60.2150537634408,80 598 | 597.0015791,60.019550342131,80 599 | 598.0105706,59.921798631476,80 600 | 599.0048289,59.8240469208211,80 601 | -------------------------------------------------------------------------------- /L14/Simulink/arduino_lab1.m: -------------------------------------------------------------------------------- 1 | function TC = arduino_lab1(heater) 2 | 3 | persistent icount a 4 | 5 | if (isempty(icount)) 6 | % include tclab.m for initialization 7 | tclab; 8 | icount = 0; 9 | else 10 | % voltage read functions 11 | v1 = @() readVoltage(a, 'A0'); 12 | v2 = @() readVoltage(a, 'A2'); 13 | 14 | % temperature calculations as a function of voltage for TMP36 15 | TC = @(V) (V - 0.5)*100.0; % Celsius 16 | TK = @(V) TC(V) + 273.15; % Kelvin 17 | TF = @(V) TK(V) * 9.0/5.0 - 459.67; % Fahrenhiet 18 | 19 | % temperature read functions 20 | T1C = @() TC(v1()); 21 | T2C = @() TC(v2()); 22 | 23 | % LED function (0 <= level <= 1) 24 | led = @(level) writePWMDutyCycle(a,'D9',max(0,min(1,level))); % ON 25 | 26 | % heater output (0 <= heater <= 100) 27 | % 0 = 0 V and 100 = 5 V 28 | h1 = @(level) writePWMVoltage(a,'D3',max(0,min(100,level))/20); 29 | h2 = @(level) writePWMVoltage(a,'D5',max(0,min(100,level))/20); 30 | end 31 | 32 | % increment counter 33 | icount = icount + 1; 34 | 35 | % read temperature 36 | TC = T1C(); 37 | % write heater 38 | h1(heater); 39 | 40 | % indicate high temperature with LED 41 | if TC > 40 42 | led(1) 43 | else 44 | led(0) 45 | end 46 | 47 | end -------------------------------------------------------------------------------- /L14/Simulink/arduino_lab2.m: -------------------------------------------------------------------------------- 1 | function TC = arduino_lab2(heater) 2 | 3 | persistent icount a 4 | 5 | if (isempty(icount)) 6 | % include tclab.m for initialization 7 | tclab; 8 | icount = 0; 9 | else 10 | % voltage read functions 11 | v1 = @() readVoltage(a, 'A0'); 12 | v2 = @() readVoltage(a, 'A2'); 13 | 14 | % temperature calculations as a function of voltage for TMP36 15 | TC = @(V) (V - 0.5)*100.0; % Celsius 16 | TK = @(V) TC(V) + 273.15; % Kelvin 17 | TF = @(V) TK(V) * 9.0/5.0 - 459.67; % Fahrenhiet 18 | 19 | % temperature read functions 20 | T1C = @() TC(v1()); 21 | T2C = @() TC(v2()); 22 | 23 | % LED function (0 <= level <= 1) 24 | led = @(level) writePWMDutyCycle(a,'D9',max(0,min(1,level))); % ON 25 | 26 | % heater output (0 <= heater <= 100) 27 | % 0 = 0 V and 100 = 5 V 28 | h1 = @(level) writePWMVoltage(a,'D3',max(0,min(100,level))/20); 29 | h2 = @(level) writePWMVoltage(a,'D5',max(0,min(100,level))/20); 30 | end 31 | 32 | % increment counter 33 | icount = icount + 1; 34 | 35 | % read temperature 36 | TC = T2C(); 37 | % write heater 38 | h2(heater); 39 | 40 | % indicate high temperature with LED 41 | if TC > 40 42 | led(1) 43 | else 44 | led(0) 45 | end 46 | 47 | end -------------------------------------------------------------------------------- /L14/Simulink/arduino_ode.m: -------------------------------------------------------------------------------- 1 | function dTdt = arduino_ode(time,T,heater) 2 | 3 | % mass 4 | m = 4 / 1000; % kg (4 gm) 5 | % heat transfer coefficient 6 | U = 10; % W/m^2-K 7 | % surface area 8 | A = 12 / 100^2; % m^2 9 | % heater input 10 | c = 0.01; % W/(heater input, 0-100) 11 | % heat capacity 12 | Cp = 500.0; % J/kg-K 13 | % ambient temperature 14 | Ta = 23 + 273.15; % K 15 | 16 | % Stefan-Boltzmann constant 17 | sigma = 5.67e-8; % W/m^2-K^4 18 | eps = 0.9; % emisivity 19 | 20 | alpha = U * A / (m*Cp); 21 | beta = eps * sigma * A / (m*Cp); 22 | gamma = c / (m*Cp); 23 | delta = alpha + 3 * beta * Ta^3; 24 | %disp(['alpha: ' num2str(alpha)]) 25 | %disp(['delta: ' num2str(delta)]) 26 | % approximate gain 27 | gain = gamma / delta; 28 | %disp(['Gain: ' num2str(gain)]) 29 | % approximate time constant 30 | tau = 1/delta; 31 | %disp(['Time constant: ' num2str(tau)]) 32 | 33 | 34 | % Accumulation = Convective heat + Radiative heat + Heat generated 35 | dTdt = (U*A * (Ta - T) + ... 36 | sigma * eps * A * (Ta^4 - T^4) + ... 37 | c * heater) / (m*Cp); 38 | end -------------------------------------------------------------------------------- /L14/Simulink/arduino_pi.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L14/Simulink/arduino_pi.slx -------------------------------------------------------------------------------- /L14/Simulink/arduino_pi_R2014a.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L14/Simulink/arduino_pi_R2014a.slx -------------------------------------------------------------------------------- /L14/Simulink/arduino_sim.m: -------------------------------------------------------------------------------- 1 | function TC = arduino_sim(heater) 2 | 3 | persistent T0 icount 4 | 5 | if (isempty(icount)), 6 | % set initial condition 7 | T0 = 23+273.15; 8 | icount = 0; 9 | end 10 | 11 | % increment counter 12 | icount = icount + 1; 13 | time = [0,1]; 14 | [time,T] = ode15s(@(t,x)arduino_ode(t,x,heater),time,T0); 15 | TK = T(end); 16 | T0 = TK; 17 | 18 | noise = (rand()-0.5)*3.0; 19 | TC = TK - 273.15 + noise; 20 | 21 | end 22 | -------------------------------------------------------------------------------- /L14/Simulink/msfun_realtime_elapsed.m: -------------------------------------------------------------------------------- 1 | function msfun_realtime_elapsed(block) 2 | % Help for Writing Level-2 M-File S-Functions: 3 | % web([docroot '/toolbox/simulink/sfg/f7-67622.html'] 4 | % http://www.mathworks.com/access/helpdesk/help/toolbox/simulink/sfg/f7-67622.html 5 | 6 | % Copyright 2009, The MathWorks, Inc. 7 | 8 | % instance variables 9 | myRealTimeBaseline = 0; 10 | 11 | setup(block); 12 | 13 | %% --------------------------------------------------- 14 | function setup(block) 15 | % Register the number of ports. 16 | block.NumInputPorts = 0; 17 | block.NumOutputPorts = 1; 18 | 19 | block.SetPreCompOutPortInfoToDynamic; 20 | block.OutputPort(1).Dimensions = 1; 21 | block.OutputPort(1).SamplingMode = 'sample'; 22 | 23 | % Set up the states 24 | block.NumContStates = 0; 25 | block.NumDworks = 0; 26 | 27 | % Register the parameters. 28 | block.NumDialogPrms = 0; % scale factor 29 | 30 | % Block is fixed in minor time step, i.e., it is only executed on major 31 | % time steps. With a fixed-step solver, the block runs at the fastest 32 | % discrete rate. 33 | block.SampleTimes = [0 1]; 34 | 35 | block.SetAccelRunOnTLC(false); % run block in interpreted mode even w/ Acceleration 36 | 37 | % methods called at run-time 38 | block.RegBlockMethod('Start', @Start); 39 | block.RegBlockMethod('Outputs', @Output); 40 | block.RegBlockMethod('SimStatusChange', @SimStatusChange); 41 | end 42 | 43 | %% 44 | function Start(block) %#ok 45 | myRealTimeBaseline = tic; 46 | end 47 | 48 | %% 49 | function Output(block) 50 | block.OutputPort(1).Data = toc(myRealTimeBaseline); 51 | end 52 | 53 | %% 54 | function SimStatusChange(block, status) %#ok 55 | if status == 1, % resume 56 | myRealTimeBaseline = tic; 57 | end 58 | end 59 | 60 | end 61 | 62 | -------------------------------------------------------------------------------- /L14/Simulink/msfun_realtime_pacer.m: -------------------------------------------------------------------------------- 1 | function msfun_realtime_pacer(block) 2 | % Help for Writing Level-2 M-File S-Functions: 3 | % web([docroot '/toolbox/simulink/sfg/f7-67622.html'] 4 | % http://www.mathworks.com/access/helpdesk/help/toolbox/simulink/sfg/f7-67622.html 5 | 6 | % Copyright 2009, The MathWorks, Inc. 7 | 8 | % instance variables 9 | mySimTimePerRealTime = 1; 10 | myRealTimeBaseline = 0; 11 | mySimulationTimeBaseline = 0; 12 | myResetBaseline = true; 13 | myTotalBurnedTime = 0; 14 | myNumUpdates = 0; 15 | 16 | setup(block); 17 | 18 | %% --------------------------------------------------- 19 | function setup(block) 20 | % Register the number of ports. 21 | block.NumInputPorts = 0; 22 | block.NumOutputPorts = 0; 23 | 24 | % Set up the states 25 | block.NumContStates = 0; 26 | block.NumDworks = 0; 27 | 28 | % Register the parameters. 29 | block.NumDialogPrms = 1; % scale factor 30 | block.DialogPrmsTunable = {'Nontunable'}; 31 | 32 | % Block is fixed in minor time step, i.e., it is only executed on major 33 | % time steps. With a fixed-step solver, the block runs at the fastest 34 | % discrete rate. 35 | block.SampleTimes = [0 1]; 36 | 37 | block.SetAccelRunOnTLC(false); % run block in interpreted mode even w/ Acceleration 38 | 39 | % methods called during update diagram/compilation. 40 | block.RegBlockMethod('CheckParameters', @CheckPrms); 41 | 42 | % methods called at run-time 43 | block.RegBlockMethod('Start', @Start); 44 | block.RegBlockMethod('Update', @Update); 45 | block.RegBlockMethod('SimStatusChange', @SimStatusChange); 46 | block.RegBlockMethod('Terminate', @Terminate); 47 | end 48 | 49 | %% 50 | function CheckPrms(block) 51 | try 52 | validateattributes(block.DialogPrm(1).Data, {'double'},{'real', 'scalar', '>', 0}); 53 | catch %#ok 54 | throw(MSLException(block.BlockHandle, ... 55 | 'Simulink:Parameters:BlkParamUndefined', ... 56 | 'Enter a number greater than 0')); 57 | end 58 | end 59 | 60 | %% 61 | function Start(block) 62 | mySimTimePerRealTime = block.DialogPrm(1).Data; 63 | myTotalBurnedTime = 0; 64 | myNumUpdates = 0; 65 | myResetBaseline = true; 66 | if strcmp(pause('query'),'off') 67 | fprintf('%s: Enabling MATLAB PAUSE command\n', getfullname(block.BlockHandle)); 68 | pause('on'); 69 | end 70 | end 71 | 72 | %% 73 | function Update(block) 74 | if myResetBaseline 75 | myRealTimeBaseline = tic; 76 | mySimulationTimeBaseline = block.CurrentTime; 77 | myResetBaseline = false; 78 | else 79 | if isinf(mySimTimePerRealTime) 80 | return; 81 | end 82 | elapsedRealTime = toc(myRealTimeBaseline); 83 | differenceInSeconds = ((block.CurrentTime - mySimulationTimeBaseline) / mySimTimePerRealTime) - elapsedRealTime; 84 | if differenceInSeconds >= 0 85 | pause(differenceInSeconds); 86 | myTotalBurnedTime = myTotalBurnedTime + differenceInSeconds; 87 | myNumUpdates = myNumUpdates + 1; 88 | end 89 | end 90 | end 91 | 92 | %% 93 | function SimStatusChange(block, status) 94 | if status == 0, 95 | % simulation paused 96 | fprintf('%s: Pausing real time execution of the model (simulation time = %g sec)\n', ... 97 | getfullname(block.BlockHandle), block.CurrentTime); 98 | elseif status == 1 99 | % Simulation resumed 100 | fprintf('%s: Continuing real time execution of the model\n', ... 101 | getfullname(block.BlockHandle)); 102 | myResetBaseline = true; 103 | end 104 | end 105 | 106 | %% 107 | function Terminate(block) 108 | if myNumUpdates > 0 109 | fprintf('%s: Average idle real time per major time step = %g sec\n', ... 110 | getfullname(block.BlockHandle), myTotalBurnedTime / myNumUpdates); 111 | end 112 | end 113 | 114 | end 115 | 116 | -------------------------------------------------------------------------------- /L14/Simulink/realtime_pacer_lib.mdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L14/Simulink/realtime_pacer_lib.mdl -------------------------------------------------------------------------------- /L14/Simulink/slblocks.m: -------------------------------------------------------------------------------- 1 | function blkStruct = slblocks 2 | 3 | blkStruct.Name = 'Real-Time Pacer'; 4 | blkStruct.OpenFcn = 'realtime_pacer_lib'; 5 | blkStruct.MaskInitialization = ''; 6 | -------------------------------------------------------------------------------- /L14/Simulink/tclab.m: -------------------------------------------------------------------------------- 1 | % connect to Arduino 2 | try 3 | a = arduino; 4 | disp(a) 5 | catch 6 | warning('Unable to connect, user input required') 7 | disp('For Windows:') 8 | disp(' Open device manager, select "Ports (COM & LPT)"') 9 | disp(' Look for COM port of Arduino such as COM4') 10 | disp('For MacOS:') 11 | disp(' Open terminal and type: ls /dev/*.') 12 | disp(' Search for /dev/tty.usbmodem* or /dev/tty.usbserial*. The port number is *.') 13 | disp('For Linux') 14 | disp(' Open terminal and type: ls /dev/tty*') 15 | disp(' Search for /dev/ttyUSB* or /dev/ttyACM*. The port number is *.') 16 | disp('') 17 | com_port = input('Specify port (e.g. COM4 for Windows or /dev/ttyUSB0 for Linux): ','s'); 18 | a = arduino(com_port,'Uno'); 19 | disp(a) 20 | end 21 | 22 | % voltage read functions 23 | v1 = @() readVoltage(a, 'A0'); 24 | v2 = @() readVoltage(a, 'A2'); 25 | 26 | % temperature calculations as a function of voltage for TMP36 27 | TC = @(V) (V - 0.5)*100.0; % Celsius 28 | TK = @(V) TC(V) + 273.15; % Kelvin 29 | TF = @(V) TK(V) * 9.0/5.0 - 459.67; % Fahrenhiet 30 | 31 | % temperature read functions 32 | T1C = @() TC(v1()); 33 | T2C = @() TC(v2()); 34 | 35 | % LED function (0 <= level <= 1) 36 | led = @(level) writePWMDutyCycle(a,'D9',max(0,min(1,level))); % ON 37 | 38 | % heater output (0 <= heater <= 100) 39 | % limit to 0-0.9 (0-100%) 40 | h1 = @(level) writePWMDutyCycle(a,'D3',max(0,min(100,level))*0.9/100); 41 | % limit to 0-0.5 (0-100%) 42 | h2 = @(level) writePWMDutyCycle(a,'D5',max(0,min(100,level))*0.5/100); 43 | -------------------------------------------------------------------------------- /L14/slprj/modeladvisor/UpgradeAdv_/arduino_pi/ModelAdvisorData: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L14/slprj/modeladvisor/UpgradeAdv_/arduino_pi/ModelAdvisorData -------------------------------------------------------------------------------- /L14/slprj/sl_proj.tmw: -------------------------------------------------------------------------------- 1 | Simulink Coder project marker file. Please don't change it. 2 | slprjVersion: 10.5_091 -------------------------------------------------------------------------------- /L15/L15_Lesson-Assignment_temperatureControlCSTR.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L15/L15_Lesson-Assignment_temperatureControlCSTR.mlx -------------------------------------------------------------------------------- /L15/L15_Lesson_Assignment_temperatureControlCSTR.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L15/L15_Lesson_Assignment_temperatureControlCSTR.mlx -------------------------------------------------------------------------------- /L15/L15_TCLab_PIDTuning.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L15/L15_TCLab_PIDTuning.mlx -------------------------------------------------------------------------------- /L15/L15_TCLab_simulinkPIDTuning.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L15/L15_TCLab_simulinkPIDTuning.mlx -------------------------------------------------------------------------------- /L15/Simulink/arduino_lab1.m: -------------------------------------------------------------------------------- 1 | function TC = arduino_lab1(heater) 2 | 3 | persistent icount a 4 | 5 | if (isempty(icount)) 6 | % include tclab.m for initialization 7 | tclab; 8 | icount = 0; 9 | else 10 | % voltage read functions 11 | v1 = @() readVoltage(a, 'A0'); 12 | v2 = @() readVoltage(a, 'A2'); 13 | 14 | % temperature calculations as a function of voltage for TMP36 15 | TC = @(V) (V - 0.5)*100.0; % Celsius 16 | TK = @(V) TC(V) + 273.15; % Kelvin 17 | TF = @(V) TK(V) * 9.0/5.0 - 459.67; % Fahrenhiet 18 | 19 | % temperature read functions 20 | T1C = @() TC(v1()); 21 | T2C = @() TC(v2()); 22 | 23 | % LED function (0 <= level <= 1) 24 | led = @(level) writePWMDutyCycle(a,'D9',max(0,min(1,level))); % ON 25 | 26 | % heater output (0 <= heater <= 100) 27 | % 0 = 0 V and 100 = 5 V 28 | h1 = @(level) writePWMVoltage(a,'D3',max(0,min(100,level))/20); 29 | h2 = @(level) writePWMVoltage(a,'D5',max(0,min(100,level))/20); 30 | end 31 | 32 | % increment counter 33 | icount = icount + 1; 34 | 35 | % read temperature 36 | TC = T1C(); 37 | % write heater 38 | h1(heater); 39 | 40 | % indicate high temperature with LED 41 | if TC > 40 42 | led(1) 43 | else 44 | led(0) 45 | end 46 | 47 | end -------------------------------------------------------------------------------- /L15/Simulink/arduino_lab2.m: -------------------------------------------------------------------------------- 1 | function TC = arduino_lab2(heater) 2 | 3 | persistent icount a 4 | 5 | if (isempty(icount)) 6 | % include tclab.m for initialization 7 | tclab; 8 | icount = 0; 9 | else 10 | % voltage read functions 11 | v1 = @() readVoltage(a, 'A0'); 12 | v2 = @() readVoltage(a, 'A2'); 13 | 14 | % temperature calculations as a function of voltage for TMP36 15 | TC = @(V) (V - 0.5)*100.0; % Celsius 16 | TK = @(V) TC(V) + 273.15; % Kelvin 17 | TF = @(V) TK(V) * 9.0/5.0 - 459.67; % Fahrenhiet 18 | 19 | % temperature read functions 20 | T1C = @() TC(v1()); 21 | T2C = @() TC(v2()); 22 | 23 | % LED function (0 <= level <= 1) 24 | led = @(level) writePWMDutyCycle(a,'D9',max(0,min(1,level))); % ON 25 | 26 | % heater output (0 <= heater <= 100) 27 | % 0 = 0 V and 100 = 5 V 28 | h1 = @(level) writePWMVoltage(a,'D3',max(0,min(100,level))/20); 29 | h2 = @(level) writePWMVoltage(a,'D5',max(0,min(100,level))/20); 30 | end 31 | 32 | % increment counter 33 | icount = icount + 1; 34 | 35 | % read temperature 36 | TC = T2C(); 37 | % write heater 38 | h2(heater); 39 | 40 | % indicate high temperature with LED 41 | if TC > 40 42 | led(1) 43 | else 44 | led(0) 45 | end 46 | 47 | end -------------------------------------------------------------------------------- /L15/Simulink/arduino_ode.m: -------------------------------------------------------------------------------- 1 | function dTdt = arduino_ode(time,T,heater) 2 | 3 | % mass 4 | m = 4 / 1000; % kg (4 gm) 5 | % heat transfer coefficient 6 | U = 10; % W/m^2-K 7 | % surface area 8 | A = 12 / 100^2; % m^2 9 | % heater input 10 | c = 0.01; % W/(heater input, 0-100) 11 | % heat capacity 12 | Cp = 500.0; % J/kg-K 13 | % ambient temperature 14 | Ta = 23 + 273.15; % K 15 | 16 | % Stefan-Boltzmann constant 17 | sigma = 5.67e-8; % W/m^2-K^4 18 | eps = 0.9; % emisivity 19 | 20 | alpha = U * A / (m*Cp); 21 | beta = eps * sigma * A / (m*Cp); 22 | gamma = c / (m*Cp); 23 | delta = alpha + 3 * beta * Ta^3; 24 | %disp(['alpha: ' num2str(alpha)]) 25 | %disp(['delta: ' num2str(delta)]) 26 | % approximate gain 27 | gain = gamma / delta; 28 | %disp(['Gain: ' num2str(gain)]) 29 | % approximate time constant 30 | tau = 1/delta; 31 | %disp(['Time constant: ' num2str(tau)]) 32 | 33 | 34 | % Accumulation = Convective heat + Radiative heat + Heat generated 35 | dTdt = (U*A * (Ta - T) + ... 36 | sigma * eps * A * (Ta^4 - T^4) + ... 37 | c * heater) / (m*Cp); 38 | end -------------------------------------------------------------------------------- /L15/Simulink/arduino_pid.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L15/Simulink/arduino_pid.slx -------------------------------------------------------------------------------- /L15/Simulink/arduino_pid_R2014a.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L15/Simulink/arduino_pid_R2014a.slx -------------------------------------------------------------------------------- /L15/Simulink/arduino_sim.m: -------------------------------------------------------------------------------- 1 | function TC = arduino_sim(heater) 2 | 3 | persistent T0 icount 4 | 5 | if (isempty(icount)), 6 | % set initial condition 7 | T0 = 23+273.15; 8 | icount = 0; 9 | end 10 | 11 | % increment counter 12 | icount = icount + 1; 13 | time = [0,1]; 14 | [time,T] = ode15s(@(t,x)arduino_ode(t,x,heater),time,T0); 15 | TK = T(end); 16 | T0 = TK; 17 | 18 | noise = (rand()-0.5)*3.0; 19 | TC = TK - 273.15 + noise; 20 | 21 | end 22 | -------------------------------------------------------------------------------- /L15/Simulink/msfun_realtime_elapsed.m: -------------------------------------------------------------------------------- 1 | function msfun_realtime_elapsed(block) 2 | % Help for Writing Level-2 M-File S-Functions: 3 | % web([docroot '/toolbox/simulink/sfg/f7-67622.html'] 4 | % http://www.mathworks.com/access/helpdesk/help/toolbox/simulink/sfg/f7-67622.html 5 | 6 | % Copyright 2009, The MathWorks, Inc. 7 | 8 | % instance variables 9 | myRealTimeBaseline = 0; 10 | 11 | setup(block); 12 | 13 | %% --------------------------------------------------- 14 | function setup(block) 15 | % Register the number of ports. 16 | block.NumInputPorts = 0; 17 | block.NumOutputPorts = 1; 18 | 19 | block.SetPreCompOutPortInfoToDynamic; 20 | block.OutputPort(1).Dimensions = 1; 21 | block.OutputPort(1).SamplingMode = 'sample'; 22 | 23 | % Set up the states 24 | block.NumContStates = 0; 25 | block.NumDworks = 0; 26 | 27 | % Register the parameters. 28 | block.NumDialogPrms = 0; % scale factor 29 | 30 | % Block is fixed in minor time step, i.e., it is only executed on major 31 | % time steps. With a fixed-step solver, the block runs at the fastest 32 | % discrete rate. 33 | block.SampleTimes = [0 1]; 34 | 35 | block.SetAccelRunOnTLC(false); % run block in interpreted mode even w/ Acceleration 36 | 37 | % methods called at run-time 38 | block.RegBlockMethod('Start', @Start); 39 | block.RegBlockMethod('Outputs', @Output); 40 | block.RegBlockMethod('SimStatusChange', @SimStatusChange); 41 | end 42 | 43 | %% 44 | function Start(block) %#ok 45 | myRealTimeBaseline = tic; 46 | end 47 | 48 | %% 49 | function Output(block) 50 | block.OutputPort(1).Data = toc(myRealTimeBaseline); 51 | end 52 | 53 | %% 54 | function SimStatusChange(block, status) %#ok 55 | if status == 1, % resume 56 | myRealTimeBaseline = tic; 57 | end 58 | end 59 | 60 | end 61 | 62 | -------------------------------------------------------------------------------- /L15/Simulink/msfun_realtime_pacer.m: -------------------------------------------------------------------------------- 1 | function msfun_realtime_pacer(block) 2 | % Help for Writing Level-2 M-File S-Functions: 3 | % web([docroot '/toolbox/simulink/sfg/f7-67622.html'] 4 | % http://www.mathworks.com/access/helpdesk/help/toolbox/simulink/sfg/f7-67622.html 5 | 6 | % Copyright 2009, The MathWorks, Inc. 7 | 8 | % instance variables 9 | mySimTimePerRealTime = 1; 10 | myRealTimeBaseline = 0; 11 | mySimulationTimeBaseline = 0; 12 | myResetBaseline = true; 13 | myTotalBurnedTime = 0; 14 | myNumUpdates = 0; 15 | 16 | setup(block); 17 | 18 | %% --------------------------------------------------- 19 | function setup(block) 20 | % Register the number of ports. 21 | block.NumInputPorts = 0; 22 | block.NumOutputPorts = 0; 23 | 24 | % Set up the states 25 | block.NumContStates = 0; 26 | block.NumDworks = 0; 27 | 28 | % Register the parameters. 29 | block.NumDialogPrms = 1; % scale factor 30 | block.DialogPrmsTunable = {'Nontunable'}; 31 | 32 | % Block is fixed in minor time step, i.e., it is only executed on major 33 | % time steps. With a fixed-step solver, the block runs at the fastest 34 | % discrete rate. 35 | block.SampleTimes = [0 1]; 36 | 37 | block.SetAccelRunOnTLC(false); % run block in interpreted mode even w/ Acceleration 38 | 39 | % methods called during update diagram/compilation. 40 | block.RegBlockMethod('CheckParameters', @CheckPrms); 41 | 42 | % methods called at run-time 43 | block.RegBlockMethod('Start', @Start); 44 | block.RegBlockMethod('Update', @Update); 45 | block.RegBlockMethod('SimStatusChange', @SimStatusChange); 46 | block.RegBlockMethod('Terminate', @Terminate); 47 | end 48 | 49 | %% 50 | function CheckPrms(block) 51 | try 52 | validateattributes(block.DialogPrm(1).Data, {'double'},{'real', 'scalar', '>', 0}); 53 | catch %#ok 54 | throw(MSLException(block.BlockHandle, ... 55 | 'Simulink:Parameters:BlkParamUndefined', ... 56 | 'Enter a number greater than 0')); 57 | end 58 | end 59 | 60 | %% 61 | function Start(block) 62 | mySimTimePerRealTime = block.DialogPrm(1).Data; 63 | myTotalBurnedTime = 0; 64 | myNumUpdates = 0; 65 | myResetBaseline = true; 66 | if strcmp(pause('query'),'off') 67 | fprintf('%s: Enabling MATLAB PAUSE command\n', getfullname(block.BlockHandle)); 68 | pause('on'); 69 | end 70 | end 71 | 72 | %% 73 | function Update(block) 74 | if myResetBaseline 75 | myRealTimeBaseline = tic; 76 | mySimulationTimeBaseline = block.CurrentTime; 77 | myResetBaseline = false; 78 | else 79 | if isinf(mySimTimePerRealTime) 80 | return; 81 | end 82 | elapsedRealTime = toc(myRealTimeBaseline); 83 | differenceInSeconds = ((block.CurrentTime - mySimulationTimeBaseline) / mySimTimePerRealTime) - elapsedRealTime; 84 | if differenceInSeconds >= 0 85 | pause(differenceInSeconds); 86 | myTotalBurnedTime = myTotalBurnedTime + differenceInSeconds; 87 | myNumUpdates = myNumUpdates + 1; 88 | end 89 | end 90 | end 91 | 92 | %% 93 | function SimStatusChange(block, status) 94 | if status == 0, 95 | % simulation paused 96 | fprintf('%s: Pausing real time execution of the model (simulation time = %g sec)\n', ... 97 | getfullname(block.BlockHandle), block.CurrentTime); 98 | elseif status == 1 99 | % Simulation resumed 100 | fprintf('%s: Continuing real time execution of the model\n', ... 101 | getfullname(block.BlockHandle)); 102 | myResetBaseline = true; 103 | end 104 | end 105 | 106 | %% 107 | function Terminate(block) 108 | if myNumUpdates > 0 109 | fprintf('%s: Average idle real time per major time step = %g sec\n', ... 110 | getfullname(block.BlockHandle), myTotalBurnedTime / myNumUpdates); 111 | end 112 | end 113 | 114 | end 115 | 116 | -------------------------------------------------------------------------------- /L15/Simulink/realtime_pacer_lib.mdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L15/Simulink/realtime_pacer_lib.mdl -------------------------------------------------------------------------------- /L15/Simulink/slblocks.m: -------------------------------------------------------------------------------- 1 | function blkStruct = slblocks 2 | 3 | blkStruct.Name = 'Real-Time Pacer'; 4 | blkStruct.OpenFcn = 'realtime_pacer_lib'; 5 | blkStruct.MaskInitialization = ''; 6 | -------------------------------------------------------------------------------- /L15/Simulink/tclab.m: -------------------------------------------------------------------------------- 1 | % connect to Arduino 2 | try 3 | a = arduino; 4 | disp(a) 5 | catch 6 | warning('Unable to connect, user input required') 7 | disp('For Windows:') 8 | disp(' Open device manager, select "Ports (COM & LPT)"') 9 | disp(' Look for COM port of Arduino such as COM4') 10 | disp('For MacOS:') 11 | disp(' Open terminal and type: ls /dev/*.') 12 | disp(' Search for /dev/tty.usbmodem* or /dev/tty.usbserial*. The port number is *.') 13 | disp('For Linux') 14 | disp(' Open terminal and type: ls /dev/tty*') 15 | disp(' Search for /dev/ttyUSB* or /dev/ttyACM*. The port number is *.') 16 | disp('') 17 | com_port = input('Specify port (e.g. COM4 for Windows or /dev/ttyUSB0 for Linux): ','s'); 18 | a = arduino(com_port,'Uno'); 19 | disp(a) 20 | end 21 | 22 | % voltage read functions 23 | v1 = @() readVoltage(a, 'A0'); 24 | v2 = @() readVoltage(a, 'A2'); 25 | 26 | % temperature calculations as a function of voltage for TMP36 27 | TC = @(V) (V - 0.5)*100.0; % Celsius 28 | TK = @(V) TC(V) + 273.15; % Kelvin 29 | TF = @(V) TK(V) * 9.0/5.0 - 459.67; % Fahrenhiet 30 | 31 | % temperature read functions 32 | T1C = @() TC(v1()); 33 | T2C = @() TC(v2()); 34 | 35 | % LED function (0 <= level <= 1) 36 | led = @(level) writePWMDutyCycle(a,'D9',max(0,min(1,level))); % ON 37 | 38 | % heater output (0 <= heater <= 100) 39 | % limit to 0-0.9 (0-100%) 40 | h1 = @(level) writePWMDutyCycle(a,'D3',max(0,min(100,level))*0.9/100); 41 | % limit to 0-0.5 (0-100%) 42 | h2 = @(level) writePWMDutyCycle(a,'D5',max(0,min(100,level))*0.5/100); 43 | -------------------------------------------------------------------------------- /L16/L16_Lesson-Assignment_maintainGlucose.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L16/L16_Lesson-Assignment_maintainGlucose.mlx -------------------------------------------------------------------------------- /L16/L16_Lesson_Assignment_maintainGlucose.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L16/L16_Lesson_Assignment_maintainGlucose.mlx -------------------------------------------------------------------------------- /L16/L16_TCLab_PIDFeedforward.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L16/L16_TCLab_PIDFeedforward.mlx -------------------------------------------------------------------------------- /L17/L17_Assignment_valveDesign.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L17/L17_Assignment_valveDesign.mlx -------------------------------------------------------------------------------- /L17/L17_Lesson_ValveDesignForFlowControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L17/L17_Lesson_ValveDesignForFlowControl.mlx -------------------------------------------------------------------------------- /L17/L17_TCLab_TCLabActuator.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L17/L17_TCLab_TCLabActuator.mlx -------------------------------------------------------------------------------- /L18/L18_Assignment_sensorDesign.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L18/L18_Assignment_sensorDesign.mlx -------------------------------------------------------------------------------- /L18/L18_Lesson_SensorsAndDataAcquisition.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L18/L18_Lesson_SensorsAndDataAcquisition.mlx -------------------------------------------------------------------------------- /L18/L18_TCLab_TemperatureSensor.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L18/L18_TCLab_TemperatureSensor.mlx -------------------------------------------------------------------------------- /L21/Arduino_lab_rubric.pdf: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L21/Arduino_lab_rubric.pdf -------------------------------------------------------------------------------- /L21/L21_TCLabProject_singleTemperatureModeling.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L21/L21_TCLabProject_singleTemperatureModeling.mlx -------------------------------------------------------------------------------- /L21/L21_TCLabProject_twoTemperatureModeling.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L21/L21_TCLabProject_twoTemperatureModeling.mlx -------------------------------------------------------------------------------- /L22/L22_TCLabProject_singleParameterRegression.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L22/L22_TCLabProject_singleParameterRegression.mlx -------------------------------------------------------------------------------- /L22/L22_TCLabProject_twoParameterRegression.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L22/L22_TCLabProject_twoParameterRegression.mlx -------------------------------------------------------------------------------- /L23/L23_TCLabProject_createPID.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L23/L23_TCLabProject_createPID.mlx -------------------------------------------------------------------------------- /L23/L23_TCLabProject_interactingPIDControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L23/L23_TCLabProject_interactingPIDControl.mlx -------------------------------------------------------------------------------- /L23/SIMULINK/arduino_lab.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L23/SIMULINK/arduino_lab.slx -------------------------------------------------------------------------------- /L23/SIMULINK/arduino_lab1.m: -------------------------------------------------------------------------------- 1 | function TC = arduino_lab1(heater) 2 | 3 | persistent icount a 4 | 5 | if (isempty(icount)) 6 | try 7 | a = arduino; 8 | disp(a) 9 | catch 10 | warning('Unable to connect, user input required') 11 | disp('For Windows:') 12 | disp(' Open device manager, select "Ports (COM & LPT)"') 13 | disp(' Look for COM port of Arduino such as COM4') 14 | disp('For MacOS:') 15 | disp(' Open terminal and type: ls /dev/*.') 16 | disp(' Search for /dev/tty.usbmodem* or /dev/tty.usbserial*. The port number is *.') 17 | disp('For Linux') 18 | disp(' Open terminal and type: ls /dev/tty*') 19 | disp(' Search for /dev/ttyUSB* or /dev/ttyACM*. The port number is *.') 20 | disp('') 21 | com_port = input('Specify port (e.g. COM4 for Windows or /dev/ttyUSB0 for Linux): ','s'); 22 | a = arduino(com_port,'Uno'); 23 | disp(a) 24 | end 25 | icount = 0; 26 | end 27 | 28 | % voltage read functions 29 | v1 = @() readVoltage(a, 'A0'); 30 | v2 = @() readVoltage(a, 'A2'); 31 | 32 | % temperature calculations as a function of voltage for TMP36 33 | TC = @(V) (V - 0.5)*100.0; % Celsius 34 | TK = @(V) TC(V) + 273.15; % Kelvin 35 | TF = @(V) TK(V) * 9.0/5.0 - 459.67; % Fahrenheit 36 | 37 | % temperature read functions 38 | T1C = @() TC(v1()); 39 | T2C = @() TC(v2()); 40 | 41 | % LED function (0 <= level <= 1) 42 | led = @(level) writePWMDutyCycle(a,'D9',max(0,min(1,level))); % ON 43 | 44 | % heater output (0 <= heater <= 100) 45 | % limit to 0-0.9 (0-100%) 46 | h1 = @(level) writePWMDutyCycle(a,'D3',max(0,min(100,level))*0.9/100); 47 | % limit to 0-0.5 (0-100%) 48 | h2 = @(level) writePWMDutyCycle(a,'D5',max(0,min(100,level))*0.5/100); 49 | 50 | % increment counter 51 | icount = icount + 1; 52 | 53 | % read temperature 54 | TC = T1C(); 55 | % write heater 56 | h1(heater); 57 | 58 | % indicate high temperature with LED 59 | if TC > 40 60 | led(1) 61 | else 62 | led(0) 63 | end 64 | 65 | end -------------------------------------------------------------------------------- /L23/SIMULINK/arduino_lab2.m: -------------------------------------------------------------------------------- 1 | function TC = arduino_lab2(heater) 2 | 3 | persistent icount a 4 | 5 | if (isempty(icount)) 6 | try 7 | a = arduino; 8 | disp(a) 9 | catch 10 | warning('Unable to connect, user input required') 11 | disp('For Windows:') 12 | disp(' Open device manager, select "Ports (COM & LPT)"') 13 | disp(' Look for COM port of Arduino such as COM4') 14 | disp('For MacOS:') 15 | disp(' Open terminal and type: ls /dev/*.') 16 | disp(' Search for /dev/tty.usbmodem* or /dev/tty.usbserial*. The port number is *.') 17 | disp('For Linux') 18 | disp(' Open terminal and type: ls /dev/tty*') 19 | disp(' Search for /dev/ttyUSB* or /dev/ttyACM*. The port number is *.') 20 | disp('') 21 | com_port = input('Specify port (e.g. COM4 for Windows or /dev/ttyUSB0 for Linux): ','s'); 22 | a = arduino(com_port,'Uno'); 23 | disp(a) 24 | end 25 | icount = 0; 26 | end 27 | 28 | % voltage read functions 29 | v1 = @() readVoltage(a, 'A0'); 30 | v2 = @() readVoltage(a, 'A2'); 31 | 32 | % temperature calculations as a function of voltage for TMP36 33 | TC = @(V) (V - 0.5)*100.0; % Celsius 34 | TK = @(V) TC(V) + 273.15; % Kelvin 35 | TF = @(V) TK(V) * 9.0/5.0 - 459.67; % Fahrenheit 36 | 37 | % temperature read functions 38 | T1C = @() TC(v1()); 39 | T2C = @() TC(v2()); 40 | 41 | % LED function (0 <= level <= 1) 42 | led = @(level) writePWMDutyCycle(a,'D9',max(0,min(1,level))); % ON 43 | 44 | % heater output (0 <= heater <= 100) 45 | % limit to 0-0.9 (0-100%) 46 | h1 = @(level) writePWMDutyCycle(a,'D3',max(0,min(100,level))*0.9/100); 47 | % limit to 0-0.5 (0-100%) 48 | h2 = @(level) writePWMDutyCycle(a,'D5',max(0,min(100,level))*0.5/100); 49 | 50 | % increment counter 51 | icount = icount + 1; 52 | 53 | % read temperature 54 | TC = T2C(); 55 | % write heater 56 | h2(heater); 57 | 58 | % indicate high temperature with LED 59 | if TC > 40 60 | led(1) 61 | else 62 | led(0) 63 | end 64 | 65 | end -------------------------------------------------------------------------------- /L23/SIMULINK/arduino_lab_R2014a.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L23/SIMULINK/arduino_lab_R2014a.slx -------------------------------------------------------------------------------- /L23/SIMULINK/arduino_lab_R2016a.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L23/SIMULINK/arduino_lab_R2016a.slx -------------------------------------------------------------------------------- /L23/SIMULINK/arduino_ode.m: -------------------------------------------------------------------------------- 1 | function dTdt = arduino_ode(time,T,heater) 2 | 3 | % mass 4 | m = 0.001; % kg (2 gm) 5 | % heat transfer coefficient 6 | h = 200; % W/m^2-K 7 | % surface area 8 | A = 2 / 100^2; % m^2 9 | % heater input 10 | alpha = 0.022; % W/(heater input) 11 | % heat capacity 12 | Cp = 4900.0; % J/kg-K 13 | 14 | % approximate time constant 15 | %tau = m*Cp/(h*A); 16 | %disp(['Time constant: ' num2str(tau)]) 17 | 18 | % ambient temperature 19 | Ta = 23 + 273.15; % K 20 | heater = 100; 21 | dTdt = (h*A * (Ta - T) + alpha * heater) / (m*Cp); 22 | 23 | end -------------------------------------------------------------------------------- /L23/SIMULINK/arduino_sim.m: -------------------------------------------------------------------------------- 1 | function TC = arduino_sim(heater) 2 | 3 | persistent T0 icount 4 | 5 | if (isempty(icount)), 6 | % set initial condition 7 | T0 = 23+273.15; 8 | icount = 0; 9 | end 10 | 11 | % increment counter 12 | icount = icount + 1; 13 | time = [0,1]; 14 | [time,T] = ode15s(@(t,x)arduino_ode(t,x,heater),time,T0); 15 | TK = T(end); 16 | T0 = TK; 17 | 18 | noise = (rand()-0.5)*3.0; 19 | TC = TK - 273.15 + noise; 20 | 21 | end 22 | -------------------------------------------------------------------------------- /L23/SIMULINK/msfun_realtime_elapsed.m: -------------------------------------------------------------------------------- 1 | function msfun_realtime_elapsed(block) 2 | % Help for Writing Level-2 M-File S-Functions: 3 | % web([docroot '/toolbox/simulink/sfg/f7-67622.html'] 4 | % http://www.mathworks.com/access/helpdesk/help/toolbox/simulink/sfg/f7-67622.html 5 | 6 | % Copyright 2009, The MathWorks, Inc. 7 | 8 | % instance variables 9 | myRealTimeBaseline = 0; 10 | 11 | setup(block); 12 | 13 | %% --------------------------------------------------- 14 | function setup(block) 15 | % Register the number of ports. 16 | block.NumInputPorts = 0; 17 | block.NumOutputPorts = 1; 18 | 19 | block.SetPreCompOutPortInfoToDynamic; 20 | block.OutputPort(1).Dimensions = 1; 21 | block.OutputPort(1).SamplingMode = 'sample'; 22 | 23 | % Set up the states 24 | block.NumContStates = 0; 25 | block.NumDworks = 0; 26 | 27 | % Register the parameters. 28 | block.NumDialogPrms = 0; % scale factor 29 | 30 | % Block is fixed in minor time step, i.e., it is only executed on major 31 | % time steps. With a fixed-step solver, the block runs at the fastest 32 | % discrete rate. 33 | block.SampleTimes = [0 1]; 34 | 35 | block.SetAccelRunOnTLC(false); % run block in interpreted mode even w/ Acceleration 36 | 37 | % methods called at run-time 38 | block.RegBlockMethod('Start', @Start); 39 | block.RegBlockMethod('Outputs', @Output); 40 | block.RegBlockMethod('SimStatusChange', @SimStatusChange); 41 | end 42 | 43 | %% 44 | function Start(block) %#ok 45 | myRealTimeBaseline = tic; 46 | end 47 | 48 | %% 49 | function Output(block) 50 | block.OutputPort(1).Data = toc(myRealTimeBaseline); 51 | end 52 | 53 | %% 54 | function SimStatusChange(block, status) %#ok 55 | if status == 1, % resume 56 | myRealTimeBaseline = tic; 57 | end 58 | end 59 | 60 | end 61 | 62 | -------------------------------------------------------------------------------- /L23/SIMULINK/msfun_realtime_pacer.m: -------------------------------------------------------------------------------- 1 | function msfun_realtime_pacer(block) 2 | % Help for Writing Level-2 M-File S-Functions: 3 | % web([docroot '/toolbox/simulink/sfg/f7-67622.html'] 4 | % http://www.mathworks.com/access/helpdesk/help/toolbox/simulink/sfg/f7-67622.html 5 | 6 | % Copyright 2009, The MathWorks, Inc. 7 | 8 | % instance variables 9 | mySimTimePerRealTime = 1; 10 | myRealTimeBaseline = 0; 11 | mySimulationTimeBaseline = 0; 12 | myResetBaseline = true; 13 | myTotalBurnedTime = 0; 14 | myNumUpdates = 0; 15 | 16 | setup(block); 17 | 18 | %% --------------------------------------------------- 19 | function setup(block) 20 | % Register the number of ports. 21 | block.NumInputPorts = 0; 22 | block.NumOutputPorts = 0; 23 | 24 | % Set up the states 25 | block.NumContStates = 0; 26 | block.NumDworks = 0; 27 | 28 | % Register the parameters. 29 | block.NumDialogPrms = 1; % scale factor 30 | block.DialogPrmsTunable = {'Nontunable'}; 31 | 32 | % Block is fixed in minor time step, i.e., it is only executed on major 33 | % time steps. With a fixed-step solver, the block runs at the fastest 34 | % discrete rate. 35 | block.SampleTimes = [0 1]; 36 | 37 | block.SetAccelRunOnTLC(false); % run block in interpreted mode even w/ Acceleration 38 | 39 | % methods called during update diagram/compilation. 40 | block.RegBlockMethod('CheckParameters', @CheckPrms); 41 | 42 | % methods called at run-time 43 | block.RegBlockMethod('Start', @Start); 44 | block.RegBlockMethod('Update', @Update); 45 | block.RegBlockMethod('SimStatusChange', @SimStatusChange); 46 | block.RegBlockMethod('Terminate', @Terminate); 47 | end 48 | 49 | %% 50 | function CheckPrms(block) 51 | try 52 | validateattributes(block.DialogPrm(1).Data, {'double'},{'real', 'scalar', '>', 0}); 53 | catch %#ok 54 | throw(MSLException(block.BlockHandle, ... 55 | 'Simulink:Parameters:BlkParamUndefined', ... 56 | 'Enter a number greater than 0')); 57 | end 58 | end 59 | 60 | %% 61 | function Start(block) 62 | mySimTimePerRealTime = block.DialogPrm(1).Data; 63 | myTotalBurnedTime = 0; 64 | myNumUpdates = 0; 65 | myResetBaseline = true; 66 | if strcmp(pause('query'),'off') 67 | fprintf('%s: Enabling MATLAB PAUSE command\n', getfullname(block.BlockHandle)); 68 | pause('on'); 69 | end 70 | end 71 | 72 | %% 73 | function Update(block) 74 | if myResetBaseline 75 | myRealTimeBaseline = tic; 76 | mySimulationTimeBaseline = block.CurrentTime; 77 | myResetBaseline = false; 78 | else 79 | if isinf(mySimTimePerRealTime) 80 | return; 81 | end 82 | elapsedRealTime = toc(myRealTimeBaseline); 83 | differenceInSeconds = ((block.CurrentTime - mySimulationTimeBaseline) / mySimTimePerRealTime) - elapsedRealTime; 84 | if differenceInSeconds >= 0 85 | pause(differenceInSeconds); 86 | myTotalBurnedTime = myTotalBurnedTime + differenceInSeconds; 87 | myNumUpdates = myNumUpdates + 1; 88 | end 89 | end 90 | end 91 | 92 | %% 93 | function SimStatusChange(block, status) 94 | if status == 0, 95 | % simulation paused 96 | fprintf('%s: Pausing real time execution of the model (simulation time = %g sec)\n', ... 97 | getfullname(block.BlockHandle), block.CurrentTime); 98 | elseif status == 1 99 | % Simulation resumed 100 | fprintf('%s: Continuing real time execution of the model\n', ... 101 | getfullname(block.BlockHandle)); 102 | myResetBaseline = true; 103 | end 104 | end 105 | 106 | %% 107 | function Terminate(block) 108 | if myNumUpdates > 0 109 | fprintf('%s: Average idle real time per major time step = %g sec\n', ... 110 | getfullname(block.BlockHandle), myTotalBurnedTime / myNumUpdates); 111 | end 112 | end 113 | 114 | end 115 | 116 | -------------------------------------------------------------------------------- /L23/SIMULINK/realtime_pacer_lib.mdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L23/SIMULINK/realtime_pacer_lib.mdl -------------------------------------------------------------------------------- /L23/SIMULINK/slblocks.m: -------------------------------------------------------------------------------- 1 | function blkStruct = slblocks 2 | 3 | blkStruct.Name = 'Real-Time Pacer'; 4 | blkStruct.OpenFcn = 'realtime_pacer_lib'; 5 | blkStruct.MaskInitialization = ''; 6 | -------------------------------------------------------------------------------- /L23/SIMULINK/tclab.m: -------------------------------------------------------------------------------- 1 | % connect to Arduino 2 | try 3 | a = arduino; 4 | disp(a) 5 | catch 6 | warning('Unable to connect, user input required') 7 | disp('For Windows:') 8 | disp(' Open device manager, select "Ports (COM & LPT)"') 9 | disp(' Look for COM port of Arduino such as COM4') 10 | disp('For MacOS:') 11 | disp(' Open terminal and type: ls /dev/*.') 12 | disp(' Search for /dev/tty.usbmodem* or /dev/tty.usbserial*. The port number is *.') 13 | disp('For Linux') 14 | disp(' Open terminal and type: ls /dev/tty*') 15 | disp(' Search for /dev/ttyUSB* or /dev/ttyACM*. The port number is *.') 16 | disp('') 17 | com_port = input('Specify port (e.g. COM4 for Windows or /dev/ttyUSB0 for Linux): ','s'); 18 | a = arduino(com_port,'Uno'); 19 | disp(a) 20 | end 21 | 22 | % voltage read functions 23 | v1 = @() readVoltage(a, 'A0'); 24 | v2 = @() readVoltage(a, 'A2'); 25 | 26 | % temperature calculations as a function of voltage for TMP36 27 | TC = @(V) (V - 0.5)*100.0; % Celsius 28 | TK = @(V) TC(V) + 273.15; % Kelvin 29 | TF = @(V) TK(V) * 9.0/5.0 - 459.67; % Fahrenhiet 30 | 31 | % temperature read functions 32 | T1C = @() TC(v1()); 33 | T2C = @() TC(v2()); 34 | 35 | % LED function (0 <= level <= 1) 36 | led = @(level) writePWMDutyCycle(a,'D9',max(0,min(1,level))); % ON 37 | 38 | % heater output (0 <= heater <= 100) 39 | % 0 = 0 V and 100 = 5 V 40 | h1 = @(level) writePWMVoltage(a,'D3',max(0,min(100,level))/20); 41 | h2 = @(level) writePWMVoltage(a,'D5',max(0,min(100,level))/20); 42 | -------------------------------------------------------------------------------- /L24/L24_Assignment_laplaceApplications.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L24/L24_Assignment_laplaceApplications.mlx -------------------------------------------------------------------------------- /L24/L24_Lesson_LaplaceTransform.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L24/L24_Lesson_LaplaceTransform.mlx -------------------------------------------------------------------------------- /L24/L24_TCLab_impulseResponse.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L24/L24_TCLab_impulseResponse.mlx -------------------------------------------------------------------------------- /L25/L25_Assignment_blockDiagrams.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L25/L25_Assignment_blockDiagrams.mlx -------------------------------------------------------------------------------- /L25/L25_Lesson_transferFunctions.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L25/L25_Lesson_transferFunctions.mlx -------------------------------------------------------------------------------- /L25/L25_TCLab_blockDiagram.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L25/L25_TCLab_blockDiagram.mlx -------------------------------------------------------------------------------- /L26/L26_Assignment_stateSpaceStirredReactor.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L26/L26_Assignment_stateSpaceStirredReactor.mlx -------------------------------------------------------------------------------- /L26/L26_Lesson_StateSpaceModels.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L26/L26_Lesson_StateSpaceModels.mlx -------------------------------------------------------------------------------- /L26/L26_TCLab_stateSpaceModels.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L26/L26_TCLab_stateSpaceModels.mlx -------------------------------------------------------------------------------- /L27/L27_Assignment_secondOrderEstimation.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L27/L27_Assignment_secondOrderEstimation.mlx -------------------------------------------------------------------------------- /L27/L27_Lesson_SecondOrderSystemsWithGraphicalFit.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L27/L27_Lesson_SecondOrderSystemsWithGraphicalFit.mlx -------------------------------------------------------------------------------- /L27/L27_TCLab_OnOffControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L27/L27_TCLab_OnOffControl.mlx -------------------------------------------------------------------------------- /L27/L27_TCLab_simulinkOnOffControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L27/L27_TCLab_simulinkOnOffControl.mlx -------------------------------------------------------------------------------- /L27/Simulink/On_Off_Control.PNG: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L27/Simulink/On_Off_Control.PNG -------------------------------------------------------------------------------- /L27/Simulink/On_Off_Control.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L27/Simulink/On_Off_Control.slx -------------------------------------------------------------------------------- /L27/Simulink/arduino_lab.m: -------------------------------------------------------------------------------- 1 | function TC = arduino_lab(heater) 2 | 3 | persistent icount a 4 | 5 | if (isempty(icount)) 6 | % include tclab.m for initialization 7 | tclab; 8 | icount = 0; 9 | else 10 | % voltage read functions 11 | v1 = @() readVoltage(a, 'A0'); 12 | v2 = @() readVoltage(a, 'A2'); 13 | 14 | % temperature calculations as a function of voltage for TMP36 15 | TC = @(V) (V - 0.5)*100.0; % Celsius 16 | TK = @(V) TC(V) + 273.15; % Kelvin 17 | TF = @(V) TK(V) * 9.0/5.0 - 459.67; % Fahrenhiet 18 | 19 | % temperature read functions 20 | T1C = @() TC(v1()); 21 | T2C = @() TC(v2()); 22 | 23 | % LED function (0 <= level <= 1) 24 | led = @(level) writePWMDutyCycle(a,'D9',max(0,min(1,level))); % ON 25 | 26 | % heater output (0 <= heater <= 100) 27 | % 0 = 0 V and 100 = 5 V 28 | h1 = @(level) writePWMVoltage(a,'D3',max(0,min(100,level))/20); 29 | h2 = @(level) writePWMVoltage(a,'D5',max(0,min(100,level))/20); 30 | end 31 | 32 | % increment counter 33 | icount = icount + 1; 34 | 35 | % read temperature 36 | TC = T1C(); 37 | % write heater 38 | h1(heater); 39 | 40 | % indicate high temperature with LED 41 | if TC > 40 42 | led(1) 43 | else 44 | led(0) 45 | end 46 | 47 | end -------------------------------------------------------------------------------- /L27/Simulink/msfun_realtime_elapsed.m: -------------------------------------------------------------------------------- 1 | function msfun_realtime_elapsed(block) 2 | % Help for Writing Level-2 M-File S-Functions: 3 | % web([docroot '/toolbox/simulink/sfg/f7-67622.html'] 4 | % http://www.mathworks.com/access/helpdesk/help/toolbox/simulink/sfg/f7-67622.html 5 | 6 | % Copyright 2009, The MathWorks, Inc. 7 | 8 | % instance variables 9 | myRealTimeBaseline = 0; 10 | 11 | setup(block); 12 | 13 | %% --------------------------------------------------- 14 | function setup(block) 15 | % Register the number of ports. 16 | block.NumInputPorts = 0; 17 | block.NumOutputPorts = 1; 18 | 19 | block.SetPreCompOutPortInfoToDynamic; 20 | block.OutputPort(1).Dimensions = 1; 21 | block.OutputPort(1).SamplingMode = 'sample'; 22 | 23 | % Set up the states 24 | block.NumContStates = 0; 25 | block.NumDworks = 0; 26 | 27 | % Register the parameters. 28 | block.NumDialogPrms = 0; % scale factor 29 | 30 | % Block is fixed in minor time step, i.e., it is only executed on major 31 | % time steps. With a fixed-step solver, the block runs at the fastest 32 | % discrete rate. 33 | block.SampleTimes = [0 1]; 34 | 35 | block.SetAccelRunOnTLC(false); % run block in interpreted mode even w/ Acceleration 36 | 37 | % methods called at run-time 38 | block.RegBlockMethod('Start', @Start); 39 | block.RegBlockMethod('Outputs', @Output); 40 | block.RegBlockMethod('SimStatusChange', @SimStatusChange); 41 | end 42 | 43 | %% 44 | function Start(block) %#ok 45 | myRealTimeBaseline = tic; 46 | end 47 | 48 | %% 49 | function Output(block) 50 | block.OutputPort(1).Data = toc(myRealTimeBaseline); 51 | end 52 | 53 | %% 54 | function SimStatusChange(block, status) %#ok 55 | if status == 1, % resume 56 | myRealTimeBaseline = tic; 57 | end 58 | end 59 | 60 | end 61 | 62 | -------------------------------------------------------------------------------- /L27/Simulink/msfun_realtime_pacer.m: -------------------------------------------------------------------------------- 1 | function msfun_realtime_pacer(block) 2 | % Help for Writing Level-2 M-File S-Functions: 3 | % web([docroot '/toolbox/simulink/sfg/f7-67622.html'] 4 | % http://www.mathworks.com/access/helpdesk/help/toolbox/simulink/sfg/f7-67622.html 5 | 6 | % Copyright 2009, The MathWorks, Inc. 7 | 8 | % instance variables 9 | mySimTimePerRealTime = 1; 10 | myRealTimeBaseline = 0; 11 | mySimulationTimeBaseline = 0; 12 | myResetBaseline = true; 13 | myTotalBurnedTime = 0; 14 | myNumUpdates = 0; 15 | 16 | setup(block); 17 | 18 | %% --------------------------------------------------- 19 | function setup(block) 20 | % Register the number of ports. 21 | block.NumInputPorts = 0; 22 | block.NumOutputPorts = 0; 23 | 24 | % Set up the states 25 | block.NumContStates = 0; 26 | block.NumDworks = 0; 27 | 28 | % Register the parameters. 29 | block.NumDialogPrms = 1; % scale factor 30 | block.DialogPrmsTunable = {'Nontunable'}; 31 | 32 | % Block is fixed in minor time step, i.e., it is only executed on major 33 | % time steps. With a fixed-step solver, the block runs at the fastest 34 | % discrete rate. 35 | block.SampleTimes = [0 1]; 36 | 37 | block.SetAccelRunOnTLC(false); % run block in interpreted mode even w/ Acceleration 38 | 39 | % methods called during update diagram/compilation. 40 | block.RegBlockMethod('CheckParameters', @CheckPrms); 41 | 42 | % methods called at run-time 43 | block.RegBlockMethod('Start', @Start); 44 | block.RegBlockMethod('Update', @Update); 45 | block.RegBlockMethod('SimStatusChange', @SimStatusChange); 46 | block.RegBlockMethod('Terminate', @Terminate); 47 | end 48 | 49 | %% 50 | function CheckPrms(block) 51 | try 52 | validateattributes(block.DialogPrm(1).Data, {'double'},{'real', 'scalar', '>', 0}); 53 | catch %#ok 54 | throw(MSLException(block.BlockHandle, ... 55 | 'Simulink:Parameters:BlkParamUndefined', ... 56 | 'Enter a number greater than 0')); 57 | end 58 | end 59 | 60 | %% 61 | function Start(block) 62 | mySimTimePerRealTime = block.DialogPrm(1).Data; 63 | myTotalBurnedTime = 0; 64 | myNumUpdates = 0; 65 | myResetBaseline = true; 66 | if strcmp(pause('query'),'off') 67 | fprintf('%s: Enabling MATLAB PAUSE command\n', getfullname(block.BlockHandle)); 68 | pause('on'); 69 | end 70 | end 71 | 72 | %% 73 | function Update(block) 74 | if myResetBaseline 75 | myRealTimeBaseline = tic; 76 | mySimulationTimeBaseline = block.CurrentTime; 77 | myResetBaseline = false; 78 | else 79 | if isinf(mySimTimePerRealTime) 80 | return; 81 | end 82 | elapsedRealTime = toc(myRealTimeBaseline); 83 | differenceInSeconds = ((block.CurrentTime - mySimulationTimeBaseline) / mySimTimePerRealTime) - elapsedRealTime; 84 | if differenceInSeconds >= 0 85 | pause(differenceInSeconds); 86 | myTotalBurnedTime = myTotalBurnedTime + differenceInSeconds; 87 | myNumUpdates = myNumUpdates + 1; 88 | end 89 | end 90 | end 91 | 92 | %% 93 | function SimStatusChange(block, status) 94 | if status == 0, 95 | % simulation paused 96 | fprintf('%s: Pausing real time execution of the model (simulation time = %g sec)\n', ... 97 | getfullname(block.BlockHandle), block.CurrentTime); 98 | elseif status == 1 99 | % Simulation resumed 100 | fprintf('%s: Continuing real time execution of the model\n', ... 101 | getfullname(block.BlockHandle)); 102 | myResetBaseline = true; 103 | end 104 | end 105 | 106 | %% 107 | function Terminate(block) 108 | if myNumUpdates > 0 109 | fprintf('%s: Average idle real time per major time step = %g sec\n', ... 110 | getfullname(block.BlockHandle), myTotalBurnedTime / myNumUpdates); 111 | end 112 | end 113 | 114 | end 115 | 116 | -------------------------------------------------------------------------------- /L27/Simulink/realtime_pacer_lib.mdl: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L27/Simulink/realtime_pacer_lib.mdl -------------------------------------------------------------------------------- /L27/Simulink/slblocks.m: -------------------------------------------------------------------------------- 1 | function blkStruct = slblocks 2 | 3 | blkStruct.Name = 'Real-Time Pacer'; 4 | blkStruct.OpenFcn = 'realtime_pacer_lib'; 5 | blkStruct.MaskInitialization = ''; 6 | -------------------------------------------------------------------------------- /L27/Simulink/tclab.m: -------------------------------------------------------------------------------- 1 | % connect to Arduino 2 | try 3 | a = arduino; 4 | disp(a) 5 | catch 6 | warning('Unable to connect, user input required') 7 | disp('For Windows:') 8 | disp(' Open device manager, select "Ports (COM & LPT)"') 9 | disp(' Look for COM port of Arduino such as COM4') 10 | disp('For MacOS:') 11 | disp(' Open terminal and type: ls /dev/*.') 12 | disp(' Search for /dev/tty.usbmodem* or /dev/tty.usbserial*. The port number is *.') 13 | disp('For Linux') 14 | disp(' Open terminal and type: ls /dev/tty*') 15 | disp(' Search for /dev/ttyUSB* or /dev/ttyACM*. The port number is *.') 16 | disp('') 17 | com_port = input('Specify port (e.g. COM4 for Windows or /dev/ttyUSB0 for Linux): ','s'); 18 | a = arduino(com_port,'Uno'); 19 | disp(a) 20 | end 21 | 22 | % voltage read functions 23 | v1 = @() readVoltage(a, 'A0'); 24 | v2 = @() readVoltage(a, 'A2'); 25 | 26 | % temperature calculations as a function of voltage for TMP36 27 | TC = @(V) (V - 0.5)*100.0; % Celsius 28 | TK = @(V) TC(V) + 273.15; % Kelvin 29 | TF = @(V) TK(V) * 9.0/5.0 - 459.67; % Fahrenhiet 30 | 31 | % temperature read functions 32 | T1C = @() TC(v1()); 33 | T2C = @() TC(v2()); 34 | 35 | % LED function (0 <= level <= 1) 36 | led = @(level) writePWMDutyCycle(a,'D9',max(0,min(1,level))); % ON 37 | 38 | % heater output (0 <= heater <= 100) 39 | % 0 = 0 V and 100 = 5 V 40 | h1 = @(level) writePWMVoltage(a,'D3',max(0,min(100,level))/20); 41 | h2 = @(level) writePWMVoltage(a,'D5',max(0,min(100,level))/20); 42 | -------------------------------------------------------------------------------- /L28/L28_Assignment_secondOrderFit.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L28/L28_Assignment_secondOrderFit.mlx -------------------------------------------------------------------------------- /L28/L28_Lesson_SecondOrderOptimization.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L28/L28_Lesson_SecondOrderOptimization.mlx -------------------------------------------------------------------------------- /L28/L28_TCLab_SecondOrderRegression.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L28/L28_TCLab_SecondOrderRegression.mlx -------------------------------------------------------------------------------- /L29/L29_Assignment_distillationControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L29/L29_Assignment_distillationControl.mlx -------------------------------------------------------------------------------- /L29/L29_Lesson_SimulationofFOPDTSOPDTandHigherOrderSystems.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L29/L29_Lesson_SimulationofFOPDTSOPDTandHigherOrderSystems.mlx -------------------------------------------------------------------------------- /L29/L29_TClab_higherOrderRegression.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L29/L29_TClab_higherOrderRegression.mlx -------------------------------------------------------------------------------- /L30/L30_Assignment_controllerStability.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L30/L30_Assignment_controllerStability.mlx -------------------------------------------------------------------------------- /L30/L30_Lesson_StabilityAnalysis.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L30/L30_Lesson_StabilityAnalysis.mlx -------------------------------------------------------------------------------- /L30/L30_TCLab_pOnlyStability.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L30/L30_TCLab_pOnlyStability.mlx -------------------------------------------------------------------------------- /L31/L31_Assignment_cascadeFFControlDesign.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L31/L31_Assignment_cascadeFFControlDesign.mlx -------------------------------------------------------------------------------- /L31/L31_Lesson_CascadeAndFeedforwardControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L31/L31_Lesson_CascadeAndFeedforwardControl.mlx -------------------------------------------------------------------------------- /L31/L31_TCLab_cascadeControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L31/L31_TCLab_cascadeControl.mlx -------------------------------------------------------------------------------- /L34/L34_Lesson_controlProjectIntroduction.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L34/L34_Lesson_controlProjectIntroduction.mlx -------------------------------------------------------------------------------- /L35/L35_Lesson_optimizationIntroduction.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L35/L35_Lesson_optimizationIntroduction.mlx -------------------------------------------------------------------------------- /L36/L36_Lesson_LinearProgramming.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L36/L36_Lesson_LinearProgramming.mlx -------------------------------------------------------------------------------- /L37/L37_Lesson_SchedulingOptimization.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L37/L37_Lesson_SchedulingOptimization.mlx -------------------------------------------------------------------------------- /L38/L38_Lesson_NonlinearProgramming.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L38/L38_Lesson_NonlinearProgramming.mlx -------------------------------------------------------------------------------- /L39/L39_Lesson_MachineLearningClassification.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L39/L39_Lesson_MachineLearningClassification.mlx -------------------------------------------------------------------------------- /L40/L40_Lesson_ModelPredictiveControl.mlx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/L40/L40_Lesson_ModelPredictiveControl.mlx -------------------------------------------------------------------------------- /L40/apm/apm.m: -------------------------------------------------------------------------------- 1 | % APM Web-Interface Command 2 | % 3 | % response = apm(server,app,command) 4 | % 5 | % This function sends a command to the APM server with 6 | % the following arguments: 7 | % 8 | % server = address of server 9 | % app = application name 10 | % command = instruction or line sent 11 | % 12 | % Some commands are: 13 | % solve : solve the model on the server 14 | % clear all : clear the application and all files 15 | % clear apm : clear just the model file (apm) 16 | % clear csv : clear just the data file (csv) 17 | % info {FV,MV,SV,CV}, {name} : create interface to variable 18 | % ss.t0 {values} : load ss.t0 (restart file) 19 | % csva {contents} : add contents to the data file (csv) 20 | % csv {line} : add one line to the data file (csv) 21 | % apm {contents} : add to apm file without carriage return 22 | % {otherwise} : add line to apm file 23 | function response = apm(server,app,aline) 24 | 25 | % Web-server URL base 26 | url_base = [deblank(server) '/online/apm_line.php']; 27 | app = lower(deblank(app)); 28 | params = ['?p=' urlencode(app) '&a=' urlencode(aline)]; 29 | url = [url_base params]; 30 | % Send request to web-server 31 | response = urlread_apm(url); 32 | 33 | % remove newline characters from response 34 | newline = sprintf('\r'); 35 | response = strrep(response,newline,''); 36 | -------------------------------------------------------------------------------- /L40/apm/apm_app.m: -------------------------------------------------------------------------------- 1 | % APM Load Application 2 | % 3 | % app = apm_app(server,name) 4 | % 5 | % Function apm_app loads a model file (apm) and optionally 6 | % a data file (csv) to the APM server with the 7 | % following arguments: 8 | % 9 | % app = application name 10 | % server = address of server 11 | % name = loads name.apm and name.csv 12 | % 13 | function [app] = apm_app(server,name) 14 | 15 | % model name with .apm extension 16 | app_model = [name '.apm']; 17 | 18 | % data file with .csv extension (optional) 19 | app_data = [name '.csv']; 20 | 21 | % application name, use random number to avoid ip conflicts 22 | app = [name '_' int2str(rand()*10000)]; 23 | app = lower(deblank(app)); 24 | 25 | % clear previous application 26 | apm(server,app,'clear all'); 27 | 28 | % check that model file exists (required) 29 | if (~exist(app_model,'file')), 30 | disp(['Error: file ' app_model ' does not exist']); 31 | app = []; 32 | return 33 | else 34 | % load model file 35 | apm_load(server,app,app_model); 36 | end 37 | 38 | % check if data file exists (optional) 39 | if (exist(app_data,'file')), 40 | % load data file 41 | csv_load(server,app,app_data); 42 | end 43 | -------------------------------------------------------------------------------- /L40/apm/apm_details.m: -------------------------------------------------------------------------------- 1 | % APM Report Problem Details 2 | % 3 | % y = apm_details(server,app,x,lam) 4 | % 5 | % This function reports the details of a problem 6 | % located on the APM server with the following arguments: 7 | % 8 | % server = address of server 9 | % app = application name 10 | % x = values of all variables 11 | % lam = Lagrange multipliers 12 | % y = structure with problem information 13 | % 14 | % Reports model details such as values, multipliers, residuals, 15 | % first derivatives, and second derivatives 16 | % 17 | % y.nvar = number of variables 18 | % y.var.lb = variable lower bounds 19 | % y.var.val = variable values 20 | % y.var.ub = variable upper bounds 21 | % y.obj = objective value 22 | % y.obj_grad = objective gradient 23 | % y.neqn = number of equations 24 | % y.eqn.lb = equation lower bounds 25 | % y.eqn.res = equation residuals 26 | % y.eqn.ub = equation upper bounds 27 | % y.jac = jacobian (1st derivatives) 28 | % y.lam = lagrange multipliers 29 | % y.hes_obj = second derivative of the objective 30 | % y.hes_eqn{i} = second derivatives of equation {i} 31 | % y.hes = full Hessian 32 | % 33 | function y = apm_details(server,app,x,lam) 34 | 35 | persistent sol_prev sol_count 36 | 37 | % initialize sol_count 38 | if (isempty(sol_count)), 39 | sol_count = 0; 40 | end 41 | 42 | % condition application name 43 | app = lower(deblank(app)); 44 | 45 | % tolerance for checking if the values are the same 46 | % as the previous call 47 | tol = 1e-10; 48 | 49 | % optionally load solution vector of variables 50 | if (nargin>=3), 51 | % create 'warm' as a column vector 52 | if (size(x,1)==1), 53 | warm = x'; 54 | else 55 | warm = x; 56 | end 57 | 58 | % see if the values are the same as a previous call 59 | warm_sum = sum(warm); 60 | for i = 1:sol_count, 61 | % check summation of warm first 62 | if (abs(sol_prev(i).y.sumx-warm_sum) <= tol), 63 | % check individual elements next 64 | if (abs(sol_prev(i).y.var.val-warm) <= tol), 65 | % return previous solution if values haven't changed 66 | y = sol_prev(i).y; 67 | return 68 | end 69 | end 70 | end 71 | 72 | % load warm.t0 to the server 73 | fid = fopen('warm.t0','w'); 74 | fprintf(fid,'%20.12e\n',warm); 75 | fclose(fid); 76 | 77 | t0_load(server,app,'warm.t0'); 78 | delete('warm.t0'); 79 | end 80 | 81 | % optionally load lagrange multipliers to server 82 | if (nargin>=4), 83 | % create 'lam' as a column vector 84 | if (size(lam,1)==1), 85 | lam = lam'; 86 | end 87 | 88 | fid = fopen('lam.t0','w'); 89 | fprintf(fid,'%20.12e\n',lam); 90 | fclose(fid); 91 | 92 | t0_load(server,app,'lam.t0'); 93 | delete('lam.t0'); 94 | end 95 | 96 | % compute details on server 97 | output = apm(server,app,'solve'); 98 | 99 | % retrieve variables and bounds 100 | apm_get(server,app,'apm_var.txt'); 101 | load apm_var.txt 102 | delete('apm_var.txt'); 103 | y.nvar = size(apm_var,1); % get number of variables 104 | y.var.lb = apm_var(:,1); 105 | y.var.val = apm_var(:,2); 106 | y.var.ub = apm_var(:,3); 107 | 108 | % retrieve objective function value 109 | apm_get(server,app,'apm_obj.txt'); 110 | load apm_obj.txt 111 | delete('apm_obj.txt'); 112 | y.obj = apm_obj; 113 | 114 | % retrieve objective gradient 115 | apm_get(server,app,'apm_obj_grad.txt'); 116 | load apm_obj_grad.txt 117 | delete('apm_obj_grad.txt'); 118 | y.obj_grad = apm_obj_grad; 119 | 120 | % retrieve equation residuals and bounds 121 | apm_get(server,app,'apm_eqn.txt'); 122 | load apm_eqn.txt 123 | delete('apm_eqn.txt'); 124 | y.neqn = size(apm_eqn,1); % get number of equations 125 | y.eqn.lb = apm_eqn(:,1); 126 | y.eqn.res = apm_eqn(:,2); 127 | y.eqn.ub = apm_eqn(:,3); 128 | 129 | % retrieve jacobian 130 | apm_get(server,app,'apm_jac.txt'); 131 | load apm_jac.txt 132 | delete('apm_jac.txt'); 133 | jac = apm_jac; 134 | y.jac = sparse(jac(:,1),jac(:,2),jac(:,3),y.neqn,y.nvar); 135 | 136 | % retrieve lagrange multipliers 137 | apm_get(server,app,'apm_lam.txt'); 138 | load apm_lam.txt 139 | delete('apm_lam.txt'); 140 | y.lam = apm_lam; 141 | 142 | % retrieve hessian of the objective only 143 | apm_get(server,app,'apm_hes_obj.txt'); 144 | load apm_hes_obj.txt 145 | delete('apm_hes_obj.txt'); 146 | hs = apm_hes_obj; 147 | y.hes_obj = sparse(hs(:,1),hs(:,2),hs(:,3),y.nvar,y.nvar); 148 | 149 | % retrieve hessian of the equations only 150 | apm_get(server,app,'apm_hes_eqn.txt'); 151 | load apm_hes_eqn.txt 152 | delete('apm_hes_eqn.txt'); 153 | hs = apm_hes_eqn; 154 | nhs = size(apm_hes_eqn,1); 155 | i1(1:y.neqn)=0; 156 | i2(1:y.neqn)=0; 157 | % equations listed in sequential order 158 | for i = 1:nhs, 159 | if(i1(hs(i,1))==0), 160 | i1(hs(i,1)) = i; 161 | end 162 | i2(hs(i,1)) = i; 163 | end 164 | for i = 1:y.neqn, 165 | if (i1(i)==0), 166 | y.hes_eqn{i} = sparse(y.nvar,y.nvar); 167 | else 168 | y.hes_eqn{i} = sparse(hs(i1(i):i2(i),2),hs(i1(i):i2(i),3),hs(i1(i):i2(i),4),y.nvar,y.nvar); 169 | end 170 | end 171 | 172 | % construct hessian from obj, lam, and eqn portions 173 | y.hes = y.hes_obj; 174 | for i = 1:y.neqn, 175 | y.hes = y.hes + y.lam(i) * y.hes_eqn{i}; 176 | end 177 | 178 | % store values 179 | sol_count = sol_count + 1; 180 | sol_prev(sol_count).y = y; 181 | sol_prev(sol_count).y.sumx = sum(y.var.val); -------------------------------------------------------------------------------- /L40/apm/apm_get.m: -------------------------------------------------------------------------------- 1 | % APM Retrieve File From Server 2 | % 3 | % [] = apm_get(server,app,filename) 4 | % 5 | % Function apm_get retrieves the file from the web-server 6 | % with the following arguments: 7 | % 8 | % server = address of server 9 | % app = application name 10 | % filename = filename to retrieve 11 | % 12 | % A list of all file names that are accessible can be 13 | % obtained by issuing the command apm_web_root(server,app) 14 | % 15 | function [] = apm_get(server,app,filename) 16 | % get ip address for web-address lookup 17 | app = lower(deblank(app)); 18 | ip = deblank(urlread_apm([deblank(server) '/ip.php'])); 19 | url = [deblank(server) '/online/' ip '_' app '/' filename]; 20 | response = urlread_apm(url); 21 | % write file 22 | fid = fopen(filename,'w'); 23 | fwrite(fid,response); 24 | fclose(fid); 25 | -------------------------------------------------------------------------------- /L40/apm/apm_info.m: -------------------------------------------------------------------------------- 1 | % APM Variable Classification 2 | % class = FV, MV, SV, CV 3 | % F or FV = Fixed value - parameter may change to a new value every cycle 4 | % M or MV = Manipulated variable - independent variable over time horizon 5 | % S or SV = State variable - model variable for viewing 6 | % C or CV = Controlled variable - model variable for control 7 | function response = apm_info(server,app,class,name) 8 | app = lower(deblank(app)); 9 | aline = ['info ' deblank(char(class)) ', ' deblank(char(name))]; 10 | response = apm(server,app,aline); 11 | -------------------------------------------------------------------------------- /L40/apm/apm_linear.m: -------------------------------------------------------------------------------- 1 | function msg = apm_linear(A,b,type,name) 2 | 3 | filename = [name '.apm']; 4 | 5 | % extract A, b in sparse form 6 | [mA,nA] = size(A); 7 | if isempty(b), 8 | b = zeros(mA,1); 9 | mB = mA; 10 | else 11 | if size(b,1)==1, 12 | b = b'; 13 | end 14 | [mB,nB] = size(b); 15 | end 16 | if (mA~=mB), 17 | error('Rows of A and b must agree'); 18 | end 19 | % convert to sparse form 20 | [ai,aj,av] = find(sparse(A)); 21 | a = [ai,aj,av]'; 22 | [bi,bj,bv] = find(sparse(b)); 23 | b = [bi,bj,bv]'; 24 | if(size(b,2)==0), 25 | b = [1,1,0]'; 26 | end 27 | br = [b(1,:); b(3,:)]; 28 | 29 | fid = fopen(filename,'w'); 30 | fprintf( fid,'\n'); 31 | fprintf( fid,'Objects \n'); 32 | fprintf( fid,[' ' name ' = axb\n']); 33 | fprintf( fid,'End Objects \n'); 34 | fprintf( fid,'\n'); 35 | fprintf( fid,'Connections\n'); 36 | fprintf( fid,[' x[1:%d] = ' name '.x[1:%d]\n'],nA,nA); 37 | fprintf( fid,'End Connections\n'); 38 | fprintf( fid,'\n'); 39 | fprintf( fid,'Model \n'); 40 | fprintf( fid,' Variables \n'); 41 | fprintf( fid,' x[1:%d] = 0\n',nA); 42 | fprintf( fid,' End Variables \n'); 43 | fprintf( fid,'\n'); 44 | fprintf( fid,' Equations \n'); 45 | fprintf( fid,' ! add any additional equations here \n'); 46 | fprintf( fid,' End Equations \n'); 47 | fprintf( fid,'End Model \n'); 48 | fprintf( fid,'\n'); 49 | fprintf( fid,['File ' name '.txt\n']); 50 | form = ['Ax' strtrim(type) 'b']; 51 | fprintf( fid,[' sparse, ' form ' ! dense or sparse, Ax=b or Axb\n']); 52 | fprintf( fid,' %d ! m=number of rows in A and b \n',mA); 53 | fprintf( fid,' %d ! n=number of columns in A or variables x\n',nA); 54 | fprintf( fid,'End File\n'); 55 | fprintf( fid,'\n'); 56 | fprintf( fid,['File ' name '.a.txt \n']); 57 | fprintf( fid,' %d %d %f\n', a ); 58 | fprintf( fid,'End File \n'); 59 | fprintf( fid,'\n'); 60 | fprintf( fid,['File ' name '.b.txt \n']); 61 | fprintf( fid,' %d %f\n', br ); 62 | fprintf( fid,'End File \n'); 63 | fclose(fid); 64 | 65 | msg = ['Created Linear (Axb) Model: ' filename]; 66 | 67 | end -------------------------------------------------------------------------------- /L40/apm/apm_linprog.m: -------------------------------------------------------------------------------- 1 | function y = apm_linprog(f,A,b,Aeq,beq,lb,ub,x0) 2 | %apm_linprog Linear programming. 3 | % y = apm_linprog(f,A,b,Aeq,beq,LB,UB,X0) writes a linear 4 | % programming model in APMonitor Modeling Language and attempts 5 | % to solve the linear programming problem: 6 | % 7 | % min f'*x subject to: A*x <= b, Aeq*x = beq 8 | % x 9 | % 10 | % lb and ub are a set of lower and upper bounds on the design variables, 11 | % x, so that the solution is in the range lb <= x <= ub. Use empty 12 | % matrices for any of the arguments. Set lb(i) = -1e20 if x(i) has no 13 | % lower limit and set ub(i) = 1e20 if x(i) has no upper limit. x0 is 14 | % the initial guess and starting point to x. This is similar to the 15 | % Matlab linprog solver but uses different solvers such as IPOPT, 16 | % APOPT, and BPOPT to solve the LP. Additional nonlinear constraints 17 | % can be added to the lp.apm model for nonlinear programming solution 18 | % with support for possible mixed-integer variables. 19 | % 20 | % The solution is returned in the structure y with y.names (variable 21 | % names), y.values (variable values), y.nvar (number of variables), 22 | % and y.x (a structure containing each variable and value). 23 | % 24 | % Example usage is below: 25 | % 26 | % clear all; close all; clc 27 | % addpath('apm') 28 | % 29 | % % example Linear program 30 | % f = [-5; -4; -6]; 31 | % A = [1 -1 1 32 | % 3 2 4 33 | % 3 2 0]; 34 | % b = [20; 42; 30]; 35 | % Aeq = []; 36 | % beq = []; 37 | % lb = zeros(3,1); 38 | % ub = []; 39 | % x0 = []; 40 | % 41 | % % generate and solve APMonitor LP model 42 | % y1 = apm_linprog(f,A,b,Aeq,beq,lb,ub,x0); 43 | % 44 | % % compare solution to linprog (MATLAB) 45 | % y2 = linprog(f,A,b,Aeq,beq,lb,ub,x0); 46 | % 47 | % disp('Validate Results with MATLAB linprog') 48 | % for i = 1:max(size(f)), 49 | % disp(['x[' int2str(i) ']: ' num2str(y1.values(i)) ' = ' num2str(y2(i))]) 50 | % end 51 | 52 | 53 | %% filename to write 54 | filename = ['lp.apm']; 55 | 56 | % extract f in sparse form 57 | if ~isempty(f), 58 | nf = max(size(f)); 59 | if size(f,1)==1, 60 | f = f'; 61 | end 62 | H = zeros(1,1); 63 | 64 | % convert to sparse form 65 | [hi,hj,hv] = find(sparse(H)); 66 | h = [hi,hj,hv]'; 67 | [fi,fj,fv] = find(sparse(f)); 68 | f = [fi,fj,fv]'; 69 | if(size(f,2)==0), 70 | f = [1,1,0]'; 71 | end 72 | fr = [f(1,:); f(3,:)]; 73 | end 74 | 75 | % extract A and b in sparse form 76 | if ~isempty(A), 77 | [mA,nA] = size(A); 78 | if isempty(b), 79 | b = zeros(mA,1); 80 | mB = mA; 81 | else 82 | if size(b,1)==1, 83 | b = b'; 84 | end 85 | [mB,nB] = size(b); 86 | end 87 | if (mA~=mB), 88 | error('Rows of A and b must agree'); 89 | end 90 | 91 | % convert to sparse form 92 | [ai,aj,av] = find(sparse(A)); 93 | if (mA==1), 94 | a = [ai;aj;av]; 95 | else 96 | a = [ai,aj,av]'; 97 | end 98 | [bi,bj,bv] = find(sparse(b)); 99 | b = [bi,bj,bv]'; 100 | if(size(b,2)==0), 101 | b = [1,1,0]'; 102 | end 103 | br = [b(1,:); b(3,:)]; 104 | end 105 | 106 | % extract Aeq and beq in sparse form 107 | if ~isempty(Aeq), 108 | [mAeq,nAeq] = size(Aeq); 109 | if isempty(beq), 110 | beq = zeros(mAeq,1); 111 | mBeq = mAeq; 112 | else 113 | if size(beq,1)==1, 114 | beq = beq'; 115 | end 116 | [mBeq,nBeq] = size(beq); 117 | end 118 | if (mAeq~=mBeq), 119 | error('Rows of Aeq and beq must agree'); 120 | end 121 | 122 | % convert to sparse form 123 | [aeqi,aeqj,aeqv] = find(sparse(Aeq)); 124 | if (mAeq==1), 125 | aeq = [aeqi;aeqj;aeqv]; 126 | else 127 | aeq = [aeqi,aeqj,aeqv]'; 128 | end 129 | [beqi,beqj,beqv] = find(sparse(beq)); 130 | beq = [beqi,beqj,beqv]'; 131 | if(size(beq,2)==0), 132 | beq = [1,1,0]'; 133 | end 134 | beqr = [beq(1,:); beq(3,:)]; 135 | end 136 | 137 | disp('Creating Linear Programming Model lp.apm'); 138 | fid = fopen(filename,'w'); 139 | fprintf( fid,'\n'); 140 | fprintf( fid,'Objects \n'); 141 | if ~isempty(f), 142 | fprintf( fid,[' h = qobj\n']); 143 | end 144 | if ~isempty(A), 145 | fprintf( fid,[' a = axb\n']); 146 | end 147 | if ~isempty(Aeq), 148 | fprintf( fid,[' aeq = axb\n']); 149 | end 150 | fprintf( fid,'End Objects \n'); 151 | fprintf( fid,'\n'); 152 | fprintf( fid,'Connections\n'); 153 | sz = -1; 154 | if ~isempty(f), 155 | fprintf( fid,[' x[1:%d] = h.x[1:%d]\n'],nf,nf); 156 | sz = nf; 157 | end 158 | if ~isempty(A), 159 | fprintf( fid,[' x[1:%d] = a.x[1:%d]\n'],nA,nA); 160 | if (sz>=0), 161 | if (nA~=sz), 162 | error('Variables in Ax < b model must be consistent'); 163 | end 164 | end 165 | end 166 | if ~isempty(Aeq), 167 | fprintf( fid,[' x[1:%d] = aeq.x[1:%d]\n'],nAeq,nAeq); 168 | if (sz>=0), 169 | if (nAeq~=sz), 170 | error('Variables in Ax = b model must be consistent'); 171 | end 172 | end 173 | end 174 | fprintf( fid,'End Connections\n'); 175 | fprintf( fid,'\n'); 176 | fprintf( fid,'Model \n'); 177 | fprintf( fid,' Variables \n'); 178 | if (isempty(x0)&&isempty(lb)&&isempty(ub)), 179 | % default initial conditions 180 | fprintf( fid,' x[1:%d] = 0\n',nH); 181 | else 182 | % create default values 183 | if (isempty(x0)), 184 | x0 = zeros(nf,1); 185 | end 186 | if (isempty(lb)), 187 | lb = -1e10 * ones(nf,1); 188 | end 189 | if (isempty(ub)), 190 | ub = 1e10 * ones(nf,1); 191 | end 192 | % generate initial conditions and bounds 193 | for i = 1:nf, 194 | fprintf( fid,' x[%i] > %d = %d < %d\n',i,lb(i),x0(i),ub(i)); 195 | end 196 | end 197 | fprintf( fid,' End Variables \n'); 198 | fprintf( fid,'\n'); 199 | fprintf( fid,' Equations \n'); 200 | fprintf( fid,' ! add any additional equations here \n'); 201 | fprintf( fid,' End Equations \n'); 202 | fprintf( fid,'End Model \n'); 203 | fprintf( fid,'\n'); 204 | 205 | if ~isempty(f), 206 | fprintf( fid,'\n'); 207 | fprintf( fid,['File h.txt\n']); 208 | fprintf( fid,[' sparse, minimize ! dense or sparse, minimize or maximize\n']); 209 | fprintf( fid,' %d ! n=number of variables \n',nf); 210 | fprintf( fid,'End File\n'); 211 | fprintf( fid,'\n'); 212 | fprintf( fid,'File h.a.txt \n'); 213 | fprintf( fid,' 1 1 0\n'); 214 | fprintf( fid,'End File \n'); 215 | fprintf( fid,'\n'); 216 | fprintf( fid,['File h.b.txt \n']); 217 | fprintf( fid,' %d %f\n', fr ); 218 | fprintf( fid,'End File \n'); 219 | end 220 | 221 | if ~isempty(A), 222 | fprintf( fid,'\n'); 223 | fprintf( fid,['File a.txt\n']); 224 | fprintf( fid,[' sparse, Ax0), 21 | discrete = true; 22 | else 23 | discrete = false; 24 | end 25 | 26 | % extract A, B, C, D matrices in sparse form 27 | [n,m] = size(sys.B); 28 | [p,m] = size(sys.D); 29 | 30 | [ai,aj,av] = find(sparse(sys.A)); 31 | a = [ai,aj,av]'; 32 | [bi,bj,bv] = find(sparse(sys.B)); 33 | b = [bi,bj,bv]'; 34 | [ci,cj,cv] = find(sparse(sys.C)); 35 | if (size(sys.C,1)==1), 36 | c = [ci;cj;cv]; 37 | else 38 | c = [ci,cj,cv]'; 39 | end 40 | [di,dj,dv] = find(sparse(sys.D)); 41 | d = [di,dj,dv]'; 42 | if(size(d,2)==0), 43 | d = [1,1,0]'; 44 | end 45 | 46 | fid = fopen(filename,'w'); 47 | fprintf( fid,'\n'); 48 | fprintf( fid,'Objects \n'); 49 | fprintf( fid,[' ' name ' = lti\n']); 50 | fprintf( fid,'End Objects \n'); 51 | fprintf( fid,'\n'); 52 | fprintf( fid,'Connections\n'); 53 | fprintf( fid,[' u[1:%d] = ' name '.u[1:%d]\n'],m,m); 54 | fprintf( fid,[' x[1:%d] = ' name '.x[1:%d]\n'],n,n); 55 | fprintf( fid,[' y[1:%d] = ' name '.y[1:%d]\n'],p,p); 56 | fprintf( fid,'End Connections\n'); 57 | fprintf( fid,'\n'); 58 | fprintf( fid,'Model \n'); 59 | fprintf( fid,' Parameters \n'); 60 | fprintf( fid,' u[1:%d] = 0\n',m); 61 | fprintf( fid,' End Parameters \n'); 62 | fprintf( fid,'\n'); 63 | fprintf( fid,' Variables \n'); 64 | fprintf( fid,' x[1:%d] = 0\n',n); 65 | fprintf( fid,' y[1:%d] = 0\n',p); 66 | fprintf( fid,' End Variables \n'); 67 | fprintf( fid,'\n'); 68 | fprintf( fid,' Equations \n'); 69 | fprintf( fid,' ! add any additional equations here \n'); 70 | fprintf( fid,' End Equations \n'); 71 | fprintf( fid,'End Model \n'); 72 | fprintf( fid,'\n'); 73 | fprintf( fid,'! dimensions\n'); 74 | fprintf( fid,'! (nx1) = (nxn)*(nx1) + (nxm)*(mx1)\n'); 75 | fprintf( fid,'! (px1) = (pxn)*(nx1) + (pxm)*(mx1)\n'); 76 | fprintf( fid,'!\n'); 77 | if discrete, 78 | fprintf( fid,'! discrete form with sampling time = %f\n',sys.Ts); 79 | fprintf( fid,'! x[k+1] = A * x[k] + B * u[k]\n'); 80 | fprintf( fid,'! y[k] = C * x[k] + D * u[k]\n'); 81 | else 82 | fprintf( fid,'! continuous form\n'); 83 | fprintf( fid,'! dx/dt = A * x + B * u\n'); 84 | fprintf( fid,'! y = C * x + D * u\n'); 85 | end 86 | fprintf( fid,['File ' name '.txt\n']); 87 | if discrete, 88 | fprintf( fid,' sparse, discrete ! dense/sparse, continuous/discrete\n'); 89 | else 90 | fprintf( fid,' sparse, continuous ! dense/sparse, continuous/discrete\n'); 91 | end 92 | fprintf( fid,' %d ! m=number of inputs\n',m); 93 | fprintf( fid,' %d ! n=number of states\n',n); 94 | fprintf( fid,' %d ! p=number of outputs\n',p); 95 | fprintf( fid,'End File\n'); 96 | fprintf( fid,'\n'); 97 | fprintf( fid,['File ' name '.a.txt \n']); 98 | fprintf( fid,' %d %d %f\n', a ); 99 | fprintf( fid,'End File \n'); 100 | fprintf( fid,'\n'); 101 | fprintf( fid,['File ' name '.b.txt \n']); 102 | fprintf( fid,' %d %d %f\n', b ); 103 | fprintf( fid,'End File \n'); 104 | fprintf( fid,'\n'); 105 | fprintf( fid,['File ' name '.c.txt \n']); 106 | fprintf( fid,' %d %d %f\n', c ); 107 | fprintf( fid,'End File \n'); 108 | fprintf( fid,'\n'); 109 | fprintf( fid,['File ' name '.d.txt \n']); 110 | fprintf( fid,' %d %d %f\n', d ); 111 | fprintf( fid,'End File \n'); 112 | fclose(fid); 113 | 114 | msg = ['Created Linear Time Invariant (LTI) Model: ' filename]; 115 | 116 | end -------------------------------------------------------------------------------- /L40/apm/apm_meas.m: -------------------------------------------------------------------------------- 1 | % APM Input Measured Value 2 | % 3 | % response = apm_meas(server,app,name,value) 4 | % 5 | % Function apm_meas sends a measurement to the APM server 6 | % with the following arguments: 7 | % 8 | % server = address of server 9 | % app = application name 10 | % name = parameter or variable name 11 | % value = measurement value 12 | % 13 | % A response is returned indicating whether the measurement 14 | % was successfully recorded 15 | % 16 | function response = apm_meas(server,app,name,value) 17 | 18 | % Web-server URL base 19 | app = lower(deblank(app)); 20 | name = strcat(name,'.meas'); 21 | params = ['?p=' urlencode(app) '&n=' urlencode(name) '&v=' urlencode(num2str(value))]; 22 | url = [deblank(server) '/online/meas.php' params]; 23 | 24 | % Send request to web-server 25 | response = urlread_apm(url); 26 | -------------------------------------------------------------------------------- /L40/apm/apm_option.m: -------------------------------------------------------------------------------- 1 | % APM Specify Options 2 | % 3 | % response = apm_option(server,app,name,value) 4 | % 5 | % Function apm_option sends an option specification 6 | % to the APM server with the following arguments: 7 | % 8 | % server = address of server 9 | % app = application name 10 | % name = option name 11 | % value = option value 12 | % 13 | % A response is returned indicating whether the option 14 | % was successfully recorded 15 | % 16 | % Either global options (NLC.option_name) or parameter/variable 17 | % options (NAME.option_name) are able to be specified with this 18 | % function. A full list of available options with their default 19 | % values are available here: 20 | % 21 | % Global Options: 22 | % http://apmonitor.com/wiki/index.php/Main/DbsGlobal 23 | % 24 | % Variable Options: 25 | % http://apmonitor.com/wiki/index.php/Main/DbsVariable 26 | % 27 | function response = apm_option(server,app,name,value) 28 | app = lower(deblank(app)); 29 | aline = ['option ' deblank(char(name)) ' = ' num2str(value)]; 30 | response = apm(server,app,aline); 31 | 32 | -------------------------------------------------------------------------------- /L40/apm/apm_quadprog.m: -------------------------------------------------------------------------------- 1 | function y = apm_quadprog(H,f,A,b,Aeq,beq,lb,ub,x0) 2 | %apm_quadprog Quadratic programming. 3 | % y = apm_quadprog(H,f,A,b,Aeq,beq,LB,UB,X0) writes a quadratic 4 | % programming model in APMonitor Modeling Language and attempts 5 | % to solve the quadratic programming problem: 6 | % 7 | % min 0.5*x'*H*x + f'*x subject to: A*x <= b, Aeq*x = beq 8 | % x 9 | % 10 | % lb and ub are a set of lower and upper bounds on the design variables, 11 | % x, so that the solution is in the range lb <= x <= ub. Use empty 12 | % matrices for any of the arguments. Set lb(i) = -1e20 if x(i) has no 13 | % lower limit and set ub(i) = 1e20 if x(i) has no upper limit. x0 is 14 | % the initial guess and starting point to x. This is similar to the 15 | % Matlab quadprog solver but uses different solvers such as IPOPT, 16 | % APOPT, and BPOPT to solve the QP. Additional nonlinear constraints 17 | % can be added to the qp.apm model for nonlinear programming solution 18 | % with support for possible mixed-integer variables. 19 | % 20 | % The solution is returned in the structure y with y.names (variable 21 | % names), y.values (variable values), y.nvar (number of variables), 22 | % and y.x (a structure containing each variable and value). 23 | % 24 | % Example usage is below: 25 | % 26 | % clear all; close all; clc 27 | % disp('APM MATLAB available for download at http://apmonitor.com') 28 | % addpath('apm') 29 | % 30 | % %% example Quadratic program 31 | % H = [1 -1; -1 2]; 32 | % f = [-2; -6]; 33 | % A = [1 1; -1 2; 2 1]; 34 | % b = [2; 2; 3]; 35 | % Aeq = []; 36 | % beq = []; 37 | % lb = zeros(2,1); 38 | % ub = []; 39 | % x0 = []; 40 | % 41 | % %% generate APMonitor QP model 42 | % y1 = apm_quadprog(H,f,A,b,Aeq,beq,lb,ub,x0); 43 | % 44 | % %% compare solution to quadprog (MATLAB) 45 | % y2 = quadprog(H,f,A,b,Aeq,beq,lb,ub,x0) 46 | % 47 | % disp('Validate Results with MATLAB linprog') 48 | % for i = 1:nx, 49 | % disp(['x[' int2str(i) ']: ' num2str(y1.values(i)) ' = ' num2str(y2(i))]) 50 | % end 51 | 52 | 53 | % filename to write 54 | filename = ['qp.apm']; 55 | 56 | % extract H and f in sparse form 57 | if ~isempty(H), 58 | [mH,nH] = size(H); 59 | if (mH~=nH), 60 | error('H must be a square matrix'); 61 | end 62 | if isempty(f), 63 | f = zeros(mH,1); 64 | mf = mH; 65 | else 66 | if size(f,1)==1, 67 | f = f'; 68 | end 69 | [mf,nf] = size(f); 70 | end 71 | if (mH~=mf), 72 | error('Rows of H and f must agree'); 73 | end 74 | 75 | % convert to sparse form 76 | [hi,hj,hv] = find(sparse(H)); 77 | h = [hi,hj,hv]'; 78 | [fi,fj,fv] = find(sparse(f)); 79 | f = [fi,fj,fv]'; 80 | if(size(f,2)==0), 81 | f = [1,1,0]'; 82 | end 83 | fr = [f(1,:); f(3,:)]; 84 | end 85 | 86 | % extract A and b in sparse form 87 | if ~isempty(A), 88 | [mA,nA] = size(A); 89 | if isempty(b), 90 | b = zeros(mA,1); 91 | mB = mA; 92 | else 93 | if size(b,1)==1, 94 | b = b'; 95 | end 96 | [mB,nB] = size(b); 97 | end 98 | if (mA~=mB), 99 | error('Rows of A and b must agree'); 100 | end 101 | 102 | % convert to sparse form 103 | [ai,aj,av] = find(sparse(A)); 104 | if (mA==1), 105 | a = [ai;aj;av]; 106 | else 107 | a = [ai,aj,av]'; 108 | end 109 | [bi,bj,bv] = find(sparse(b)); 110 | b = [bi,bj,bv]'; 111 | if(size(b,2)==0), 112 | b = [1,1,0]'; 113 | end 114 | br = [b(1,:); b(3,:)]; 115 | end 116 | 117 | % extract Aeq and beq in sparse form 118 | if ~isempty(Aeq), 119 | [mAeq,nAeq] = size(Aeq); 120 | if isempty(beq), 121 | beq = zeros(mAeq,1); 122 | mBeq = mAeq; 123 | else 124 | if size(beq,1)==1, 125 | beq = beq'; 126 | end 127 | [mBeq,nBeq] = size(beq); 128 | end 129 | if (mAeq~=mBeq), 130 | error('Rows of Aeq and beq must agree'); 131 | end 132 | 133 | % convert to sparse form 134 | [aeqi,aeqj,aeqv] = find(sparse(Aeq)); 135 | if (mAeq==1), 136 | aeq = [aeqi;aeqj;aeqv]; 137 | else 138 | aeq = [aeqi,aeqj,aeqv]'; 139 | end 140 | [beqi,beqj,beqv] = find(sparse(beq)); 141 | beq = [beqi,beqj,beqv]'; 142 | if(size(beq,2)==0), 143 | beq = [1,1,0]'; 144 | end 145 | beqr = [beq(1,:); beq(3,:)]; 146 | end 147 | 148 | disp('Creating Quadratic Programming Model qp.apm'); 149 | fid = fopen(filename,'w'); 150 | fprintf( fid,'\n'); 151 | fprintf( fid,'Objects \n'); 152 | if ~isempty(H), 153 | fprintf( fid,[' h = qobj\n']); 154 | end 155 | if ~isempty(A), 156 | fprintf( fid,[' a = axb\n']); 157 | end 158 | if ~isempty(Aeq), 159 | fprintf( fid,[' aeq = axb\n']); 160 | end 161 | fprintf( fid,'End Objects \n'); 162 | fprintf( fid,'\n'); 163 | fprintf( fid,'Connections\n'); 164 | sz = -1; 165 | if ~isempty(H), 166 | fprintf( fid,[' x[1:%d] = h.x[1:%d]\n'],nH,nH); 167 | sz = nH; 168 | end 169 | if ~isempty(A), 170 | fprintf( fid,[' x[1:%d] = a.x[1:%d]\n'],nA,nA); 171 | if (sz>=0), 172 | if (nA~=sz), 173 | error('Variables in Ax < b model must be consistent'); 174 | end 175 | end 176 | end 177 | if ~isempty(Aeq), 178 | fprintf( fid,[' x[1:%d] = aeq.x[1:%d]\n'],nAeq,nAeq); 179 | if (sz>=0), 180 | if (nAeq~=sz), 181 | error('Variables in Ax = b model must be consistent'); 182 | end 183 | end 184 | end 185 | fprintf( fid,'End Connections\n'); 186 | fprintf( fid,'\n'); 187 | fprintf( fid,'Model \n'); 188 | fprintf( fid,' Variables \n'); 189 | if (isempty(x0)&&isempty(lb)&&isempty(ub)), 190 | % default initial conditions 191 | fprintf( fid,' x[1:%d] = 0\n',nH); 192 | else 193 | % create default values 194 | if (isempty(x0)), 195 | x0 = zeros(nH,1); 196 | end 197 | if (isempty(lb)), 198 | lb = -1e10 * ones(nH,1); 199 | end 200 | if (isempty(ub)), 201 | ub = 1e10 * ones(nH,1); 202 | end 203 | % generate initial conditions and bounds 204 | for i = 1:nH, 205 | fprintf( fid,' x[%i] > %d = %d < %d\n',i,lb(i),x0(i),ub(i)); 206 | end 207 | end 208 | fprintf( fid,' End Variables \n'); 209 | fprintf( fid,'\n'); 210 | fprintf( fid,' Equations \n'); 211 | fprintf( fid,' ! add any additional equations here \n'); 212 | fprintf( fid,' End Equations \n'); 213 | fprintf( fid,'End Model \n'); 214 | fprintf( fid,'\n'); 215 | 216 | if ~isempty(H), 217 | fprintf( fid,'\n'); 218 | fprintf( fid,['File h.txt\n']); 219 | fprintf( fid,[' sparse, minimize ! dense or sparse, minimize or maximize\n']); 220 | fprintf( fid,' %d ! n=number of variables \n',mH); 221 | fprintf( fid,'End File\n'); 222 | fprintf( fid,'\n'); 223 | fprintf( fid,['File h.a.txt \n']); 224 | fprintf( fid,' %d %d %f\n', h ); 225 | fprintf( fid,'End File \n'); 226 | fprintf( fid,'\n'); 227 | fprintf( fid,['File h.b.txt \n']); 228 | fprintf( fid,' %d %f\n', fr ); 229 | fprintf( fid,'End File \n'); 230 | end 231 | 232 | if ~isempty(A), 233 | fprintf( fid,'\n'); 234 | fprintf( fid,['File a.txt\n']); 235 | fprintf( fid,[' sparse, Ax--- Launch APM Web Interface ---']) 26 | %%disp([' ' url]) -------------------------------------------------------------------------------- /L40/apm/apm_web_root.m: -------------------------------------------------------------------------------- 1 | % APM Open Web Root Folder in Internet Browser 2 | % 3 | % stat = apm_web_root(server,app) 4 | % 5 | % Function apm_web_root opens the default web-browser 6 | % and loads a list of files that can be selected for 7 | % download or viewing 8 | % 9 | % server = address of server 10 | % app = application name 11 | % stat = message returned when opening browser 12 | % 13 | function [stat] = apm_web_root(server,app) 14 | % get ip address for web-address lookup 15 | ip = deblank(urlread_apm([deblank(server) '/ip.php'])); 16 | app = lower(deblank(app)); 17 | url = [deblank(server) '/online/' ip '_' app '/']; 18 | 19 | % load web-interface in default browser 20 | stat = web(url,'-browser'); % doesn't work in some older MATLAB versions 21 | -------------------------------------------------------------------------------- /L40/apm/apm_web_var.m: -------------------------------------------------------------------------------- 1 | % APM Open Web Page with Variable Values 2 | % 3 | % stat = apm_web_var(server,app) 4 | % 5 | % Function apm_web_var opens the default web-browser 6 | % and loads a table of variable values 7 | % 8 | % server = address of server 9 | % app = application name 10 | % stat = message returned when opening browser 11 | % 12 | function [stat] = apm_web_var(server,app) 13 | % get ip address for web-address lookup 14 | ip = deblank(urlread_apm([deblank(server) '/ip.php'])); 15 | app = lower(deblank(app)); 16 | url = [deblank(server) '/online/' ip '_' app '/' ip '_' app '_var.htm']; 17 | 18 | % load web-interface in default browser 19 | stat = web(url,'-browser'); % doesn't work in some older MATLAB versions 20 | 21 | % display web address and allow the user to click to open 22 | %%disp(['--- Launch APM Web Interface ---']) 23 | %%disp([' ' url]) -------------------------------------------------------------------------------- /L40/apm/csv_data.m: -------------------------------------------------------------------------------- 1 | % Load CSV File into MATLAB 2 | % 3 | % A = csv_data(filename) 4 | % 5 | % Function csv_data extracts data from a comma 6 | % separated value (csv) file and returns it 7 | % to the matrix A 8 | % 9 | function [A] = csv_data(filename) 10 | % load data from csv file with header 11 | fid = fopen(filename, 'r'); 12 | aline = fgetl(fid); 13 | 14 | % Split header 15 | A(1,:) = deblank(parse(aline, ',')); 16 | 17 | % Parse and read rest of file 18 | ctr = 1; 19 | while(~feof(fid)) 20 | if ischar(aline) 21 | ctr = ctr + 1; 22 | aline = fgetl(fid); 23 | A(ctr,:) = parse(aline, ','); 24 | else 25 | break; 26 | end 27 | end 28 | fclose(fid); 29 | -------------------------------------------------------------------------------- /L40/apm/csv_element.m: -------------------------------------------------------------------------------- 1 | % Retrieve CSV element 2 | % 3 | % value = csv_element(name,row,csv) 4 | % 5 | % This function looks up "name" in the cell 6 | % array "csv" and returns the value in row 7 | % number "row" 8 | % 9 | function value = csv_element(name,row,csv) 10 | % Size of CSV data 11 | [rows,cols] = size(csv); 12 | % Take last row if beyond max rows 13 | if (row>rows), 14 | row = rows-1; 15 | end 16 | % get column number 17 | col = csv_lookup(name,csv); 18 | if (col>=1), 19 | value = str2num(csv{row+1,col}); 20 | else 21 | value = NaN; 22 | end 23 | -------------------------------------------------------------------------------- /L40/apm/csv_load.m: -------------------------------------------------------------------------------- 1 | % APM Load Data File 2 | % 3 | % response = csv_load(server,app,filename) 4 | % 5 | % Function csv_load uploads the data file (csv) to the web-server 6 | % with the following arguments: 7 | % 8 | % server = address of server 9 | % app = application name 10 | % filename = data filename 11 | % 12 | % A response is returned indicating whether the file was 13 | % uploaded successfully to the server 14 | % 15 | function [response] = csv_load(server,app,filename) 16 | % convert to lowercase and deblank 17 | app = lower(deblank(app)); 18 | 19 | % load model 20 | fid=fopen(filename,'r'); 21 | tline = []; 22 | while 1 23 | aline = fgets(fid); 24 | if ~ischar(aline), break, end 25 | % remove any double quote marks 26 | aline = [strrep(aline,'"',' ')]; 27 | tline = [tline aline]; 28 | end 29 | fclose(fid); 30 | 31 | % send to server once for every 2000 characters 32 | ts = size(tline,2); 33 | block = 2000; 34 | cycles = ceil(ts/block); 35 | for i = 1:cycles, 36 | if icourse overview 5 | 6 | ![YouTube Logo](./images/youtube.png) [View MathWorks Webinar](https://youtu.be/SAjFN8mnFCU) 7 | 8 | This course focuses on methods that are used in practice for simple or complex systems. It is divided into three main parts including (1) data driven modeling and controller development, (2) physics-based modeling and controller development, and (3) advanced controls with optimization. Example problems are provided throughout in the MATLAB programming language. 9 | 10 | [![View Process Dynamics and Control Course on File Exchange](https://www.mathworks.com/matlabcentral/images/matlab-file-exchange.svg)](https://www.mathworks.com/matlabcentral/fileexchange/116500-process-dynamics-and-control-course) 11 | 12 | ## Professor 13 | ![John Hedengren](./images/hedengren.jpg) 14 | 15 | [John Hedengren](https://www.linkedin.com/in/hedengren/) leads the [BYU PRISM](https://apm.byu.edu/) group with interests in combining data science, optimization, and automation with current projects in hybrid nuclear energy system design and unmanned aerial vehicle photogrammetry. He earned a doctoral degree at the University of Texas at Austin and worked 5 years with ExxonMobil Chemical prior to joining BYU in 2011. 16 | ## Teaching Assistant 17 | ![Joshua Hammond](./images/hammond.jpg) 18 | 19 | [Joshua Hammond](https://www.linkedin.com/in/j-edward-hammond) is an experienced researcher in Process Systems Engineering leveraging Data Science, Machine Learning, Optimization, and domain knowledge to achieve optimal solutions. Joshua developed the MATLAB dynamics and control course from the [Process Dynamics and Control Course](https://apmonitor.com/pdc/index.php/Main/CourseSchedule) with technical support from [Colin Anderson](https://www.linkedin.com/in/colin-r-anderson/) and [Nathanael Nelson](https://www.linkedin.com/in/nathanael-martin-nelson-eit-a3183598/). Assignment solution videos are published to the [Horizon PSE](https://www.youtube.com/channel/UCGsMPf9oCqIeuOtZEKAxaqg) YouTube Channel. 20 | ## Course Objectives 21 | It is the intent of this course to help the student to: 22 | 1. Understand and be able to describe quantitatively the dynamic behavior of process systems. 23 | 2. Learn the fundamental principles of classical control theory, including different types of controllers and control strategies. 24 | 3. Develop the ability to describe quantitatively the behavior of simple control systems and to design control systems. 25 | 4. Develop the ability to use computer software to help describe and design control systems. 26 | 5. Learn how to tune a control loop and to apply this knowledge in the laboratory. 27 | 6. Gain a brief exposure to advanced control strategies. 28 | 29 | ## Course Schedule 30 | 31 | course overview 32 | 33 | | Class | Topic | Assignment | TCLab Activity | 34 | |-------------------------------------------------------|--------------------------------------------------------------------------------|---------------------------------------------|----------------------------------------------| 35 | | [L01](https://github.com/APMonitor/mdc/tree/main/L01) | Course Introduction | Begin MATLAB | Begin MATLAB (Continued) | 36 | | [L02](https://github.com/APMonitor/mdc/tree/main/L02) | Simulate Dynamics in MATLAB | Simulate HIV Infection | Step Test Simulation | 37 | | [L03](https://github.com/APMonitor/mdc/tree/main/L03) | Physics-based Dynamic Modeling | Derive Balance Equations | Convective Heat Transfer | 38 | | [L04](https://github.com/APMonitor/mdc/tree/main/L04) | Transient Balance Equations | Tank Blending Simulation | Radiative Heat Transfer | 39 | | [L05](https://github.com/APMonitor/mdc/tree/main/L05) | Linearize Balance Equations | Linearize Differential Equations | Linearize Energy Balance | 40 | | [L06](https://github.com/APMonitor/mdc/tree/main/L06) | First-Order Linear Dynamics with Dead Time using Graphical Fitting Methods | Graphical FOPDT Fit | TCLab Graphical FOPDT Fit | 41 | | [L07](https://github.com/APMonitor/mdc/tree/main/L07) | Optimize Model Parameter Fit | Parameter Regression | Regression FOPDT | 42 | | L08 | Exam Review on Modeling and Dynamics | Practice Exam | | 43 | | L09 | Exam on Dynamic Modeling | | | 44 | | | | | | 45 | | Class | Topic | Assignment | TCLab Activity | 46 | | [L10](https://github.com/APMonitor/mdc/tree/main/L10) | Control Design | Controller Design Exercise | TCLab Controller Design | 47 | | [L11](https://github.com/APMonitor/mdc/tree/main/L11) | Proportional-only (P-only) Control | Tank Level | P-only Control | 48 | | [L12](https://github.com/APMonitor/mdc/tree/main/L12) | Proportional Integral (PI) Control | Auto Cruise Control | PI Control | 49 | | [L13](https://github.com/APMonitor/mdc/tree/main/L13) | Proportional Integral Derivative (PID) Control | Blending Control | PID Control | 50 | | [L14](https://github.com/APMonitor/mdc/tree/main/L14) | Case Study: Level Control | Level Control | PI Control Tuning | 51 | | [L15](https://github.com/APMonitor/mdc/tree/main/L15) | Case Study: Nonlinear System Control | Exothermic Reactor | PID Control Tuning | 52 | | [L16](https://github.com/APMonitor/mdc/tree/main/L16) | Case Study: Disturbances | Type-I Diabetic Blood Glucose | PID with Feedforward | 53 | | [L17](https://github.com/APMonitor/mdc/tree/main/L17) | Valve Design Principles | Valve Design Exercise | Heater Actuator | 54 | | [L18](https://github.com/APMonitor/mdc/tree/main/L18) | Sensors and Data Acquisition | Sensor Design Exercise | Temperature Sensor | 55 | | L19 | Exam Review on Sensors, Actuators, and Controllers | Practice Exam | | 56 | | L20 | Exam on Sensors, Actuators, and Controllers | | | 57 | | | | | | 58 | | Class | Topic | Assignment | TCLab Activity | 59 | | [L21](https://github.com/APMonitor/mdc/tree/main/L21) | Single Heater Modeling | [TCLab Project Overview](https://github.com/APMonitor/mdc/tree/main/L21/Arduino_lab_rubric.pdf) | Dual Heater Modeling 2 | 60 | | [L22](https://github.com/APMonitor/mdc/tree/main/L22) | Single Heater Regression | | Dual Heater Regression 2 | 61 | | [L23](https://github.com/APMonitor/mdc/tree/main/L23) | Single Heater Control | 2 Page Report | Dual Heater Control 2 | 62 | | | | | | 63 | | [L24](https://github.com/APMonitor/mdc/tree/main/L24) | Laplace Transforms | Laplace Transform Applications | Impulse Response | 64 | | [L25](https://github.com/APMonitor/mdc/tree/main/L25) | Transfer Functions | Block Diagrams with Transfer Functions | Block Diagram | 65 | | [L26](https://github.com/APMonitor/mdc/tree/main/L26) | State Space Models | Reactor State Space | State Space Simulation | 66 | | [L27](https://github.com/APMonitor/mdc/tree/main/L27) | Second Order Systems with Graphical Fitting | Second Order Estimation: Graphical | On/Off Control | 67 | | [L28](https://github.com/APMonitor/mdc/tree/main/L28) | Second Order Optimization | Second Order Estimation: Optimization | Second Order Regression | 68 | | [L29](https://github.com/APMonitor/mdc/tree/main/L29) | Simulation of FOPDT, SOPDT, and Higher Order Systems | Distillation Control | Higher Order Regression | 69 | | [L30](https://github.com/APMonitor/mdc/tree/main/L30) | Stability Analysis | Controller Stability Limits | P-Only Stability Analysis | 70 | | [L31](https://github.com/APMonitor/mdc/tree/main/L31) | Cascade Control and Feedforward Control | Cascade or Feedforward Control Design | Cascade Control | 71 | | L32 | Exam Review on Dynamic Systems Analysis | Practice Exam | | 72 | | L33 | Exam on Dynamic Systems Analysis | | | 73 | | | | | | 74 | | Class | Topic | Assignment | TCLab Activity | 75 | | [L34](https://github.com/APMonitor/mdc/tree/main/L34) | Control Project Introduction | Control Project | | 76 | | [L35](https://github.com/APMonitor/mdc/tree/main/L35) | Optimization Introduction | Control Project | | 77 | | [L36](https://github.com/APMonitor/mdc/tree/main/L36) | Linear Programming | Control Project | | 78 | | [L37](https://github.com/APMonitor/mdc/tree/main/L37) | Scheduling Optimization | Control Project | | 79 | | [L38](https://github.com/APMonitor/mdc/tree/main/L38) | Nonlinear Programming | Control Project | | 80 | | [L39](https://github.com/APMonitor/mdc/tree/main/L39) | Machine Learning Classification | Control Project | | 81 | | [L40](https://github.com/APMonitor/mdc/tree/main/L40) | Model Predictive Control | Control Project | | 82 | | L41 | Project Help Session | Control Project | | 83 | | L42 | Final Exam Review | Practice Exam | | 84 | | Final | Project Report (2 pages) and Presentation (5 min) Final Exam | | | 85 | 86 | ![Github Logo](./images/github.png) [MATLAB](https://github.com/APMonitor/mdc) and [Python](https://github.com/APMonitor/pdc) Repository on Github 87 | 88 | ![Github Logo](./images/apm.png) [Course Web-site](https://apmonitor.com/pdc) and [Schedule](https://apmonitor.com/pdc/index.php/Main/CourseSchedule) 89 | 90 | ![Mathworks Logo](./images/matlab.png) View the [Repository on MATLAB Drive](https://drive.matlab.com/sharing/ac9d959a-e586-4478-ad56-5078ed578753) 91 | 92 | ![TCLab](./images/tclab.png) [Temperature Control Lab](https://apmonitor.com/heat.htm) 93 | 94 | ![YouTube Logo](./images/youtube.png) [View MathWorks Webinar](https://youtu.be/SAjFN8mnFCU) 95 | 96 | The materials in this archive are released under the [MIT License](./LICENSE). The financial assistance of MathWorks is gratefully acknowledged with technical assistance of [Melda Ulusoy](https://www.linkedin.com/in/melda-ulusoy-323bb670/) and others at MathWorks. 97 | -------------------------------------------------------------------------------- /data.txt: -------------------------------------------------------------------------------- 1 | 0,3,0.935 2 | 0.100200400801603,3,0.935032671609404 3 | 0.200400801603206,3,0.93505954336181 4 | 0.30060120240481,3,0.935077642186285 5 | 0.400801603206413,3,0.935090264764325 6 | 0.501002004008016,3,0.935099753865229 7 | 0.601202404809619,3,0.935107418962671 8 | 0.701402805611222,3,0.935113977141749 9 | 0.801603206412826,3,0.935119826845232 10 | 0.901803607214429,7,0.935125191387749 11 | 1.00200400801603,7,0.936252990480154 12 | 1.10220440881764,7,0.9382969024648 13 | 1.20240480961924,7,0.940589815268764 14 | 1.30260521042084,7,0.942935622320904 15 | 1.40280561122244,7,0.945254621397939 16 | 1.50300601202405,7,0.947510315691456 17 | 1.60320641282565,7,0.949685591664548 18 | 1.70340681362725,7,0.951772982267524 19 | 1.80360721442886,7,0.953770120512619 20 | 1.90380761523046,7,0.955677427603678 21 | 2.00400801603206,7,0.957496867233905 22 | 2.10420841683367,7,0.959231246139619 23 | 2.20440881763527,7,0.960883809385916 24 | 2.30460921843687,7,0.962458001097334 25 | 2.40480961923848,7,0.963957321066778 26 | 2.50501002004008,7,0.96538523842175 27 | 2.60521042084168,7,0.966745140011396 28 | 2.70541082164329,7,0.968040300313913 29 | 2.80561122244489,7,0.969273864873908 30 | 2.90581162324649,7,0.97044884232798 31 | 3.0060120240481,7,0.971568101903518 32 | 3.1062124248497,7,0.972634374394805 33 | 3.2064128256513,7,0.973650255320209 34 | 3.30661322645291,7,0.974618209409917 35 | 3.40681362725451,7,0.975540575862242 36 | 3.50701402805611,7,0.976419573996123 37 | 3.60721442885772,7,0.977257309053366 38 | 3.70741482965932,7,0.978055777988791 39 | 3.80761523046092,7,0.978816875143512 40 | 3.90781563126253,7,0.979542397735422 41 | 4.00801603206413,7,0.980234051127308 42 | 4.10821643286573,7,0.980893453850998 43 | 4.20841683366733,7,0.981522142378037 44 | 4.30861723446894,7,0.98212157563558 45 | 4.40881763527054,7,0.982693139271555 46 | 4.50901803607214,7,0.983238149676603 47 | 4.60921843687375,7,0.983757857772487 48 | 4.70941883767535,7,0.984253452577844 49 | 4.80961923847695,7,0.984726064562808 50 | 4.90981963927856,7,0.985176768804164 51 | 5.01002004008016,7,0.9856065879526 52 | 5.11022044088176,7,0.986016495023334 53 | 5.21042084168337,7,0.986407416020948 54 | 5.31062124248497,7,0.986780232408781 55 | 5.41082164328657,7,0.987135783432712 56 | 5.51102204408818,7,0.987474868308598 57 | 5.61122244488978,7,0.987798248282101 58 | 5.71142284569138,7,0.988106648569101 59 | 5.81162324649299,7,0.988400760184367 60 | 5.91182364729459,7,0.988681241665681 61 | 6.01202404809619,7,0.988948720700111 62 | 6.1122244488978,7,0.989203795658717 63 | 6.2124248496994,7,0.989447037045524 64 | 6.312625250501,7,0.989678988866223 65 | 6.41282565130261,7,0.989900169921676 66 | 6.51302605210421,7,0.990111075030972 67 | 6.61322645290581,7,0.990312176188427 68 | 6.71342685370742,7,0.990503923658673 69 | 6.81362725450902,7,0.990686747013623 70 | 6.91382765531062,7,0.990861056114919 71 | 7.01402805611222,7,0.99102724204516 72 | 7.11422845691383,7,0.991185677991013 73 | 7.21442885771543,7,0.991336720081095 74 | 7.31462925851703,7,0.991480708181306 75 | 7.41482965931864,7,0.991617966650124 76 | 7.51503006012024,7,0.99174880505618 77 | 7.61523046092184,7,0.991873518860317 78 | 7.71543086172345,7,0.991992390064129 79 | 7.81563126252505,7,0.992105687826898 80 | 7.91583166332665,7,0.992213669052686 81 | 8.01603206412826,7,0.992316578949235 82 | 8.11623246492986,7,0.992414651560203 83 | 8.21643286573146,7,0.992508110272206 84 | 8.31663326653307,7,0.992597168297974 85 | 8.41683366733467,7,0.992682029136918 86 | 8.51703406813627,7,0.992762887014266 87 | 8.61723446893788,7,0.992839927299875 88 | 8.71743486973948,7,0.992913326907775 89 | 8.81763527054108,7,0.99298325467739 90 | 8.91783567134268,7,0.993049871737377 91 | 9.01803607214429,7,0.993113331852926 92 | 9.11823647294589,7,0.993173781757331 93 | 9.21843687374749,7,0.993231361468605 94 | 9.3186372745491,7,0.993286204591841 95 | 9.4188376753507,7,0.993338438608005 96 | 9.5190380761523,7,0.993388185149803 97 | 9.61923847695391,7,0.993435560265211 98 | 9.71943887775551,7,0.993480674669262 99 | 9.81963927855711,7,0.993523633984609 100 | 9.91983967935872,7,0.993564538971388 101 | 10.0200400801603,7,0.993603485746867 102 | 10.1202404809619,7,0.993640565995334 103 | 10.2204408817635,7,0.993675867168674 104 | 10.3206412825651,7,0.993709472678038 105 | 10.4208416833667,7,0.99374146207701 106 | 10.5210420841683,7,0.993771911236645 107 | 10.6212424849699,7,0.993800892512736 108 | 10.7214428857715,7,0.993828474905649 109 | 10.8216432865731,7,0.993854724213064 110 | 10.9218436873747,7,0.993879703175916 111 | 11.0220440881764,7,0.993903471617849 112 | 11.122244488978,7,0.993926086578453 113 | 11.2224448897796,7,0.993947602440565 114 | 11.3226452905812,7,0.993968071051887 115 | 11.4228456913828,7,0.993987541841166 116 | 11.5230460921844,7,0.994006061929191 117 | 11.623246492986,7,0.994023676234795 118 | 11.7234468937876,7,0.994040427576128 119 | 11.8236472945892,7,0.994056356767361 120 | 11.9238476953908,7,0.994071502711054 121 | 12.0240480961924,7,0.994085902486363 122 | 12.124248496994,7,0.994099591433258 123 | 12.2244488977956,7,0.994112603232954 124 | 12.3246492985972,7,0.99412496998469 125 | 12.4248496993988,7,0.994136722279038 126 | 12.5250501002004,7,0.994147889267887 127 | 12.625250501002,7,0.994158498731239 128 | 12.7254509018036,7,0.99416857714098 129 | 12.8256513026052,7,0.994178149721732 130 | 12.9258517034068,7,0.99418724050894 131 | 13.0260521042084,7,0.994195872404296 132 | 13.12625250501,7,0.994204067228637 133 | 13.2264529058116,7,0.994211845772408 134 | 13.3266533066132,7,0.994219227843818 135 | 13.4268537074148,7,0.994226232314786 136 | 13.5270541082164,7,0.994232877164763 137 | 13.627254509018,7,0.994239179522547 138 | 13.7274549098196,7,0.994245155706162 139 | 13.8276553106212,7,0.9942508212609 140 | 13.9278557114228,7,0.994256190995605 141 | 14.0280561122244,7,0.994261279017271 142 | 14.1282565130261,7,0.994266098764047 143 | 14.2284569138277,7,0.994270663036703 144 | 14.3286573146293,7,0.994274984028638 145 | 14.4288577154309,7,0.994279073354495 146 | 14.5290581162325,7,0.994282942077437 147 | 14.6292585170341,7,0.994286600735164 148 | 14.7294589178357,7,0.994290059364707 149 | 14.8296593186373,7,0.994293327526069 150 | 14.9298597194389,7,0.99429641432476 151 | 15.0300601202405,7,0.994299328433283 152 | 15.1302605210421,7,0.994302078111607 153 | 15.2304609218437,7,0.994304671226688 154 | 15.3306613226453,7,0.99430711527107 155 | 15.4308617234469,7,0.994309417380618 156 | 15.5310621242485,7,0.994311584351412 157 | 15.6312625250501,7,0.994313622655856 158 | 15.7314629258517,7,0.994315538458024 159 | 15.8316633266533,7,0.994317337628282 160 | 15.9318637274549,7,0.994319025757228 161 | 16.0320641282565,7,0.994320608168968 162 | 16.1322645290581,7,0.994322089933777 163 | 16.2324649298597,7,0.994323475880148 164 | 16.3326653306613,7,0.994324770606287 165 | 16.4328657314629,7,0.994325978491052 166 | 16.5330661322645,7,0.994327103704389 167 | 16.6332665330661,7,0.99432815021726 168 | 16.7334669338677,7,0.994329121811115 169 | 16.8336673346693,7,0.994330022086906 170 | 16.9338677354709,7,0.994330854473679 171 | 17.0340681362725,7,0.994331622236758 172 | 17.1342685370741,7,0.994332328485541 173 | 17.2344689378758,7,0.994332976180927 174 | 17.3346693386774,7,0.99433356814239 175 | 17.434869739479,7,0.994334107054718 176 | 17.5350701402806,7,0.994334595474434 177 | 17.6352705410822,7,0.994335035835905 178 | 17.7354709418838,7,0.994335430457173 179 | 17.8356713426854,7,0.994335781545498 180 | 17.935871743487,3,0.994336091202641 181 | 18.0360721442886,3,0.994302487905782 182 | 18.1362725450902,3,0.994223474469176 183 | 18.2364729458918,3,0.994116613231991 184 | 18.3366733466934,3,0.993990097280965 185 | 18.436873747495,3,0.993848368497527 186 | 18.5370741482966,3,0.993694071891551 187 | 18.6372745490982,3,0.993528872414824 188 | 18.7374749498998,3,0.993353849373837 189 | 18.8376753507014,3,0.993169709326948 190 | 18.937875751503,3,0.992976911900203 191 | 19.0380761523046,3,0.992775750175319 192 | 19.1382765531062,3,0.992566405587773 193 | 19.2384769539078,3,0.992348987391911 194 | 19.3386773547094,3,0.992123561961909 195 | 19.438877755511,3,0.991890174814453 196 | 19.5390781563126,3,0.991648867053472 197 | 19.6392785571142,3,0.991399687354607 198 | 19.7394789579158,3,0.991142700320025 199 | 19.8396793587174,3,0.990877991883403 200 | 19.939879759519,3,0.990605672351035 201 | 20.0400801603206,3,0.990325877591327 202 | 20.1402805611222,3,0.990038768817165 203 | 20.2404809619238,3,0.989744531339792 204 | 20.3406813627255,3,0.989443372609517 205 | 20.4408817635271,3,0.989135519799383 206 | 20.5410821643287,3,0.988821217134549 207 | 20.6412825651303,3,0.988500723123437 208 | 20.7414829659319,3,0.988174307807054 209 | 20.8416833667335,3,0.987842250110074 210 | 20.9418837675351,3,0.987504835350794 211 | 21.0420841683367,3,0.987162352946116 212 | 21.1422845691383,3,0.986815094331595 213 | 21.2424849699399,3,0.986463351104432 214 | 21.3426853707415,3,0.986107413388395 215 | 21.4428857715431,3,0.985747568413389 216 | 21.5430861723447,3,0.985384099298135 217 | 21.6432865731463,3,0.985017284021779 218 | 21.7434869739479,3,0.984647394568793 219 | 21.8436873747495,3,0.984274696230935 220 | 21.9438877755511,3,0.983899447050107 221 | 22.0440881763527,3,0.983521897386461 222 | 22.1442885771543,3,0.983142289596874 223 | 22.2444889779559,3,0.982760857809945 224 | 22.3446893787575,3,0.982377827784704 225 | 22.4448897795591,3,0.981993416841391 226 | 22.5450901803607,3,0.981607833853763 227 | 22.6452905811623,3,0.981221279293471 228 | 22.7454909819639,3,0.98083394531811 229 | 22.8456913827655,3,0.980446015895464 230 | 22.9458917835671,3,0.980057666957416 231 | 23.0460921843687,3,0.97966906657776 232 | 23.1462925851703,3,0.979280375168919 233 | 23.2464929859719,3,0.978891745693241 234 | 23.3466933867735,3,0.978503323885126 235 | 23.4468937875751,3,0.978115248480772 236 | 23.5470941883768,3,0.977727651452818 237 | 23.6472945891784,3,0.977340658247555 238 | 23.74749498998,3,0.976954388022743 239 | 23.8476953907816,3,0.976568953884417 240 | 23.9478957915832,3,0.976184463121304 241 | 24.0480961923848,3,0.975801017435755 242 | 24.1482965931864,3,0.975418713170279 243 | 24.248496993988,3,0.975037641528965 244 | 24.3486973947896,3,0.974657888793215 245 | 24.4488977955912,3,0.974279536531375 246 | 24.5490981963928,3,0.973902661801934 247 | 24.6492985971944,3,0.973527337350069 248 | 24.749498997996,3,0.97315363179742 249 | 24.8496993987976,3,0.972781609825003 250 | 24.9498997995992,3,0.972411332349264 251 | 25.0501002004008,3,0.972042856691314 252 | 25.1503006012024,3,0.971676236739415 253 | 25.250501002004,3,0.971311523104842 254 | 25.3507014028056,3,0.97094876327123 255 | 25.4509018036072,3,0.970588001737603 256 | 25.5511022044088,3,0.970229280155213 257 | 25.6513026052104,3,0.969872637458414 258 | 25.751503006012,3,0.969518109989735 259 | 25.8517034068136,3,0.969165731619367 260 | 25.9519038076152,3,0.968815533859262 261 | 26.0521042084168,3,0.968467545972043 262 | 26.1523046092184,3,0.968121795074941 263 | 26.25250501002,3,0.967778306238946 264 | 26.3527054108216,3,0.967437102583382 265 | 26.4529058116232,3,0.967098205366096 266 | 26.5531062124249,3,0.966761634069458 267 | 26.6533066132265,3,0.966427406482345 268 | 26.7535070140281,3,0.966095538778309 269 | 26.8537074148297,3,0.965766045590086 270 | 26.9539078156313,3,0.965438940080629 271 | 27.0541082164329,3,0.965114234010816 272 | 27.1543086172345,3,0.964791937803998 273 | 27.2545090180361,3,0.964472060607537 274 | 27.3547094188377,3,0.964154610351473 275 | 27.4549098196393,3,0.963839593804467 276 | 27.5551102204409,3,0.963527016627146 277 | 27.6553106212425,3,0.963216883422971 278 | 27.7555110220441,3,0.962909197786772 279 | 27.8557114228457,3,0.962603962351034 280 | 27.9559118236473,3,0.962301178830066 281 | 28.0561122244489,3,0.962000848062158 282 | 28.1563126252505,3,0.961702970049802 283 | 28.2565130260521,3,0.961407543998109 284 | 28.3567134268537,3,0.961114568351475 285 | 28.4569138276553,3,0.960824040828612 286 | 28.5571142284569,3,0.960535958456004 287 | 28.6573146292585,3,0.960250317599877 288 | 28.7575150300601,3,0.959967113996755 289 | 28.8577154308617,3,0.959686342782666 290 | 28.9579158316633,3,0.959407998521072 291 | 29.0581162324649,3,0.959132075229584 292 | 29.1583166332665,3,0.958858566405514 293 | 29.2585170340681,3,0.958587465050328 294 | 29.3587174348697,3,0.958318763693058 295 | 29.4589178356713,3,0.958052454412711 296 | 29.5591182364729,3,0.957788528859731 297 | 29.6593186372745,3,0.957526978276561 298 | 29.7595190380762,3,0.957267793517346 299 | 29.8597194388778,3,0.957010965066815 300 | 29.9599198396794,3,0.956756483058387 301 | 30.060120240481,3,0.956504337291531 302 | 30.1603206412826,3,0.956254517248423 303 | 30.2605210420842,3,0.956007012109924 304 | 30.3607214428858,3,0.95576181077092 305 | 30.4609218436874,3,0.955518901855046 306 | 30.561122244489,3,0.955278273728821 307 | 30.6613226452906,3,0.955039914515237 308 | 30.7615230460922,3,0.954803812106797 309 | 30.8617234468938,3,0.954569954178062 310 | 30.9619238476954,3,0.954338328197698 311 | 31.062124248497,3,0.954108921440068 312 | 31.1623246492986,3,0.953881720996372 313 | 31.2625250501002,3,0.953656713785367 314 | 31.3627254509018,3,0.953433886563684 315 | 31.4629258517034,3,0.953213225935742 316 | 31.563126252505,3,0.95299471836331 317 | 31.6633266533066,3,0.952778350174694 318 | 31.7635270541082,3,0.952564107573592 319 | 31.8637274549098,3,0.952351976647624 320 | 31.9639278557114,3,0.952141943376539 321 | 32.064128256513,3,0.951933993640125 322 | 32.1643286573146,3,0.951728113225837 323 | 32.2645290581162,3,0.951524287836134 324 | 32.3647294589178,3,0.951322503095561 325 | 32.4649298597194,3,0.951122744557573 326 | 32.565130260521,3,0.950924997711105 327 | 32.6653306613226,3,0.950729247986916 328 | 32.7655310621242,3,0.950535480763702 329 | 32.8657314629259,3,0.950343681373985 330 | 32.9659318637275,3,0.950153835109799 331 | 33.0661322645291,3,0.949965927228168 332 | 33.1663326653307,3,0.949779942956392 333 | 33.2665330661323,3,0.949595867497138 334 | 33.3667334669339,3,0.94941368603336 335 | 33.4669338677355,3,0.949233383733034 336 | 33.5671342685371,3,0.949054945753728 337 | 33.6673346693387,3,0.948878357247009 338 | 33.7675350701403,3,0.948703603362695 339 | 33.8677354709419,3,0.948530669252947 340 | 33.9679358717435,3,0.948359540076222 341 | 34.0681362725451,3,0.94819020100108 342 | 34.1683366733467,3,0.948022637209855 343 | 34.2685370741483,3,0.947856833902192 344 | 34.3687374749499,3,0.947692776298458 345 | 34.4689378757515,3,0.947530449643023 346 | 34.5691382765531,3,0.947369839207428 347 | 34.6693386773547,3,0.947210930293431 348 | 34.7695390781563,3,0.947053708235943 349 | 34.8697394789579,3,0.946898158405851 350 | 34.9699398797595,3,0.946744266212742 351 | 35.0701402805611,3,0.946592017107515 352 | 35.1703406813627,3,0.946441396584901 353 | 35.2705410821643,3,0.946292390185882 354 | 35.3707414829659,3,0.946144983500021 355 | 35.4709418837675,3,0.945999162167693 356 | 35.5711422845691,3,0.945854911882236 357 | 35.6713426853707,3,0.945712218392016 358 | 35.7715430861723,3,0.945571067502399 359 | 35.8717434869739,3,0.945431445077656 360 | 35.9719438877756,5,0.94529333704278 361 | 36.0721442885772,5,0.945499856802262 362 | 36.1723446893788,5,0.946123476910244 363 | 36.2725450901804,5,0.946914523960779 364 | 36.372745490982,5,0.947783721846738 365 | 36.4729458917836,5,0.948689406481477 366 | 36.5731462925852,5,0.949609290234896 367 | 36.6733466933868,5,0.950530487583182 368 | 36.7735470941884,5,0.951445188478483 369 | 36.87374749499,5,0.952348521582587 370 | 36.9739478957916,5,0.953237402400175 371 | 37.0741482965932,5,0.954109872862887 372 | 37.1743486973948,5,0.95496470535945 373 | 37.2745490981964,5,0.955801157188085 374 | 37.374749498998,5,0.956618814173101 375 | 37.4749498997996,5,0.957417488807933 376 | 37.5751503006012,5,0.958197152566757 377 | 37.6753507014028,5,0.958957890062851 378 | 37.7755511022044,5,0.959699867423349 379 | 37.875751503006,5,0.960423310067298 380 | 37.9759519038076,5,0.961128486802834 381 | 38.0761523046092,5,0.961815698239017 382 | 38.1763527054108,5,0.962485268192001 383 | 38.2765531062124,5,0.963137537204238 384 | 38.376753507014,5,0.963772857580541 385 | 38.4769539078156,5,0.964391589532041 386 | 38.5771543086172,5,0.964994098143484 387 | 38.6773547094188,5,0.965580750962883 388 | 38.7775551102204,5,0.966151916069365 389 | 38.877755511022,5,0.966707960514234 390 | 38.9779559118236,5,0.967249249057486 391 | 39.0781563126253,5,0.967776143141386 392 | 39.1783567134269,5,0.968289000056439 393 | 39.2785571142285,5,0.968788172265179 394 | 39.3787575150301,5,0.969274006856554 395 | 39.4789579158317,5,0.969746845109217 396 | 39.5791583166333,5,0.970207022146188 397 | 39.6793587174349,5,0.970654866666585 398 | 39.7795591182365,5,0.971090700742598 399 | 39.8797595190381,5,0.97151483967186 400 | 39.9799599198397,5,0.971927591876941 401 | 40.0801603206413,5,0.972329258844954 402 | 40.1803607214429,5,0.972720135101308 403 | 40.2805611222445,5,0.973100508212514 404 | 40.3807615230461,5,0.97347065881363 405 | 40.4809619238477,5,0.973830860656579 406 | 40.5811623246493,5,0.974181380676054 407 | 40.6813627254509,5,0.974522479070163 408 | 40.7815631262525,5,0.974854409393366 409 | 40.8817635270541,5,0.975177418659536 410 | 40.9819639278557,5,0.975491747453301 411 | 41.0821643286573,5,0.975797630048042 412 | 41.1823647294589,5,0.976095294529133 413 | 41.2825651302605,5,0.976384962921204 414 | 41.3827655310621,5,0.976666851318376 415 | 41.4829659318637,5,0.976941170016538 416 | 41.5831663326653,5,0.977208123646889 417 | 41.6833667334669,5,0.977467911310046 418 | 41.7835671342685,5,0.977720726710149 419 | 41.8837675350701,5,0.977966758288458 420 | 41.9839679358717,5,0.978206189356008 421 | 42.0841683366733,5,0.978439198224976 422 | 42.1843687374749,5,0.978665958338447 423 | 42.2845691382766,5,0.978886638398326 424 | 42.3847695390782,5,0.9791014024912 425 | 42.4849699398798,5,0.979310410211962 426 | 42.5851703406814,5,0.979513816785077 427 | 42.685370741483,5,0.979711773183378 428 | 42.7855711422846,5,0.979904426244298 429 | 42.8857715430862,5,0.980091918783504 430 | 42.9859719438878,5,0.980274389705875 431 | 43.0861723446894,5,0.980451974113796 432 | 43.186372745491,5,0.980624803412781 433 | 43.2865731462926,5,0.980793005414403 434 | 43.3867735470942,5,0.980956704436562 435 | 43.4869739478958,5,0.981116021401107 436 | 43.5871743486974,5,0.981271073928833 437 | 43.687374749499,5,0.981421976431906 438 | 43.7875751503006,5,0.981568840203741 439 | 43.8877755511022,5,0.981711773506388 440 | 43.9879759519038,5,0.981850881655465 441 | 44.0881763527054,5,0.981986267102703 442 | 44.188376753507,5,0.982118029516136 443 | 44.2885771543086,5,0.98224626585801 444 | 44.3887775551102,5,0.982371070460457 445 | 44.4889779559118,5,0.982492535098985 446 | 44.5891783567134,5,0.982610749063856 447 | 44.689378757515,5,0.982725799229392 448 | 44.7895791583166,5,0.982837770121273 449 | 44.8897795591182,5,0.982946743981889 450 | 44.9899799599198,5,0.983052800833782 451 | 45.0901803607214,5,0.983156018541257 452 | 45.190380761523,5,0.983256472870198 453 | 45.2905811623246,5,0.983354237546143 454 | 45.3907815631263,5,0.98344938431068 455 | 45.4909819639279,5,0.9835419829762 456 | 45.5911823647295,5,0.983632101479073 457 | 45.6913827655311,5,0.983719805931275 458 | 45.7915831663327,5,0.983805160670533 459 | 45.8917835671343,5,0.983888228309013 460 | 45.9919839679359,5,0.983969069780615 461 | 46.0921843687375,5,0.984047744386904 462 | 46.1923847695391,5,0.984124309841724 463 | 46.2925851703407,5,0.984198822314534 464 | 46.3927855711423,5,0.984271336472506 465 | 46.4929859719439,5,0.984341905521423 466 | 46.5931863727455,5,0.984410581245416 467 | 46.6933867735471,5,0.984477414045565 468 | 46.7935871743487,5,0.984542452977416 469 | 46.8937875751503,5,0.984605745787434 470 | 46.9939879759519,5,0.984667338948425 471 | 47.0941883767535,5,0.984727277693969 472 | 47.1943887775551,5,0.984785606051878 473 | 47.2945891783567,5,0.984842366876721 474 | 47.3947895791583,5,0.984897601881445 475 | 47.4949899799599,5,0.984951351668103 476 | 47.5951903807615,5,0.985003655757738 477 | 47.6953907815631,5,0.985054552619432 478 | 47.7955911823647,5,0.985104079698551 479 | 47.8957915831663,5,0.985152273444206 480 | 47.9959919839679,5,0.985199169335965 481 | 48.0961923847695,5,0.98524480190982 482 | 48.1963927855711,5,0.985289204783444 483 | 48.2965931863727,5,0.985332410680757 484 | 48.3967935871744,5,0.985374451455816 485 | 48.496993987976,5,0.985415358116055 486 | 48.5971943887776,5,0.985455160844884 487 | 48.6973947895792,5,0.985493889023686 488 | 48.7975951903808,5,0.985531571253198 489 | 48.8977955911824,5,0.985568235374325 490 | 48.997995991984,5,0.985603908488386 491 | 49.0981963927856,5,0.985638616976807 492 | 49.1983967935872,5,0.985672386520287 493 | 49.2985971943888,5,0.985705242117444 494 | 49.3987975951904,5,0.985737208102959 495 | 49.498997995992,5,0.98576830816523 496 | 49.5991983967936,5,0.985798565363551 497 | 49.6993987975952,5,0.985828002144835 498 | 49.7995991983968,5,0.985856640359874 499 | 49.8997995991984,5,0.985884501279182 500 | 50,5,0.985911605608394 501 | -------------------------------------------------------------------------------- /images/apm.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/images/apm.png -------------------------------------------------------------------------------- /images/github.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/images/github.png -------------------------------------------------------------------------------- /images/hammond.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/images/hammond.jpg -------------------------------------------------------------------------------- /images/hedengren.jpg: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/images/hedengren.jpg -------------------------------------------------------------------------------- /images/matlab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/images/matlab.png -------------------------------------------------------------------------------- /images/pdc_overview.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/images/pdc_overview.png -------------------------------------------------------------------------------- /images/tclab.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/images/tclab.png -------------------------------------------------------------------------------- /images/webinar.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/images/webinar.png -------------------------------------------------------------------------------- /images/youtube.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/APMonitor/mdc/16aa3e9dd95d5d5c735acf9b8904d19370a01289/images/youtube.png -------------------------------------------------------------------------------- /tclab.m: -------------------------------------------------------------------------------- 1 | classdef tclab 2 | properties 3 | device 4 | board 5 | platform 6 | lab 7 | end 8 | methods 9 | function obj = tclab(com) 10 | % connect to Arduino 11 | board = 'Leonardo'; 12 | try 13 | % Install Arduino support with "pkg install -forge arduino" 14 | % See https://wiki.octave.org/Arduino_package 15 | pkg load arduino 16 | platform = 'octave'; 17 | catch 18 | % Install Arduino support with Arduino support package 19 | platform = 'matlab'; 20 | end 21 | 22 | try 23 | if nargin==0 24 | lab = arduino; 25 | else 26 | disp(['Connecting on COM port: ',com]) 27 | lab = arduino(com,board); 28 | end 29 | catch 30 | disp('Arduino reset, setup, or COM port needed') 31 | disp('1. Reset the Arduino (recommended if connected previously)') 32 | disp('2. Run "arduinosetup" from the command line to load firmware (if not previously connected)') 33 | disp('3. If still unable to connect, try COM port input with: lab=tclab("COM4")') 34 | disp('') 35 | disp('For Windows:') 36 | disp(' Open device manager, select "Ports (COM & LPT)"') 37 | disp(' Look for COM port of Arduino such as COM4') 38 | disp('For MacOS:') 39 | disp(' Open terminal and type: ls /dev/*.') 40 | disp(' Search for /dev/tty.usbmodem* or /dev/tty.usbserial*. The port number is *.') 41 | disp('For Linux') 42 | disp(' Open terminal and type: ls /dev/tty*') 43 | disp(' Search for /dev/ttyUSB* or /dev/ttyACM*. The port number is *.') 44 | disp('') 45 | lab = []; 46 | end 47 | obj.device = 'TCLab'; 48 | obj.board = board; 49 | obj.platform = platform; 50 | obj.lab = lab; 51 | end 52 | function r = v1a(obj) 53 | r=readVoltage(obj.lab, 'A0'); 54 | end 55 | function r = v2a(obj) 56 | r=readVoltage(obj.lab, 'A2'); 57 | end 58 | function r = v1(obj,n) 59 | r = 0; 60 | for i = 1:n 61 | r = r + obj.v1a; 62 | end 63 | r = r/n; 64 | end 65 | function r = v2(obj,n) 66 | r = 0; 67 | for i = 1:n 68 | r = r + obj.v2a; 69 | end 70 | r = r/n; 71 | end 72 | function r = TC(obj,V) 73 | r = (V - 0.5)*100.0; 74 | end 75 | function r = T1(obj) 76 | r = obj.TC(obj.v1(10)); 77 | end 78 | function r = T2(obj) 79 | r = obj.TC(obj.v2(10)); 80 | end 81 | function r = LED(obj,level) 82 | % LED function (0 <= level <= 100) 83 | if obj.platform=='octave' 84 | pkg load arduino 85 | end 86 | writePWMDutyCycle(obj.lab,'D9',max(0,min(1,level/100))); 87 | r = level; 88 | end 89 | function r = Q1(obj,level) 90 | % heater output (0 <= heater <= 100) 91 | % limit to 0-0.9 (0-100%) 92 | if obj.platform=='octave' 93 | pkg load arduino 94 | end 95 | writePWMDutyCycle(obj.lab,'D3',max(0,min(100,level))*0.9/100); 96 | r = level; 97 | end 98 | function r = Q2(obj,level) 99 | % heater output (0 <= heater <= 100) 100 | % limit to 0-0.5 (0-100%) 101 | if obj.platform=='octave' 102 | pkg load arduino 103 | end 104 | writePWMDutyCycle(obj.lab,'D5',max(0,min(100,level))*0.5/100); 105 | r = level; 106 | end 107 | function r = off(obj) 108 | if obj.platform=='octave' 109 | pkg load arduino 110 | end 111 | writePWMDutyCycle(obj.lab,'D3',0); 112 | writePWMDutyCycle(obj.lab,'D5',0); 113 | writePWMDutyCycle(obj.lab,'D9',0); 114 | r = 'TCLab heaters and LED off'; 115 | end 116 | function r = blink(obj,sec) 117 | obj.LED(100); 118 | pause(sec); 119 | obj.LED(0); 120 | r = ['LED Blink for ',num2str(sec),' sec']; 121 | end 122 | function r = test(obj) 123 | disp('30 Second Test, Turn on Heaters to 100%') 124 | obj.Q1(100); obj.Q2(100); 125 | for i = 1:30 126 | disp([' T1: ' num2str(obj.T1)... 127 | ' T2: ' num2str(obj.T2)]) 128 | % blink LED each cycle 129 | obj.LED(100); pause(0.8); obj.LED(0); pause(0.2) 130 | end 131 | disp('Turn off heaters') 132 | obj.off(); 133 | r = ['TCLab test complete']; 134 | end 135 | end 136 | end 137 | --------------------------------------------------------------------------------