Función de transferencia

11

Click here to load reader

description

Respuesta en Frecuencia implementada en lenguaje C

Transcript of Función de transferencia

Page 1: Función de transferencia

UNIVERSIDAD AUTÓNOMA DE QUERÉTARO

FACULTAD DE INGENIERÍA

MAESTRÍA EN MECATRÓNICA

Nombre del alumno:

Carlos Andrés Pérez Ramírez

Materia:

Control Avanzado

Práctica 2

Obtención de la respuesta en frecuencia de una función discreta utilizando el lenguaje C

Nombre del Catedrático

Dr. Luis Morales Velázquez

San Juan del Rio, Querétaro. 4 de septiembre de 2013

Page 2: Función de transferencia

Introducción

La respuesta en frecuencia de una función en tiempo discreto permite conocer tanto los cambios en la amplitud así como en la fase que sufrirá una señal al ser aplicada a dicha función. El conocimiento de estos parámetros es necesario para poder realizar una correcta implementación de la función en una plataforma en hardware.

Además, la evaluación de los parámetros antes mencionados permite saber si la función en cuestión tiene un comportamiento similar al de algún tipo de filtro selectivo en frecuencia.

Objetivo

Realizar un programa en el lenguaje C para obtener la respuesta en frecuencia de una función arbitraria discreta.

Metodología

Supóngase una función discreta (F(z)) formada por el cociente de dos funciones en tiempo discreto, esto es:

(1)

donde A(z) y B(z) son polinomios de grado n. De esta manera la ecuación (1) se puede reescribir como

(2)

Para realizar la evaluación de la respuesta en frecuencia de la función F(z) es necesario evaluar ésta usando una exponencial compleja, lo que da como resultado

(3)

Si se emplea la identidad de Euler, además de las leyes de los exponentes, la ecuación (3) puede expresarse empleado senos y cosenos, es decir

(4)

Page 3: Función de transferencia

Como se aprecia en la ecuación (4), las partes real e imaginaria pueden ser sumadas para obtener el número complejo resultante tanto para el numerador como para el denominador, obteniéndose

(5)

Transformando tanto el numerador como el denominador a su forma polar, el cálculo de la magnitud y la fase, es decir, la respuesta en frecuencia, se reduce a una división y una resta. Matemáticamente es

(6)

Para expresar la ganancia en dB, se calcula el logaritmo base 10 del resultado del cociente y se multiplica por 20.

(7)

Desarrollo

La implementación de las ecuaciones 5, 6 y 7 se realiza de la siguiente manera. Es necesario generar una estructura que contenga un puntero del tipo flotante para almacenar los coeficientes así como el orden del polinomio. La estructura propuesta es

typedef struct Poly_Tag

{

float *coeff;

int grado;

}Poly

Para almacenar la fase y la magnitud del número complejo se propone una estructura que contenga un par de variables flotantes que contengan a éstas. Ésta es

typedef struct cmpx_Tag

{

double Mag,Ph;

}cmpx;

Page 4: Función de transferencia

Una vez propuestas las estructuras, es necesario proponer las funciones que interactuarán con éstas. Para inicializar la estructura que contiene al polinomio se usa la función createPoly, cuya sintaxis es

void createPoly(Poly *a);

La función recibe un puntero a la estructura poly, para acceder a los miembros de ésta. Se pregunta por el orden del polinomio; con este valor se reserva memoria para n+1 coeficientes. Una vez que se reserva la memoria, se procede a solicitar al usuario los valores de los coeficientes, empezando desde el menos significativo (el término independiente). Esto se realiza con la función fillPoly, cuya sintaxis es

void fillPoly(Poly *a);

Posteriormente, se calcula la respuesta en frecuencia del polinomio empleando la función respFrec. La sintaxis de esta función es:

void respFrec(Poly *a,cmpx *b,float frec,float fs);

En esta función se realiza la implementación de la ecuación 5 y se resume como sigue: se emplea un ciclo iterativo que inicia desde 0 hasta el orden del polinomio y se calcula tanto el seno y el coseno de la frecuencia normalizada (multiplicada por el periodo de muestreo). Una vez finalizado el ciclo, se calcula la magnitud del número y la fase empleando la función atan2 (toma en cuenta la ubicación en los cuadrantes) y almacena estos parámetros la estructura b. Todas las estructuras se pasan a la función usando punteros.

La implementación de la ecuación 6 se hace con la función respFrecFun, cuya sintaxis es

void respFrecFun(cmpx *a,cmpx *b,cmpx *c);

y consiste , para el cálculo de la magnitud de la función, en la división de la magnitud a (representa al numerador) entre la magnitud de b (representa al denominador); para la fase, se resta la fase de a menos la de b utilizando una función para el ajuste de fase, adjPhase. Los parámetros se pasan a la función empleando punteros.

Para realizar el ajuste de fase se utiliza la función adjPhase(float a, float b), cuya sintaxis es

float adjPhase(float a, float b);

Esta función usa los valores calculados dentro de respFrecFun y calcula el ángulo según el signo de las partes real e imaginaria; se utilizan variables flotantes como entrada y salida.

Para imprimir el resultado se emplea la función printCpmx, cuya sintaxis es

void printCmpx(cmpx *a);

y consiste en el uso de la función printf para imprimir en pantalla los parámetros del número complejo a. Si se desea conocer la magnitud en dB, se emplea la función printCmpxdB, cuya sintaxis es la misma que la anterior; el funcionamiento de ésta varía de la previa dado que implementa la ecuación 7, empleando la función logaritmo base 10.

Resultados

Page 5: Función de transferencia

Para realizar la comprobación de la función, se utilizó el polinomio definido en la ecuación (8)

(8)

Con este polinomio, se procedió a graficar, con la ayuda de la función bode de MATLAB, la gráfica de la respuesta en frecuencia de la función mostrada en la ecuación 8, que se ilustra en la figura 1.

Cabe aclarar que el periodo de muestreo utilizado fue de 1 kHz. Ésta se expresa en Hz. La frecuencia de evaluación es expresada en radianes.

Figura 1. Respuesta en frecuencia para la función propuesta.

Una vez definido el periodo de muestreo así como la obtención de los valores de referencia, se procedió a evaluar las funciones propuestas empleado 3 valores de frecuencia, expresados en radianes. La salida de cada evaluación está expresada en dB para realizar una correcta comparación. La tabla 1 resume los resultados obtenidos

Frecuencia (rad) MATLAB (dB) Obtenido (dB)29.3 23.2 23.16695580 5.28 5.294331

1570 -10.8 -10.834454Tabla 1. Magnitud obtenida

En la tabla 2 se muestra la fase obtenida para cada frecuencia con el programa propuesto así como las obtenidas con MATLAB

Frecuencia (rad) MATLAB (°) Obtenido (°)

Page 6: Función de transferencia

29.3 -8.55 -8.540346580 -159 -159.18343

1570 -174 -174.18799Tabla 2. Fase obtenida

Como se aprecia, en el caso de la magnitud se tiene que los valores obtenidos con el código propuesto corresponden uno con otro. La pequeña diferencia se debe al número de decimales que toma cada programa para realizar sus operaciones. En el caso de la fase, como ya se mencionó, el uso del compensador de fase permite reportar correctamente ésta, pues los rangos de operación de atan de –pi/2 a pi/2 y para atan2 de –pi a pi, lo que es claramente inapropiado. Los valores obtenidos en ambas plataformas coinciden el uno con el otro. La figura 1 muestra el código en ejecución.

Figura 1. Programa en operación

Conclusión

Se propuso un programa, desarrollado en el lenguaje C, capaz de calcular la respuesta en frecuencia de una función discreta. El programa consiste en la solicitud al usuario de la frecuencia de muestreo, la frecuencia a evaluar así como los órdenes de los polinomios del numerador y denominador. Con estos valores se procede a reservar dinámicamente la memoria para almacenar los coeficientes. Tomando ventaja de la identidad de Euler, además de la forma polar de un número complejo, se aproxima la respuesta de la función como una suma de senos y cosenos. El poder reservar dinámicamente la memoria da al algoritmo propuesto la flexibilidad de poder trabajar con órdenes diferentes tanto para el denominador como el numerador. Los resultados obtenidos muestran que el algoritmo propuesto realiza de manera satisfactoria la operación requerida. Como trabajo a futuro se plantea la codificación del algoritmo propuesto en el lenguaje C++, ya que se podrán crear operadores únicos sin la necesidad de generar funciones para cada operación requerida.

Page 7: Función de transferencia

Anexos

Anexo 1. Código utilizado para la elaboración de la práctica

#include <stdio.h>#include <stdlib.h>#include <math.h>

#define pi 3.141592653589793

typedef struct Poly_Tag{

float *coeff;int grado;

}Poly;

typedef struct cmpx_Tag{

double Mag,Ph;}cmpx;

void createPoly(Poly *a);void fillPoly(Poly *a);void printCmpx(cmpx *a);void printCmpxdB(cmpx *a);void respFrec(Poly *a,cmpx *b,float frec,float fs);void respFrecFun(cmpx *a,cmpx *b,cmpx *c);float adjPhase(float a, float b);

int main(void){ float fs=0,frec=0; Poly Num,Den; cmpx RF_Num,RF_Den,RF; printf("Frecuencia de meustreo:"); scanf("%f",&fs); printf("Frecuencia a evaluar:"); scanf("%f",&frec); printf("\nNumerador\n"); createPoly(&Num); fillPoly(&Num); printf("\nDenominador\n");

Page 8: Función de transferencia

createPoly(&Den); fillPoly(&Den); respFrec(&Num,&RF_Num,frec,1/fs); respFrec(&Den,&RF_Den,frec,1/fs); respFrecFun(&RF_Num,&RF_Den,&RF); printCmpxdB(&RF); free(Num.coeff); free(Den.coeff); fflush(stdin); getchar(); return 0;}

void createPoly(Poly *a){

int f;printf("Orden del polinomio:");

scanf("%d",&f); a->grado=f;

a->coeff=(float*)malloc((a->grado+1)*sizeof(float)); if(a->coeff==NULL) { printf("Error, no se pudo reservar memoria"); fflush(stdin); getchar(); exit(1); }}

void fillPoly(Poly *a){ int i;

float tmp;fflush(stdin);for(i=0;i<=a->grado;i++)

{ printf("\n Coeficiente [%i]: ",i);

scanf("%f",&tmp); a->coeff[i]=tmp; } printf("\n");}

void printCmpx(cmpx *a){

printf("Magnitud:%f\nFase(rad):%f\nFase(deg):%f\n\n",a->Mag,a->Ph,((a->Ph)*180)/pi);}

Page 9: Función de transferencia

void printCmpxdB(cmpx *a){

printf("Magnitud:%f\nFase:%f\nFase(deg):%f\n\n",20*log10(a->Mag),a->Ph,((a->Ph)*180)/pi);}

void respFrec(Poly *a,cmpx *b,float frec,float fs){

int i=0;float tmp_real=0,tmp_img=0,tmp_frec=0;for(i=0;i<=a->grado;i++)

{ tmp_frec=frec*i*fs; tmp_real=tmp_real+a->coeff[i]*cos(tmp_frec); tmp_img=tmp_img+a->coeff[i]*sin(tmp_frec); //printf("\n %f %f %f",tmp_frec,tmp_real,tmp_img); } b->Mag=sqrt((tmp_real*tmp_real)+(tmp_img*tmp_img)); b->Ph=adjPhase(tmp_real, tmp_img);}

void respFrecFun(cmpx *a,cmpx *b,cmpx *c){

c->Mag=(a->Mag)/(b->Mag);c->Ph=(a->Ph)-(b->Ph);

}

float adjPhase(float a, float b){ float c; if(a>0&&b>0) { c=atan(b/a); } else if(a<0&&b>0) { c=pi-atan(b/abs(a)); } else if(a<0&&b<0) { c=pi+atan(b/a); } else { c=2*pi-atan(abs(b)/a); } return c;

Page 10: Función de transferencia

}