Autor Tema: Medidor avanzado LCR ( se puede hacer??)  (Leído 13652 veces)

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

Desconectado splasma2

  • PIC16
  • ***
  • Mensajes: 131
Re: Medidor avanzado LCR ( se puede hacer??)
« Respuesta #30 en: 25 de Junio de 2012, 07:59:37 »

Citar

Luego puedes restar la fase con cálculos.



Si, eso pensaba hacer con un proceso inicial de calibrado,  pero queria ver si me podia evitar ese "apaño", dejando la salida del DAC sin filtrar. En todos los esquemas que he encontrado relacionados con esto siempre aparecen filtros de 2 orden o más, supongo que es importante tener una señal limpia para conseguir exactitud en la medida, yo ire a minimos:  una RC y a ver que pasa.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Medidor avanzado LCR ( se puede hacer??)
« Respuesta #31 en: 25 de Junio de 2012, 13:00:24 »
Ten en cuenta que para una señal de 1KHz con 32 pasos, el ruido comienza en 32KHz y tiene una amplitud de 1.5% de la onda principal.

Saludos.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Medidor avanzado LCR ( se puede hacer??)
« Respuesta #32 en: 12 de Julio de 2012, 09:41:34 »
Empiezo a conseguir los primeros resultados.
La función seno y coseno para multiplicar no debe tener componente continua (sumando todos los valores del ciclo debe resultar cero). En caso contrario los cálculos dan problemas.

La señal de entrada puede tener componente continua porque desaparece con los cálculos. Lo que no se es si merece la pena disminuir la continua lo máximo posible para mejorar la precisión.


Saludos.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Medidor avanzado LCR ( se puede hacer??)
« Respuesta #33 en: 04 de Diciembre de 2012, 18:02:03 »
Tengo un esquema funcionando que puede medir impedancias (Z) con una resolución de 1 miliohmio y un rango de 2 ohmios.

Cambiando la ganancia del amplificador de instrumentación, puede medir rangos de resistencias más altas y capacidades más bajas.

Adjunto esquema con el que estoy trabajando




Saludos
« Última modificación: 04 de Diciembre de 2012, 18:19:10 por Picuino »

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Medidor avanzado LCR ( se puede hacer??)
« Respuesta #34 en: 04 de Diciembre de 2012, 18:17:36 »
Adjunto programa con el que estoy trabajando.
Con el PIC18F2550 a 48Mhz no he tenido problemas de velocidad.
Se puede multiplicar la lectura del ADC por el valor del seno y por el valor del coseno con 4 instrucciones de multiplicación de tipo byte muy rápidas (4 ciclos de reloj cada una).


Código: [Seleccionar]
/****************************************************************************
    LOCK-IN DIGITAL AMPLIFIER
    IMPEDANCE METER


    License:
    ========
    Creative Commons Reconocimiento-CompartirIgual 3.0 España License.
    Work title: Picuino C Library
    Attribute work to name: Picuino
    Attribute work to URL: https://sites.google.com/site/picuino

    THIS SOFTWARE IS PROVIDED IN AN “AS IS” CONDITION. NO WARRANTIES,
    WHETHER EXPRESS, IMPLIED OR STATUTORY, INCLUDING, BUT NOT LIMITED
    TO, IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A
    PARTICULAR PURPOSE APPLY TO THIS SOFTWARE. NOBODY SHALL,
    IN ANY CIRCUMSTANCES, BE LIABLE FOR SPECIAL, INCIDENTAL OR
    CONSEQUENTIAL DAMAGES, FOR ANY REASON WHATSOEVER.

 ****************************************************************************/


/****************************************************************************
      GLOBAL INCLUDE AND DEFINITIONS
 ****************************************************************************/
#include <p18cxxx.h>
#include <stdio.h>
#include <math.h>

#include "rs232.h"
#include "configuration.h"

static unsigned char isr_ticks, isr_go, phi;

/*
  Seno(x) adaptado a un byte para la multiplicación
  sen[n] = int(127.5 + 127*sen(n*2*pi/32))
  Promedio = 127
*/
#define DC     127
#define seno_0   0
#define seno_1  25
#define seno_2  49
#define seno_3  71
#define seno_4  90
#define seno_5 106
#define seno_6 117
#define seno_7 125
#define seno_8 127
const unsigned char seno[] = {
   DC + seno_0, DC + seno_1, DC + seno_2, DC + seno_3, DC + seno_4, DC + seno_5, DC + seno_6, DC + seno_7,
   DC + seno_8, DC + seno_7, DC + seno_6, DC + seno_5, DC + seno_4, DC + seno_3, DC + seno_2, DC + seno_1,     
   DC - seno_0, DC - seno_1, DC - seno_2, DC - seno_3, DC - seno_4, DC - seno_5, DC - seno_6, DC - seno_7,
   DC - seno_8, DC - seno_7, DC - seno_6, DC - seno_5, DC - seno_4, DC - seno_3, DC - seno_2, DC - seno_1,
};

const unsigned char coseno[] = {
   DC + seno_8, DC + seno_7, DC + seno_6, DC + seno_5, DC + seno_4, DC + seno_3, DC + seno_2, DC + seno_1,     
   DC - seno_0, DC - seno_1, DC - seno_2, DC - seno_3, DC - seno_4, DC - seno_5, DC - seno_6, DC - seno_7,
   DC - seno_8, DC - seno_7, DC - seno_6, DC - seno_5, DC - seno_4, DC - seno_3, DC - seno_2, DC - seno_1,
   DC + seno_0, DC + seno_1, DC + seno_2, DC + seno_3, DC + seno_4, DC + seno_5, DC + seno_6, DC + seno_7,
};


// sen[n] para producir una tensión de salida en el puerto B Conversor R-2R de 6 bits
// 0 - 63
const unsigned char seno_port[] =
/* {
   104, 124, 144, 160, 176, 192, 200, 208,
   208, 208, 200, 192, 176, 160, 144, 124,
   104,  84,  64,  48,  32,  16,   8,   0,
     0,   0,   8,  16,  32,  48,  64,  84,
}; */
{
   124, 148, 172, 192, 212, 228, 240, 244,
   248, 244, 240, 228, 212, 192, 172, 148,
   124, 100,  76,  56,  36,  20,   8,   4,
     0,   4,   8,  20,  36,  56,  76, 100,
};

/****************************************************************************
      INTERRUPT SERVICE ROUTINE
 ****************************************************************************/

#pragma interrupt isr_low_main
void isr_low_main(void) {
   // Timer2 interrupt counter
   if (PIR1bits.TMR2IF == 1) {
      PIR1bits.TMR2IF = 0;
      if (--isr_ticks==0) {
         isr_ticks = 3;
         isr_go = 1;

         // Compute next output signal
         phi++;
         phi &= 0x1F;
         PORTB = seno_port[phi];         

         // ADC Hold and Start Analog-Digital conversion
         ADCON0bits.GO = 1;
      }
   }
}

#pragma code high_vector=0x08
void isr_high(void) {
   _asm GOTO isr_low_main  _endasm
}

#pragma code low_vector=0x18
void isr_low(void) {
   _asm GOTO isr_low_main  _endasm
}


/****************************************************************************
      PROGRAM FUNCTIONS
 ****************************************************************************/

#pragma code

/*
   Timer 2 configure and reset
*/
void timer2_init(void) {
   TMR2 = 0;
   T2CON = (unsigned char)
          (0<<3)    // postscaler
                    // 0 = 1:1 postscaler
                    // 1 = 1:2 postscaler
                    // 15 = 1:16 postscaler
         +(1<<2)    // TMR2ON: 1 = Timer2 is on
         +(0b00);   // T2CKPS: Timer2 Clock Prescale Select bits
                    // 1x = 1:16 Prescaler value
                    // 01 = 1:4 Prescaler value
                    // 00 = 1:1 Prescaler value
   PR2 = 124;       // PWM Period = [(PR2) + 1] • TCY •(TMR2 Prescale Value)]
   PIR1bits.TMR2IF = 0;
   PIE1bits.TMR2IE = 1;
   IPR1bits.TMR2IP = 0;
}


/*
   Init ADC
   Select input pin to sample and hold circuit
*/
void adc_init(unsigned char channel) {
   // Configure ADC
   ADCON0 = 0b00000001 + (channel<<2);   // ADC on. Select channel
   ADCON1 = 0b00000000;   // Analog inputs
   ADCON2 = (unsigned char)
          (1<<7)    // ADFM: 0 = Result Left justified
         +(2<<3)    // ACQT2: A/D Acquisition Time
                    // 7 = 20 Tad
                    // 6 = 16 Tad
                    // 5 = 12 Tad
                    // 4 = 8 Tad
                    // 3 = 6 Tad
                    // 2 = 4 Tad
                    // 1 = 2 Tad
                    // 0 = 0 Tad
         +(6);      // ADCS2: A/D Conversion Clock
                    // 7 = Frc
                    // 6 = Fosc/64
                    // 5 = Fosc/16
                    // 4 = Fosc/4
                    // 3 = Frc
                    // 2 = Fosc/32
                    // 1 = Fosc/8
                    // 0 = Fosc/2

}


/* Print float number with sign */
void print_float(static float num) {
   if (num<0)
      printf ("-%lu\t", (long)-num);
   else
      printf ("%lu\t", (long)num);
}

/* Compute modulo of a vector */
float modulo(static float x, static float y) {
   return sqrt(x*x + y*y);
}


/* Compute angle of a vector */
float angle(static float x, static float y) {
   if (x == 0) {
      if (y > 0) return  3.141592654/2.0;
      else       return -3.141592654/2.0;
   }
   return atan(y/x);
}


/****************************************************************************
      MAIN PROGRAM
 ****************************************************************************/

void main(void) {
   static float Vz_re, Vz_im, Vz_mod, Vz_phi;
   static float Vr_re, Vr_im, Vr_mod, Vr_phi;
   static float Z_re, Z_im, Z_mod, Z_phi;
   static unsigned char sen, cos;
   static unsigned int counter, samples;
   static long seno_mul_sum, seno_mul_sum2;
   static long coseno_mul_sum, coseno_mul_sum2;
   static long vin_sum;
   static union {
      unsigned int word;
      struct {
          unsigned char lob;
          unsigned char hib;
      };
   } mul, vin;

   // Peripheral config
   TRISB = 0b00000011;     // Digital to Analog output
   TRISA = 0b11111111;
   rs232_init();
   adc_init(ANALOG_RA0_CHANNEL);
   timer2_init();

   // Interrupt config
   RCONbits.IPEN = 0;
   INTCONbits.GIE = 1;
   INTCONbits.PEIE = 1;

   rs232_puts("System OK\n");

   samples = 32*1024;

   // Main loop
   while(1) {
      counter = samples;
      seno_mul_sum = seno_mul_sum2 = 0;
      coseno_mul_sum = coseno_mul_sum2 = 0;
      vin_sum = 0;

      TRISCbits.TRISC0 = 0;

      // wait first step and read ADC
      while(phi!=0);
      while(ADCON0bits.GO == 1);
      vin.lob = ADRESL;
      vin.hib = ADRESH;

      // Compute 32*1024 samples
      do {

         // wait next step
         isr_go = 0;
         while(isr_go==0);

         // Compute sen, cos and Increment pointers
         sen = seno[phi];
         cos = coseno[phi];

         // Lock-in detector
         vin_sum += vin.word;

         // Compute Vin * sen
         mul.lob = vin.lob * sen;
         mul.hib = PRODH;
         seno_mul_sum += (unsigned long)mul.word;

         mul.lob = vin.hib * sen;
         mul.hib = PRODH;
         seno_mul_sum2 += (unsigned long)mul.word;

         // Compute Vin * cos
         mul.lob = vin.lob * cos;
         mul.hib = PRODH;
         coseno_mul_sum += (unsigned long)mul.word;

         mul.lob = vin.hib * cos;
         mul.hib = PRODH;
         coseno_mul_sum2 += (unsigned long)mul.word;

         // Read Analog-Digital conversion
         while(ADCON0bits.GO == 1);
         vin.lob = ADRESL;
         vin.hib = ADRESH;

      } while(--counter);

      // Add low mul and high mul
      seno_mul_sum += seno_mul_sum2<<8;
      coseno_mul_sum += coseno_mul_sum2<<8;
   
      // Compute X,Y components without DC
      Vz_re = seno_mul_sum - (vin_sum*127);
      Vz_im = coseno_mul_sum - (vin_sum*127);
 
      // print results
      printf ("\r\n");
      #define VZ_CORRECTION    0.99099*0.9875
      Vz_re *= VZ_CORRECTION*2.0*5.0/(1024.0*127.0*32.0*1024.0*1.41421);
      Vz_im *= VZ_CORRECTION*2.0*5.0/(1024.0*127.0*32.0*1024.0*1.41421);   
      Vz_phi = angle(Vz_re, Vz_im)-(16.780*3.1415927/180.0);
      Vz_mod = modulo(Vz_re, Vz_im);
      Vz_re = Vz_mod * sin(Vz_phi+1.570796327);
      Vz_im = Vz_mod * sin(Vz_phi);
      //printf ("Vz_re=\t");   print_float(Vz_re*10000.0);
      //printf ("Vz_im=\t");   print_float(Vz_im*10000.0);
      printf ("Vz_mod=\t");  print_float(Vz_mod*1000.0);
      printf ("Vz_phi=\t");  print_float(Vz_phi*(1000.0*180.0/3.1415927));

      Vr_re = 0.8002 - Vz_re;
      Vr_im = 0.0000 - Vz_im;
      Vr_mod = modulo(Vr_re, Vr_im);
      Vr_phi = angle(Vr_re, Vr_im);
      printf ("Vr_mod=\t");  print_float(Vr_mod*1000.0);
      printf ("Vr_phi=\t");  print_float(Vr_phi*(1000.0*180.0/3.1415927));

      Z_mod = 990.0 * Vz_mod / Vr_mod;
      Z_phi = Vz_phi - Vr_phi;
      Z_re = Z_mod * sin(Z_phi+1.570796327);
      Z_im = Z_mod * sin(Z_phi);

      //printf ("Z_mod=\t");   print_float(Z_mod*10.0);
      //printf ("Z_phi=\t");   print_float(Z_phi*(100.0*180.0/3.1415927));
      printf ("R=\t");       print_float(Z_re*10.0);
      printf ("Zc=\t");      print_float(Z_im*10.0);
     
      Z_im = 1000000000.0/(6283.1853*Z_im);
      printf ("C[nF]=\t");      print_float(Z_im);

   }
}

Saludos.

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Medidor avanzado LCR ( se puede hacer??)
« Respuesta #35 en: 04 de Diciembre de 2012, 19:00:46 »
Los amplificadores operacionales y de instrumentación utilizados son de Microchip.
Tienen una tensión de alimentación de 5V con entradas y salidas Rail to Rail, que significa que pueden ir desde cero a 5 voltios.
Funcionan bastante bien, son baratos (gratuitos en caso de pedirles como samples) y no necesitan utilizar una fuente de alimentación simétrica.

Amplificador de instrumentación MCP6N11: http://ww1.microchip.com/downloads/en/DeviceDoc/25073A.pdf

Amplificadores operacionales MCP6L92: http://ww1.microchip.com/downloads/en/DeviceDoc/22141b.pdf


Saludos.

Desconectado splasma2

  • PIC16
  • ***
  • Mensajes: 131
Re: Medidor avanzado LCR ( se puede hacer??)
« Respuesta #36 en: 14 de Diciembre de 2012, 12:02:58 »
Estupendo trabajo Picuino, yo lo deje abandonado....  :oops: pero veo que tú lo conseguiste.

Una duda, las resitencias son de precisión (1%) o no influyen en la medida ???

Saludos,

Repito, magnifico resultado. ;-)


Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Medidor avanzado LCR ( se puede hacer??)
« Respuesta #37 en: 15 de Diciembre de 2012, 20:07:56 »
Todavía no lo he conseguido.
Estoy esperando poder pedir más samples de Microchip para completar el circuito.
Por las pruebas que he realizado hasta ahora, si he comprobado que se puede hacer.

Cuando tenga más avances los postearé. La herramienta me parece increíble.

Con este aparato puedes medir resistencias desde un miliohmio hasta cientos de megaohmios, puedes medir la resistencia en serie de condensadores, la resistencia serie equivalente de una pila, inductancias, capacidades.
Parece el medidor perfecto de impedancias. Por ahora tengo la intención de seguir con ello hasta que lo consiga.


Saludos.
« Última modificación: 15 de Diciembre de 2012, 20:16:23 por Picuino »

Desconectado Picuino

  • Moderadores
  • DsPIC33
  • *****
  • Mensajes: 5883
    • Picuino
Re: Medidor avanzado LCR ( se puede hacer??)
« Respuesta #38 en: 15 de Diciembre de 2012, 20:13:41 »
Una duda, las resitencias son de precisión (1%) o no influyen en la medida ???

No estoy utilizando resistencias de precisión, pero en el aparato final si que se tendrán que utilizar.

El valor de la resistencia R1 no es muy importante porque hay que calibrar el instrumento y cualquier desviación se puede corregir. El problema es que R1 varíe con la temperatura o con el tiempo, porque el aparato necesitaría continuamente calibración. Por eso se deben utilizar resistencias muy precisas (0.1% en el caso del circuito de Elektor)

En mi caso, utilizaré resistencias smd del 1%  (me conformo con esa exactitud)

Saludos.

Desconectado sirias52

  • PIC10
  • *
  • Mensajes: 40
Re: Medidor avanzado LCR ( se puede hacer??)
« Respuesta #39 en: 19 de Diciembre de 2012, 03:42:35 »
Siguiendo el Hilo, muy interesante Picuino y te felicito por no dejar atras este interesante proyecto.


 

anything