├── .gitattributes ├── Block Diagram of System on MATLAB Simulink.png ├── FuzzyPID_PMSM.slx ├── Fuzzy_Logic.c ├── PID_PMSM.slx ├── PMSM_Plant.c ├── README.md ├── RFOC.c ├── SPWM.c ├── Speed_Controller_FuzzyPID.c └── Speed_Controller_PID.c /.gitattributes: -------------------------------------------------------------------------------- 1 | # Auto detect text files and perform LF normalization 2 | * text=auto 3 | -------------------------------------------------------------------------------- /Block Diagram of System on MATLAB Simulink.png: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IrfanArif18/MATLAB-Simulink-PMSM-FuzzyPIDController-Experiment/8667eeb74c800f80bca48a4946059023377b086d/Block Diagram of System on MATLAB Simulink.png -------------------------------------------------------------------------------- /FuzzyPID_PMSM.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IrfanArif18/MATLAB-Simulink-PMSM-FuzzyPIDController-Experiment/8667eeb74c800f80bca48a4946059023377b086d/FuzzyPID_PMSM.slx -------------------------------------------------------------------------------- /Fuzzy_Logic.c: -------------------------------------------------------------------------------- 1 | #define S_FUNCTION_LEVEL 2 2 | #define S_FUNCTION_NAME Fuzzy_Logic // s-Function Block Name 3 | #include "simstruc.h" 4 | #include 5 | 6 | #define U(element) (*uPtrs[element]) /* Pointer to Input Port0 */ 7 | 8 | static void mdlInitializeSizes(SimStruct *S) { 9 | ssSetNumDiscStates(S, 5); 10 | 11 | if (!ssSetNumInputPorts(S, 1)) return; 12 | ssSetInputPortWidth(S, 0, 2); // Number of Inputs 13 | ssSetInputPortDirectFeedThrough(S, 0, 1); 14 | ssSetInputPortOverWritable(S, 0, 1); 15 | 16 | if (!ssSetNumOutputPorts(S, 1)) return; 17 | ssSetOutputPortWidth(S, 0, 5); // Number of Outputs 18 | ssSetNumSampleTimes(S, 1); 19 | 20 | ssSetOptions(S, (SS_OPTION_EXCEPTION_FREE_CODE 21 | | SS_OPTION_DISCRETE_VALUED_OUTPUT)); 22 | } 23 | 24 | static void mdlInitializeSampleTimes(SimStruct *S) { 25 | ssSetSampleTime(S, 0, 1e-4); 26 | ssSetOffsetTime(S, 0, 0.0); 27 | } 28 | 29 | #define MDL_INITIALIZE_CONDITIONS 30 | 31 | static void mdlInitializeConditions(SimStruct *S) { 32 | real_T *X0 = ssGetRealDiscStates(S); 33 | int_T nXStates = ssGetNumDiscStates(S); 34 | InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); 35 | int_T i; 36 | 37 | /* Initialize the states to 0.0 */ 38 | for (i = 0; i < nXStates; i++) X0[i] = 0.0; 39 | } 40 | 41 | static void mdlOutputs(SimStruct *S, int_T tid) { 42 | real_T *Y = ssGetOutputPortRealSignal(S,0); 43 | real_T *X = ssGetRealDiscStates(S); 44 | 45 | real_T delta_Kp = X[1]; 46 | real_T delta_Ki = X[2]; 47 | real_T delta_Kd = X[3]; 48 | 49 | Y[0] = delta_Kp; 50 | Y[1] = delta_Ki; 51 | Y[2] = delta_Kd; 52 | Y[3] = X[0]; // Error 53 | Y[4] = X[5]; // Change of Error 54 | } 55 | 56 | #define MDL_UPDATE 57 | static void mdlUpdate(SimStruct *S, int_T tid) { 58 | real_T *X = ssGetRealDiscStates(S); 59 | InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S,0); 60 | 61 | real_T dt = 1e-4; 62 | 63 | // Input Ports 64 | real_T w_ref = U(0); 65 | real_T theta_m = U(1); 66 | 67 | real_T theta_old = X[4]; 68 | 69 | real_T w_act = (theta_m - theta_old)/dt; 70 | real_T e_old = X[0]; 71 | 72 | // Scaling 73 | real_T e_scale = 10; 74 | real_T ec_scale = 5; 75 | 76 | // Linguistic Variables 77 | real_T NL, NM, NS, Z, PS, PM, PL; 78 | 79 | // Fuzzification Logic 80 | real_T e_MFleft, e_DOMleft, e_MFright, e_DOMright; 81 | real_T e_MFleft_1, e_MFleft_2, e_MFright_1, e_MFright_2; 82 | 83 | real_T ec_MFleft, ec_DOMleft, ec_MFright, ec_DOMright; 84 | real_T ec_MFleft_1, ec_MFleft_2, ec_MFright_1, ec_MFright_2; 85 | 86 | // Error 87 | real_T e = w_ref - w_act; 88 | // Change of Error 89 | real_T ec = (e - e_old); 90 | 91 | // Normalization 92 | e = e / e_scale; 93 | ec = ec / ec_scale; 94 | 95 | // Degree of Membership for Error 96 | NL = -0.75 * e_scale; 97 | NM = -0.50 * e_scale; 98 | NS = -0.25 * e_scale; 99 | Z = 0.00 * e_scale; 100 | PS = 0.25 * e_scale; 101 | PM = 0.50 * e_scale; 102 | PL = 0.75 * e_scale; 103 | 104 | // Fuzzification for Error 105 | if (e <= NL) { 106 | e_MFleft = NL; // Lower NL Upper NL 107 | e_MFright = NL; // Lower NL Upper NL 108 | e_DOMleft = 1; 109 | e_DOMright = 1; 110 | } 111 | else if (e >= PL) { 112 | e_MFleft = PL; // Lower PL Upper PL 113 | e_MFright = PL; // Lower PL Upper PL 114 | e_DOMleft = 1; 115 | e_DOMright = 1; 116 | } 117 | else if (e == NM) { 118 | e_MFleft = NM; // Lower NM Upper NM 119 | e_MFright = NM; // Lower NM Upper NM 120 | e_DOMleft = 1; 121 | e_DOMright = 1; 122 | } 123 | else if (e == NS) { 124 | e_MFleft = NS; // Lower NS Upper NS 125 | e_MFright = NS; // Lower NS Upper NS 126 | e_DOMleft = 1; 127 | e_DOMright = 1; 128 | } 129 | else if (e == Z) { 130 | e_MFleft = Z; // Lower Z Upper Z 131 | e_MFright = Z; // Lower Z Upper Z 132 | e_DOMleft = 1; 133 | e_DOMright = 1; 134 | } 135 | else if (e == PS) { 136 | e_MFleft = PS; // Lower PS Upper PS 137 | e_MFright = PS; // Lower PS Upper PS 138 | e_DOMleft = 1; 139 | e_DOMright = 1; 140 | } 141 | else if (e == PM) { 142 | e_MFleft = PM; // Lower PM Upper PM 143 | e_MFright = PM; // Lower PM Upper PM 144 | e_DOMleft = 1; 145 | e_DOMright = 1; 146 | } 147 | // Negative Side 148 | else if (NL < e && e < Z) { 149 | if (NL < e && e < NM) { 150 | e_MFleft = NL; // Lower NL Upper NL 151 | e_MFright = NM; // Lower NL Upper NS 152 | 153 | e_DOMleft = (NM - e) / (NM - NL); 154 | 155 | e_MFright_1 = (e - NL) / (NM - NL); 156 | e_MFright_2 = (NS - e) / (NS - NM); 157 | 158 | if (e_MFright_1 > e_MFright_2) e_DOMright = e_MFright_2; 159 | else if (e_MFright_1 < e_MFright_2) e_DOMright = e_MFright_1; 160 | if (e_DOMright > 0) e_DOMright = e_DOMright; 161 | else if (e_DOMright < 0) e_DOMright = 0; 162 | } 163 | else if (NM < e && e < NS) { 164 | e_MFleft = NM; // Lower NL Upper NS 165 | e_MFright = NS; // Lower NM Upper Z 166 | 167 | e_MFleft_1 = (e - NL) / (NM - NL); 168 | e_MFleft_2 = (NS - NL) / (NS-NM); 169 | 170 | e_MFright_1 = (e - NM) / (NS - NM); 171 | e_MFright_2 = (Z - e) / (Z - NS); 172 | 173 | if (e_MFleft_1 > e_MFleft_2) e_DOMleft = e_MFleft_2; 174 | else if (e_MFleft_1 < e_MFleft_2) e_DOMleft = e_MFleft_1; 175 | if (e_DOMleft > 0) e_DOMleft = e_DOMleft; 176 | else if (e_DOMleft < 0) e_DOMleft = 0; 177 | 178 | if (e_MFright_1 > e_MFright_2) e_DOMright = e_MFright_2; 179 | else if (e_MFright_1 < e_MFright_2) e_DOMright = e_MFright_1; 180 | if (e_DOMright > 0) e_DOMright = e_DOMright; 181 | else if (e_DOMright < 0) e_MFright = 0; 182 | } 183 | else if (NS < e && e < Z) { 184 | e_MFleft = NS; // Lower NM Upper Z 185 | e_MFright = Z; // Lower NS Upper PS 186 | 187 | e_MFleft_1 = (e - NM) / (NS - NM); 188 | e_MFleft_2 = (Z - e) / (Z - NS); 189 | 190 | e_MFright_1 = (e - NS) / (Z - NS); 191 | e_MFright_2 = (PS - e) / (PS - Z); 192 | 193 | if (e_MFleft_1 > e_MFleft_2) e_DOMleft = e_MFleft_2; 194 | else if (e_MFleft_1 < e_MFleft_2) e_DOMleft = e_MFleft_1; 195 | if (e_DOMleft > 0) e_DOMleft = e_DOMleft; 196 | else if (e_DOMleft < 0) e_DOMleft = 0; 197 | 198 | if (e_MFright_1 > e_MFright_2) e_DOMright = e_MFright_2; 199 | else if (e_MFright_1 < e_MFright_2) e_DOMright = e_MFright_1; 200 | if (e_DOMright > 0) e_DOMright = e_DOMright; 201 | else if (e_DOMright < 0) e_DOMright = 0; 202 | } 203 | } 204 | // Positive Side 205 | else if (Z < e && e < PL) { 206 | if (Z < e && e < NS) { 207 | e_MFleft = Z; // Lower NS Upper PS 208 | e_MFright = PS; // Lower Z Upper PM 209 | 210 | e_MFleft_1 = (e - NS) / (Z - NS); 211 | e_MFleft_2 = (PS - e) / (PS-Z); 212 | 213 | e_MFright_1 = (e - Z) / (PS - Z); 214 | e_MFright_2 = (PM - e) / (PM - PS); 215 | 216 | if (e_MFleft_1 > e_MFleft_2) e_DOMleft = e_MFleft_2; 217 | else if (e_MFleft_1 < e_MFleft_2) e_DOMleft = e_MFleft_1; 218 | if (e_DOMleft > 0) e_DOMleft = e_DOMleft; 219 | else if (e_DOMleft < 0) e_DOMleft = 0; 220 | 221 | if (e_MFright_1 > e_MFright_2) e_DOMright = e_MFright_2; 222 | else if (e_MFright_1 < e_MFright_2) e_DOMright = e_MFright_1; 223 | if (e_DOMright > 0) e_DOMright = e_DOMright; 224 | else if (e_DOMright < 0) e_DOMright = 0; 225 | } 226 | else if (NS < e && e < PM) { 227 | e_MFleft = PS; // Lower Z Upper PM 228 | e_MFright = PM; // Lower PS Upper PL 229 | 230 | e_MFleft_1 = (e - Z) / (PS - Z); 231 | e_MFleft_2 = (PM - e) / (PM - PS); 232 | 233 | e_MFright_1 = (e - PS) / (PM - PS); 234 | e_MFright_2 = (PL - e) / (PL - PM); 235 | 236 | if (e_MFleft_1 > e_MFleft_2) e_DOMleft = e_MFleft_2; 237 | else if (e_MFleft_1 < e_MFleft_2) e_DOMleft = e_MFleft_1; 238 | if (e_DOMleft > 0) e_DOMleft = e_DOMleft; 239 | else if (e_DOMleft < 0) e_DOMleft = 0; 240 | 241 | if (e_MFright_1 > e_MFright_2) e_DOMright = e_MFright_2; 242 | else if (e_MFright_1 < e_MFright_2) e_DOMright = e_MFright_1; 243 | if (e_DOMright > 0) e_DOMright = e_DOMright; 244 | else if (e_DOMright < 0) e_DOMright = 0; 245 | } 246 | else if (PM < e < PL) { 247 | e_MFleft = PM; // Lower PS Upper PL 248 | e_MFright = PL; // Lower PL Upper PL 249 | 250 | e_MFleft_1 = (e - PS) / (PM - PS); 251 | e_MFleft_2 = (PL - e) / (PL - PM); 252 | 253 | e_DOMright = (PL - e) / (PL - PM); 254 | 255 | if (e_MFleft_1 > e_MFleft_2) e_DOMleft = e_MFleft_2; 256 | else if (e_MFleft_1 < e_MFleft_2) e_DOMleft = e_MFleft_1; 257 | if (e_DOMleft > 0) e_DOMleft = e_DOMleft; 258 | else if (e_DOMleft < 0) e_DOMleft = 0; 259 | } 260 | } 261 | 262 | // Degree of Membership for Change of Error 263 | NL = -0.75 * ec_scale; 264 | NM = -0.50 * ec_scale; 265 | NS = -0.25 * ec_scale; 266 | Z = 0.00 * ec_scale; 267 | PS = 0.25 * ec_scale; 268 | PM = 0.50 * ec_scale; 269 | PL = 0.75 * ec_scale; 270 | 271 | // Fuzzification for Change of Error 272 | if (ec <= NL) { 273 | ec_MFleft = NL; // Lower NL Upper NL 274 | ec_MFright = NL; // Lower NL Upper NL 275 | ec_DOMleft = 1; 276 | ec_DOMright = 1; 277 | } 278 | else if (ec >= PL) { 279 | ec_MFleft = PL; // Lower PL Upper PL 280 | ec_MFright = PL; // Lower PL Upper PL 281 | ec_DOMleft = 1; 282 | ec_DOMright = 1; 283 | } 284 | else if (ec == NM) { 285 | ec_MFleft = NM; // Lower NM Upper NM 286 | ec_MFright = NM; // Lower NM Upper NM 287 | ec_DOMleft = 1; 288 | ec_DOMright = 1; 289 | } 290 | else if (ec == NS) { 291 | ec_MFleft = NS; // Lower NS Upper NS 292 | ec_MFright = NS; // Lower NS Upper NS 293 | ec_DOMleft = 1; 294 | ec_DOMright = 1; 295 | } 296 | else if (ec == Z) { 297 | ec_MFleft = Z; // Lower Z Upper Z 298 | ec_MFright = Z; // Lower Z Upper Z 299 | ec_DOMleft = 1; 300 | ec_DOMright = 1; 301 | } 302 | else if (ec == PS) { 303 | ec_MFleft = PS; // Lower PS Upper PS 304 | ec_MFright = PS; // Lower PS Upper PS 305 | ec_DOMleft = 1; 306 | ec_DOMright = 1; 307 | } 308 | else if (ec == PM) { 309 | ec_MFleft = PM; // Lower PM Upper PM 310 | ec_MFright = PM; // Lower PM Upper PM 311 | ec_DOMleft = 1; 312 | ec_DOMright = 1; 313 | } 314 | // Negative Side 315 | else if (NL < ec && ec < Z) { 316 | if (NL < ec && ec < NM) { 317 | ec_MFleft = NL; // Lower NL Upper NL 318 | ec_MFright = NM; // Lower NL Upper NS 319 | 320 | ec_DOMleft = (NM - ec) / (NM - NL); 321 | 322 | ec_MFright_1 = (ec - NL) / (NM - NL); 323 | ec_MFright_2 = (NS - ec) / (NS - NM); 324 | 325 | if (ec_MFright_1 > ec_MFright_2) ec_DOMright = ec_MFright_2; 326 | else if (ec_MFright_1 < ec_MFright_2) ec_DOMright = ec_MFright_1; 327 | if (ec_DOMright > 0) ec_DOMright = ec_DOMright; 328 | else if (ec_DOMright < 0) ec_DOMright = 0; 329 | } 330 | else if (NM < ec && ec < NS) { 331 | ec_MFleft = NM; // Lower NL Upper NS 332 | ec_MFright = NS; // Lower NM Upper Z 333 | 334 | ec_MFleft_1 = (ec - NL) / (NM - NL); 335 | ec_MFleft_2 = (NS - NL) / (NS - NM); 336 | 337 | ec_MFright_1 = (ec - NM) / (NS - NM); 338 | ec_MFright_2 = (Z - ec) / (Z - NS); 339 | 340 | if (ec_MFleft_1 > ec_MFleft_2) ec_DOMleft = ec_MFleft_2; 341 | else if (ec_MFleft_1 < ec_MFleft_2) ec_DOMleft = ec_MFleft_1; 342 | if (ec_DOMleft > 0) ec_DOMleft = ec_DOMleft; 343 | else if (ec_DOMleft < 0) ec_DOMleft = 0; 344 | 345 | if (ec_MFright_1 > ec_MFright_2) ec_DOMright = ec_MFright_2; 346 | else if (ec_MFright_1 < ec_MFright_2) ec_DOMright = ec_MFright_1; 347 | if (ec_DOMright > 0) ec_DOMright = ec_DOMright; 348 | else if (ec_DOMright < 0) ec_MFright = 0; 349 | } 350 | else if (NS < ec && ec < Z) { 351 | ec_MFleft = NS; // Lower NM Upper Z 352 | ec_MFright = Z; // Lower NS Upper PS 353 | 354 | ec_MFleft_1 = (ec - NM) / (NS - NM); 355 | ec_MFleft_2 = (Z - ec) / (Z - NS); 356 | 357 | ec_MFright_1 = (ec - NS) / (Z - NS); 358 | ec_MFright_2 = (PS - ec) / (PS-Z); 359 | 360 | if (ec_MFleft_1 > ec_MFleft_2) ec_DOMleft = ec_MFleft_2; 361 | else if (ec_MFleft_1 < ec_MFleft_2) ec_DOMleft = ec_MFleft_1; 362 | if (ec_DOMleft > 0) ec_DOMleft = ec_DOMleft; 363 | else if (ec_DOMleft < 0) ec_DOMleft = 0; 364 | 365 | if (ec_MFright_1 > ec_MFright_2) ec_DOMright = ec_MFright_2; 366 | else if (ec_MFright_1 < ec_MFright_2) ec_DOMright = ec_MFright_1; 367 | if (ec_DOMright > 0) ec_DOMright = ec_DOMright; 368 | else if (ec_DOMright < 0) ec_DOMright = 0; 369 | } 370 | } 371 | // Positive Side 372 | else if (Z < ec && ec < PL) { 373 | if (Z < ec && ec < NS) { 374 | ec_MFleft = Z; // Lower NS Upper PS 375 | ec_MFright = PS; // Lower Z Upper PM 376 | 377 | ec_MFleft_1 = (ec - NS) / (Z - NS); 378 | ec_MFleft_2 = (PS - ec) / (PS - Z); 379 | 380 | ec_MFright_1 = (ec - Z) / (PS - Z); 381 | ec_MFright_2 = (PM - ec) / (PM - PS); 382 | 383 | if (ec_MFleft_1 > ec_MFleft_2) ec_DOMleft = ec_MFleft_2; 384 | else if (ec_MFleft_1 < ec_MFleft_2) ec_DOMleft = ec_MFleft_1; 385 | if (ec_DOMleft > 0) ec_DOMleft = ec_DOMleft; 386 | else if (ec_DOMleft < 0) ec_DOMleft = 0; 387 | 388 | if (ec_MFright_1 > ec_MFright_2) ec_DOMright = ec_MFright_2; 389 | else if (ec_MFright_1 < ec_MFright_2) ec_DOMright = ec_MFright_1; 390 | if (ec_DOMright > 0) ec_DOMright = ec_DOMright; 391 | else if (ec_DOMright < 0) ec_DOMright = 0; 392 | } 393 | else if (NS < ec && ec < PM) { 394 | ec_MFleft = PS; // Lower Z Upper PM 395 | ec_MFright = PM; // Lower PS Upper PL 396 | 397 | ec_MFleft_1 = (ec - Z) / (PS - Z); 398 | ec_MFleft_2 = (PM - ec) / (PM - PS); 399 | 400 | ec_MFright_1 = (ec - PS) / (PM - PS); 401 | ec_MFright_2 = (PL - ec) / (PL - PM); 402 | 403 | if (ec_MFleft_1 > ec_MFleft_2) ec_DOMleft = ec_MFleft_2; 404 | else if (ec_MFleft_1 < ec_MFleft_2) ec_DOMleft = ec_MFleft_1; 405 | if (ec_DOMleft > 0) ec_DOMleft = ec_DOMleft; 406 | else if (ec_DOMleft < 0) ec_DOMleft = 0; 407 | 408 | if (ec_MFright_1 > ec_MFright_2) ec_DOMright = ec_MFright_2; 409 | else if (ec_MFright_1 < ec_MFright_2) ec_DOMright = ec_MFright_1; 410 | if (ec_DOMright > 0) ec_DOMright = ec_DOMright; 411 | else if (ec_DOMright < 0) ec_DOMright = 0; 412 | } 413 | else if (PM < ec && ec < PL) { 414 | ec_MFleft = PM; // Lower PS Upper PL 415 | ec_MFright = PL; // Lower PL Upper PL 416 | 417 | ec_MFleft_1 = (ec - PS) / (PM - PS); 418 | ec_MFleft_2 = (PL - ec) / (PL - PM); 419 | 420 | ec_DOMright = (PL - ec)/(PL - PM); 421 | 422 | if (ec_MFleft_1 > ec_MFleft_2) ec_DOMleft = ec_MFleft_2; 423 | else if (ec_MFleft_1 < ec_MFleft_2) ec_DOMleft = ec_MFleft_1; 424 | if (ec_DOMleft > 0) ec_DOMleft = ec_DOMleft; 425 | else if (ec_DOMleft < 0) ec_DOMleft = 0; 426 | } 427 | } 428 | 429 | // Output of Fuzzy Variables 430 | real_T KP_OMF, KI_OMF, KD_OMF; 431 | real_T e_OMF, e_ODOM, ec_OMF, ec_ODOM; 432 | 433 | // Weighted Average 434 | e_OMF = (e_DOMleft * e_MFleft + e_DOMright * e_MFright) / (e_DOMleft + e_DOMright); 435 | ec_OMF = (ec_DOMleft * ec_MFleft + ec_DOMright * ec_MFright) / (ec_DOMleft + ec_DOMright); 436 | 437 | // Inference Engine 438 | // Base Rule for KP KI KD 439 | if (ec_OMF == NL) { 440 | if (e_OMF == NL) {KP_OMF = PL; KI_OMF = NL; KD_OMF = PS;} 441 | else if (e_OMF == NM) {KP_OMF = PL; KI_OMF = NL; KD_OMF = PS;} 442 | else if (e_OMF == NS) {KP_OMF = PM; KI_OMF = NL; KD_OMF = Z;} 443 | else if (e_OMF == Z) {KP_OMF = PM; KI_OMF = NM; KD_OMF = Z;} 444 | else if (e_OMF == PS) {KP_OMF = PS; KI_OMF = NM; KD_OMF = Z;} 445 | else if (e_OMF == PM) {KP_OMF = PS; KI_OMF = Z; KD_OMF = PL;} 446 | else if (e_OMF == PL) {KP_OMF = Z; KI_OMF = Z; KD_OMF = PL;} 447 | } 448 | else if (ec_OMF == NM) { 449 | if (e_OMF == NL) {KP_OMF = PL; KI_OMF = NL; KD_OMF = NS;} 450 | else if (e_OMF == NM) {KP_OMF = PL; KI_OMF = NL; KD_OMF = NS;} 451 | else if (e_OMF == NS) {KP_OMF = PM; KI_OMF = NM; KD_OMF = NS;} 452 | else if (e_OMF == Z) {KP_OMF = PM; KI_OMF = NM; KD_OMF = NS;} 453 | else if (e_OMF == PS) {KP_OMF = PS; KI_OMF = NS; KD_OMF = Z;} 454 | else if (e_OMF == PM) {KP_OMF = Z; KI_OMF = Z; KD_OMF = NS;} 455 | else if (e_OMF == PL) {KP_OMF = Z; KI_OMF = Z; KD_OMF = PM;} 456 | } 457 | else if (ec_OMF == NS) { 458 | if (e_OMF == NL) {KP_OMF = PM; KI_OMF = NM; KD_OMF = NL;} 459 | else if (e_OMF == NM) {KP_OMF = PM; KI_OMF = NM; KD_OMF = NL;} 460 | else if (e_OMF == NS) {KP_OMF = PM; KI_OMF = NS; KD_OMF = NM;} 461 | else if (e_OMF == Z) {KP_OMF = PS; KI_OMF = NS; KD_OMF = NS;} 462 | else if (e_OMF == PS) {KP_OMF = Z; KI_OMF = Z; KD_OMF = Z;} 463 | else if (e_OMF == PM) {KP_OMF = NS; KI_OMF = PS; KD_OMF = PS;} 464 | else if (e_OMF == PL) {KP_OMF = NM; KI_OMF = PS; KD_OMF = PM;} 465 | } 466 | else if (ec_OMF == Z) { 467 | if (e_OMF == NL) {KP_OMF = PS; KI_OMF = NS; KD_OMF = NL;} 468 | else if (e_OMF == NM) {KP_OMF = PS; KI_OMF = NS; KD_OMF = NM;} 469 | else if (e_OMF == NS) {KP_OMF = PS; KI_OMF = NS; KD_OMF = NM;} 470 | else if (e_OMF == Z) {KP_OMF = Z; KI_OMF = Z; KD_OMF = NS;} 471 | else if (e_OMF == PS) {KP_OMF = NS; KI_OMF = PS; KD_OMF = Z;} 472 | else if (e_OMF == PM) {KP_OMF = NM; KI_OMF = PS; KD_OMF = PS;} 473 | else if (e_OMF == PL) {KP_OMF = NM; KI_OMF = PM; KD_OMF = PM;} 474 | } 475 | else if (ec_OMF == PS) { 476 | if (e_OMF == NL) {KP_OMF = PS; KI_OMF = NS; KD_OMF = NL;} 477 | else if (e_OMF == NM) {KP_OMF = PS; KI_OMF = NS; KD_OMF = NM;} 478 | else if (e_OMF == NS) {KP_OMF = Z; KI_OMF = Z; KD_OMF = NS;} 479 | else if (e_OMF == Z) {KP_OMF = NS; KI_OMF = PS; KD_OMF = NS;} 480 | else if (e_OMF == PS) {KP_OMF = NM; KI_OMF = PS; KD_OMF = Z;} 481 | else if (e_OMF == PM) {KP_OMF = NM; KI_OMF = PM; KD_OMF = PS;} 482 | else if (e_OMF == PL) {KP_OMF = NM; KI_OMF = PM; KD_OMF = PS;} 483 | } 484 | else if (ec_OMF == PM) { 485 | if (e_OMF == NL) {KP_OMF = Z; KI_OMF = Z; KD_OMF = NM;} 486 | else if (e_OMF == NM) {KP_OMF = Z; KI_OMF = Z; KD_OMF = NS;} 487 | else if (e_OMF == NS) {KP_OMF = NS; KI_OMF = PS; KD_OMF = NS;} 488 | else if (e_OMF == Z) {KP_OMF = NM; KI_OMF = PM; KD_OMF = NS;} 489 | else if (e_OMF == PS) {KP_OMF = NM; KI_OMF = PM; KD_OMF = Z;} 490 | else if (e_OMF == PM) {KP_OMF = NM; KI_OMF = PL; KD_OMF = PS;} 491 | else if (e_OMF == PL) {KP_OMF = NL; KI_OMF = PL; KD_OMF = PS;} 492 | } 493 | else if (ec_OMF == PL) { 494 | if (e_OMF == NL) {KP_OMF = Z; KI_OMF = Z; KD_OMF = PS;} 495 | else if (e_OMF == NM) {KP_OMF = NS; KI_OMF = Z; KD_OMF = Z;} 496 | else if (e_OMF == NS) {KP_OMF = NS; KI_OMF = PS; KD_OMF = Z;} 497 | else if (e_OMF == Z) {KP_OMF = NM; KI_OMF = PM; KD_OMF = Z;} 498 | else if (e_OMF == PS) {KP_OMF = NM; KI_OMF = PL; KD_OMF = Z;} 499 | else if (e_OMF == PM) {KP_OMF = NL; KI_OMF = PL; KD_OMF = PL;} 500 | else if (e_OMF == PL) {KP_OMF = NL; KI_OMF = PL; KD_OMF = PL;} 501 | } 502 | 503 | // Crisp Output Variables 504 | real_T delta_Kp, delta_Ki, delta_Kd; 505 | 506 | // Defuzzification 507 | // Crisp Value for Output 508 | if (KP_OMF == NL) {delta_Kp = -3;} 509 | else if (KP_OMF == NM) {delta_Kp = -2;} 510 | else if (KP_OMF == NS) {delta_Kp = -1;} 511 | else if (KP_OMF == Z) {delta_Kp = 0;} 512 | else if (KP_OMF == PS) {delta_Kp = 1;} 513 | else if (KP_OMF == PM) {delta_Kp = 2;} 514 | else if (KP_OMF == PL) {delta_Kp = 3;} 515 | 516 | if (KI_OMF == NL) {delta_Ki = -3;} 517 | else if (KI_OMF == NM) {delta_Ki = -2;} 518 | else if (KI_OMF == NS) {delta_Ki = -1;} 519 | else if (KI_OMF == Z) {delta_Ki = 0;} 520 | else if (KI_OMF == PS) {delta_Ki = 1;} 521 | else if (KI_OMF == PM) {delta_Ki = 2;} 522 | else if (KI_OMF == PL) {delta_Ki = 3;} 523 | 524 | if (KD_OMF == NL) {delta_Ki = -3;} 525 | else if (KD_OMF == NM) {delta_Kd = -2;} 526 | else if (KD_OMF == NS) {delta_Kd = -1;} 527 | else if (KD_OMF == Z) {delta_Kd = 0;} 528 | else if (KD_OMF == PS) {delta_Kd = 1;} 529 | else if (KD_OMF == PM) {delta_Kd = 2;} 530 | else if (KD_OMF == PL) {delta_Kd = 3;} 531 | 532 | X[0] = e; 533 | X[1] = delta_Kp; 534 | X[2] = delta_Ki; 535 | X[3] = delta_Kd; 536 | X[4] = theta_m; 537 | X[5] = ec; 538 | } 539 | 540 | static void mdlTerminate(SimStruct *S) 541 | {} /* Keep this function empty since no memory is allocated */ 542 | 543 | #ifdef MATLAB_MEX_FILE 544 | /* Is this file being compiled as a MEX-file? */ 545 | #include "simulink.c" /* MEX-file interface mechanism */ 546 | #else 547 | #include "cg_sfun.h" /* Code generation registration function */ 548 | #endif -------------------------------------------------------------------------------- /PID_PMSM.slx: -------------------------------------------------------------------------------- https://raw.githubusercontent.com/IrfanArif18/MATLAB-Simulink-PMSM-FuzzyPIDController-Experiment/8667eeb74c800f80bca48a4946059023377b086d/PID_PMSM.slx -------------------------------------------------------------------------------- /PMSM_Plant.c: -------------------------------------------------------------------------------- 1 | #define S_FUNCTION_LEVEL 2 2 | #define S_FUNCTION_NAME PMSM_Plant // s-Function Block Name 3 | #include "simstruc.h" 4 | #include 5 | 6 | #define U(element) (*uPtrs[element]) /* Pointer to Input Port0 */ 7 | 8 | static void mdlInitializeSizes(SimStruct *S) { 9 | ssSetNumContStates(S, 4); 10 | 11 | if (!ssSetNumInputPorts(S, 1)) return; 12 | ssSetInputPortWidth(S, 0, 4); // Number of Inputs 13 | ssSetInputPortDirectFeedThrough(S, 0, 1); 14 | ssSetInputPortOverWritable(S, 0, 1); 15 | 16 | if (!ssSetNumOutputPorts(S, 1)) return; 17 | ssSetOutputPortWidth(S, 0, 7); // Number of Outputs 18 | ssSetNumSampleTimes(S, 1); 19 | 20 | ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE); 21 | } 22 | 23 | static void mdlInitializeSampleTimes(SimStruct *S) { 24 | ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); 25 | ssSetOffsetTime(S, 0, 0.0); 26 | } 27 | 28 | #define MDL_INITIALIZE_CONDITIONS 29 | static void mdlInitializeConditions(SimStruct *S) { 30 | 31 | real_T *X0 = ssGetContStates(S); 32 | int_T nStates = ssGetNumContStates(S); 33 | int_T i; 34 | 35 | /* Initialize the states to 0.0 */ 36 | for (i = 0; i < nStates; i++) X0[i] = 0.0; 37 | } 38 | 39 | static void mdlOutputs(SimStruct *S, int_T tid) { 40 | real_T *Y = ssGetOutputPortRealSignal(S, 0); 41 | real_T *X = ssGetContStates(S); 42 | InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0); 43 | 44 | real_T Wm, Theta_e, Isd, Isq, Te, Ia, Ib, Ic, Vsd, Vsq; 45 | real_T I_Alfa, I_Beta; 46 | 47 | // Transformation Constants 48 | real_T Constant = 0.816497; 49 | real_T Constant2 = 0.866025; 50 | 51 | // PMSM Parameters 52 | real_T N = 4; 53 | 54 | // State Variables 55 | Wm = X[0]; 56 | Theta_e = X[1]; 57 | Isq = X[2]; 58 | Isd = X[3]; 59 | Te = X[4]; 60 | 61 | // dq to AlphaBeta (Inverse Park) 62 | I_Alfa = Isd * cos(Theta_e) - Isq * sin(Theta_e); 63 | I_Beta = Isd * sin(Theta_e) + Isq * cos(Theta_e); 64 | 65 | // AlphaBeta to ABC (Inverse Clarke) 66 | Ia = Constant * I_Alfa; 67 | Ib = Constant * (-0.5 * I_Alfa + (Constant2) * I_Beta); 68 | Ic = Constant * (-0.5 * I_Alfa - (Constant2) * I_Beta); 69 | 70 | Y[0] = Ia; 71 | Y[1] = Ib; 72 | Y[2] = Ic; 73 | Y[3] = Wm; 74 | Y[4] = Te; 75 | Y[5] = Theta_e / N; 76 | Y[6] = Theta_e; 77 | } 78 | 79 | #define MDL_DERIVATIVES 80 | static void mdlDerivatives(SimStruct *S) { 81 | real_T *dX = ssGetdX(S); 82 | real_T *X = ssGetContStates(S); 83 | InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0); 84 | 85 | real_T Va, Vb, Vc, Vsalfa, Vsbeta, Vsd, Vsq; 86 | real_T Te, Tl, Wm, Wm_dot, Isd_dot, Isq_dot; 87 | real_T Theta_e, Theta_e_dot, Isd, Isq; 88 | real_T Ia, Ib, Ic, I_Alfa, I_Beta; 89 | 90 | // Transformation Constants 91 | real_T Constant = 0.816497; // sqrt(2/3) 92 | real_T Constant2 = 0.866025; // sqrt(3)/2 93 | 94 | // PMSM Parameters 95 | real_T N = 4; 96 | real_T psi = 0.121; 97 | real_T Lsd = 16.61e-3; 98 | real_T Lsq = 16.22e-3; 99 | real_T Rs = 0.55; 100 | real_T J = 0.01; 101 | 102 | // Input Ports 103 | Tl = U(0); 104 | Va = U(1); 105 | Vb = U(2); 106 | Vc = U(3); 107 | 108 | // State Variables 109 | Wm = X[0]; 110 | Theta_e = X[1]; 111 | Isd = X[2]; 112 | Isq = X[3]; 113 | 114 | // ABC to AlphaBeta (Clarke) 115 | Vsalfa = Constant * (Va - 0.5 * Vb - 0.5 * Vc); 116 | Vsbeta = Constant * Constant2 * (Vb - Vc); 117 | 118 | // AlphaBeta to dq (Park) 119 | Vsd = Vsalfa * cos(Theta_e) + Vsbeta * sin(Theta_e); 120 | Vsq = -Vsalfa * sin(Theta_e) + Vsbeta * cos(Theta_e); 121 | 122 | // PMSM dq Model 123 | Te = N * (psi + (Lsd - Lsq) * Isd) * Isq; 124 | Wm_dot = (Te - Tl) / J; 125 | Theta_e_dot = N * Wm; 126 | Isd_dot = (Vsd - Rs * Isd + N * Wm * Lsq * Isq) / Lsd; 127 | Isq_dot = (Vsq - Rs * Isq - N * Wm * (Lsd * Isd + psi)) / Lsq; 128 | 129 | // State Variable Derivatives 130 | dX[0] = Wm_dot; 131 | dX[1] = Theta_e_dot; 132 | dX[2] = Isd_dot; 133 | dX[3] = Isq_dot; 134 | 135 | X[4] = Te; 136 | } 137 | 138 | static void mdlTerminate(SimStruct *S) 139 | {} /* Keep this function empty since no memory is allocated */ 140 | 141 | #ifdef MATLAB_MEX_FILE 142 | /* Is this file being compiled as a MEX-file? */ 143 | #include "simulink.c" /* MEX-file interface mechanism */ 144 | #else 145 | #include "cg_sfun.h" /* Code generation registration function */ 146 | #endif -------------------------------------------------------------------------------- /README.md: -------------------------------------------------------------------------------- 1 | # MATLAB-Simulink-PMSM FuzzyPIDController Experiment 2 | MATLAB Simulink experiment of Permanent Magnet Synchronous Motor (PMSM) with Fuzzy Logic PID Controller. 3 | Done for semester's final project for Sistem Kendali Motor Listrik (Electrical Motor Control System) in Universitas Indonesia (University of Indonesia), third year 2022. 4 | 5 | Block diagram of system on MATLAB Simulink: 6 |

7 | 8 |

9 | 10 | Side note: This model unfortunately still has many flaws. 11 | -------------------------------------------------------------------------------- /RFOC.c: -------------------------------------------------------------------------------- 1 | #define S_FUNCTION_LEVEL 2 2 | #define S_FUNCTION_NAME RFOC // s-Function Block Name 3 | #include "simstruc.h" 4 | #include 5 | 6 | #define U(element) (*uPtrs[element]) /* Pointer to Input Port0 */ 7 | 8 | static void mdlInitializeSizes(SimStruct *S) { 9 | ssSetNumDiscStates(S, 8); 10 | 11 | if (!ssSetNumInputPorts(S, 1)) 12 | return; 13 | ssSetInputPortWidth(S, 0, 5); 14 | ssSetInputPortDirectFeedThrough(S, 0, 1); 15 | ssSetInputPortOverWritable(S, 0, 1); 16 | 17 | if (!ssSetNumOutputPorts(S, 1)) 18 | return; 19 | ssSetOutputPortWidth(S, 0, 3); 20 | ssSetNumSampleTimes(S, 1); 21 | 22 | ssSetOptions(S, (SS_OPTION_EXCEPTION_FREE_CODE 23 | | SS_OPTION_DISCRETE_VALUED_OUTPUT)); 24 | } 25 | 26 | static void mdlInitializeSampleTimes(SimStruct *S) { 27 | ssSetSampleTime(S, 0, 1e-3); 28 | ssSetOffsetTime(S, 0, 0.0); 29 | } 30 | 31 | #define MDL_INITIALIZE_CONDITIONS 32 | static void mdlInitializeConditions(SimStruct *S) { 33 | real_T *X0 = ssGetRealDiscStates(S); 34 | int_T nXStates = ssGetNumDiscStates(S); 35 | InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0); 36 | int_T i; 37 | 38 | /* Initialize the states to 0.0 */ 39 | for (i = 0; i < nXStates; i++) X0[i] = 0.0; 40 | } 41 | 42 | static void mdlOutputs(SimStruct *S, int_T tid) { 43 | real_T *Y = ssGetOutputPortRealSignal(S, 0); 44 | real_T *X = ssGetRealDiscStates(S); 45 | 46 | real_T Va, Vb, Vc; 47 | 48 | Va = X[5]; 49 | Vb = X[6]; 50 | Vc = X[7]; 51 | 52 | Y[0] = Va; 53 | Y[1] = Vb; 54 | Y[2] = Vc; 55 | } 56 | 57 | #define MDL_UPDATE 58 | static void mdlUpdate(SimStruct *S, int_T tid) { 59 | real_T *X = ssGetRealDiscStates(S); 60 | InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0); 61 | 62 | real_T dt = 1e-3; 63 | 64 | real_T iq, id, theta_e, ia, ib, ic, isalfa, isbeta, isd, isq, we; 65 | real_T Vsd, Vsq, V_Alfa, V_Beta, Va, Vb, Vc; 66 | real_T integral_old_q, integral_q, error_q, pi_q; 67 | real_T integral_old_d, integral_d, error_d, pi_d; 68 | real_T theta_e_old, wm, iq_old, id_old, iq_new, id_new; 69 | real_T Kpd, Ki, Kpq; 70 | 71 | // Input Ports 72 | iq = U(0); 73 | theta_e = U(1); 74 | ia = U(2); 75 | ib = U(3); 76 | ic = U(4); 77 | id = 0.00; 78 | 79 | // Transformation Constants 80 | real_T Constant = 0.816497; // sqrt(2/3) 81 | real_T Constant2 = 0.866025; // sqrt(3)/2 82 | 83 | // PMSM Parameters 84 | real_T N = 4; 85 | real_T psi = 0.121; 86 | real_T Lsd = 16.61e-3; 87 | real_T Lsq = 16.22e-3; 88 | real_T Rs = 0.55; 89 | real_T Td = 0.01; 90 | 91 | // ABC to AlphaBeta (Clarke) 92 | isalfa = Constant * (ia - 0.5 * ib - 0.5 * ic); 93 | isbeta = Constant * Constant2 * (ib - ic); 94 | 95 | // AlphaBeta to dq (Park) 96 | isd = isalfa * cos(theta_e) + isbeta * sin(theta_e); 97 | isq = -isalfa * sin(theta_e) + isbeta * cos(theta_e); 98 | 99 | // PI Parameters 100 | Kpd = (Lsd / Td); 101 | Kpq = (Lsq / Td); 102 | Ki = (Rs / Td); 103 | 104 | // PI Iq 105 | integral_old_q = X[0]; 106 | error_q = iq - isq; 107 | integral_q = integral_old_q + error_q * dt; 108 | pi_q = Kpq * error_q + Ki * integral_q; 109 | 110 | // PI Id 111 | integral_old_d = X[1]; 112 | error_d = id - isd; 113 | integral_d = integral_old_d + error_d * dt; 114 | pi_d = Kpd * error_d + Ki * integral_d; 115 | 116 | // Output Vsd and Vsq 117 | theta_e_old = X[2]; 118 | iq_old = X[3]; 119 | id_old = X[4]; 120 | wm = (theta_e - theta_e_old) / (dt * N); 121 | iq_new = iq_old + (iq - iq_old) * dt / Td; 122 | id_new = id_old + (id - id_old) * dt / Td; 123 | Vsd = pi_d - N * wm * Lsq * iq_new; 124 | Vsq = pi_q + N * wm * (Lsd * id_new + psi); 125 | 126 | // dq to AlphaBeta (Inverse Park) 127 | V_Alfa = Vsd * cos(theta_e) - Vsq * sin(theta_e); 128 | V_Beta = Vsd * sin(theta_e) + Vsq * cos(theta_e); 129 | 130 | // AlphaBeta to ABC (Inverse Clarke) 131 | Va = Constant * V_Alfa; 132 | Vb = Constant * (-0.5 * V_Alfa + (Constant2)*V_Beta); 133 | Vc = Constant * (-0.5 * V_Alfa - (Constant2)*V_Beta); 134 | 135 | // State Variables 136 | X[0] = integral_q; 137 | X[1] = integral_d; 138 | X[2] = theta_e; 139 | X[3] = iq_new; 140 | X[4] = id_new; 141 | X[5] = Va; 142 | X[6] = Vb; 143 | X[7] = Vc; 144 | } 145 | 146 | static void mdlTerminate(SimStruct *S) 147 | {} /* Keep this function empty since no memory is allocated */ 148 | 149 | #ifdef MATLAB_MEX_FILE 150 | /* Is this file being compiled as a MEX-file? */ 151 | #include "simulink.c" /* MEX-file interface mechanism */ 152 | #else 153 | #include "cg_sfun.h" /* Code generation registration function */ 154 | #endif -------------------------------------------------------------------------------- /SPWM.c: -------------------------------------------------------------------------------- 1 | #define S_FUNCTION_LEVEL 2 2 | #define S_FUNCTION_NAME SPWM // s-Function Block Name 3 | #include "simstruc.h" 4 | #include 5 | 6 | #define U(element) (*uPtrs[element]) /* Pointer to Input Port0 */ 7 | 8 | static void mdlInitializeSizes(SimStruct *S) { 9 | if (!ssSetNumInputPorts(S, 1)) return; 10 | ssSetInputPortWidth(S, 0, 5); // Number of Inputs 11 | ssSetInputPortDirectFeedThrough(S, 0, 1); 12 | ssSetInputPortOverWritable(S, 0, 1); 13 | 14 | if (!ssSetNumOutputPorts(S, 1)) return; 15 | ssSetOutputPortWidth(S, 0, 3); // Number of Outputs 16 | ssSetNumSampleTimes(S, 1); 17 | 18 | ssSetOptions(S, SS_OPTION_EXCEPTION_FREE_CODE); 19 | } 20 | 21 | static void mdlInitializeSampleTimes(SimStruct *S) { 22 | ssSetSampleTime(S, 0, CONTINUOUS_SAMPLE_TIME); 23 | ssSetOffsetTime(S, 0, 0.0); 24 | } 25 | 26 | static void mdlOutputs(SimStruct *S, int_T tid) { 27 | real_T *Y = ssGetOutputPortRealSignal(S, 0); 28 | InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0); 29 | real_T t = ssGetT(S); 30 | 31 | real_T halfVDC = (0.5 * U(0)); 32 | int_T i; 33 | 34 | for(i = 0; i < 3; i++) { 35 | if(fabs(U(i + 2)) / halfVDC >= fabs(U(0) * (fabs(fmod(t, 2 / U(1)) - 1 / U(1)) * U(1)))) { 36 | Y[i] = halfVDC; 37 | } else { 38 | Y[i] = 0.0; 39 | }; 40 | 41 | if(U(i + 2) < 0.0) { 42 | Y[i] = -Y[i]; 43 | }; 44 | } 45 | } 46 | 47 | static void mdlTerminate(SimStruct *S) 48 | {} /* Keep this function empty since no memory is allocated */ 49 | 50 | #ifdef MATLAB_MEX_FILE 51 | /* Is this file being compiled as a MEX-file? */ 52 | #include "simulink.c" /* MEX-file interface mechanism */ 53 | #else 54 | #include "cg_sfun.h" /* Code generation registration function */ 55 | #endif -------------------------------------------------------------------------------- /Speed_Controller_FuzzyPID.c: -------------------------------------------------------------------------------- 1 | #define S_FUNCTION_LEVEL 2 2 | #define S_FUNCTION_NAME Speed_Controller_FuzzyPID // s-Function Block Name 3 | #include "simstruc.h" 4 | #include 5 | 6 | #define U(element) (*uPtrs[element]) /* Pointer to Input Port0 */ 7 | 8 | static void mdlInitializeSizes(SimStruct *S) { 9 | ssSetNumDiscStates(S, 3); 10 | 11 | if (!ssSetNumInputPorts(S, 1)) return; 12 | ssSetInputPortWidth(S, 0, 8); // Number of Inputs 13 | ssSetInputPortDirectFeedThrough(S, 0, 1); 14 | ssSetInputPortOverWritable(S, 0, 1); 15 | 16 | if (!ssSetNumOutputPorts(S, 1)) return; 17 | ssSetOutputPortWidth(S, 0, 1); // Number of Outputs 18 | ssSetNumSampleTimes(S, 1); 19 | 20 | ssSetOptions(S, (SS_OPTION_EXCEPTION_FREE_CODE 21 | | SS_OPTION_DISCRETE_VALUED_OUTPUT)); 22 | } 23 | 24 | static void mdlInitializeSampleTimes(SimStruct *S) { 25 | ssSetSampleTime(S, 0, 1e-3); 26 | ssSetOffsetTime(S, 0, 0.0); 27 | } 28 | 29 | #define MDL_INITIALIZE_CONDITIONS 30 | static void mdlInitializeConditions(SimStruct *S) { 31 | real_T *X0 = ssGetRealDiscStates(S); 32 | int_T nXStates = ssGetNumDiscStates(S); 33 | InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0); 34 | int_T i; 35 | 36 | /* Initialize the states to 0.0 */ 37 | for(i = 0; i < nXStates; i++) X0[i] = 0.0; 38 | } 39 | 40 | static void mdlOutputs(SimStruct *S, int_T tid) { 41 | real_T *Y = ssGetOutputPortRealSignal(S, 0); 42 | real_T *X = ssGetRealDiscStates(S); 43 | 44 | Y[0] = X[0]; // Control Signal 45 | } 46 | 47 | #define MDL_UPDATE 48 | static void mdlUpdate(SimStruct *S, int_T tid) { 49 | real_T *X = ssGetRealDiscStates(S); 50 | InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0); 51 | 52 | real_T dt = 1e-3; 53 | 54 | real_T Kp, Ki, Kd, pid; 55 | real_T W_ref, W_act, error, theta_m, theta_old; 56 | real_T integral_error, integral_error_old; 57 | real_T derivative_error, error_old; 58 | real_T delta_Kp, delta_Ki, delta_Kd; 59 | 60 | // Input Ports 61 | theta_m = U(0); 62 | W_ref = U(1); 63 | Kp = U(2); 64 | Ki = U(3); 65 | Kd = U(4); 66 | delta_Kp = U(5); 67 | delta_Ki = U(6); 68 | delta_Kd = U(7); 69 | 70 | // PID Controller 71 | theta_old = X[1]; 72 | error_old = X[2]; 73 | integral_error_old = X[3]; 74 | 75 | W_act = (theta_m - theta_old) / dt; 76 | error = W_ref - W_act; 77 | integral_error = integral_error_old + error * dt; 78 | derivative_error = (error - error_old); 79 | 80 | pid = (Kp + delta_Kp) * error + 81 | (Ki + delta_Ki) * integral_error + 82 | (Kd + delta_Kd) * derivative_error; 83 | 84 | // State Variables 85 | X[0] = pid; 86 | X[1] = theta_m; 87 | X[2] = error; 88 | X[3] = integral_error; 89 | } 90 | 91 | static void mdlTerminate(SimStruct *S) 92 | {} /* Keep this function empty since no memory is allocated */ 93 | 94 | #ifdef MATLAB_MEX_FILE 95 | /* Is this file being compiled as a MEX-file? */ 96 | #include "simulink.c" /* MEX-file interface mechanism */ 97 | #else 98 | #include "cg_sfun.h" /* Code generation registration function */ 99 | #endif -------------------------------------------------------------------------------- /Speed_Controller_PID.c: -------------------------------------------------------------------------------- 1 | #define S_FUNCTION_LEVEL 2 2 | #define S_FUNCTION_NAME Speed_Controller_PID // s-Function Block Name 3 | #include "simstruc.h" 4 | #include 5 | 6 | #define U(element) (*uPtrs[element]) /* Pointer to Input Port0 */ 7 | 8 | static void mdlInitializeSizes(SimStruct *S) { 9 | ssSetNumDiscStates(S, 3); 10 | 11 | if (!ssSetNumInputPorts(S, 1)) return; 12 | ssSetInputPortWidth(S, 0, 5); // Number of Inputs 13 | ssSetInputPortDirectFeedThrough(S, 0, 1); 14 | ssSetInputPortOverWritable(S, 0, 1); 15 | 16 | if (!ssSetNumOutputPorts(S, 1)) return; 17 | ssSetOutputPortWidth(S, 0, 3); // Number of Outputs 18 | ssSetNumSampleTimes(S, 1); 19 | 20 | ssSetOptions(S, (SS_OPTION_EXCEPTION_FREE_CODE 21 | | SS_OPTION_DISCRETE_VALUED_OUTPUT)); 22 | } 23 | 24 | static void mdlInitializeSampleTimes(SimStruct *S) { 25 | ssSetSampleTime(S, 0, 1e-3); 26 | ssSetOffsetTime(S, 0, 0.0); 27 | } 28 | 29 | #define MDL_INITIALIZE_CONDITIONS 30 | static void mdlInitializeConditions(SimStruct *S) { 31 | real_T *X0 = ssGetRealDiscStates(S); 32 | int_T nXStates = ssGetNumDiscStates(S); 33 | InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0); 34 | int_T i; 35 | 36 | /* Initialize the states to 0.0 */ 37 | for(i = 0; i < nXStates; i++) X0[i] = 0.0; 38 | } 39 | 40 | static void mdlOutputs(SimStruct *S, int_T tid) { 41 | real_T *Y = ssGetOutputPortRealSignal(S, 0); 42 | real_T *X = ssGetRealDiscStates(S); 43 | 44 | Y[0] = X[2]; // Control Signal 45 | Y[1] = X[3]; // Error 46 | Y[2] = X[4]; // Change of Error 47 | } 48 | 49 | #define MDL_UPDATE 50 | static void mdlUpdate(SimStruct *S, int_T tid) { 51 | real_T *X = ssGetRealDiscStates(S); 52 | InputRealPtrsType uPtrs = ssGetInputPortRealSignalPtrs(S, 0); 53 | 54 | real_T dt = 1e-3; 55 | 56 | real_T Kp, Ki, Kd, pid; 57 | real_T W_ref, W_act, error, theta_m, theta_old; 58 | real_T integral_error, integral_error_old; 59 | real_T derivative_error, error_old; 60 | 61 | // Input Ports 62 | W_ref = U(0); 63 | theta_m = U(1); 64 | Kp = U(2); 65 | Ki = U(3); 66 | Kd = U(4); 67 | 68 | // PID Controller 69 | integral_error_old = X[0]; 70 | theta_old = X[1]; 71 | error_old = X[3]; 72 | 73 | W_act = (theta_m - theta_old) / dt; 74 | error = W_ref - W_act; 75 | integral_error = integral_error_old + error * dt; 76 | derivative_error = error - error_old; 77 | 78 | // derivative_error = (error - error_old) / dt; 79 | 80 | pid = (Kp * error) + 81 | (Ki * integral_error) + 82 | (Kd * derivative_error); 83 | 84 | // State Variables 85 | X[0] = integral_error; 86 | X[1] = theta_m; 87 | X[2] = pid; 88 | X[3] = error; 89 | X[4] = derivative_error; 90 | } 91 | 92 | static void mdlTerminate(SimStruct *S) 93 | {} /* Keep this function empty since no memory is allocated */ 94 | 95 | #ifdef MATLAB_MEX_FILE 96 | /* Is this file being compiled as a MEX-file? */ 97 | #include "simulink.c" /* MEX-file interface mechanism */ 98 | #else 99 | #include "cg_sfun.h" /* Code generation registration function */ 100 | #endif --------------------------------------------------------------------------------