Pero cuando lo simulo en Proteus, no me genera siquiera el ciclo "negativo" que debería tener pues de la señal analoga
No no, borra lo que te dije del voltaje negativo, lo que quiero básicamente es que me salga una señal seno escalonada, sin embargo me están saliendo unos picos muy grandes, por eso te pregunto cómo podría corregir los picos que ves en la señal...
Tengo una duda respecto a la opción del pwm. Lo que pasa es que lo que me piden es que el periodo de muestreo sea de 10ms, eso lo garantizo con las interrupciones del timer 1. Lo que no estoy seguro es para cuadrar la frecuencia del pwm es si setear otro timer para dejar esta frecuencia distinta? Y si el filtro lo calculo para esa frecuencia del pwm, o para la frecuencia del generador de onda?
...
Hola buenas ya pude filtrarla un poco mejor para una frecuencia de PWM de 8kHz.
Pero ahora lo que me piden es utilizar la función seno, solo que en ecuaciones en diferencia. ¿ alguna idea de como pueda plasmar una ecuación en diferencia en lenguaje C?
No entiendo/encuentro como llegaste a esa formula.
Puedo pensar en matematica discreta pero sigo sin ver el aproximado de la misma. Y sino podrías dar un ejemplo de como serian las primeras 4 resultados de esa ecuación?, Segun mi entendimiento seria:
Xn = k*Xn-1 - Xn-2
n = 0
Xn = k*0 - 0
n = 1
Xn = 2*cos(ang)*A*sen(ang) - 0
n = 2
Xn = ¿?¿??¿ - 2*cos(ang)*A*sen(ang)
Si me decís que tengo que variar el angulo de coseno y seno, significa que necesito implementar 2 tablas, una de seno y otra de coseno! para obtener el seno ¿?¿?
O sigue entrando un A*sen(ang) ?
#include <stdio.h>
#include <math.h>
void main(void){
// Declaracion de variables
int n ;
double k , ang , A ;
double xn1 , xn ;
// Inicializacion
ang = 4*M_PI/180 ; // Angulo de avance de 4°
A = 1000 ; // Amplitud 1000
k = 2*cos(ang) ;
xn1 = 0 ; xn = A*sin(ang) ; // Valores iniciales
// Salida de 200 valores , para no hacer
// un bucle infinito
printf("%.3lf\n%.3lf\n",xn1,xn); // Muestro los dos
// primeros
for(n=2;n<200;n++){
xn = -xn1 + k*(xn1=xn) ; // Esto es la única operación que se repite
printf("%.3lf\n",xn) ;
}
}
#include <stdio.h>
#include <math.h>
void main(void){
// Declaracion de variables
int n ;
double k , ang , A ;
double xn , dn ;
// Inicializacion
ang = 4*M_PI/180 ; // Angulo de avance de 4°
A = 1000 ; // Amplitud 1000
k = 2*sin(ang/2);
k *= k ;
xn = 0 ; dn = A*sin(ang) ; // Valores iniciales
// Salida de 200 valores , para no hacer
// un bucle infinito
printf("%.3lf\n",xn); // Muestro el valor inicial
for(n=1;n<200;n++){
xn += dn -= k*xn ;
printf("%.3lf\n",xn) ;
}
}
En todos lados veo que usan series de taylor, o se puede usar los polinomios de Chebyshev, pero la anti trasformada como la planteas no la vi nunca.
Por mi:
Si quiere un calculo con una ecuación en diferencia, que cargue una tabla con la diferencia entre un punto y otro, y no el valor total. Algo simple y sigue siendo una ecuación en diferencia, el concepto esta, es culpa de el docente por no ser especifico.
Y por supuesto, la suma de todos los valores que cargues en la tabla te debe dar 0 si o si. Y nunca sobrepasar los limites 0 y el limite superior que elijas ( ejemplo 4095 )
Bien, teniendo la expresión como tal, nos hizo entender que es importante escalizar la salida de esa operación previamente dicha. Observando tu codigo, y teniendo en cuenta lo que el nos dijo, iniciamos a evaluar cuando n=2, ahora bien, tengo un par de inquietudes...
¿cómo puedo escalizar esa señal teniendo en cuenta que ese valor es el que va a leer el PWM para mostrarlo en la salida del CPP ?
¿basicamente lo unico que va en el ciclo sería la operación como tal? en mi caso, ¿iría dentro del while y el resto de la definición iria en el main?, considerando que nos dice que cada 10 ms, el programa tiene que repasar la operación...
int1 tic = 0 ;
#INT_TIMER1
void tic_10ms() {
set_timer1(xxxx); // xxxx el que haga falta para 10ms
tic = 1 ;
}
int16 xpwm ; // Global por si la uso fuera de main
void main(){
......... demás definiciones
.................
float32 x = .95 ; // Valor inicial = Amplitud. Por prevención ligeramente menor que 1
float32 d = 0 ;
float32 k = 1/32 ;
// El ángulo de avance será ang = 2*asin(sqrt(k)/2)
// Y la frecuencia f = ang/(2*PI*T)
// para T=10ms, k=1/32 resulta f=2.68Hz
..... Habilitaciones, etc
...................................
xpwm = (x+1)*512 ; // pwm duty
while(TRUE)
{
if(tic){
tic = 0 ;
x += d -= x*k ; // genero el nuevo valor de seno
xpwm = (x+1)*512 ; // pwm duty
......... reajustar el duty cycle
......... si sincronizado, mejor.
}
......... Demás tareas
.........................
}
}
y1=y;
y2=y1;
y2=y1;
y1=y;
float32 y1 = 1.61 ;
float32 y2 = 1 ;
float32 y1 = 0.587 ; // A*seno(2*PI*f*tic)
float32 y2 = 0 ; // Cero , pues inicia en 0
float32 y1 = .95 ; // La amplitud real es ligeramente mayor
float32 y2 = .95 ; // que 0.95
float32 y;
int16 q;
xpwm = (y+2)*512 ; // pwm duty q=read_adc();
y=q*(1.61*y1)-y2 ; // ecuacion en diferencias, asumiendo 10Hz
Ahí multiplicando por q, además que no se qué quisiste hacer, destrozás la recurrencia. xpwm = (y+2)*512;// escalización
set_pwm1_duty(xpwm);
y1=y;
y2=y1;
y2 = y1 ;
y1 = y ;
La recurrencia para un seno es Xn = k*Xn-1 - Xn-2 , n > 1
Siendo
k = 2*cos(ang) , ang : El ángulo que avanza en cada paso.
Si querés usar el valor del ADC para variar la amplitud lo tenés que hacer en el escalado: xpwm = q*y/2+512 ;
Lo que hice fue realizar una tabla de valores para la ecuación en diferencias:
..............
Hace de cuenta que partí de esta ecuación, asumiendo una f=10Hz y un Ts=10ms. Como el ángulo es w.Ts=2pi*10*0.01=0.628, por eso, al reemplazar y operar esa k que tienes, se obtiene 1.61, que es el valor inicial que tome. Básicamente lo que observé en la tabla de valores que armé, es que el seno que se forma, tiene una amplitud aproximada a 2, por eso hice la escalización a 2.
CitarSi querés usar el valor del ADC para variar la amplitud lo tenés que hacer en el escalado: xpwm = q*y/2+512 ;
Por qué pones y/2?
Sin embargo, hay dos cosas que aun no te entiendo del codigo que me sugeriste a seguir:
Por qué un if (tic), y declararlo al principio como tic=0, luego como 1, y así?
Por qué me dices que hay que multiplicar por el 512 al xpwm?
#include <16f877a.h>
#device adc=10
#fuses hs,nowdt,noprotect,noput
#use delay (clock=4M)
int1 tic = 0 ;
int16 xpwm ;
#define PERIODO 65536-625
#INT_TIMER1
void tic_10ms()
{
tic = 1 ;
set_timer1(PERIODO);
set_pwm1_duty(xpwm);
}
void main(){
set_tris_c(0b000);
setup_timer_1(t1_internal|t1_div_by_8);
set_timer1(PERIODO);
setup_timer_2(T2_DIV_BY_1, 199, 1);
setup_ccp1(CCP_PWM);
set_pwm1_duty(0);
enable_interrupts(int_timer1);
enable_interrupts(global);
float32 k = 1.937 ; // 2*cos(2*PI*f*T)
float32 y1 = .2363 ; // Amp*seno(2*PI*f*T)
float32 y2 = 0 ; // Amp = .95 f = 4 Hz T = .01s
float32 y ;
xpwm = (y1+1)*400 ;
while(TRUE)
{
if(tic)
{
tic = 0 ;
y = k*y1-y2 ;
xpwm = (y+1)*400 ;
y2 = y1 ; y1 = y ;
}
}
}
La recurrencia para un seno es Xn = k*Xn-1 - Xn-2 , n > 1
Siendo
k = 2*cos(ang) , ang : El ángulo que avanza en cada paso.
X0 = 0
X1 = A*seno(ang) , A : Amplitud.
....
¿por qué asumes 400 para la escalización a 4 MHz, porque es simplemente un valor entre 0 y 800? ¿ahora bien, hay alguna fórmula o expresión que dicte que ese valor tiene que ser entre 0 y 800?
¿por qué en la recurrencia:
................................
X1=A*sen(ang)?
Xn - 2*cos(a)*Xn-1 + Xn-2 = sin(a)*En-1
Okay, revisaré el datasheet.CitarXn - 2*cos(a)*Xn-1 + Xn-2 = sin(a)*En-1
Como tal hasta acá entiendo que haces, pero no entiendo porque asumes un X1=A*sin(ang). Hastá aca, lo que el seno esta multiplicando es a la entrada retrasada una muestra, lo que en algun punto va a ser 0 si asumimos una entrada impulso. Por esto no te entiendo porqué asumes que X1 tome ese valor, y luego sea que lo asumas como x(n-1)... :-/
Saludos, tengo una consulta, estoy buscando un pic con 20 entradas analogicas para poder conectar sensores, mi pregunta es que si es posible utilizar las 20 entradas analogicas de un pic?
gracias
atte
micronet