Autor Tema: PID Digital (paso a paso)  (Leído 84302 veces)

0 Usuarios y 1 Visitante están viendo este tema.

Desconectado Nocturno

  • Administrador
  • DsPIC33
  • *******
  • Mensajes: 18310
    • MicroPIC
Re: PID Digital (paso a paso)
« Respuesta #60 en: 09 de Marzo de 2010, 16:32:37 »
Os dejo unas capturas del modelo PID que ha calculado MATLAB y el código generado.
Seguiré informando, porque ahora toca implementarlo en mi montaje real.





Este es el código que ha generado:

Código: C
  1. /*
  2.  * ControlPID.c
  3.  *
  4.  * Real-Time Workshop code generation for Simulink model "ControlPID.mdl".
  5.  *
  6.  * Model Version              : 1.4
  7.  * Real-Time Workshop version : 7.4  (R2009b)  29-Jun-2009
  8.  * C source code generated on : Tue Mar 09 20:28:17 2010
  9.  *
  10.  * Target selection: rsim.tlc
  11.  * Note: GRT includes extra infrastructure and instrumentation for prototyping
  12.  * Embedded hardware selection: 32-bit Generic
  13.  * Emulation hardware selection:
  14.  *    Differs from embedded hardware (MATLAB Host)
  15.  * Code generation objectives: Unspecified
  16.  * Validation result: Not run
  17.  */
  18.  
  19. #include <math.h>
  20. #include "ControlPID.h"
  21. #include "ControlPID_private.h"
  22. #include "ControlPID_dt.h"
  23.  
  24. /* user code (top of parameter file) */
  25. const int_T gblNumToFiles = 0;
  26. const int_T gblNumFrFiles = 0;
  27. const int_T gblNumFrWksBlocks = 0;
  28.  
  29. /* Root inports information  */
  30. const int_T gblNumRootInportBlks = 0;
  31. const int_T gblNumModelInputs = 0;
  32. extern rtInportTUtable *gblInportTUtables;
  33. extern const char *gblInportFileName;
  34. const int_T gblInportDataTypeIdx[] = { -1 };
  35.  
  36. const int_T gblInportDims[] = { -1 } ;
  37.  
  38. const int_T gblInportComplex[] = { -1 };
  39.  
  40. const int_T gblInportInterpoFlag[] = { -1 };
  41.  
  42. const int_T gblInportContinuous[] = { -1 };
  43.  
  44. #include "simstruc.h"
  45. #include "fixedpoint.h"
  46.  
  47. /* Block signals (auto storage) */
  48. BlockIO rtB;
  49.  
  50. /* Continuous states */
  51. ContinuousStates rtX;
  52.  
  53. /* Block states (auto storage) */
  54. D_Work rtDWork;
  55.  
  56. /* Parent Simstruct */
  57. static SimStruct model_S;
  58. SimStruct *const rtS = &model_S;
  59.  
  60. /* Initial conditions for root system: '<Root>' */
  61. void MdlInitialize(void)
  62. {
  63.   /* InitializeConditions for TransferFcn: '<Root>/Transfer Fcn' */
  64.   rtX.TransferFcn_CSTATE = 0.0;
  65.  
  66.   /* InitializeConditions for DiscreteIntegrator: '<S1>/Filter' */
  67.   rtDWork.Filter_DSTATE = rtP.Filter_IC;
  68.  
  69.   /* InitializeConditions for DiscreteIntegrator: '<S1>/Integrator' */
  70.   rtDWork.Integrator_DSTATE = rtP.Integrator_IC;
  71. }
  72.  
  73. /* Start for root system: '<Root>' */
  74. void MdlStart(void)
  75. {
  76.   MdlInitialize();
  77. }
  78.  
  79. /* Outputs for root system: '<Root>' */
  80. void MdlOutputs(int_T tid)
  81. {
  82.   /* local block i/o variables */
  83.   real_T rtb_TransferFcn;
  84.  
  85.   {
  86.     real_T currentTime;
  87.     if (ssIsSampleHit(rtS, 1, 0)) {
  88.       /* Step: '<Root>/Step' */
  89.       currentTime = ssGetTaskTime(rtS,0);
  90.       if (ssIsMajorTimeStep(rtS)) {
  91.         if (currentTime >= rtP.Step_Time) {
  92.           rtDWork.Step_MODE = 1;
  93.         } else {
  94.           rtDWork.Step_MODE = 0;
  95.         }
  96.       }
  97.  
  98.       rtB.Step = rtDWork.Step_MODE == 1 ? rtP.Step_YFinal : rtP.Step_Y0;
  99.     }
  100.  
  101.     /* TransferFcn: '<Root>/Transfer Fcn' */
  102.     rtb_TransferFcn = rtP.TransferFcn_C*rtX.TransferFcn_CSTATE;
  103.  
  104.     /* Sum: '<Root>/Sum' */
  105.     rtB.Sum = rtB.Step - rtb_TransferFcn;
  106.     if (ssIsSampleHit(rtS, 2, 0)) {
  107.       /* Gain: '<S1>/Filter Coefficient' incorporates:
  108.        *  DiscreteIntegrator: '<S1>/Filter'
  109.        *  Gain: '<S1>/Derivative Gain'
  110.        *  Sum: '<S1>/SumD'
  111.        */
  112.       rtB.FilterCoefficient = ((real_T)rtP.DerivativeGain_Gain * rtB.Sum -
  113.         rtDWork.Filter_DSTATE) * (real_T)rtP.FilterCoefficient_Gain;
  114.  
  115.       /* Gain: '<S1>/Integral Gain' */
  116.       rtB.IntegralGain = (real_T)rtP.IntegralGain_Gain * rtB.Sum;
  117.  
  118.       /* Sum: '<S1>/Sum' incorporates:
  119.        *  DiscreteIntegrator: '<S1>/Integrator'
  120.        *  Gain: '<S1>/Proportional Gain'
  121.        */
  122.       rtB.Sum_e = ((real_T)rtP.ProportionalGain_Gain * rtB.Sum +
  123.                    rtDWork.Integrator_DSTATE) + rtB.FilterCoefficient;
  124.     }
  125.   }
  126.  
  127.   /* tid is required for a uniform function interface.
  128.    * Argument tid is not used in the function. */
  129.   UNUSED_PARAMETER(tid);
  130. }
  131.  
  132. /* Update for root system: '<Root>' */
  133. void MdlUpdate(int_T tid)
  134. {
  135.   if (ssIsSampleHit(rtS, 2, 0)) {
  136.     /* Update for DiscreteIntegrator: '<S1>/Filter' */
  137.     rtDWork.Filter_DSTATE = rtP.Filter_gainval * rtB.FilterCoefficient +
  138.       rtDWork.Filter_DSTATE;
  139.  
  140.     /* Update for DiscreteIntegrator: '<S1>/Integrator' */
  141.     rtDWork.Integrator_DSTATE = rtP.Integrator_gainval * rtB.IntegralGain +
  142.       rtDWork.Integrator_DSTATE;
  143.   }
  144.  
  145.   /* tid is required for a uniform function interface.
  146.    * Argument tid is not used in the function. */
  147.   UNUSED_PARAMETER(tid);
  148. }
  149.  
  150. /* Derivatives for root system: '<Root>' */
  151. void MdlDerivatives(void)
  152. {
  153.   /* Derivatives for TransferFcn: '<Root>/Transfer Fcn' */
  154.   {
  155.     ((StateDerivatives *) ssGetdX(rtS))->TransferFcn_CSTATE = rtB.Sum_e;
  156.     ((StateDerivatives *) ssGetdX(rtS))->TransferFcn_CSTATE +=
  157.       (rtP.TransferFcn_A)*rtX.TransferFcn_CSTATE;
  158.   }
  159. }
  160.  
  161. /* Projection for root system: '<Root>' */
  162. void MdlProjection(void)
  163. {
  164. }
  165.  
  166. /* InitSystemMatrices for root system: '<Root>' */
  167. void MdlInitSystemMatrices(void)
  168. {
  169. }
  170.  
  171. /* ZeroCrossings for root system: '<Root>' */
  172. void MdlZeroCrossings(void)
  173. {
  174.   /* ZeroCrossings for Step: '<Root>/Step' */
  175.   ((ZCSignalValues *) ssGetSolverZcSignalVector(rtS))->Step_StepTime_ZC = ssGetT
  176.     (rtS) - rtP.Step_Time;
  177. }
  178.  
  179. /* Termination for root system: '<Root>' */
  180. void MdlTerminate(void)
  181. {
  182. }
  183.  
  184. /* Function to initialize sizes */
  185. void MdlInitializeSizes(void)
  186. {
  187.   ssSetNumContStates(rtS, 1);          /* Number of continuous states */
  188.   ssSetNumY(rtS, 0);                   /* Number of model outputs */
  189.   ssSetNumU(rtS, 0);                   /* Number of model inputs */
  190.   ssSetDirectFeedThrough(rtS, 0);      /* The model is not direct feedthrough */
  191.   ssSetNumSampleTimes(rtS, 3);         /* Number of sample times */
  192.   ssSetNumBlocks(rtS, 12);             /* Number of blocks */
  193.   ssSetNumBlockIO(rtS, 5);             /* Number of block outputs */
  194.   ssSetNumBlockParams(rtS, 13);        /* Sum of parameter "widths" */
  195. }
  196.  
  197. /* Function to initialize sample times. */
  198. void MdlInitializeSampleTimes(void)
  199. {
  200.   /* task periods */
  201.   ssSetSampleTime(rtS, 0, 0.0);
  202.   ssSetSampleTime(rtS, 1, 0.0);
  203.   ssSetSampleTime(rtS, 2, 0.01);
  204.  
  205.   /* task offsets */
  206.   ssSetOffsetTime(rtS, 0, 0.0);
  207.   ssSetOffsetTime(rtS, 1, 1.0);
  208.   ssSetOffsetTime(rtS, 2, 0.0);
  209. }
  210.  
  211. /* Function to register the model */
  212. SimStruct * ControlPID(void)
  213. {
  214.   static struct _ssMdlInfo mdlInfo;
  215.   (void) memset((char *)rtS,0,
  216.                 sizeof(SimStruct));
  217.   (void) memset((char *)&mdlInfo,0,
  218.                 sizeof(struct _ssMdlInfo));
  219.   ssSetMdlInfoPtr(rtS, &mdlInfo);
  220.  
  221.   /* timing info */
  222.   {
  223.     static time_T mdlPeriod[NSAMPLE_TIMES];
  224.     static time_T mdlOffset[NSAMPLE_TIMES];
  225.     static time_T mdlTaskTimes[NSAMPLE_TIMES];
  226.     static int_T mdlTsMap[NSAMPLE_TIMES];
  227.     static int_T mdlSampleHits[NSAMPLE_TIMES];
  228.     static boolean_T mdlTNextWasAdjustedPtr[NSAMPLE_TIMES];
  229.     static int_T mdlPerTaskSampleHits[NSAMPLE_TIMES * NSAMPLE_TIMES];
  230.     static time_T mdlTimeOfNextSampleHit[NSAMPLE_TIMES];
  231.  
  232.     {
  233.       int_T i;
  234.       for (i = 0; i < NSAMPLE_TIMES; i++) {
  235.         mdlPeriod[i] = 0.0;
  236.         mdlOffset[i] = 0.0;
  237.         mdlTaskTimes[i] = 0.0;
  238.         mdlTsMap[i] = i;
  239.         mdlSampleHits[i] = 1;
  240.       }
  241.     }
  242.  
  243.     ssSetSampleTimePtr(rtS, &mdlPeriod[0]);
  244.     ssSetOffsetTimePtr(rtS, &mdlOffset[0]);
  245.     ssSetSampleTimeTaskIDPtr(rtS, &mdlTsMap[0]);
  246.     ssSetTPtr(rtS, &mdlTaskTimes[0]);
  247.     ssSetSampleHitPtr(rtS, &mdlSampleHits[0]);
  248.     ssSetTNextWasAdjustedPtr(rtS, &mdlTNextWasAdjustedPtr[0]);
  249.     ssSetPerTaskSampleHitsPtr(rtS, &mdlPerTaskSampleHits[0]);
  250.     ssSetTimeOfNextSampleHitPtr(rtS, &mdlTimeOfNextSampleHit[0]);
  251.   }
  252.  
  253.   ssSetSolverMode(rtS, SOLVER_MODE_SINGLETASKING);
  254.  
  255.   /*
  256.    * initialize model vectors and cache them in SimStruct
  257.    */
  258.  
  259.   /* block I/O */
  260.   {
  261.     ssSetBlockIO(rtS, ((void *) &rtB));
  262.     (void) memset(((void *) &rtB),0,
  263.                   sizeof(BlockIO));
  264.   }
  265.  
  266.   /* parameters */
  267.   ssSetDefaultParam(rtS, (real_T *) &rtP);
  268.  
  269.   /* states (continuous)*/
  270.   {
  271.     real_T *x = (real_T *) &rtX;
  272.     ssSetContStates(rtS, x);
  273.     (void) memset((void *)x,0,
  274.                   sizeof(ContinuousStates));
  275.   }
  276.  
  277.   /* states (dwork) */
  278.   {
  279.     void *dwork = (void *) &rtDWork;
  280.     ssSetRootDWork(rtS, dwork);
  281.     (void) memset(dwork, 0,
  282.                   sizeof(D_Work));
  283.   }
  284.  
  285.   /* data type transition information */
  286.   {
  287.     static DataTypeTransInfo dtInfo;
  288.     (void) memset((char_T *) &dtInfo,0,
  289.                   sizeof(dtInfo));
  290.     ssSetModelMappingInfo(rtS, &dtInfo);
  291.     dtInfo.numDataTypes = 14;
  292.     dtInfo.dataTypeSizes = &rtDataTypeSizes[0];
  293.     dtInfo.dataTypeNames = &rtDataTypeNames[0];
  294.  
  295.     /* Block I/O transition table */
  296.     dtInfo.B = &rtBTransTable;
  297.  
  298.     /* Parameters transition table */
  299.     dtInfo.P = &rtPTransTable;
  300.   }
  301.  
  302.   /* Model specific registration */
  303.   ssSetRootSS(rtS, rtS);
  304.   ssSetVersion(rtS, SIMSTRUCT_VERSION_LEVEL2);
  305.   ssSetModelName(rtS, "ControlPID");
  306.   ssSetPath(rtS, "ControlPID");
  307.   ssSetTStart(rtS, 0.0);
  308.   ssSetTFinal(rtS, 1.0);
  309.  
  310.   /* Setup for data logging */
  311.   {
  312.     static RTWLogInfo rt_DataLoggingInfo;
  313.     ssSetRTWLogInfo(rtS, &rt_DataLoggingInfo);
  314.   }
  315.  
  316.   /* Setup for data logging */
  317.   {
  318.     rtliSetLogXSignalInfo(ssGetRTWLogInfo(rtS), (NULL));
  319.     rtliSetLogXSignalPtrs(ssGetRTWLogInfo(rtS), (NULL));
  320.     rtliSetLogT(ssGetRTWLogInfo(rtS), "tout");
  321.     rtliSetLogX(ssGetRTWLogInfo(rtS), "");
  322.     rtliSetLogXFinal(ssGetRTWLogInfo(rtS), "");
  323.     rtliSetSigLog(ssGetRTWLogInfo(rtS), "");
  324.     rtliSetLogVarNameModifier(ssGetRTWLogInfo(rtS), "rt_");
  325.     rtliSetLogFormat(ssGetRTWLogInfo(rtS), 0);
  326.     rtliSetLogMaxRows(ssGetRTWLogInfo(rtS), 1000);
  327.     rtliSetLogDecimation(ssGetRTWLogInfo(rtS), 1);
  328.     rtliSetLogY(ssGetRTWLogInfo(rtS), "");
  329.     rtliSetLogYSignalInfo(ssGetRTWLogInfo(rtS), (NULL));
  330.     rtliSetLogYSignalPtrs(ssGetRTWLogInfo(rtS), (NULL));
  331.   }
  332.  
  333.   {
  334.     static ssSolverInfo slvrInfo;
  335.     static boolean_T contStatesDisabled[1];
  336.     static real_T solverAbsTol[1] = { 1.0E-006 };
  337.  
  338.     static boolean_T solverAutoAbsTol[1] = { 1 };
  339.  
  340.     static uint8_T zcAttributes[1] = { (ZC_EVENT_ALL_UP) };
  341.  
  342.     static ssNonContDerivSigInfo nonContDerivSigInfo[1] = {
  343.       { 1*sizeof(real_T), (char*)(&rtB.Sum_e), (NULL) }
  344.     };
  345.  
  346.     ssSetSolverRelTol(rtS, 0.001);
  347.     ssSetSolverAbsTol(rtS, solverAbsTol);
  348.     ssSetSolverAutoAbsTol(rtS, solverAutoAbsTol);
  349.     ssSetStepSize(rtS, 0.0);
  350.     ssSetMinStepSize(rtS, 0.0);
  351.     ssSetMaxNumMinSteps(rtS, -1);
  352.     ssSetMinStepViolatedError(rtS, 0);
  353.     ssSetMaxStepSize(rtS, 0.01);
  354.     ssSetSolverMaxOrder(rtS, -1);
  355.     ssSetSolverRefineFactor(rtS, 1);
  356.     ssSetOutputTimes(rtS, (NULL));
  357.     ssSetNumOutputTimes(rtS, 0);
  358.     ssSetOutputTimesOnly(rtS, 0);
  359.     ssSetOutputTimesIndex(rtS, 0);
  360.     ssSetZCCacheNeedsReset(rtS, 0);
  361.     ssSetDerivCacheNeedsReset(rtS, 0);
  362.     ssSetNumNonContDerivSigInfos(rtS, 1);
  363.     ssSetNonContDerivSigInfos(rtS, nonContDerivSigInfo);
  364.     ssSetSolverInfo(rtS, &slvrInfo);
  365.     ssSetSolverName(rtS, "ode45");
  366.     ssSetVariableStepSolver(rtS, 1);
  367.     ssSetSolverConsistencyChecking(rtS, 0);
  368.     ssSetSolverAdaptiveZcDetection(rtS, 0);
  369.     ssSetSolverRobustResetMethod(rtS, 0);
  370.     ssSetSolverStateProjection(rtS, 0);
  371.     ssSetSolverMassMatrixType(rtS, (ssMatrixType)0);
  372.     ssSetSolverMassMatrixNzMax(rtS, 0);
  373.     ssSetModelOutputs(rtS, MdlOutputs);
  374.     ssSetModelLogData(rtS, rt_UpdateTXYLogVars);
  375.     ssSetModelUpdate(rtS, MdlUpdate);
  376.     ssSetModelDerivatives(rtS, MdlDerivatives);
  377.     ssSetSolverZcSignalAttrib(rtS, zcAttributes);
  378.     ssSetSolverNumZcSignals(rtS, 1);
  379.     ssSetModelZeroCrossings(rtS, MdlZeroCrossings);
  380.     ssSetSolverConsecutiveZCsStepRelTol(rtS, 2.8421709430404007E-013);
  381.     ssSetSolverMaxConsecutiveZCs(rtS, 1000);
  382.     ssSetSolverConsecutiveZCsError(rtS, 2);
  383.     ssSetSolverMaxConsecutiveMinStep(rtS, 1);
  384.     ssSetSolverShapePreserveControl(rtS, 2);
  385.     ssSetTNextTid(rtS, INT_MIN);
  386.     ssSetTNext(rtS, rtMinusInf);
  387.     ssSetSolverNeedsReset(rtS);
  388.     ssSetNumNonsampledZCs(rtS, 1);
  389.     ssSetContStateDisabled(rtS, contStatesDisabled);
  390.     ssSetSolverMaxConsecutiveMinStep(rtS, 1);
  391.   }
  392.  
  393.   ssSetChecksumVal(rtS, 0, 159084874U);
  394.   ssSetChecksumVal(rtS, 1, 215820345U);
  395.   ssSetChecksumVal(rtS, 2, 994859013U);
  396.   ssSetChecksumVal(rtS, 3, 1666355192U);
  397.   return rtS;
  398. }

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: PID Digital (paso a paso)
« Respuesta #61 en: 09 de Marzo de 2010, 21:37:20 »
Que chulo!!

Si disminuyes el tiempo de muestreo, disminuirá el sobrepaso máximo ... como para que quede un poco mas sobreamortiguado
El papel lo aguanta todo

Desconectado NANO1985

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1698
    • Desarrollos Tecnologicos - Tucuman - Argentina
Re: PID Digital (paso a paso)
« Respuesta #62 en: 10 de Mayo de 2010, 18:11:06 »
hasta ahora siempre los diseños de PIDs,... siempre lo vi en base a hornos y demas, donde la respuesta temporal es muy lenta.... pero que pasa si se requiere hacer un control PID, donde la respuesta para correjir el error debe ser lo más rápida posible, y no es posible hacer una prueba manual del sistema.
como se hace para determinar las componentes de la ecuacion PID?
saludos
« Última modificación: 10 de Mayo de 2010, 18:18:54 por NANO1985 »
"La inquebrantable voluntad de vencer"
"hay dos cosas infinitas... El universo y la Estupidez humana" Albert Einstein
 "El sabio actua sin anhelos, permanece sosegado,... así no es afectado por el resultado de sus acciones sean éstas el triunfo o el fracaso"
- UNIVERSIDAD TECNOLOGICA NACIONAL - FACULTAD REGIONAL TUCUMAN -

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: PID Digital (paso a paso)
« Respuesta #63 en: 10 de Mayo de 2010, 18:46:23 »
Hola.

Si la respuesta debe ser rápida, lo mejor es buscar otro algoritmo de control ... el PID tiene sus cosas ...

Para sintonizar teóricamente creo que se iguala el polinomio del controlador y la planta con el polinomio característico deseado.

Saludos
El papel lo aguanta todo

Desconectado NANO1985

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1698
    • Desarrollos Tecnologicos - Tucuman - Argentina
Re: PID Digital (paso a paso)
« Respuesta #64 en: 10 de Mayo de 2010, 18:49:55 »
me mataste MLO_ jajajaja  :D
"La inquebrantable voluntad de vencer"
"hay dos cosas infinitas... El universo y la Estupidez humana" Albert Einstein
 "El sabio actua sin anhelos, permanece sosegado,... así no es afectado por el resultado de sus acciones sean éstas el triunfo o el fracaso"
- UNIVERSIDAD TECNOLOGICA NACIONAL - FACULTAD REGIONAL TUCUMAN -

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: PID Digital (paso a paso)
« Respuesta #65 en: 10 de Mayo de 2010, 19:04:54 »
jeje ...

El polinomio característico deseado sería:

$ P(z) = 1 + G_{c}(z)G_{p}(z)

en donde:
Gc(z) : Función de transferencia del controlador
Gp(z) : Función de transferencia de la planta

Saludos
El papel lo aguanta todo

Desconectado micro_pepe

  • Moderadores
  • DsPIC30
  • *****
  • Mensajes: 3216
Re: PID Digital (paso a paso)
« Respuesta #66 en: 01 de Octubre de 2010, 06:02:19 »
Al comienzo de este hilo se describe un ejemplo de control de temperatura de un horno. Para obtener la función de la planta, se enciende la resistencia del horno, y se toman valores de temperatura cada cierto intervalo de tiempo.

Pero, si en lugar de calentar, quiero enfriar un disipador, como tengo que tomar esas lecturas de temperatura? Haciendo que se caliente el disipador, y una vez caliente quitar la fuente de calor, poner el ventilador en marcha, y a partir de ahí tomar valores de temperatura?

O poniendo en marcha el ventilador y la fuente de calor al tiempo, y tomar valores?

Saludos.
Se obtiene más en dos meses interesandose por los demás, que en dos años tratando de que los demás se interesen por ti.

新年快乐     的好奇心的猫死亡

Desconectado Suky

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: PID Digital (paso a paso)
« Respuesta #67 en: 01 de Octubre de 2010, 08:44:07 »
Como en realidad va a funcionar el sistema, lo que tu quieres es encontrar un modelo matemático de la dinámica del sistema. Si los 2 se mantienen encendidos al mismo tiempo, no creo, la obtienes de esa manera.


Saludos!
No contesto mensajes privados, las consultas en el foro

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: PID Digital (paso a paso)
« Respuesta #68 en: 02 de Octubre de 2010, 20:38:29 »
Hola.

En tu sistema la fuente de calor va a estar presente? si es así, debe estar a la hora de tomar los datos.

El sistema de refrigeración debe "sacar" el calor necesario para mantener la temperatura mínima establecida, por ello el sistema de refrigeración debe ser mas eficiente que el sistema que entrega calor (por ello se usan disipadores con aletas y conveccion forzada), si no ... no habrá controlador que te sirva  ;-)

Saludos
El papel lo aguanta todo

Desconectado cdanielm_58

  • PIC10
  • *
  • Mensajes: 2
Re: PID Digital (paso a paso)
« Respuesta #69 en: 05 de Noviembre de 2010, 14:16:22 »
Hola amigo. He seguido tus pasos casi al pie de la letra y todo está bien hasta que me llegaron unos inconvenientes.

Primero, como dices que usaste el metodo de ragazzini si por favor me indicas que es el essp y como hallar Zita ahh y lo de los polos que en tiempo discreto no se como es.

Lo segundo, es que como mi docente me dice que para hallar la verdadera función de transferencia de mi planta tengo que hacer varias muestras con varias entradas, me explico. Uso un bombillo de 9v (Exploradora) para calentar mi caja a la que mido la temperatura y la muestro en el ordenador con JAVA a traves de USB con un PIC 2550, pero ahora tengo que cambiar por un bombillo de 110V para hacer muestras con 50V 30V 60V, etc.

Me dicen que tengo que usar PWM porque la señal de entrada es análoga y tendria que pasarla a DC y para regularla a través del PIC se usa el Triger, pero todavía estoy corto en eso.... si me puedes dar un empujoncito te lo agradezco.

Desconectado MLO__

  • Colaborador
  • DsPIC33
  • *****
  • Mensajes: 4581
Re: PID Digital (paso a paso)
« Respuesta #70 en: 05 de Noviembre de 2010, 17:32:50 »
Hola.

Seria mejor hacer control de fase, de esa manera puedes obtener el valor del voltaje en función del ángulo de disparo (V_RMS)

Saludos
El papel lo aguanta todo

Desconectado loqui

  • PIC10
  • *
  • Mensajes: 1
Re: PID Digital (paso a paso)
« Respuesta #71 en: 06 de Julio de 2011, 10:37:18 »
Hola a todos, una pregunta para el amigo nocturno por este comentario:

"Os dejo unas capturas del modelo PID que ha calculado MATLAB y el código generado.
Seguiré informando, porque ahora toca implementarlo en mi montaje real."

Quería saber si ha logrado implementar el controlador en su modelo real, también preguntar como obtener la función de transferencia con los valores P, I, D, N, calculados con el matlab  “los que se muestra en la figura ”
 
Y como se obtiene la ecuación en diferencias a partir de estos valores.
Otra cosa, el código en C generado por el matlab como se puede  programar en el pic.


Desconectado phantom879

  • PIC10
  • *
  • Mensajes: 2
Re: PID Digital (paso a paso)
« Respuesta #72 en: 31 de Octubre de 2011, 20:46:59 »
Hola a todos.

Amigos tengo un proyecto para una materia y me gustaria que me ayudaran, pero la verdad es que no quiero nada hecho, lo que deseo es que me ayuden a hacerlo paso a paso, uds me guian y yo lo hago, quiza algunas cosas ya esten hechas, pero si no hago las cosas no aprendo y esa es mi mas grande ilusion.

Objetivo: Crear un control PID digital usando pic16f877a para controlar la temperatura de un horno.

Datos: La planta sera un cajon de madera y en su interior estara una bombilla de 60W la cual hara las veces de calefactor, esta bombilla se controlara usando pwm, el cual con la ayuda de un circuito adicional controlara la intensidad luminica de la bombilla y a su vez el calor generado. Para sensar la temperatura se usara un LM35 el cual da 10mV/ºC

Nota: Ire editando este post a medida como vaya realizando nuevas cosas y recibiendo sugerencias y correcciones de su parte.


PASO 1:

* Armamos el circuito sensor usando el LM35, probamos de que sense bien la temperatura y lo introducimos en nuestra caja de madera, previamente elaborada; hay que tener en cuenta de que la caja quede bien sellada una vez se cierre, o habra problemas al momento de controlar y sensar la temperatura.


PASO 2:

* Graficamos los datos y hallamos la ecuacion caracteristica de la planta, esta ecuacion es distinta para cada planta, podemos usar un cicruito/programa sensor de temperatura que nos ayude a tomar los datos de la temperatura cada cierto intervalo de tiempo.... o ..... usamos lapiz, papel y cronometro para hacer todo manual... yo lo hare manual.

 -- Con estos datos pasamos a elaborar la grafica, manualmente, usando excel o usando matlab, como aqui lo que queremos es aprender, pues usaremos matlab, para eso ingresamos los datos en matlab en forma de dos matrices (tiempo/temperatura) y que nos la grafique.

Codigo para graficar los datos (esto es un ejemplo, los datos reales son demasiados):

clc;
tiempo[0 1 2 3 4 5 6 7 8 9 10];
temperatura[25 25 26 27 28 29 30 30 31 31 31];
plot(tiempo,temperatura)


Listo ahora tenemos graficada la respuesta de la planta ante una entrada escalon unitario.

Lo siguiente lo pueden hacer como lo explico a continuacion o como lo explica blackcat en un post mas adelante, los dos metodos son validos, ya cada quien escogera.

Para hallar la ecuacion, nos vamos a matlab (donde esta el workspace), alli veremos un boton que dice START (con el logo de matlab), pulsamos ese boton, luego click en toolboxes, luego en curve fitting y por ultimo en curve fitting tool: (figura 1)


Figura 1

Se nos abrira una ventana nueva y alli daremos click en el boton Data... en la ventana que se abrio en X data ponemos la variable tiempo y en Y data la variable temperatura (o sus los nombres que uds les tengan asignados) .. si no les aparece nada es por que tienen que haber corrido su codigo de graficacion de sus datos reales para que las variables del tiempo y temperatura aparezcan en el workspace...

luego daremos click en Create date set. y click en close (figura 2)


Figura 2

La grafica mostrada sera muy similar a la de su figure 1, pero en forma de puntos, lo cual no es ningun problema, por que ahora vamos a hallar nuestra ecuacion, para eso hacemos lo siguiente:

click en el boton fitting, luego en new fit .... aqui es donde les voy a recomendar algo a titulo personal...

Recomendacion: traten de la ecuacion quede en terminos de eulers y no en forma de polinomio, ya que si es asi todos los polos les quedaran en el mismo lugar (en cero) y no es muy buena idea para los calculos, pero en fin ya sabran uds como hacerlo...

Vamos a modificar unicamente donde dice Tye of fitt. ahi podran ver todo el tipo de ecuaciones con las cuales se puede representar nuestra curva caracteristica de la planta... si siguen mi recomendacion entonces buscar donde dice exponential y escogemos el tipo de ecuacion ( a*exp(bx) + c*exp(dx) ) y hacemos click en apply... luego de eso nos aparecera nuestra ecuacion (la que nos describe nuestros datos) ... si tienen dudas de que valores para las constantes escoger, escojan los promedios, osea los valores que estan fuera de los parentesis ... (figura 3)


Figura 3

Ahora damos click en close y confirmamos que la ecuacion reproduce lo mas fielmente posible la grafica de nuestros datos si es asi ya tienemos nuestro y(t) = a*exp(bt) + c*exp(dt) y tambien los valores de las constantes... y si no s asi buscamos la que mejor lo haga.. pero estoy un 90% seguro de que la funcion exponential lo hara de maravilla.

Por lo tanto obtenemos una ecuacion y(t) = a*exp(b*t) + c*exp(d*t) aplicando laplace obtenemos:

                32.98 s + 0.06097
Y(S) =   ----------------------------
         s^2 + 0.00141 s - 9.773e-009

Para mi caso ... a uds les dara una ecuacion similar .. matlab tambien lo hace usando el codigo

syms t
a = 42.98;
b = -6.9x10^-6;
c = -10.15;
d = 0.001417;
yt = a*exp(b*t) + c*exp(d*t)
YS = laplace (yt)


pero la verdad es que se ve muy raro y desordenado, asi que recomiendo lapiz y papel que hacerlo no es dificil y ademas sale directo, luego se aplica un poco de algebra, se reemplazan valores y listo.

Ahora sabemos que dentro de Y(S) tenemos implicito nuestra entrada escalon unitario, po lo tanto nuestra G(S) sera:

           32.93 s^2 + 0.06097 s
G(S) = ----------------------------
           s^2 + 0.00141 s - 9.773e-009

Ahora tenemos que determinar el tiempo de muestreo (T) para eso podemos usar el metodo que describe blackcat mas adelante o podemos asumirlo, ya cada quien decidira, por mi parte lo sumire como T=0.1

Pasamos a la parte en que tenemos que aplicar la transformada Z para poder discretizar nuestro G(S) y obtener nuestro G(Z) .. pero recuerden que G(Z) no es igual a la transformada Z de G(S) si no que lleva incorporado un retenedor de un orden cualquiera, para este caso usaremos uno de orden cero... y lo llamaremos Bo(S) asi que:

G(Z) = Z/ Bo(S) G(S) donde Z/ sera la tranformada Z de todo eso... bueno para los amantes del lapiz y papel, podeis hacerlo, por que por mi parte no lo voy a hacer, para eso voy a usar matlab y el siguiente codigo.

n1=32.98;
n2=0.06097;
d1=1;
d2=0.0014101;
d3=-(9.773/1000000000);
GS=tf( [n1 n2 0], [d1 d2 d3])

T=0.1;
GZ=C2D(GS,T,'zoh')


donde zoh indica a matlab que se va a usar un retenedor de orden cero. osea nuestro Bo(S)

y el resultado que nos entrega matlab sera el siguiente:

             3.293 z - 3.292
G(Z) =   ------------------
           z^2 - 2 z + 0.9999
 
Sampling time: 0.1


Bueno hasta aqui todos deberiamos llevar algo similar, ahora es donde yo me he decidido por hacer un controlar por el metodo de ragazzini .. asi que por ahi es donde lo haremos....

lo primero es hallar los polos deseados teniendo en cuenta las siguientes condiciones de lazo cerrado.
essp = 0 ; Test 5% = 10 seg ; T = 0.1 ; Zcita = 0.5

usando formulas ya conocidas en nuestros estudios realizados obtenemos los dos polos deseados Z(1,2):

Z(1,2) = 0.9691 +/- j 0.0504    lo cual llamaremos (alfa +/- j beta) para comodidad

El metodo ragazzini nos dice que:

F(Z) = K / P(Z)

ahora P(Z) = (Z - Z1) (Z - Z2) como ya sabemos los valores de Z1 y Z2 entonces reemplazamos... pero podemos hacer algo mejor y es reemplazar por las letras y despejar para que nos quede algo asi:

P(Z) = Z^2 - 2 alfa Z + (alfa^2 + beta^2) ahora se reemplazan los valores y listo.

para que ragazzini funcione se dice que F(1) = 1 .. lo cual es de gran ayuda.. sabemos por formula que:

F(Z) = K / P(Z) --- reemplazamos P(Z) y nos quedara asi:

F(Z) = K / Z^2 - 1.9382 Z + 0.94169 --- hacemos F(1) = 1 --- quedando: 1 = K / 1^2 - 1.9382 + 0.94169 -- despejando K

K = 0.00349 ahora pasamos a la parte interesante...

D(Z) = [ 1/G(Z) ] [ F(Z) / 1 - F(Z) ]

pero como todo se puede simplificar entonces lo hacemos.

D(Z) = [ 1 / G(Z) ] [ K / P(Z) - K ]

como ya conocemos todas las variables y ecuaciones, simplemente hallamos D(Z)

D(Z) = [ 0.001058Z^2 - 0.002116Z + 0.001058 ] / [ Z^3 - 2.93769Z^2 - 0.9379 ]

Bueno la parte final es hallar la ley de control, para eso cambiamos D(Z) por u(Z)/ e(Z) y multiplicamos al otro lado por Z^-3 / Z^-3

quedandomos asi:

u(Z)     0.001058Z^-1 - 0.002116Z^-2 + 0.001058Z^-3
----- = ---------------------------------------------------------
e(z)     1 - 2.93769Z^-1 + 0.9382Z^-2 - 0.9379Z^-3

ahora el denominador pasa a multimplicar a u(Z) y e(Z) a multiplicar al numerador. luego de lo cual despejamos u(Z) y de paso usamos una un teorema que dice en resumen que u(Z)Z^-1 = u(Z-1) .. lo mismo con e(Z) .... ahora cambiamos Z por k quedando finalmente la ley de control asi:

u(k) = 0.001058 e(k-1) - 0.002116 e(k-2) + 0.001058 e(k-3) + 2.93769 u(k-1) - 0.9382 u(k-2) + 0.9379 u(k-3)

esta ley de control u(k) es la que programamos para poder controlar nuestro sistema



SE EDITARA A MEDIDA QUE SE AGREGUEN NUEVAS COSAS....





Saludos a todos, tengo una duda elemental, ¿por qué al usar una entrada escalón unitario, ese vector tiene valores que van creciendo de 0 a el max del escalón?
un escalón unitario no es un único valor para todo tiempo?, estoy sumamente confundido en algo tan elemental :'(

Desconectado phantom879

  • PIC10
  • *
  • Mensajes: 2
Re: PID Digital (paso a paso)
« Respuesta #73 en: 31 de Octubre de 2011, 23:48:58 »
Hola ...

Para poder estimar un sistema con matlab se utiliza la herramienta IDENT .. esta es muy facil de usar, lo que se necesita es lo siguiente:

-> un vector de entradas (x) ... la señal de estimulo que aplicaste al sistema
-> un vector de salidas (y) ... la señal de respuesta que obtuviste del sistema al aplicar la señal de entrada
-> un vector de tiempo (t) ... los tiempos de cada muestra, deben ser constantes, es decir, 1, 2, 3, 4 segundos etc ... y no 1, 1.5, 2, 3, 5, 8 .. etc..

Con eso IDENT identificará el sistema que se encuentra adentro.



Lo que necesitas es una señal de prende o apaga el bombillo .. o bien una señal de volaje RMS que le aplicas al bombillo, luego debes medir en tiempo real el comportamiento de la temperatura ante la señal. Un escalon como lo estas haciendo, es posible, sin embargo solo tenes el comportamiento de calentar y no de enfriar.

Para poner a prueba el IDENT me inventé un sistema tipico y muy facil de entender .. un filtro pasobajos RC de primer orden, representado en Laplace como:

\begin{equation}
G(s) = \frac{1}{1 + 0.001s}
\end{equation}

Es decir R = 1k y C = 1uF ... siendo tau = 1ms;


>> R = 1000
>> C = 1e-6
>> G = tf( 1, [R*C 1] )


Lo que voy hacer es inventar un vector de entradas, estimulare el sistema con esas entradas y utilizaré IDENT para identificar el sistema; lo ideal es que obtenga un resultado como en de la ecuacion anterior. En el caso practico, no conozco la ecuación del sistema, pero lo que se acostumbra es estimular el sistema con diferentes vectores de entrada y estimar varios modelos y comparar el resultado con los otros vectores.

Como mencioné, es necesario que tenga un vector de datos de entrada y ver la respuesta del sistema (salida) ante esa entrada, el mejor vector de entrada es aquel que tenga un buen contenido de frecuencia, ruido por ejemplo; sin embargo, dependiendo del sistema esto se complica, por ejemplo, en un motor; lo recomendable es estimar el modelo matemáticamente y ver que frecuencias son las aptas para crear una señal de estímulo; por ejemplo, el modelo de un motor es parecido a un filtro pasobajos, entonces utilizamos una señal que contenga componentes de frecuencia dentro del ancho de banda del motor.

Como en este caso, el ejemplo es simulado, utilizo la función RAND para generar un vector de entrada aleatorio de 100 muestras:

>> x = rand([100, 1])



Esta es mi señal de entrada, ahora, necesito el vector de salida, estimularé el sistema con la función LSIM, entre los datos de esta funcion está el vector de tiempo. Aqui voy a utilizar tiempo discreto y elejiré que el tiempo de muestreo sea un décimo de la constante de tiempo del sistema (tau = RC); en este caso, ts = 0.1ms. Genero un vector de tiempo de 100 datos desde 0 hasta 99*0.1e-3.

>> n = (0:99)'
>> ts = 0.1e-3
>> t = n*ts


Ahora utilizo LSIM ....

>> y = lsim(G, x, t)

La grafica que obtengo en el tiempo es:



donde la linea azul es la entrada y la linea verde es la salida, veran que esta filtrada.

Ya tengo listo mi vector de entrada, salida y tiempo; esto es lo que tendria en la practica, una señal de entrada, el comportamiento de la salida y el tiempo en que fue tomado cada dato.  En el caso de la temperatura, el vector de entrada seria pulsos rectangulares, que me dicen cuando se prendio el bombillo y cuando permanecio apagado; la salida seria el aumento de temperatura y la disminucion de temperatura, el tiempo seria cada cuanto tome la muestra, como es temperatura puede ser de 1 o 3seg, constantes y no interrumpidos ... en este caso, tomar los datos a reloj en mano no es conveniente.

Yo conozco el sistema; sin embargo, la idea es estimar el sistema en tiempo discreto utilizando el vector de entrada, salida y tiempo; luego transformar el sistema a tiempo continuo y comparar.

Ejecuto IDENT

>>ident

Y aparece una pantalla como la siguiente:



Lo que hacemos es en IMPORT DATA seleccionamos TIME DOMAIN DATA ... esto porque nuestros datos de entrada, salida y tiempo estan en el tiempo. Aparece un cuadro como asi:



Y lo lleno con la informacion que tengo, entrada (x), salida (y), tiempo de inicio (0), tiempo entre muestras (ts) como lo hice en la figura. Damos IMPORT ..



En la columna de cuadros izquierda me aparece el bloque de datos que cargue en IDENT; ahi puedo cargar la cantidad de datos que desee y puedo combinar datos como de estimulo y verificacion, esto es que con un conjunto de datos puedo estimar el sistema y con otro conjunto puedo verificar si la estimacion está correcta.

Ahora, sobre ESTIMATE damos LINER PARAMETRIC MODELS ... aqui escogemos el método de estimación que mas nos guste o que mejor de resultados, sobre el tipo de estimador se puede encontrar información en internet:

http://www.ie.itcr.ac.cr/einteriano/control2/Laboratorio/3.Models.pdf

Yo elejí ARX tanto de orden 1 como de orden 2 ... entre mas orden es mejor la estimación; sin embargo, hay un compromiso, pues estimar un compensador para un sistema que tiene un orden alto es mas dificil que para uno bajo, entonces escogemos el modelo de menor orden. Seleccionando la casilla MODEL OUTPUT aparecerá una gráfica que nos dice cual modelo es el que mejor se ajusta a los datos de salida. Vemos que con el modelo de 1º orden tenemos un ajuste de 100.



Ahora arrastramos el cuadro que dice ARX111 de la columna derecha sobre el cuadro TO WORKSPACE ... eso hara que los datos del modelo lo tengamos en la linea de comando. Para ver el modelo ejecutamos:

>> H = tf(arx111)
 
Transfer function from input "u1" to output "y1":
 0.09516
----------
z - 0.9048
 
Transfer function from input "v@y1" to output "y1":
1.665e-016 z
------------
 z - 0.9048
 
Input groups:           
      Name      Channels
    Measured       1   
     Noise         2   
                       
Sampling time: 0.0001


Entonces nuestro modelo estimado en tiempo discreto es:

\begin{equation}
G(z) = \frac{0.09516}{z - 0.9048}
\end{equation}

Usamos:

>> G2 = d2c(H)

y obtenemos:

\begin{equation}
G(s) = \frac{1000}{s + 1000}
\end{equation}

Vemos que IDENT identificó el sistema correctamente ...  Utilizando este modelo podemos usar SISOTOOL y calcular de manera sencilla un compensador  :)

Saludos y espero que les sirva de algo!

PD: Espero sus comentarios y estamos listos para la implementación PID en un PIC!


Buenas, tengo una duda muy grande, cuando explicas tu procedimiento usando ident, partes de la FT de un filtro, no sé si estoy interpretando mal, pero cómo hago para hallar la FT de la planta partiendo de nada, estoy muy confundido :s

Desconectado Suky

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 6758
Re: PID Digital (paso a paso)
« Respuesta #74 en: 01 de Noviembre de 2011, 01:11:26 »
Busca sobre identificación de sistemas.


Saludos!
No contesto mensajes privados, las consultas en el foro


 

anything