Autor Tema: Calibración de frecuencímetros a distancia aprovechando la frecuencia de red.  (Leído 4209 veces)

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

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Voy a proponer un método curioso para que dos foreros que se encuentren alejados puedan comparar y calibrar entre ellos una base de tiempos con precisión mejor de 1ppm.

La base del método consiste en que todas las personas que quieran calibrar sus bases de tiempos deben estar en el mismo sistema eléctrico. Por ejemplo valdría para dos españoles peninsulares o para dos argentinos pero no para un español y un argentino ni para un argentino y un cubano.
También serían incompatibles entre si los sistemas insulares (como Canarias, Balerares, Cuba, etc) que al estar aislados no tienen conexión eléctrica con el resto de territorios.
Por su parte los sistemas interconectados también son compatibles Argentina-Uruguay, España-Francia, etc.

El fundamento técnico está basado en las variaciones de la frecuencia de red eléctrica. La frecuencia de la red eléctrica es la misma para todos los usuarios de un mismo sistema eléctrico y todos ellos comparten las variaciones de frecuencia y los desfases que sufre la onda senoidal de la red eléctrica de un pais.

Los pasos para calibrar un oscilador son los siguientes:

1.- Un "maestro" debe tener una base de tiempos estable y con una gran precisión. Por ejemplo un oscilador OCXO de 10Mhz y error de 0.1ppm.
     Los "seguidores" tienen una base de tiempos estable y precisa pero que no está calibrada. Por ejemplo osciladores TCXO controlados por tensión 0-5V.

2.- Todos ellos deben tener un circuito de medición de la frecuencia de la red con desfase acumulado.
    ver el post en el que lo he publicado: Medición de la frecuencia de red eléctrica

3.- A cierta hora concreta todos se ponen de acuerdo y miden el desfase de frecuencia de la red eléctrica durante un periodo de una hora.

4.- A continuación el "maestro" publica los datos de desfase con el tiempo:
Tiempo   Pulsos   Frecuencia   Error de tiempo
0,994087   100   100,594817   -5,913
1,994324   200   100,284588   -5,676
2,994631   300   100,179281   -5,369
3,994962   400   100,126114   -5,038
4,995292   500   100,094253   -4,708
5,995661   600   100,072362   -4,339
6,996055   700   100,056386   -3,945
7,996403   800   100,044988   -3,597
8,996738   900   100,036260   -3,262
9,997173   1000   100,028276   -2,827
10,997678   1100   100,021110   -2,322
11,998153   1200   100,015392   -1,847
12,998564   1300   100,011050   -1,436
13,998979   1400   100,007296   -1,021
14,999398   1500   100,004011   -0,602
15,999775   1600   100,001406   -0,225
17,000091   1700   99,999467   0,091
18,000327   1800   99,998181   0,327
19,000529   1900   99,997215   0,529
20,000706   2000   99,996468   0,706
21,000850   2100   99,995952   0,850
22,000893   2200   99,995940   0,893
23,000904   2300   99,996069   0,904
24,000921   2400   99,996162   0,921
25,000913   2500   99,996349   0,913
26,000793   2600   99,996951   0,793
27,000608   2700   99,997748   0,608
28,000438   2800   99,998435   0,438
29,000301   2900   99,998962   0,301
30,000143   3000   99,999525   0,143
30,999977   3100   100,000075   -0,023
31,999839   3200   100,000503   -0,161
...
...




5.- Los "seguidores" tendrán una gráfica o serie de datos igual que la del maestro, con las mismas crestas y los mismos valles, pero con una inclinación hacia arriba o hacia abajo diferente. Esta "deriva" de la gráfica y los datos indican que sus bases de tiempo adelantan o atrasan.  El tiempo que adelantan o atrasan las bases de tiempo de los seguidores se puede calcular por la diferencia de tiempo entre las dos gráficas dividido por el tiempo total de muestreo.

6.- Una vez conocido el error de las bases de tiempo "seguidoras" se puede corregir compensando en la misma cantidad que el error medido.


El método se debe pulir y podría utilizar un programa a través de internet para automatizar todo el proceso.
Esto permitiría calibrar instrumentos en tiempo real a distancia y con precisión.

Saludos.
« Última modificación: 03 de Mayo de 2012, 19:36:50 por Picuino »

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Archivo de Excel para realizar los cálculos (incorpora la macro que transforma hexadecimal a decimal):


Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Programa para PIC18F2550 para medir frecuencia y desfases:

Código: C
  1. /****************************************************************************
  2. Precision Frequency counter
  3.  
  4. Processor:  PIC 18F2550
  5. Input Pin:  RC2 / CPP1
  6.  
  7. Base frequency:
  8.    Timer1 counting Fosc/4
  9.  
  10. Count mode:
  11.   Capture Timer1 count at CPP1 falling edge
  12.   Send both values in hexadecimal by UART
  13.  
  14. ****************************************************************************/
  15.  
  16. #include <p18cxxx.h>
  17. #include <stdlib.h>
  18. #include <stdio.h>
  19. #include <delays.h>
  20. #include "main.h"
  21.  
  22. /****************************************************************************
  23.      GLOBAL VARS AND DEFINITIONS
  24. ****************************************************************************/
  25. #pragma udata
  26. char str_buf[20];
  27. static unsigned char sys_clk, cent_second;
  28. static unsigned short timer1_carry;  // Timer1 extended counter
  29.  
  30. // Timer1 long counter (48 bits)
  31. union {
  32.   struct {
  33.      unsigned int _word;
  34.      unsigned long dword;
  35.   };
  36.   unsigned int  word[3];
  37.   unsigned char byte[6];
  38. } timer1_count, timer1_capture;
  39.  
  40.  
  41. #define TMR0_COUNT      (FOSC/((unsigned long)4*250*100))      // Number of carrys per second
  42. #define FOSC 20000000    // clock oscillator
  43. #define BAUD 57600       // usart baud speed
  44.  
  45.  
  46. /****************************************************************************
  47.      INTERRUPT SERVICE ROUTINE
  48. ****************************************************************************/
  49.  
  50. #pragma interrupt isr_main
  51. void isr_main(void) {
  52.  
  53.   // Timer1 interrupt counter
  54.   if (PIR1bits.TMR1IF == 1) {
  55.       PIR1bits.TMR1IF = 0;
  56.       timer1_count.dword++;
  57.   }
  58. }
  59.  
  60.  
  61. #pragma code high_vector=0x08
  62. void isr_high(void) {
  63.   _asm GOTO isr_main  _endasm
  64. }
  65.  
  66. #pragma code
  67.  
  68.  
  69. /****************************************************************************
  70.      USART AND RS232 FUNCTIONS
  71. ****************************************************************************/
  72.  
  73. /*
  74.  Initialize USART for RS232 comunications
  75. */
  76.  
  77. void rs232_init(void) {
  78.   BAUDCONbits.BRG16 = 0;             // BRG16: 16-Bit Baud Rate Register Enable bit
  79.   SPBRGH = 0;
  80.   SPBRG = (FOSC/(16*BAUD))-1;   // Real Baud = FOSC/(16*(SPBRG+1))
  81.  
  82.   TXSTA = (char)
  83.           (0<<7)    // CSRC:  1 = Syncronous Master mode
  84.         + (0<<6)    // TX9:   1 = Selects 9-bit transmission
  85.         + (1<<5)    // TXEN:  1 = Transmit enabled
  86.         + (0<<4)    // SYNC:  1 = Synchronous mode
  87.         + (0<<3)    // SENDB: 1 = Asynchronous mode: Send Sync Break on next transmission (cleared by hardware upon completion)
  88.         + (1<<2)    // BRGH:  1 = Asynchronous mode: High speed
  89.         + (1<<1)    // TRMT:  1 = TSR empty
  90.         + (0<<0);   // TX9D:  Ninth bit of Transmit Data
  91.  
  92.   RCSTA = (char)
  93.           (1<<7)    // SPEN:  1 = Serial port enabled
  94.         + (0<<6)    // RX9:   1 = Selects 9-bit reception
  95.         + (0<<5)    // SREN:  1 = Enables single receive in Master Synchronous mode
  96.         + (1<<4)    // CREN:  1 = Enables Continuous Receive
  97.         + (0<<3)    // ADDEN: 1 = Enables address detection (RX9 = 1)
  98.         + (0<<2)    // FERR:  1 = Framing error
  99.         + (0<<1)    // OERR:  1 = Overrun error (can be cleared by clearing bit CREN)
  100.         + (0<<0);   // RX9D:  Ninth bit of Received Data
  101.  
  102.   TRISCbits.TRISC6 = 0;      // Enable TX output
  103.   PIE1bits.TXIE = 0;         // Disable RS232 interrupts
  104.   PIR1bits.TXIF = 0;
  105.   //TXREG = 0;
  106. }
  107.  
  108.  
  109. /*
  110.   Puts rom buffer to usart
  111. */
  112. void rs232_puts(char const rom *str) {
  113.   while(*str) {
  114.      if (*str == '\n')
  115.         rs232_putc('\r');
  116.      rs232_putc(*str);
  117.      str++;
  118.   }
  119. }
  120.  
  121. /*
  122.   Send char to USART with pooling
  123. */
  124. void rs232_putc(char c) {
  125.   while (PIR1bits.TXIF == 0);
  126.   TXREG = c;
  127. }
  128.  
  129.  
  130. /*
  131.   Return Hexadecimal character of a nibble
  132. */
  133. char Hexdec(char nibble) {
  134.   char bin2hex[] = "0123456789ABCDEF";
  135.   return bin2hex[nibble & 0x0F];
  136. }
  137.  
  138.  
  139. /****************************************************************************
  140.      CAPTURE MODE
  141.      Timer1 counts time
  142.      Input by CCP1
  143. ****************************************************************************/
  144.  
  145. void capture_init(void) {
  146.   T1CON = (unsigned char)
  147.       (1<<7)    // RD16: 1 = 16-Bit Read/Write Mode Enable bit
  148.      +(0<<6)    // T1RUN: 1 = Device clock is derived from Timer1 oscillator
  149.      +(0b00<<4) // T1CKPS: Timer1 Input Clock Prescale Select bits
  150.                 // 11 = 1:8 Prescale value
  151.               // 10 = 1:4 Prescale value
  152.                 // 01 = 1:2 Prescale value
  153.                 // 00 = 1:1 Prescale value
  154.      +(0<<3)    // T1OSCEN: 0 = Timer1 oscillator is shut off
  155.      +(1<<2)    // T1SYNC: 1 = Do not synchronize external clock input
  156.      +(0<<1)    // TMR1CS: 1 = External clock from RC0 pin, 0 = Internal clock (FOSC/4)
  157.      +(1<<0);   // TMR1ON: 1 = Enables Timer1
  158.  
  159.   // Reset Timer1 counters
  160.   TMR1H = 0;
  161.   TMR1L = 0;
  162.   timer1_count.word[0] = 0;
  163.   timer1_count.word[1] = 0;
  164.   timer1_count.word[2] = 0;
  165.  
  166.   // Reset Timer1 interrupts
  167.   PIR1bits.TMR1IF = 0;
  168.   PIE1bits.TMR1IE = 1;
  169.   INTCONbits.GIE = 1;  
  170.   INTCONbits.PEIE = 1;
  171.  
  172.  
  173.   // CCP1 config
  174.   TRISCbits.TRISC2 = 1;  // CPP1 input
  175.   CCP1CON = 0b00000100;  // Capture every falling edge. Prescaler = 1
  176.   CCPR1H = 0;
  177.   CCPR1L = 0;
  178.   PIR1bits.CCP1IF = 0;
  179.   PIE1bits.CCP1IE = 0;
  180.  
  181.   T3CONbits.T3CCP1 = 0; // Timer1 is the capture clock source for both CCP modules.
  182.   T3CONbits.T3CCP1 = 0;
  183. }
  184.  
  185.  
  186. void capture_read(void) {
  187.   // Wait for falling edge
  188.   while (PIR1bits.CCP1IF == 0);
  189.   PIR1bits.CCP1IF = 0;
  190.  
  191.   // Read timer1
  192.   timer1_capture.byte[0] = CCPR1L;
  193.   timer1_capture.byte[1] = CCPR1H;
  194.  
  195.   // Read timer1 overflow counter
  196.   timer1_capture.dword = timer1_count.dword;
  197.   timer1_count.byte[0] = TMR1L;
  198.   timer1_count.byte[1] = TMR1H;
  199.   if (timer1_count.word[0] < timer1_capture.word[0]) {
  200.      timer1_capture.dword = timer1_count.dword-1;
  201.   }
  202. }
  203.  
  204.  
  205. /****************************************************************************
  206.      MAIN PROGRAM
  207. ****************************************************************************/
  208. #pragma code
  209.  
  210. #define PPB_ERROR  (2900)
  211.  
  212. /*
  213.   MAIN ROUTINE
  214. */
  215. void main(void) {
  216.   int i;
  217.   union {
  218.       unsigned char byte[4];
  219.       unsigned long dword;
  220.   } pulses;
  221.  
  222.   // Initialize subsystems
  223.   rs232_init();
  224.   capture_init();
  225.   pulses.dword = 0;
  226.  
  227.  
  228.   // Pulse and time counter
  229.   while(1) {
  230.  
  231.      // Wait 100 pulses
  232.      for(i=100; i>0; i--) {
  233.         capture_read();
  234.         pulses.dword++;
  235.      }
  236.  
  237.      // Print Time count by Timer1
  238.      rs232_puts("t=\t");
  239.      //rs232_putc(Hexdec(timer1_capture.byte[5]<<4));
  240.      //rs232_putc(Hexdec(timer1_capture.byte[5]));
  241.      rs232_putc(Hexdec(timer1_capture.byte[4]>>4));
  242.      rs232_putc(Hexdec(timer1_capture.byte[4]));
  243.      rs232_putc(Hexdec(timer1_capture.byte[3]>>4));
  244.      rs232_putc(Hexdec(timer1_capture.byte[3]));
  245.      rs232_putc(Hexdec(timer1_capture.byte[2]>>4));
  246.      rs232_putc(Hexdec(timer1_capture.byte[2]));
  247.      rs232_putc(Hexdec(timer1_capture.byte[1]>>4));
  248.      rs232_putc(Hexdec(timer1_capture.byte[1]));
  249.      rs232_putc(Hexdec(timer1_capture.byte[0]>>4));
  250.      rs232_putc(Hexdec(timer1_capture.byte[0]));
  251.      rs232_puts("\t*200ns\t");
  252.  
  253.      // Print falling edges counted
  254.      rs232_puts("N=\t");
  255.      rs232_putc(Hexdec(pulses.byte[2]>>4));
  256.      rs232_putc(Hexdec(pulses.byte[2]));
  257.      rs232_putc(Hexdec(pulses.byte[1]>>4));
  258.      rs232_putc(Hexdec(pulses.byte[1]));
  259.      rs232_putc(Hexdec(pulses.byte[0]>>4));
  260.      rs232_putc(Hexdec(pulses.byte[0]));
  261.      rs232_puts("\n");
  262.   }
  263. }

Saludos.
« Última modificación: 03 de Mayo de 2012, 18:23:25 por Picuino »

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5892
    • Picuino
Circuito detector de cruce por cero:



Página original:
http://www.dextrel.net/diyzerocrosser.htm

El circuito anterior tiene el peligro de estar conectado directamente a la red eléctrica.
Para evitar este inconveniente se puede modificar cambiando R1 = R2 = 22K y conectar los extremos a un transformador de 12v.
Con esta modificación se evita el peligro de manejar directamente la tensión de red y el riesgo que conlleva.


Saludos.
« Última modificación: 03 de Mayo de 2012, 19:49:21 por Picuino »


 

anything