Autor Tema: Me ayudais a optimizar el calculo de un duty cycle?  (Leído 1246 veces)

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

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1835
    • IDEAA
Me ayudais a optimizar el calculo de un duty cycle?
« en: 26 de Julio de 2021, 15:00:11 »
Buenas!
Hace años hice una libreria que decodifica mandos a distancia chinos analizando los pulsos, y estoy queriendo optimizarla por eficiencia y sobre todo velocidad de ejecucion.

En resumidas cuentas:
-un pulso con un duty de alrededor de 25% se considera un CERO
-un pulso con un duty de alrededor de 75% se considera un UNO
-un pulso con un duty de alrededor de 3,125% se considera el fin de la trama de pulsos (SYNC).

Otra forma de verlo es:
-CERO: 1 frame high, 3 frame low
-UNO: 3 frame high, 1 frame low
-SYNC: 1 frame high, 31 frame low

El mando a distancia envia 24 pulsos con CEROS o UNOS, y un ultimo pulso de SYNC.

Tengo un receptor RF conectado al pin de INT_EXT y cada vez que hay un flanco ascendente o descendente el PIC interrumpe y "registra" los tiempos.
En los flancos ascendentes comienza un nuevo pulso y pone el timer a 0
En los flancos descendentes guarda el tiempo del pulso (HighDuration)
En un nuevo flanco ascendente guarda el tiempo total del pulso (TotalDuration)

Con la siguiente formula obtengo el "duty" del pulso:
Código: [Seleccionar]
Duty = ((int32)HighDuration * 100) / TotalDuration;
Para darle un poco de margen no establezco un valor exacto para el duty, sino que pongo un rango de valores validos:
Código: [Seleccionar]
#define MIN_ZERO 15
#define ZERO 25 //teorico
#define MAX_ZERO 35

#define MIN_ONE 65
#define ONE 75 //teorico
#define MAX_ONE 85

#define MIN_SYNC 1
#define SYNC 3.125 //teorico
#define MAX_SYNC 5

Para saber si mi pulso es un CERO, UNO, SYNC o RUIDO lo paso por estos IF:
Código: [Seleccionar]
/* PULSO SYNC */
if((MIN_SYNC <= Duty) && (Duty <= MAX_SYNC)){
...
}
/* PULSO CERO */
else if((MIN_ZERO <= Duty) && (Duty <= MAX_ZERO)){
...
}
/* PULSO UNO */
else if((MIN_ONE <= Duty) && (Duty <= MAX_ONE)){
...
}
/* RUIDO */
else{
...
}

En resumen, mido cada pulso y luego lo paso por unos IF para ver si encaja en alguno y asi saber de que se trata.
Pero tanto la multiplicacion y division de int32, asi como la multitud de IFs me parece que hacen que sea un codigo muy poco optimo.
Funciona bien, pero creo que lo podria exprimir bastante mas.
Creo que calcular el duty en un valor de 0 a 100 (base 10) es algo innecesario, y seguramente trabajar en base 2 lo haria mucho mas optimo.
Al mismo tiempo los IF con > y < puedan evitarse o abreviarse.

Se os ocurren algunos truquitos de optimizacion?
Si quereis ver el codigo entero lo tengo en github: https://github.com/ideaalab/rf_library

Gracias por la ayuda!
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Desconectado remi04

  • PIC24F
  • *****
  • Mensajes: 657
Re:Me ayudais a optimizar el calculo de un duty cycle?
« Respuesta #1 en: 26 de Julio de 2021, 18:00:57 »
Puedes atacar a la relación y no al %.

  Como tú ya sabes que puede venir un 25%, un 75% o un 3,125 (3% a efectos prácticos para evitar un float) pues sabes que sus relaciónes  son:
 
 100 / 25 = 4
 100 / 75 = 1,33  (1 para un entero)
 100 / 3 =  33,33 (33 para un entero).

  Lo que tienes que hacer es dividir el tiempo total del pulso completo entre el tiempo del primer cambio de estado, y te tiene que dar 4 o 1 o 33. No hay más.

  Al quedarte solo con la parte entera de la división, se truncan los decimales y eso ya te va a auto proporcionar tu rango de tolerancia.

  Para el caso del 75%, te va a dar 1 a partir del 51% hasta el 100% de dutty.
  Para el caso del 25% te va a dar 4 a partir de 21% hasta el propio 25%. Si te pasas de 25% ya te empieza a dar 3
  Para el caso del 3% te va a dar 33.

  En los if entonces preguntas de mayor a menor o al revés y tomas como opcion por defecto la del otro extremo, así ahorras un else if.

 Por ejemplo, 

 Barriendo de mayor a menor:

  Inicialmente asumo que el dutty es un 3%, es decir, que la relación da más de 20 (por el margen y esas cosas), por lo tanto pongo a 1 la bandera de SYNC.

  Ahora pregunto,

   - if (¿El resultado es menor que 6?) 

   SI: Modifico la asignación inicial, a partir de ahora asumo que el dutty es el 25%. Pongo a cero bandera de sync y pongo a 0 la bandera del estado logico representado.


   - if ( ¿El resultado es menor que 2?)

  SI: Modifico la asignación que tenga y a partir de ahora asumo que el dutty es el 75%.

  Bandera sync a cero, bandera de estado lógico representado a 1.

  Más o menos sería la idea.
 
   
« Última modificación: 27 de Julio de 2021, 05:48:23 por remi04 »

Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1835
    • IDEAA
Re:Me ayudais a optimizar el calculo de un duty cycle?
« Respuesta #2 en: 27 de Julio de 2021, 06:02:39 »
Gracias remi por tu respuesta!
Creo que la tolerancia al error es muy alta en el caso de 75% ya que desde 51% hasta 100%  se considera lo mismo. Tengo que acotar mas.
En el caso de 25% la tolerancia es baja y no admitiria pulsos de 26% por ejemplo.
Tampoco puedo aceptar que lo que no sea una de los anteriores se considere como 3%. Ya que un pulso de 45% de duty lo consideraria como 3%
Los receptores RF estan recibiendo ruido todo el tiempo, por lo que tengo que ser mas especifico, sino cualquier ruido siempre se consideraria como una señal valida.
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.

Conectado Eduardo2

  • PIC24F
  • *****
  • Mensajes: 965
Re:Me ayudais a optimizar el calculo de un duty cycle?
« Respuesta #3 en: 27 de Julio de 2021, 10:23:55 »
Mirando el daasheet del PT2264 y googleando un poco encuentro:
 

* PT2264.jpg
(48.92 kB, 640x475 - visto 201 veces)

 

* PT2264_2.jpg
(30.43 kB, 640x184 - visto 223 veces)


y un ejemplo de recepción:
 

* ejemplo.jpg
(130.25 kB, 1245x593 - visto 202 veces)


entiendo que lo recibido es:  ffff ffff 0010 'Sync'


De acuerdo a esto, calcular los dutys en cada pulso es un extremo de refinamiento,  bastaría comparar si la duración de cada pulso es mayor o menor que un umbral (8*alfa en la gráfica) para ver si es 0 o 1  y para validar comparar si los 4 datos del CODEFRAME son iguales.




Desconectado Marttyn

  • Colaborador
  • PIC24H
  • *****
  • Mensajes: 1835
    • IDEAA
Re:Me ayudais a optimizar el calculo de un duty cycle?
« Respuesta #4 en: 02 de Agosto de 2021, 14:16:46 »
Esta libreria la hice hace unos cuantos años. Y desde entonces he vendido varios productos que hacen la decodificacion calculando el duty y demas como explique al principio... En total se han vendido varios miles de productos que funcionan perfectamente!
Pocos años despues habia hecho algunas pruebas con algo mas simple como lo que habeis propuesto, pero no estaba demasiado convencido.
Ahora entre el osciloscopio, el analizador logico y vuestras ideas lo simplifique a algo tan basico como:
Código: [Seleccionar]
short DataFrameComplete(void){ //check received pulse, return TRUE if data frame is complete
int32 syncMax = TotalDuration >> 4; //duty tiene que ser menor que el tiempo total / 16
int32 dutyLowMax = TotalDuration >> 1; //duty tiene que ser menor que el tiempo total / 2

if(TotalDuration > MIN_PULSE){ //check if pulse is long enough, to avoid noise

/* PULSO SYNC */
if(HighDuration < syncMax){
if(CountedBits == BUFFER_SIZE){ //data frame complete?
CountedBits = 0; //restart counted bits
rfBuffer.Bytes.Nul = 0;
return(TRUE); //data frame complete, returns TRUE
}

CountedBits = 0; //restart counted bits
}
else{
/* PULSO CERO */
if(HighDuration < dutyLowMax){
shift_right(&rfBuffer,3,0); //shift in received bit

if(CountedBits < BUFFER_SIZE) //no more than BUFFER_SIZE
++CountedBits; //adds one
}
/* PULSO UNO */
else{
shift_right(&rfBuffer,3,1); //shift in received bit

if(CountedBits < BUFFER_SIZE) //no more than BUFFER_SIZE
++CountedBits; //adds one
}
}
}
else{
CountedBits = 0; //noise
}

return(FALSE); //incomplete data frame, returns FALSE

Optimizo todos los calculos a tan solo unos "shift". Primero compruebo que el pulso tiene al menos una duracion determinada, que es la minima aceptable segun el datasheet, y asi evito ruido.

La funcion antes ocupaba 230 ROM. Ahora ocupa 96 ROM.
Solo me queda hacer pruebas intensivas para ver si se puede colar ruido como una señal valida. Pero en cualquier caso, como esa señal se tiene que comparar con un valor previamente almacenado, es altamente improbable que se active de forma espuria.
La gente ve las cosas que existen y se pregunta por qué.
Yo prefiero imaginar lo que no existe y preguntarme por qué no.


 

anything