Cálculo de capacitor de filtrado de señal para voltimetro

#1
Hola gente!

Hace un tiempo que estoy trabajando en un circuito que tuve que abandonar en la etapa de prueba por la facultad pero ahora lo estoy intentando retomar.
El circuito consta de tomar la tension que se encuentra en la bateria de un auto al conectarle un amplificador ya sea para combos de subwoofer o 6x9".

Lo hice funcionar con un arduino nano cuyo ADC es de 10 bits y básicamente el programa lee varios valores de tensión (que provienen de un divisor de tensión) en un tiempo determinado (100 mS) y hace un promedio de todos esos valores. En la prueba con tensiones estables con una fuente dc, el programa y el circuito en general funcionan muy bien, entregan los valores deseados y la cantidad de promedios resulta ser buena.

El problema surge (como esperaba desde el principio) en que al tener una batería de Níquel sea demasiado lenta como para responder a bajos profundos o consumos grandes por tiempos cortos y para poder entregar la potencia deseada la batería baja su tensión. Ahí es donde comienzan las complicaciones.

Las soluciones que encuentro disponibles son:
1) Conectar un capacitor en la entrada de tensión del amplificador para entregar grandes corrientes por tiempos cortos. Esto no es muy factible ya que se ponen generalmente capacitores de 1F cada 1000W y el amplificador a medir es de 500W y el costo es elevado.

2) Baterias de litio: Son caras y no son necesarias para el caso que describo.

3) Colocar un capacitor en paralelo al divisor resistivo para tener una tension "estable" entre sus bornes.

La ultima opcion es por la que vengo a pedir ayuda...

Colocar un valor elevado (como veo que hacen algunos en sus proyectos para generalizar con 4700uF) puede ser perjudicial porque tendría que esperar su descarga para medir un valor estable realmente.
Si coloco un valor muy pequeño no llegaria a eliminar esa variacion de tension, obteniendo el mismo problema del principio...

Por lo cual... Saben de alguna formula o forma de calcular un capacitor ideal para estas situaciones con el fin de no generalizar valores?

Muchas gracias!! espero sus respuestas.
 
#2
Creo que estas mezclando dos cosas distintas, y contradictorio, no quieres los bajones de la bateria y en tonces que es exactamentelo que deses medir
 
#3
Pandacba, gracias por responder.

Tenes razon, fue un poco confuso.

La bateria entrega una tension que suele bajar unos voltios cuando hay un bajo en el audio. Pero al tener una duracion muy corta no lo quiero promediar ya que me bajaria el valor general del promedio.

Mi idea es con esos valores saber que porcentaje de bateria tengo en el auto y para eso me baso en los valores promediados de tension para saber cuanta carga tengo comparandolos con valores fijos por programa. Al conectarlo como lo tengo ahora casi que no puedo leer un valor sin muchas variaciones, la tension varia entre 12.4v y 11.3v, por eso pensaba en un valor de capacitor que por ese tiempo corto sostenga el valor de tension con el que venia anteriormente para no promediar mal.
 
#4
Si taponas la señal que quieres medir, ya no la mides.
Haz la media por software, y de paso tendrás mas datos estadísticos como la duración de los huecos etc..
Yo rectificaba por sofware la mediada de una conversor AD que medía la corriente a 230V 50Hz.
El software es gratis y no ocupa. Como lo normal es que te sobre tiempo de máquina para aburrir, lo ocupas en esto.
 

Dr. Zoidberg

Well-known-Papá Pitufo
#5
Al conectarlo como lo tengo ahora casi que no puedo leer un valor sin muchas variaciones, la tension varia entre 12.4v y 11.3v, por eso pensaba en un valor de capacitor que por ese tiempo corto sostenga el valor de tension con el que venia anteriormente para no promediar mal.
Podés hacer un promedio pesando las muestras por la cantidad de tiempo "que duran", pero si duran tan poco como decís no sé que influencia tan grande puedan tener en el promedio...
Digo, si tenés 98 muestras en 12.4 y dos 11.3 el promedio es 12.378V
 
#6
Hola dr. Zoidberg y scooter, gracias por responder.

Si! Por programa hago promedios cada 10mS durante 100mS y eso lo tomo como un valor, luego vuelvo a promediar y actualizo ese valor.
El problema es cuando dentro de esos 100ms leo por ejemplo 12.5v ocho veces y 11.4v dos veces, el promedio es bastante bajo, por eso pense en eliminar esos dos valores de 11.4v con un capacitor.

Esta noche llego a mi casa y adjunto la subrutina que hice para realizar estos promedios.
Pensaba en conectar un osciloscopio en el borne positivo de alimentacion, pero no voy a lograr ver esas variaciones. Lo pense como algo cercano a sacar el factor de ripple de un rectificador, ya que estaria haciendo algo bastante parecido.

Puede ser que si scooter ya hizo esta clase de codigos pueda recomendarme algo tambien cuando suba el codigo
 
#7
Pensemos lo que queremos, y lo que tenemos. Tu quieres medir la tensión de batería, la cual, sacando esos bajones por los "graves" de duración muy corta, en general la tensión de batería se va a mantener mas o menos estable y la caída de tensión de la misma va a ser muy lenta comparada con las caídas producto de los bajos, por lo cual el colocar un capacitor en el divisor tensión no es tan errada a la solución, ya que las grandes variaciones no las va a tener en cuenta, funcionando así como un promediador. Comienza a probar con valores bajos de capacitores y empieza a aumentar hasta obtener el resultado que quieres.
 
#8
El problema de los filtros es su tiempo de establecimiento; si filtras poco seguirá viendo los 11,4 o en su lugar verás 11,42
Si filtras mucho tarda tiempo en establecerse el valor y si la batería empieza a fallar tardas tiempo en averiguar que ha fallado, ocupan bastante y según el caso lo mismo necesitas un circuito auxiliar para la primera carga o te da que está la batería conectada cuando hace tiempo que la desconectaste.

Por software un filtro sencillo es minimizar la última lectura; de ese modo la última lectura no influye casi pero puedes facilmente ajuistar la "intensidad" del filtrado
En plan
media = media * 0,9 + lectura *0.1
o
media = (media *9 + lectura )/10
Así la última lectura pesa un décimo y promedia con las nueve anteriores.
Al arrancar el sistema haces que la lectura inicial sea el promedio anterior o que un valor guardado "de batería buena" sea el promedio
Puedes probar a un décimo, o al número que te venga bien.

También puedes borrar las lecturas que se salgan en un tanto por ciento de la media y no sumarlas de forma que solo afecten las variaciones lentas de la batería y no afecten las puntuales.
Algo así como:
if (lectura >= media - media *0,15) {
media = (media *9 + lectura )/10;
}
 
Última edición:
#9
Hola, viendo lo que requieres es simple. No es necesario añadir ningún condensador o el hardware que sea.
Si quieres tener un valor estable de la batería, pues entonces debes tomar todas las muestras que quieras. Pero si alguna de ellas es menor o mayor que el 10%(ejem), del valor del promedio, se descarta.
 
#10
Pensemos lo que queremos, y lo que tenemos. Tu quieres medir la tensión de batería, la cual, sacando esos bajones por los "graves" de duración muy corta, en general la tensión de batería se va a mantener mas o menos estable y la caída de tensión de la misma va a ser muy lenta comparada con las caídas producto de los bajos, por lo cual el colocar un capacitor en el divisor tensión no es tan errada a la solución, ya que las grandes variaciones no las va a tener en cuenta, funcionando así como un promediador. Comienza a probar con valores bajos de capacitores y empieza a aumentar hasta obtener el resultado que quieres.
Hola juanma2468, gracias por responder.
Exacto, queria basarme en esa idea de evitar las variaciones, pero al comenzar a probar con valores bajos e ir aumentando la capacidad perderia mucha precision, por eso recurri aca a ver si alguno tenia alguna forma exacta de saber que tengo a la salida con un valor fijo de tension


El problema de los filtros es su tiempo de establecimiento; si filtras poco seguirá viendo los 11,4 o en su lugar verás 11,42
Si filtras mucho tarda tiempo en establecerse el valor y si la batería empieza a fallar tardas tiempo en averiguar que ha fallado, ocupan bastante y según el caso lo mismo necesitas un circuito auxiliar para la primera carga o te da que está la batería conectada cuando hace tiempo que la desconectaste.

Por software un filtro sencillo es minimizar la última lectura; de ese modo la última lectura no influye casi pero puedes facilmente ajuistar la "intensidad" del filtrado
En plan
media = media * 0,9 + lectura *0.1
o
media = (media *9 + lectura )/10
Así la última lectura pesa un décimo y promedia con las nueve anteriores.
Al arrancar el sistema haces que la lectura inicial sea el promedio anterior o que un valor guardado "de batería buena" sea el promedio
Puedes probar a un décimo, o al número que te venga bien.

También puedes borrar las lecturas que se salgan en un tanto por ciento de la media y no sumarlas de forma que solo afecten las variaciones lentas de la batería y no afecten las puntuales.
Algo así como:
if (lectura >= media - media *0,15) {
media = (media *9 + lectura )/10;
}
Scooter, es verdad, puede ser que agregar mas filtros hagan que el sistema pase a ser muy lento, el comentario me hizo pensar tambien en las perdidas de los cables a corrientes altas. Adjunto mi codigo al final, pero voy a intentar adaptar lo que dijiste, es buena la idea de pensar en descartar las mediciones.

Hola, viendo lo que requieres es simple. No es necesario añadir ningún condensador o el hardware que sea.
Si quieres tener un valor estable de la batería, pues entonces debes tomar todas las muestras que quieras. Pero si alguna de ellas es menor o mayor que el 10%(ejem), del valor del promedio, se descarta.
Hola Guidino Roberto duberlin, gracias por responder.

El unico problema que le veo a tu solucion es la cantidad de mediciones que hago. Cuando estaba en etapas de pruebas intente tomando el doble de mediciones (sin descartar ninguna) y el sistema se volvia totalmente lento e inexacto. Voy a probar como dije antes descartando valores y probando la velocidad del sistema.

Adjunto la funcion que hice para hacer el promedio de mediciones:

C:
float tension1()
{
       int i, j, k;
      
       float Ten1, Ten2, cont, Tension;
       float Prom1 [Num1];

       Ten1 = 0;
       Ten2 = 0;
       i = 0;
       j = 0;
       k = 0;
       cont = 0;
      
       for (k=0; k<=Num1; k++)
       {
        Prom1 [k] = 0;
       }

       for (i=0; i<=Num1; i++)
       {
        Prom1 [i] = (((analogRead(4) * 4.98)/ 1024)/ Req);

        delay (10);
       }

       for (j=0; j<=Num1; j++)
       {
        Ten1 = Ten1 + Prom1 [j];
        cont = cont + 1;
       }
      
        Ten2 = Ten1 / cont;
        
        return Ten2;
}
 
#11
El unico problema que le veo a tu solucion es la cantidad de mediciones que hago. Cuando estaba en etapas de pruebas intente tomando el doble de mediciones (sin descartar ninguna) y el sistema se volvia totalmente lento e inexacto. Voy a probar como dije antes descartando valores y probando la velocidad del sistema.
El problema está en que no trabajas con interrupciones del timer, sino que usas la instruccion delay(10) en la medición de tensión que lo unico que hace es frenarte tu programa sin poder hacer nada más, eso es nefasto para este tipo de cosas. Si usaras las interrupciones podrias hacer incluso hasta 100 muestras por segundo y aun asi no lo notarias en tu display. El software está bien, pero hay cosas para pulir y agregar en función de lo que Guidino Roberto te comento. Unas mejoras serían estas:
C:
float tension1()
{
       int i, Contador = 0;
       float TensionPromedio,TensionInstantanea,Tension = 0;

       if (TensionPromedio != 0) // Para cuando recien se inicia, el promedio es cero
       {
           for (i=0; i<=Num1; i++)
           {
               TensionInstantanea = (((analogRead(4) * 4.98)/ 1024)/ Req);
               if ((TensionPromedio*0,9<TensionInstantanea)&(TensionPromedio*1,1>TensionInstantanea)) // Descarto los valores que se apartan un 10% por arriba y por abajo del valor promedio
               {
                  Tension = Tension + TensionInstantanea;
                  Contador++;
               }
               else
                  Contador--; // Si descarto un valor, tengo que bajar en uno la variable contador para que el promedio de bien
               delay (10);
           }
       }
       else
       {
           for (i=0; i<=Num1; i++)
           {
            Tension = Tension + (((analogRead(4) * 4.98)/ 1024)/ Req); // Para obtener el primer promedio de tension
            delay (10);
           }
           Contador = Num1;
       }
       TensionPromedio = Tension / Contador;
   
       return TensionPromedio;
}
 
Última edición:
#12
Cada vez que usáis un delay Dios mata a un gatito.

Por otro lado la rutina de lectura de las entradas analógicas es una castaña porque tarda una salvajada. Un conversor AD por aproximaciones sucesivas suele tardar el número de ciclos que sean los bits del conversor, así que 10uS sería si el reloj va a 1MHz más o menos. No sé por qué diablos tarda diez veces más.

Me autocontesto. Se puede aumentar la frecuencia de muestreo hay que buscar en el foro de arduino.
 
Última edición:
#14
El problema está en que no trabajas con interrupciones del timer, sino que usas la instruccion delay(10) en la medición de tensión que lo unico que hace es frenarte tu programa sin poder hacer nada más, eso es nefasto para este tipo de cosas. Si usaras las interrupciones podrias hacer incluso hasta 100 muestras por segundo y aun asi no lo notarias en tu display. El software está bien, pero hay cosas para pulir y agregar en función de lo que Guidino Roberto te comento. Unas mejoras serían estas:
C:
float tension1()
{
       int i, Contador = 0;
       float TensionPromedio,TensionInstantanea,Tension = 0;

       if (TensionPromedio != 0) // Para cuando recien se inicia, el promedio es cero
       {
           for (i=0; i<=Num1; i++)
           {
               TensionInstantanea = (((analogRead(4) * 4.98)/ 1024)/ Req);
               if ((TensionPromedio*0,9<TensionInstantanea)&(TensionPromedio*1,1>TensionInstantanea)) // Descarto los valores que se apartan un 10% por arriba y por abajo del valor promedio
               {
                  Tension = Tension + TensionInstantanea;
                  Contador++;
               }
               else
                  Contador--; // Si descarto un valor, tengo que bajar en uno la variable contador para que el promedio de bien
               delay (10);
           }
       }
       else
       {
           for (i=0; i<=Num1; i++)
           {
            Tension = Tension + (((analogRead(4) * 4.98)/ 1024)/ Req); // Para obtener el primer promedio de tension
            delay (10);
           }
           Contador = Num1;
       }
       TensionPromedio = Tension / Contador;
  
       return TensionPromedio;
}

Perfecto juanma, dame unos dias para probarlo como enuncias en tu codigo y te comento los resultados! Muchas gracias!!

Cada vez que usáis un delay Dios mata a un gatito.

Por otro lado la rutina de lectura de las entradas analógicas es una castaña porque tarda una salvajada. Un conversor AD por aproximaciones sucesivas suele tardar el número de ciclos que sean los bits del conversor, así que 10uS sería si el reloj va a 1MHz más o menos. No sé por qué diablos tarda diez veces más.

Me autocontesto. Se puede aumentar la frecuencia de muestreo hay que buscar en el foro de arduino.

Jajajajajaja no sabia que era tan grave usar delays. El metodo que me recomiendan empezar a aplicar por el resto de mi vida es interrupciones por timer como decia juanma? en caso de que no... Cual es el metodo que usan?? Asi no me retan mas jajaja.

Mi idea era probarlo con un arduino nano pero despues pasarlo a un pcb que incluya adaptador de tension de alimentacion y cableado solamente con un Atmega 328p smd y un cristal de 16MHz como usa el arduino, asi que en caso de tener que adaptar algun componente externo para realizar mas mediciones no habria problema.

Le veo muchos buenos resultados a hacer mas mediciones y descartar mediciones no deseadas. Tiene mas sentido que poner capacitores para arreglar todo jajaja.

Gracias!
 

Dr. Zoidberg

Well-known-Papá Pitufo
#15
Jajajajajaja no sabia que era tan grave usar delays. El metodo que me recomiendan empezar a aplicar por el resto de mi vida es interrupciones por timer como decia juanma? en caso de que no... Cual es el metodo que usan?? Asi no me retan mas jajaja.
Eso depende de vos. Tenes que aprender a discernir entre cuando un "delay" es inocuo y cuando te destruye la operación del software. Para esto no hay recetas pre-cocidas, pero en general hay que preferir el uso de interrupciones cuando hay varios periféricos operando concurrentemente. Ahora, si vas a hacer un juego de luces para un kiosco.... bue...podés usar delays sin demasiado problema, pero si hay teclados y displays la historia cambia.
 
#16
Cada vez que usáis un delay Dios mata a un gatito.
Que fue eso????
No te gusta ver un delay, y criticas a quienes lo usan pero no he visto un solo post tuyo que enseñe a quienes no saben a como no hacerlo, si vas a criticar esta primero a enseñar y si no estas dispuesto a enseñar no critiques porque ese tipo de critica no contruye nada de nada y no le sirve a nadie tampoco
 
#17
Que fue eso????
No te gusta ver un delay, y criticas a quienes lo usan pero no he visto un solo post tuyo que enseñe a quienes no saben a como no hacerlo, si vas a criticar esta primero a enseñar y si no estas dispuesto a enseñar no critiques porque ese tipo de critica no contruye nada de nada y no le sirve a nadie tampoco
Era una broma. Si a alguien ofendí le pido disculpas.

En ese caso en concreto no se que sentido tiene un delay(10) detras de una lectura de un pin analógico que equivale a un delay(100). ¿Es mejor que tarde 110ms que que tarde 100?
De hecho acto seguido comento que he visto la solución para minimizar el tiempo que tarda el conversor AD del arduino que es desaforadamente leeeento.
Aparte de mi conocido "odio" a los delays, ya que prefiero usar timers, no entiendo por qué en muchos códigos veo delays que no sé que sentido tienen, me da la sensación de que en muchos casos (por no decir en todos) están por estar. Y me sorprende mucho que en parte de esos casos se hace uso de una CPU especialmente rápida para acto seguido sebrar todo el código de delays.


@tinchoball Mira la librería flexitimer que permite aplicar temporizaciones sin "asesinar" la CPU


Edito, me he equivocado: No son 100ms lo que tarda el conversor del arduino, son 100us que de todos modos son muchos 20us o así debería de ser suficientes.
Como opcion al delay 10 propongo leer cien veces el pin analógico y hacer la media, así se hace algo útil en lugar de fundir ciclos de máquina.
O leer el teclado, o actualizar el LCD o mirar si hay datos en el buffer del puerto serie o actualizar el RTC o... seguro que hay dos o tres mil cosas potencialmente útiles.
 
Última edición:
#18
Hola gente!
Disculpen la demora en responder pero nuevamente me atacaron los parciales jajaja.

Estuve leyendo bastante información sobre los timers en arduino y la verdad tienen mucha mas ventaja que los delays... Las habia leído varias veces pero no considere que eran tan necesarias hasta que investigue sobre el tema y... si lo son... jajajaj

En este caso no vi que haga falta contaminar el tema mostrando el 100% de la utilidad que le quiero dar a mi proyecto, ya que seria resolver un problema puntual de un proyecto en vez de dar una forma de medición buena, aplicable en muchos proyectos mas, pero en este caso creo que es necesario.

Al terminar de hacer esas mediciones, envió por bluetooth esos datos de tensión a una aplicación en mi celular. Junto con este valor de tensión calculo en que rango de valores cae el promedio y entrego una letra a mi aplicación para hacer unos cambios en la misma.

Por lo que leí hasta ahora supongo que no habría problema de enviarlos por bluetooth ya que entre medio de las interrupciones timer habría tiempo para enviar todo y calcular.

Adjunto el codigo completo porque estoy mas que seguro que podran ayudarme aplicando las interrupciones que ahora me intriga infinitamente usar.

C:
#include <SoftwareSerial.h>

SoftwareSerial BTest (10,11);

float R1 = 10000;
float R2 = 3300;
int Num1 = 10;
float Prom1 [10];
float tension1();
float Req = R2/(R1+R2);
char alerta;
int a = 0;
float Prom2 [5];
int j = 0;
float valalerta = 0;

void setup()
{ 
  BTest.begin(9600);
}

void loop()
{
        float tensionf = tension1();

        Prom2[j] = tensionf;
        
        j = j + 1;

        if (j == 4)
        {
          for (int h; h<=5; h++)
          {
             valalerta = valalerta + Prom2[h];
          }
             valalerta = valalerta / 5;

          for (int w; w<=5; w++)
          {
            Prom2[w]= 0;
          }
         j = 0;
        }
        
        if (valalerta < 12)
        {
          a = a + 1;
        }
            else
            {
              a = 0;
            }

        if (a==1)
        {
          alerta = 'A';
          valalerta = 0;
        }
            else
            {
               alerta = 'B';
            }

        if(tensionf < 10)
        {
          BTest.print(0);
        }
      
        BTest.print(tensionf);
        BTest.print('L');
        BTest.print(alerta);
        
        delay(100);
}


float tension1()
{
       int i, j, k;
      
       float Ten1, Ten2, cont, Tension;
       float Prom1 [Num1];

       Ten1 = 0;
       Ten2 = 0;
       i = 0;
       j = 0;
       k = 0;
       cont = 0;
      
       for (k=0; k<=Num1; k++)
       {
        Prom1 [k] = 0;
       }

       for (i=0; i<=Num1; i++)
       {
        Prom1 [i] = (((analogRead(4) * 4.98)/ 1024)/ Req);

        delay (10);
       }

       for (j=0; j<=Num1; j++)
       {
        Ten1 = Ten1 + Prom1 [j];
        cont = cont + 1;
       }
      
        Ten2 = Ten1 / cont;
        
        return Ten2;
}
Todavia no aplique sobre este codigo lo que me propuso juanma2468, dependiendo de lo que me propongan ahora lo pruebo.

Eviten retarme demasiado jajaja, gracias por responder!
 
#19
No se para que incluyes la librería sofware serial. Usa la uart hardware e intenta usar lo menos posible por soft, tiene muchísimas "contraindicaciones"

Me resulta demasiado grande ese código para lo poco que hace
Para hacer una media "continua" basta con ponderar la suma:
media = media * 0.9 + nueva_lectura*0,1
Así arrastras la media "desde siempre" con una operación sencilla y no la borras cada vez.
Si diez te parece poco lo ponderas a mas medidas,

El código sería algo así como

loop{
media = (media*9 + lectura)/10;
if media > valor todo ok
if media < valor alarma
print media en el dislay o en el puerto serie...
}

Si 10 te parecen pocos
media = (media *999 + lectura)/1000

La pega de esto es que tarda mucho al arrancar en llegar a un valor estable (1000 lecturas) así que en el setup le pones el valor nominal o le pones lo que tenga de lectura la batería.

si quieres hacer eso por interrupciones de tiempo, defines con flexitimer el plazo y le cuelgas ese código
 
#20
Scooter, no se a que te referis con la uart hardware, no la escuche nunca en arduino y la busque pero tampoco encontre. podrias explicarte un poco mas??

En el caso que me mostraste:

loop{
media = (media*9 + lectura)/10;
if media > valor todo ok
if media < valor alarma
print media en el dislay o en el puerto serie...
}
Como limito la cantidad de lecturas que hago antes de enviarlas? antes yo usaba un for y cada una cantidad de mediciones mandaba ese valor, pero ahora tendria infinitas mediciones y mandaria todo el tiempo o no?

Lo de interrupciones lo voy a seguir investigando, ya que estamos quiero aprender a usarlas bien en este proyecto, sino es demasiado simple todo jajaja.

gracias por responder
 
Última edición:
Arriba