Matematica Interpolacion sen(x) / x o similares (osciloscopio)

Bueno, pues para hacer una prueba con datos reales, he cogido los primeros 60 puntos de tu fichero testdata, y los he decimado por un factor de 5 (es como si hubieras generado una onda de 20kHz*5=100kHz.

En la gráfica represento los samples en rojo, sus uniones mediante rectas en verde:

Para la primera función de splines, corresponde a la curva azul (interpolada a 25 puntos por segmento aunque el aspecto sería prácticamente el mismo si fueran 100 puntos):

Caso real-splines.png

Para la función de splines nueva, corresponde a la curva negra, igual que antes, interpolada a 25 puntos por segmento:

Caso real-splines 2.png

Como ves, la mejora con respecto a la función antigua y a la unión por rectas es sustancial, sobre todo al ampliar mucho la forma de onda en la pantalla.
 
Última edición:
Excelente! me estas brindando mucho mas de lo que esperaba y lo agradezco de verdad. Actualmente le deje el codigo de la funcion splines implementado al programa. Esta noche cuando me ponga con mis ediciones nuevamente voy a aplicar lo que aqui me describis.

Como comentario: Por alguna razon, estimo que electrica, el primer dato de las series de samples para cada canal tiene un valor con mas "salto" que el resto de los samples, se me hace que es alguna inestabilidad en el momento que el trigger se dispara.

Dicho esto, en la muestra de samples que adjunte antes ese dato existe (porque grabo raw data como viene por usb) y por eso en tu curva ves la primera parte como mas "recta" pero en el programa del osciloscopio, descarto unas 3-4 primeras muestras (no recuerdo el numero pero si que descarto)
 
Bueno, me he tomado un tiempo de leer el resto del material que me han dado y por esos enlaces encontre un PDF que me aclaro algunos otros conceptos. http://www2.dis.ulpgc.es/~lalvarez/...nsparenciasTema7_InterpolacionFunciones_2.pdf

Intente aplicar lo que me especifico Eduardo sobre la funcion sinc

mathtex.cgi


Sin embargo se me escapan algunos conceptos. Veo claramente que es
(sen(valor) / valor) * valordeunsample. Todo esto en sumatoria de los 10 samples (o calculos) anteriores y 10 posteriores

Lo que se me escapa creo es que no sabria que es ω. Entiendo que multiplica al valor de "tiempo" - la constante de entrada K (supongo los -10+10) * 1, siendo 1 si realizara una interpolacion de 1 elemento (intervalo entre muestreos? o te referis a tiempo?)

En fin, entonces aplique la 2da version de la funcion de palurdo con los siguientes resultados.

Señal de 20khz generando 16 puntos cada 2 samples, uniendolos solo con segmentos (linea de sample 1 a 2, o sea, este caso no genera puntos sino que saltea 16 pixels y dibuja linea entre ellos)

20khz-interpolar-segmentos16.png

Lo siguiente es la nueva funcion de palurdo con Y2

20khz-interpolar-splines16.png

Como se puede ver, hay un error al inicio del grafico. Sobre este error, estoy casi 100% seguro que se debe a que por alguna razon que aun no encontre, los primeros datos del vector de puntos estan incorrectos (tal vez este tomando en el canal B amarillo al inicio, los ultimos datos del canal A)

Entonces, implemente un descarte de los primeros 10 datos haciendo que el vector en X sea X+10 y completando el vector (por cuestiones de programacion y limite de array) con ceros antes de pasarlo a la funcion de interpolacion.

El resultado es este:

20khz-interpolar-splines16-descarte10.png

Como ven, va perfecto, solamente que al final, como tengo un cambio brusco a 0 (que no es real) la funcion tira cualquier cosa.

Me toca averiguar porque razon tengo ese inicio de grafica raro. Tal vez sea que no estoy parando la captura en el lugar que yo creo (tiempos de pic) o que estoy contando mal algun dato en los vectores del programa. De hecho, en la primera imagen donde no hay matematica sino simple union de puntos, se nota claramente que hay un dato del canal amarillo que no esta bien al inicio.

Tambien me resulta curioso que no haya demasiada diferencia visual entre unir con segmentos y calcular realmente los puntos. Sin embargo en las graficas que pone aqui palurdo se nota claramente la diferencia. Es posible que la diferencia se empiece a notar en señales de mayor amplitud, donde los saltos de Y entre un sample y otro son mayores.
 
Tambien me resulta curioso que no haya demasiada diferencia visual entre unir con segmentos y calcular realmente los puntos. Sin embargo en las graficas que pone aqui palurdo se nota claramente la diferencia. Es posible que la diferencia se empiece a notar en señales de mayor amplitud, donde los saltos de Y entre un sample y otro son mayores.

En realidad se empieza a notar en señales de mayor frecuencia. Cuando la distancia de los puntos es corta (hay muchos puntos para dibujar una onda), las inclinaciones de las rectas de los puntos contiguos es bastante parecida, por lo que dos rectas que se unen con una ligera inclinación, parecen una curva. Es por eso por lo que te dije que para señales de baja frecuencia con muchos samples simplemente uniendo con rectas es suficiente (Yo te diría que para una senoidal de 60 puntos no hay mucha diferencia entre unir con rectas y unir interpolando), ya que la inclinación de la curva en el punto 1 (por decir un punto cualquiera de la muestra) es muy similar a la del punto 2, por lo que la recta es una buena aproximación.

El problema es cuando tienes pocos puntos por periodo de señal, entonces la inclinación entre un punto y otro de la gráfica es muy alta y es cuando el margen de error de unir con rectas se puede apreciar bastante. Uno de los casos extremos es el que te presenté cuando la onda tiene sólo 6 puntos (en el caso de frecuencias cercanas a nyquist, un periodo de onda sólo tiene un par de puntos). En ese caso unir con rectas no da una idea de la onda senoidal, sin embargo interpolando puedes ampliar todo lo que quieras la onda, ya que seguirá pareciendo senoidal.

Es por eso por lo que decimé tus datos por 5, para simular una onda senoidal de 100kHz, o lo que era lo mismo, de 12 samples por periodo. Si hubiera dejado la onda original (los 60 samples) habría obtenido el mismo resultado que tu, una onda muy similar interpolando y uniendo con rectas, ya que con 60 puntos por periodo senoidal las dos aproximaciones son buenas.

Haz la prueba, en lugar de dibujar todos los samples, de dibujar sólo 1 de cada 10 samples en pantalla y unirlos con rectas (a 2X dibuja el sample 0 en posición 0, el 10 en posición 20, el 20 en 40...), y después interpla por 10 (o a 2X por 20), y verás el cambio entre una y otra gráfica. En este caso estarías haciendo como si hubieras muestreado una senoidal de 200kHz.



Te voy mostrar un ejemplo:

Dos señales senoidales de duración 28 muestras. La primera de ellas tiene un periodo de 27 muestras, lo que con 28 muestras se dibuja la onda en la pantalla completamente. En la siguiente gráfica dibujo, en la parte de arriba, la onda unida con rectas y en la parte de abajo, la interpolada. Aunque la interpolada es más suave y en la de arriba se notan trozos rectos de segmento, la diferencia más o menos es como en tu gráfica (onda de 60 puntos que al ampliar por 2 es como si tuvieras una onda de 30 puntos).

lineal-vs-bicubic-1.png

Ahora la segunda senoidal. La longitud de la muestra es lo mismo, 28 muestras. La amplitud es la misma, entre -1 y 1. Pero el periodo de la senoidal es un periodo de 5,4 muestras, por lo que cada 27 muestras, cuando en la primera senoidal teníamos una onda en la segunda tenemos 5 ondas.

lineal-vs-bicubic-2.png

La imagen habla por sí misma. Cabe destacar que las variaciones entre los puntos consecutivos son mayores cuanto mayor es la frecuencia de la señal (es decir, menor es el periodo), aunque la amplitud total de la onda sea la misma a una frecuencia o a otra.
 
Última edición:
Bueno, como supongo mi función de interpolación puede ser útil para ser implementada en un procesador de baja potencia, voy a tratar de optimizar la ecuación de interpolación para utilizar aritmética de números enteros (mucho más rápida que la aritmética de punto fijo y punto flotante), así mismo tratar de evitar todas las operaciones de multiplicación y división que sean posibles, a fin de que el algoritmo de evaluación del polinomio interpolador sea eficiente en una CPU o MCU que no tenga implementado por hardware la multiplicación y la división, como podría ser un PIC, por ejemplo.

Para ello, vamos a transformar la expresión matemática, tanto de los coeficientes del polinomio interpolador como la del polinomio en sí, por una expresión equivalente.

En aritmética de enteros, es importante aplazar las operaciones de división a las últimas etapas del cálculo, ya que si se ha de multiplicar dos enteros, la multiplicación siempre será entera, pero si se han de dividir 2 enteros, la división no siempre será entera, y entonces habría que descartar la parte decimal, es decir, introducir un error. Por lo tanto cuanto más temprano se haga una división más error saldrá en el resultado final de la fórmula.

Por otro lado, nos interesa que las divisiones y multiplicaciones sean del tipo 2^u, porque multiplicar un número N por 2^u es desplazar N hacia la izquierda u bits, y dividir N por 2^u, desplazar u bits hacia la derecha (con lo cual no se están haciendo multiplicaciones y divisiones verdaderas sino sólo bit-shift).

Así vamos a definir unos coeficientes alternativos a los A,B,C,D, pero que sean números enteros, a los que llamaré A',B',C' y C':

transformar coeficientes a prima.gif

Ahora iremos a la ecuación original Y=AX^3+BX^2+CX+D. Resulta que tenemos un problema, ya que X tiene que ir desde el rango 0..1, es decir que X son todo decimales, y nosotros buscamos hacer cálculos enteros así que tenemos que transformar nuestras X a algo que podamos usar con aritmética de enteros.

Pongamos que queremos partir un segmento en cuatro segmentos. El primer punto empieza en X=0, el segundo en X=0,25, el tercero X= 0,5 y el cuarto en x=0,75. Pero es que podemos ver que es lo mismo que X[0]=0, X[1]=1/4, X[2]=2/4, X[3]=3/4. En general, si partimos un segmento en un número potencia de 2, como sería 2^n, tendremos que X[0..(2^n)-1]=(0..(2^n)-1)/2^n. Si partimos en 4 trozos, estamos partiendo en 2^2 trozos. Si partimos en 16 trozos, en 2^4 trozos, 64 trozos->2^6, y 256 trozos->2^8.

Hasta aquí queda claro que podemos partir en X[0..1] en 2^n trozos mediante (0..(2^n)-1)/2^n. Entonces la nueva X iría desde 0 hasta 2^n-1, sustituyendo en la ecuación:

Transformar a sólo una división por 2^n.gif

Como se ve, en la última ecuación hemos utilizado la sustitución de los coeficientes por sus primas, de esa manera la única división que aparece en todo el cálculo es el denominador de la fracción, que además es del tipo 2^(3n+1), lo que significa que para dividir el numerador, sólo hay que desplazar hacia la derecha 3n+1 bits. Los bits decimales que resultaran de ahí se descartan ya que no nos interesan ya que si representan pixeles a dibujar en pantalla, no hay pixeles fraccionales.

Otra cosa es que en pantalla se esté haciendo un zoom vertical(pongamos un zoom de 2^p), por lo que en lugar de desplazar hacia la derecha 3n+1 bits, se podrían desplazar simplemente 3n+1-p bits y de nuevo descartar decimales.

Ahora bien, el polinomio de arriba, con las X variando de 1 en 1 desde 0..2^n-1, tiene varias exponenciaciones y multiplicaciones. Los multiplicadores del tipo 2 elevado a algo es trivial simplemente desplazando hacia la izquierda tantos bits como sea ese algo. Ahora, las exponenciaciones hay un método muy bueno para evitarlas y transformarlas en multiplicaciones sencillas:

Evaluación polinómica optimizada.gif

Simplemente agrupando y sacando factores comunes, acabamos por eliminar las potencias de X. La operación es sencilla. Se va guardando en la variable de resultado las operaciones que van desde los parentesis interiores hacia los exteriores hasta que se completa el polinomio.

De de manera que ahora sólo nos hace falta multiplicar por X, pero ¿como lo hacemos en un procesador que no dispone de multiplicación?, no queda más remedio que hacer una multiplicación por software ,pero OJO, lo importante es el rango de las X que nos va a definir cómo de compleja será esa multiplicación, con respecto a las sumas y desplazamientos necesarios.

Vamos a hacer números para saber cuantos bits necesitamos de memoria para cada variable y para el resultado, teniendo en cuenta varias consideraciones:

-El rango de los datos es de 0 a 255 (8 bits).
-Vamos a interpolar como máximo 2^6 puntos entre 2 muestras reales (es decir, sacar 64 puntos entre 2 muestras. Luego en la fórmula el índice de la X recorrerá desde 0 hasta 63 para cada pareja de puntos a interpolar.
-Luego calcularemos lo que necesitamos si decidimos un rango de 2^8 puntos.

Bueno, pues sabiendo esto, y haciendo unos cálculos, tenemos que

max(A')=1020; max(B')=1530;max(C')=255;max(D')=510
min(A')=-1020; min(B')=-1530;min(C')=-255;min(D')=0

Por lo que necestamos 11 bits para A', 12 bits para B', 9 bits para C' y 10 bits para D' (en teoría para D' son 9 bits también, pero consideramos más util poder operar como si min(D') fuera -510.

Por consideraciones prácticas, para cada coeficiente asignamos 2 bytes de memoria (16 bits).

Ahora en la expresión fórmula, para resolver el polinomio numerador, necesitamos saber el tamaño del resultado del numerador. Resulta que el término que domina es A*X^3, ya que X^3 se hace pronto mucho más grande que X^2 y X^1, aunque B sea mayor que A. Sin embargo el hecho de estar multiplicados por 2^(u*n) donde u=0,1,2,3, iguala todos los coeficientes en rango, por lo que habría que hacer la suma de A'+B'+C'+D' máximos y multiplicar por 2^(3n) para saber cuantos bits nos hacen falta. Así necesitamos 13+3n bits. Para el caso de 64 particiones, necesitamos 31 bits en total, que podemos empaquetar en 4 bytes (considerando enteros con signo en complemento a 2). Es decir, tenemos que implementar sumas de 4 bytes (no es muy complicado el código ya que son 4 sumas con arrastre en cascada byte a byte). Para el caso de 256 particiones necesitamos 37 bits, por lo que las sumas serán en paquetes de 5 bytes (40 bits).

Por otro lado, X va a ir desde 0 a (2^n)-1, es decir, que para n=6 cuando se multiplica por n, habría que implementar la multiplicación con 6 sumas y 6 desplazamientos como máximo (si X es 0, son 0 sumas y 0 desplazamientos). Si n es 8 (particiones de 256 interpolaciones), las multiplicaciones serán 8 sumas y 8 desplazamientos.

Es decir, que ahora yendo a la última ecuación, para n=6, se efectuan 3 multiplicaciones por X, 3 desplazamientos de bits, y 3 sumas. Además un desplazamiento hacia la derecha para efectuar la división de 2^(3n+1) que será un desplazamiento de 19 bits, lo que nos deja un resultado final de 31-19=12 bits posibles para el valor de interpolación (11 bits mas el signo, es decir, que la onda podría ir en el peor de los casos hasta el valor 2048 y en el peor a -2048, aunque por lo general se quedará dentro del intervalo 0-255). Pero cada multiplicación como máximo son 6 sumas y 6 desplazamientos, por lo que tenemos en total que para calcular un punto interpolado se necesitan :

6*3+3=21 sumas de 4 bytes y 6*3+3+1=22 desplazamientos. Supongamos que todo el proceso nos ocupa 43*4(bytes por número)=172us en un pic a 4MHz, podríamos calcular aproximadamente unos 5800 puntos interpolados cada segundo (sin contar los cálculos de los coeficientes de los polinomios).

Bueno, espero que estos cálculos les sea útiles a alguien, porque puede venir muy bien para implementar un osciloscopio LCD portátil con un procesador que no sea muy potente.

Un saludo.
 
Palurdo:

En tu primer mensaje se ve claramente la diferencia y es muy considerable. Lo que voy a hacer es ponerme a corregir el programa del micro para poder hacer un descarte efectivo de las primeras muestras. Tengo 910 bytes de memoria por canal de los cuales estoy usando 896 asi que bien puedo descartar, digamos una potencia de 2 al inicio (porque la cantidad de samples "corruptos" parece depender de la escala de tiempo) y usar samples del final, de esos 910 bytes, que no estoy usando. Esto haria que se me corra el trigger algunos uS en el tiempo pero es tolerable ya que de por si la mecanica que uso produce este efecto. El trigger dispara la captura automatica y luego el micro se "da cuenta" que disparo el trigger y temporiza el final de la captura. Hasta que el micro se entero de que el trigger disparo pasan un minimo de 160nS aprox y eso puede estar corrompiendo los datos iniciales.

Sobre el segundo desarrollo, esta muy bueno para implementarlo como decis en osciloscopio portatil. El micro mio corre a 48mhz o sea, 83.33ns por instruccion asi que bien se podria bancar ese algoritmo sin hacerse muy lento, pero disponiendo de la potencia de calculo de la PC, lo dejo para una version portatil con LCD y ADC mas lentos.

cosme: Bienvenido al thread! nos hemos cruzado en varios de estos de osciloscopio asi que se que el tema te interesa. Para responderte, el micro es el PIC18F2550 corriendo a 48mhz, pero el ADC no es el del micro sino un TLC5540 de texas instruments que puede correr hasta 40mhz. Entre el micro y el adc hay una memoria FIFO D42101G. A pesar de que el datasheet de la misma dice que sus ciclos son de 34ns, se banca perfectamente ciclos de 25ns para escritura.

El osciloscopio es de 2 canales duplicando adc y memoria. Bien se podria haber implementado lo mismo con solo 1 conjunto adc-memoria y haciendo un distribuidor de señal para los 2 canales pero como disponia de ellos, use 2 para simplificar. Es automata, es decir, el micro le da la orden al circuito de ponerse en modo captura y cuando la señal de trigger aparece el circuito funciona solo (ahi el micro esta a la espera de fin de captura nada mas). Cuando termina la captura, el micro detiene la secuencia y se pone a leer las 2 memorias por el puerto B, para transferirlas a la PC. En el circuito de captura, hay un mux digital que selecciona la base de tiempos de la siguiente forma:

Oscilador 40mhz -> contador 4040 para hacer division de tiempo -> mux digital para elegir la base de tiempos.

Cuando esto no es suficiente (desde los 320us/DIV para arriba) el micro toma el control y temporiza el mismo la base de tiempos (ahi hubo que contar instrucciones generadas de C a ASM)

Entonces, tengo divisiones en escala de tiempo de: 2.5us, 5us, 10us, 20us, 40us, 80us, 160us, 320us, 500us, 1ms, 2ms, 10ms, etc.etc.

El algoritmo de interpolacion se activa a partir de valores de escala menores a 2.5us, con 1 punto de interpolacion tengo 1.25us/DIV y asi sucesivamente.

En cuanto a la parte analogica, dispongo de selectores AC/DC, divisores 1:1, 1:2, 1:5 y multiplicador 1x5 para los dos canales + 1 trigger externo.

El trigger lo implemente con 2 flip flops integrados en el 74F74. Uno esta asociado al selector de nivel de trigger (que es un DAC hecho con un 4094 y una escalera r2r) y el otro tiene una base de tiempos RC para que dispare automaticamente el trigger si no se produce un evento de trigger real (trigger mode auto, queda desenganchado de la señal)

El flip flop actua sobre la compuerta NAND que habilita el circuito de reloj de captura.

Como reflexion, la parte digital la verdad que se ve compleja pero es sencillisima. Lo que fue un desafio para mi fue la parte analogica. Segun mediciones contrastadas con un osciloscopio comercial DSO-5200A funciono muy bien!

La desventaja del sistema de trigger (precisamente, con el nivel de trigger) es que tengo de 0 a 5volts por lo tanto en escalas de division se me reduce el rango del mismo.
Tambien le voy a implementar un divisor 1:2 en la entrada que se active automaticamente cuando selecciono escalas de mayor vpp que -5+5 (en este momento, si pongo mas de 10vpp en la entrada tengo recorte de señal, logico.)

Otro errorcito de diseño es que hice que la referencia del ADC sea de 5v, lo que me da 256/5v de resolucion. Tendria que haber implementado una referencia de 2v y hacer que la entrada adapte el nivel a fin de tener mejor resolucion vertical.

Por ultimo, los operacionales de entrada son LMH6644 lo que me da un ancho de banda analogico teorico de 130mhz pero ese valor es para señal de salida de 200mvpp. Un dato interesante es que se consiguen muy facilmente y baratos los operacionales LM318 que son de unos 15mhz lo cual es interesante.
 
La verdad es que tu proyecto es muy interesante seaarg. Voy a disfrutar del diseño cuando lo tengas acabado y lo publiques. Una pregunta. Cómo haces para muestrear? me refiero al sistema de Sample&Hold que utilizas. Creo haber leido por ahí que usas un 4066 por algún lado. Qué fin tiene en tu circuito?. Un saludo y espero tus novedades.
 
Gracias!

Me voy a volver loco para pasar los esquematicos jeje mas que nada por la cantidad de lineas de bus de datos entre las 2 memorias hacia el micro. El programa livewire no se si tiene la opcion para hacer un bus.

Adjunto aca lo que seria el nucleo del sistema de captura:

clock.png

Representa conexiones desde el micro y trigger hacia el control de memoria y ADC.

RST = Reset de memoria, tanto escritura como lectura. Recordemos que son memorias FIFO que permiten grabar por un lado y leer por otro a la vez o a distintos tiempos y en vez de tener lineas de direccion, solo tienen un clock de escritura y otro de lectura que hacen que cambie la direccion secuencialmente. Como ven, conecta directamente 1 pin del micro a los reset de lectura y de escritura de las 2 memorias.

SCK = Señal de control con doble funcion: Por un lado, es el clock de lectura cuando transfiero los datos de la memoria hacia el PIC, y por otro lado, es el clock de grabacion para bases de tiempo mayores a 320 us/div cuando el pic es el que controla el tiempo entre muestras. Se observa que esta señal controla el clock del ADC (ADC x CK) y el clock de grabacion de las memorias WCK X (negado con respecto al adc)

Cuando estoy en modo grabacion automatica (base de tiempo de 320us/div hacia abajo) este pin controla la habilitacion o no del sampleo. Es decir, deja de ser un clock para ser un pin de control.

25mhz = Dice 25 porque originalmente usaba un oscilador de 50mhz fijo, pero en realidad esto no es una señal de esa frecuencia, sino que es de 40mhz, 20mhz, 10mhz, 5mhz, 2.5mhz y asi sucesivamente, dependiendo de la base de tiempo seleccionada. Como conte mas arriba, esta señal de reloj esta formada por un oscilador fijo de 80mhz que entra al clock de un contador 74HC4040 y sus salidas desde Q0-Q7 son las distintas frecuencias mencionadas. Estas pasan por un mux digital para seleccionar la que nos interese en la base de tiempos.

FCK EN = Habilitacion o no de la toma de samples automatica (fast clock). Esta señal no viene del micro (originalmente si) sino que viene de un flip-flop del sistema de trigger. Es decir, para hacer una pagina de samples, el micro pone SCK = 1 y habilita el trigger para que dispare la señal FCK EN, dejando pasar la frecuencia de la base de tiempos al ADC y memoria. Transcurrido un tiempo determinado por la base de tiempos, el micro pone SCK = 0 y el control de trigger = 0 para detener la captura.

~WE = No mucho que decir: Habilita la escritura de memoria. Este pin esta constantemente en cero.

RCK = Read clock: Clock de lectura de memoria, se usa solo en transferencia memoria-pic.

~RE = Como veran, uso la ultima nand que me queda en el 74F00 como inversor. Esto es simplemente el selector canal A, canal B para la lectura de la memoria hacia el pic. (En el momento de escritura las memorias se escriben a la vez)

De a poquito voy a ir armando el esquematico completo de todo esto para compartir con todos ustedes. Es sencillo solamente que un poco largo y mis habilidades con los programas de esquematicos son limitadas :) El osciloscopio lo hice mayormente directo en PCB wizard, usando un poco el proteus para simular algunas condiciones. (entrada analogica, trigger,etc pero la parte de captura digital la hice "en la cabeza")

Respondiendo concretamente a tu pregunta, el sample & hold lo hace solo el ADC que mencione mas arriba. Solamente hay que darle un clock y el hace su trabajo.

La llave 4066 no interviene en la captura, sus funciones son:
- Seleccionar o no trigger canal B / Externo (el canal A se selecciona desde un mux que mezcla la fuente de trigger)
- Seleccionar o no el auto-trigger (que es un flip flop que dispara el trigger automaticamente si no viene el disparo normal de trigger desde un operacional usado como comparador)

Les adjunto tambien un zip con los 3 pcb que forman este osciloscopio. No creo que les sirvan de nada sin los esquematicos pero si alguien quiere pegarle una mirada, ahi estan.

Por ultimo: Buenas noticias! Esta tarde implemente un descarte de las primeras 6 muestras y un retraso de algunos nanosegundos (dependientes de la escala de tiempos) antes de detener la captura y ahora las ondas estan perfectas, ya no tengo el salto que habia al inicio o al final de la pagina de samples, por lo tanto, ahora puedo hacer una mejor implementacion de los algoritmos brindados por palurdo sin que esos valores corruptos afecten el polinomio. De hecho, en un par de pruebas pude ver la diferencia entre los segmentos y el algoritmo y si, definitivamente la curva es suave.

Ahora tengo que hacer algunos numeros para resolver lo siguiente:

- Dado el tiempo minimo entre muestras de 25ns, y usando 100 pixels por division, tengo 2.5us / div como base de tiempos minima. Usando el algoritmo de interpolacion, empiezo a bajar esa base de tiempos. Si intercalo solo 1 sample calculado entre 2 reales, tengo 1.25us / div, pero cuando intercalo 3 samples calculados entre 2 reales, tengo 625ns/div y esos numeros no me gustan mucho. Quiero hacer cuentas para ver cuantos samples tengo que intercalar para hacer, digamos, en vez de 625ns/div: 500ns/div, 200ns/div, etc. (numeros mas redondos)

Una pregunta aparte: Como uso 896 samples por canal, a 100 pixels por division en una pantalla cubro 8.96 divisiones. Si yo quisiera hacer que el programa simplemente calcule los pixeles restantes para llegar a 1000 samples (o sea, las 10 divisiones normales de cualquier osci) esta funcion polinomica no me sirve verdad? Supongo que no debido a que necesita 2 samples para calcular los intermedios y cuando X > 895 ya no dispongo de mas samples. Se que podria hacerlo de alguna otra forma pero no lo tengo muy claro. Alguna sugerencia?

Otra: Una vez perfeccionado el soft en la parte de interpolacion, planeo que el mismo me de datos utiles, como ser, una etiqueta que me diga de que frecuencia es la señal. Se me ocurrio que, mientras voy recorriendo los samples, calcular el valor minimo y maximo: Luego, cuando tengo esos datos, contar cuantos samples pasan desde un minimo pasando por un maximo y hasta un minimo de nuevo. Ahi podria calcular la frecuencia. Tendria que poner algo con un error de un cierto % debido a que esos minimos y maximos bien pueden ser picos en la señal y no la señal en si. No me gusta... es muy "fuerza bruta". ¿Hay algo mejor para hacer esto?

Disculpen! me entusiasme escribiendo! :oops:
 

Adjuntos

  • osciloscopio_pcb.zip
    64.4 KB · Visitas: 13
Bueno, mas resultados!

Logre encontrar la causa de los datos iniciales corruptos. Me habia olvidado que el ADC tiene un pipeline de 4 muestras (a pesar de ser flash) por lo que cualquier lectura antes de los 4 clocks debe tomarse como invalida. Entonces, modifique el firmware para hacer algunas lecturas previas que no se envian a la PC.

Solucionado esto, le meti una señal de 20khz en ambos canales pero en una escala lenta de 500us/div.

Esto es lo que se ve:

20khz-500us.png

Entonces, para tener una referencia de como deberia verse la interpolacion, capture una pantalla de la misma señal pero a 40us/div (aclaro: no se va a ver igual porque utilizare interpolacion 16 y no da exactamente 40us/div sino mas abajo, en relacion a 500us/div)

Esta es la señal:

20khz-40us.png

Vuelvo la escala de base de tiempos a 500us/div pero esta vez, aplicando interpolacion 16 simplemente uniendo con 1 segmento entre samples: (salteo 15 pixels)

20khz-500us-interpolacion16-segmentos.png

Y ahora, la interpolacion 16 pero con la funcion polinomica: (fabrico 15 puntos en Y)

20khz-500us-interpolacion16-poly.png

Si comparo con la señal original en 40us/div, como pueden ver esta muy parecida! y las curvas son suavecitas exceptuando al final donde no tengo mas samples entonces la funcion utiliza un cero para Y2. Esta perfecto.

Toca empezar a probar con señales cuadradas a ver que pasa, me fabricare un oscilador con un inversor y un cristal de 4mhz como fuente de señal. Ademas, como dije antes, me queda aun mucha matematica que implementar para que el programa me de los datos relevantes de la señal: Frecuencia, vmin, vmax, vpp, etc. asi como tambien hacer escalas de tiempo un poco mejores, mas redondas. Y luego de tener un soft bastante funcional, toca hacer los esquematicos para compartir por aqui.

Muchisimas gracias! :apreton:
 
- Dado el tiempo minimo entre muestras de 25ns, y usando 100 pixels por division, tengo 2.5us / div como base de tiempos minima. Usando el algoritmo de interpolacion, empiezo a bajar esa base de tiempos. Si intercalo solo 1 sample calculado entre 2 reales, tengo 1.25us / div, pero cuando intercalo 3 samples calculados entre 2 reales, tengo 625ns/div y esos numeros no me gustan mucho. Quiero hacer cuentas para ver cuantos samples tengo que intercalar para hacer, digamos, en vez de 625ns/div: 500ns/div, 200ns/div, etc. (numeros mas redondos)

Bueno, pues este tema es muy interesante que lo propongas, porque gracias a que tienes polinomios interpoladores, puedes poner la base de tiempo arbitraria que necesites. Al tener la onda formada por una combinación de funciones continuas, puedes evaluar cada tramo de la función en el valor que necesites, no necesariamente una partición entera del intervalo original. Pongamos un ejemplo:

Si intecalas 4 samples entre 2 reales, tendrás una base de 500ns/div, ya que creas 5 segmentos por lo que partes un segmento de 2500ns/div entre 5. Esto equivale a ir recorriendo las X en pasos de [0 0,2 0,4 0,6 0,8 1] (los puntos 0 y 1 son reales, el resto son interpolados). Si te has dado cuenta, lo que hacemos es dividir la escala nueva por la escala vieja para obtener el paso necesario para pasar de un punto interpolado al siguiente, es decir, tenemos 500ns/2500ns=0,2. Ahora, si en lugar de 500ns queremos una escala de 1000, pues hacemos lo mismo, 1000ns/2500ns=0,4. Ahora los pasos para dibujar serán [0 0,4 0,8 1,2 1,6 2], donde 0 y 2 son puntos reales y los demás puntos interpolados.

¿Pero qué ha pasado con el punto 1?, pues que al quedarse entre medias no se imprime en pantalla, pero ya se imprimen los valores cercanos los puntos que están alrededor, es decir 0,8 y 1,2, por lo que la onda sigue fielmente representada en pantalla. De todas formas la función de interpolación sólo funciona en el intervalo 0 a 1, por lo que tenemos que partir el cálculo de los puntos interpolados [0,4 0,8 1,2 1,6] en 2 partes: La primera Y0 e Y1 serán el punto 0, y el 1, y los puntos a calcular serán 0,4 y 0,8. Y la segunda Y0 será ahora el punto 1 y Y1 el punto 2, y los puntos a calcular serán 0,2 (1,2-1) y 0,6 (1,6-1). Parece un poco lío, pero de forma algorítmica se resuelve simple y elegántemente con un bucle que vaya dibujando los pixeles en pantalla (o los guarde en un vector de gráfica para luego imprimirlos).

De hecho el incremento de cada paso no tiene por qué ser un valor tan limpio, puede ser cualquier valor real, de manera que podemos hacer una opción para personalizar la base de tiempos a nuestro antojo, por ejemplo si el usuario requiere que la base de tiempo sea de 720ns, pues 720/2500 = 0,288, así la secuencia interpolada será [0 0,288 0,576 0,864 1,152 1,440 1,728 2,016 2,304...] (los cálculos serán de 0,288, 0,576, 0,864 sobre el intervalo 0...1, 0,152, 0,440 0,728, sobre el intervalo 1...2, 0,016, 0,304... sobre el intervalo 2...3 y así hasta completar los pixeles en pantalla.

Así podría definir el algoritmo en pseudo C de la siguiente manera:

Código:
double incremento=escalanueva/escalavieja,j=0,X=0;

for(int i=0;(i<MAX_PIXEL)&&(j<MAX_DATOS);i++) {

  X=trunc(j); //X será la parte entera de J.

  if (X==j) Dibujapunto(i,DATOS[X]); //si j es entero, dibuja Y0 en el punto DATOS[X];

  else {

    Y0=DATOS[X];     //Preparamos los coeficientes para pasarlos a la función
    Y1=DATOS[X+1];   
    Y2=DATOS[X+2];
    Y_1=DATOS[X-1];

    X=j-X; //ahora X es la parte decimal, ya que X debe de ir entre 0 y 1.

    Y_interpolado=splines(Y_1,Y0,Y1,Y2,X); //Evaluamos X en el polinomio interpolado.

    Dibujapunto(i,Y_interpolado);

  }

  j+=incremento;
}

Una pregunta aparte: Como uso 896 samples por canal, a 100 pixels por division en una pantalla cubro 8.96 divisiones. Si yo quisiera hacer que el programa simplemente calcule los pixeles restantes para llegar a 1000 samples (o sea, las 10 divisiones normales de cualquier osci) esta funcion polinomica no me sirve verdad? Supongo que no debido a que necesita 2 samples para calcular los intermedios y cuando X > 895 ya no dispongo de mas samples. Se que podria hacerlo de alguna otra forma pero no lo tengo muy claro. Alguna sugerencia?

Lamentablemente, mientras interpolar da una buena idea de una función si esta no es una función muy irregular (por ejemplo una función fractal no es interpolable ya que es infinitamente discontinua), ya que el objetivo de interpolar es representar una curva suave, el calcular puntos fuera de un intervalo, lo que ya no es interpolar sino extrapolar, no es que sea dificil si no que la señal que obtienes extrapolando no es que no sea real (que lo es, al igual que los puntos interpolados dentro de un intervalo), es que ni siquiera lo parece ya que cuanto más te alejas de los puntos utilizados para calcular el valor irreal, más se desvía dicho valor de algo parecido a la función original. Por ejemplo puedes interpolar sin problemas una senoidal de 100 puntos, pero cuando vas a calcular los 50 puntos siguientes de fuera de la senoidal, te encuentras cualquier cosa menos la senoidal.

Pues sobre ideas, una que no me gusta mucho, y otra que me gusta más. La que no me gusta mucho es suponer que al ser la señal periódica, reproducir una parte del principio a continuación del final. No me gusta esto porque cuando la señal no es periódica estás engañando a quien ve la captura. Por ejemplo, imagina que estamos viendo un tren de bits modulados. Cuando terminara esa zona de pantalla con los datos reales, lo siguiente sería o bien extrapolación o duplicado del principio, lo que confundiría a la hora de analizar los datos, ya que por ejemplo si los datos son 1 0 0 1 0 1 0 0 pero en pantalla solo se han capturado la representación modulada de 1 0 0 1, veríamos esto 1 0 0 1 1 0... lo cual no es la señal original y puede dar muchos dolores de cabeza a quien esté analizándola.

La idea que se me pasa por la cabeza es hacer la ventana más pequeña de manera que en lugar de que te falten datos te sobren, por ejemplo: haces una división cada 50 pixeles y cubres 500 muestras en 10 divisiones. El resto de samples los usas como buffer de pantalla, de manera que el usuario pueda recorrer la ventana mediante flechas o botones desde 0 hasta 895 samples (por ejemplo podría situar la ventana entre el sample 165 y el 665). ¿Que la ventana se queda muy pequeña?, no hay problema, haces zoom x2, división cada 100 pixeles e interpolas 1 punto entre muestras para tener en total 1792, y haces la ventana de 1000 puntos (a recorrer entre 0 y 1791).

Esta solución es la más elegante y la que creo que implementan muchísimos osciloscopios.

Otra: Una vez perfeccionado el soft en la parte de interpolacion, planeo que el mismo me de datos utiles, como ser, una etiqueta que me diga de que frecuencia es la señal. Se me ocurrio que, mientras voy recorriendo los samples, calcular el valor minimo y maximo: Luego, cuando tengo esos datos, contar cuantos samples pasan desde un minimo pasando por un maximo y hasta un minimo de nuevo. Ahi podria calcular la frecuencia. Tendria que poner algo con un error de un cierto % debido a que esos minimos y maximos bien pueden ser picos en la señal y no la señal en si. No me gusta... es muy "fuerza bruta". ¿Hay algo mejor para hacer esto?

Vamos a ver. Parámetros interesantes para calcular cuando tenemos una onda:

-Valor Máximo
-Valor Mínimo
-Frequencia principal
-Nivel de continua
-Valor eficaz (RMS).

Con el tema de la frecuencia, tienes razón, el que comentas es un método poco fiable para poder medir la frecuencia, ya que el hecho de que hayan máximos y mínimos locales (crestas y valles) no significa que la frecuencia sea la inversa de la distancia entre cresta y cresta. Podrías estar calculando sin querer la frecuencia de un armónico (la señal de normal será la suma de varios armónicos que hacen que la onda vaya subiendo y bajando muchas veces más que la frecuencia original).

Para tener una indicación fiable no hay más remedio que usar una transformación de la serie temporal de los datos a una serie frecuencial, es decir calcular la FFT. Aunque tienes 896 puntos, puedes calcular la FFT óptima de 1024 puntos ya que añadir los puntos de valor 0 que faltan no varía las componentes frecuenciales de la FFT.

La FFT te va a calcular puntos en el plano complejo, cada punto tiene una parte real y otra imaginaria, pero a ti lo que te interesa es conocer el módulo de cada frecuencia (amplitud). Dado un número complejo, a+bi, su módulo es sqrt(a^2+b^2). Ya de entrada te digo que una vez calculada la FFT, la componente primera, es la de frecuencia 0, entonces esa primera componente es el valor medio, o la componente en continua, de la señal muestreada. Buscando un valor que nos interesa nos hemos encontrado con otro valor que también nos interesa.

Ahora, si tenemos 1024 puntos, y hacemos una FFT, la primera frecuencia es la componente que se repite cada 0 samples(la continua). La segunda es la que se repite cada FFT/2, la tercera se repite cada FFT/4, la cuarta cada 3/4 FFT, y así, hasta la componente 512 que es la frecuencia que se repite cada 2 samples (la frecuencia de nyquist). Del 513 al 1024 es la misma FFT que de 1 a 512, pero reflejada en orden descendente, por lo que no hace falta que te fijes en ese tramo... Así sabiendo la frecuencia de la FFT que te interesa, sabes cual es la frecuencia de la señal que necesitas.

La frecuencia principal de una onda, quitando su valor de continua FFT[0], es la frecuencia de la componente de la FFT que tenga mayor amplitud. Así que para saber la frecuencia de tu señal, recorres las amplitudes de las 512 frecuencias de la FFT, y te quedas con la frecuencia de mayor amplitud. Así sabrás cada cuantos samples la onda se repite.

El problema es que la FFT te va a dar una aproximación digital de la frecuencia, nunca una frecuencia que no sea racional (porque usando series discretas sólo podemos tener frecuencias racionales, es decir, frecuencias que se puedan expresar en una fracción de la frecuencia de muestreo). Cuando tienes muchos puntos, esta frecuencia digital será bastante próxima a la frecuencia real de la señal, (por ejemplo, pongamos que la frecuencia real es 3.141593 MHz, y al calcular la FFT de la señal muestreada, nos da una frecuencia de 3.142857 MHz..., que es el resultado de que la razón de la señal con respecto a la frecuencia de muestreo sea de 22/7. Entonces pongamos que cada 7 puntos la señal se repite en el análisis digital, pero en realidad se debería de ir repitiendo cada 7.0028174 puntos. Tienes ahí una pequeña fracción de 0,0028174 que te va a introducir un error en el cálculo de la frecuencia (esto es sólo una estimación, el error real entre el muestreo y la frecuencia real va creciendo conforme la onda va acercándose a la frecuencia de muestreo).

Entonces podemos ayudarnos con las funciones polinómicas de interpolación para aproximar el punto X exacto donde la onda se repite. Ponemos que una onda vale 5 en el punto 0, y la FFT nos dice que su frecuencia principal es de 16 samples. Pues en el sample 16 deberíamos esperar encontrar un 5, pero nos encontramos con un 6. En el sample anterior, el 15, tenemos un 4,5. Entonces tenemos un intervalo, desde X=15,Y=4,5 hasta X=16,Y=6, y entre un valor de ,llamemosla Xu, de entre 15 a 16, debe de haber un valor de Xu donde Yu sea 5. Pongamos que podemos construir dentro de ese intervalo un polinomio interpolador que llamaremos P(X). Podemos construir una función F(X)=P(X)-Yu, de forma que F(X) sea 0 para el valor de Xu esperado. Entonces debemos aproximar X a Xu para conseguir que F(Xu)=0. Esto lo podemos hacer bien resolviendo directamente las soluciones del polinomio interpolador de tercer grado (un peaso de fórmula increiblemente grande, pero se puede hacer), o bien numéricamente en varios pasos con el método de la bisección, el de la secante, o el de newton (el de la bisección da buen resultado ya que tenemos un intervalo definido). Entonces encontramos una Xu=15,37 por ejemplo, la cual F(15,37)=0, por lo tanto P(15,37)=5= valor del sample 0. Entonces 15,37 samples será una mejor aproximación de la frecuencia que el valor de 16 samples que nos había dado la FFT.


Sobre los valores máximos y mínimos: Pues puedes recorrer todos los valores de la muestra e ir investigando si el valor actual es mayor o menor que el máximo y mínimo provisionales, hasta finalizar el vector de muestras. El problema de nuevo lo tenemos en que estamos midiendo unos valores máximos y mínimos sobre muestras discretas, y sin embargo disponemos de funciones continuas donde podemos calcular el máximo y el mínimo de cualquier tramo de la función, por lo que encontrar la cresta y el valle en esas funciones nos sería muy útil ya que casi nunca va a coincidir el valor de la muestra con el valor de cresta o valle de la onda.

Bueno, pues resulta que para encontrar la cresta y el valle de un polinomio de tercer grado (el punto donde la pendiente de subida y bajada se hace 0), lo que hay que hacer es derivarlo e igualar la derivada a 0, de manera que obtenemos una ecuación sencilla de segundo grado que podemos resolver teniendo dos soluciones Xa y Xb, mediante la conocidisima fórmula de ecuaciones de segundo grado, pero adaptada a los coeficientes de la derivada de nuestro polinomio interpolador:

fortran-cuadratica.gif


Esas soluciones existirán siempre (excepto cuando lo que multiplica a X^2 es cero, porque entonces tenemos solución única que será X=-c/b. Pero tanto Xa como Xb tienen que encontrarse dentro del intervalo 0 y 1 para que nos sirvan, de forma que si Xa y Xb vale por ejemplo -1,34 y 2,37, pues en el intervalo 0 y 1 no tiene un punto de valle ni de cresta, entonces para saber dentro de ese intervalo cual es el máximo o el mínimo, sólo hay que ver el valor en el punto 0 y el 1 y ver cual es mayor que el otro. En definitiva, para saber el máximo y el mínimo de un intervalo 0...1, tenemos considerar 4 puntos y ver cual es el mayor y cual es el menor dentro de ese intervalo, es decir X=0, X=Xa, X=Xb, X=1. Y luego ir recorriendo el vector hasta encontrar el valor máximo absoluto y el mínimo.

El programa lo he implementado y probado en Octave:

Código:
function [xmax ymax xmin ymin] = maxminsplines(samples)

  Y_1=samples(length(samples));

xmax=0;
ymax=0;
xmin=0;
ymin=0;

  for i=1:(length(samples)-1)

	Y0=samples(i);
	Y1=samples(i+1);
	if (i==length(samples)-1) 
 	  Y2=samples(1);
	else 
        	  Y2=samples(i+2);
	end

	S=Y2+Y0-2*Y1;
	T=Y1+Y_1-2*Y0;

	A=(S-T)/2;
	B=(2*T-S)/2;
	C=(Y1-Y_1)/2;
	D=Y0;
                  
        if  A==0
		X1=-C/(2*B);
		X2=X1;
	else
		X1=(-2*B+sqrt(4*B^2-12*A*C))/(6*A);
		X2=(-2*B-sqrt(4*B^2-12*A*C))/(6*A);
	end

	Y1=A*X1^3+B*X1^2+C*X1+D;
	Y2=A*X2^3+B*X2^2+C*X2+D;

	if X1>0 && X1<1 && imag(X1)==0
		if Y1 >ymax
			ymax=Y1;
			xmax=i+X1;
		end
		if Y1 <ymin
			ymin=Y1;
			xmin=i+X1;
		end
	end

	if X2>0 && X2<1 && imag(X2)==0
		if Y2 >ymax
			ymax=Y2;
			xmax=i+X2;
		end
		if Y2 <ymin
			ymin=Y2;
			xmin=i+X2;
		end
	end

	if D>ymax
		ymax=D;
		xmax=i;
	end 
	if (A+B+C+D)>ymax
		ymax=A+B+C+D;
		xmax=i+1;
	end
	if D<ymin
		ymin=D;
		xmin=i;
	end 
	if (A+B+C+D)<ymin
		ymin=A+B+C+D;
		xmin=i+1;
	end 
	Y_1=Y0;
	end
 return
end

Como ves, ahora ya no hace falta introducir en el programa el número de puntos a interpolar, ya que lo que se calcula es el valor máximo y mínimo absoluto en un X que no tiene que ser una partición fracional del intervalo 0..1 sino que se encontrará en cualquier parte de ese intervalo. Ahora tampoco se devuelve el vector de interpolación sino los valores X e Y máximos y mínimos.

Ejemplo, tenemos estos puntos representados en la siguiente gráfica:

Ejemplo Max Min 1.png

Y para comparar con la función interpolada N=25 que sería esta:

Ejemplo Max Min 2.png

Ahora usamos la función maxminsplines para encontrar los X e Y máximos y mínimos de los polinomios interpoladores de los samples y tenemos este resultado:

Código:
octave-3.6.4.exe:49> [xmax ymax xmin ymin]=maxminsplines(Y)
xmax =  12.574
ymax =  0.99667
xmin =  17.603
ymin = -0.99680

octave-3.6.4.exe:50> [y x]=max(Y)
y =  0.96350
x =  13
octave-3.6.4.exe:51> [y x]=min(Y)
y = -0.96781
x =  18

Es decir, sin interpolar, el máximo lo da en el sample 13, con valor 0,96350, y el mínimo en el sample 18 con el valor -0,96781. Usando los máximos y mínimos encontrados por interpolación, encontramos un máximo en el sample 12,574 con valor 0,99667 y un mínimo en el sample 17,603 con valor -0.99680. Como ves, uno se acerca al sample 13 y el otro al 18. Los máximos y mínimos se acercan más al máximo y mínimo teóricos de una senoidal que es 1 y -1.

Bueno, pues sobre el valor eficaz de la señal ya hablaré más adelante y te iré explicando qué es y cómo se calcula (es que se me ha hecho ya tarde). Por lo pronto te enseño una función que he hecho otra vez en matlab para calcular el valor eficaz de las funciones interpoladas de una secuencia de samples:

Código:
function salida = RMSsplines(samples)

  Y_1=samples(length(samples));

  intparcial=0;
  for i=1:(length(samples)-1)

	Y0=samples(i);
	Y1=samples(i+1);
	if (i==length(samples)-1) 
 	  Y2=samples(1);
	else 
        	  Y2=samples(i+2);
	end

	S=Y2+Y0-2*Y1;
	T=Y1+Y_1-2*Y0;

	A=(S-T)/2;
	B=(2*T-S)/2;
	C=(Y1-Y_1)/2;
	D=Y0;

	intparcial=intparcial+A^2/7+(A*B+2*B*D+C^2)/3+(2*A*C+B^2)/5+(A*D+B*C)/2+C*D+D^2;
	Y_1=Y0;
	end

salida=sqrt(intparcial/length(samples));

 return
end

Esta función es una función que devuelve un valor que es el valor RMS REAL, no aproximado, de la secuencia de polinomios interpoladores. Cuanto más parecidos sean los polinomios interpoladores a la onda real, más se parecerá el valor RMS real de los polinomios al valor RMS de la onda que aproximan.

Saludos.
 
Última edición:
Intente aplicar lo que me especifico Eduardo sobre la funcion sinc

mathtex.cgi


Lo que se me escapa creo es que no sabria que es ω. Entiendo que multiplica al valor de "tiempo" - la constante de entrada K (supongo los -10+10) * 1, siendo 1 si realizara una interpolacion de 1 elemento (intervalo entre muestreos? o te referis a tiempo?)

Los detalles de la fórmula anterior se explican en el Teorema del Muestreo.
 
Última edición:
palurdo, como decimos por aca, sos un grande! :)

Una explicacion digna de analizarla con paciencia e ir aplicandola. Por lo pronto, les cuento las ultimas modificaciones:

Pude resolver lo que pregunte sobre las bases de tiempo haciendome un dibujito en un papel, y llegando a la misma conclusion que vos me decias aqui: Que si tengo un tiempo entre samples de 25ns, para poder tener 1us/div debo intercalar 4 samples, con un pequeño truco:

- Selecciono en el mux una frecuencia de sampleo para 5us/div y utilizo 5 samples, 2 reales, 3 calculados. (Esto claro, x100) Entonces, entre los 2 samples reales tengo 50ns / 5 = 10ns * 100 = 1000ns/div

Es decir, la escala minima "real" de mi osciloscopio es de 2.5us/div pero no utilizo esa para 1us/div sino la siguiente 5us/div y uso interpolacion.

A partir de alli para abajo, si uso la 2.5us/div como frecuencia de muestreo y hago:
- 2500ns / 5 (2 reales, 3 calculados) = 500ns/div
- 2500ns / 10 = 250ns/div
- 2500ns / 25 = 100ns/div
- 2500ns / 50 = 50ns/div

y ahi paro nomas, porque en esa ultima ya tengo tan solo 2 samples reales por division. Podria seguir pero ya es suficiente por el momento.

No me puse a investigar el tema de los calculos de datos utiles (muchas gracias! me diste mucha informacion para aplicar) porque me encontre con un problema:

Me fabrique un oscilador de onda cuadrada con un cristal de 16mhz, inversor schmitt trigger 74HC14 y un 74HC4040 para hacer divisiones. Lo alimente con una bateria que tenia por ahi de 6v.

Resulta que, midiendo con osciloscopio comercial, veo que la señal tiene entre 0v-5.86v y yo, como un tonto, tengo una referencia del adc de 5v entonces veo la parte de abajo de la señal pero arriba "hace tope" con vcc.

Entonces, aproveche el divisor 2:1 que tenia hecho con los mux y lo deje por defecto activado, reemplazando la cuenta 5 / 256 en el programa por 10 / 256 para saber a cuantos volts corresponde cada incremento en el resultado del ADC.

Entonces, incremente el voltaje de los operacionales desde +-5v a +-7v (son rail to rail) y puse un regulador 78L05 con un preset de ajuste a la referencia del ADC.

Con esto logre que, si tengo una señal de 10vpp en la entrada del osciloscopio (5 positivos, 5 negativos), en la entrada del ADC tengo 5vpp centrados en 2.5v (gracias al ex divisor 2:1, ahora llamado 1:1)

Lo que antes era 1:1 ahora pasa a llamarse 1:2 (multiplicador ahora) quedandome:
1:1
1x2
2.5:1 (ex divisor 5:1)
1x10 (ex multiplicador 1x5)

De esta forma, logre que la señal en pantalla, en las mismas escalas, coincida con la de un osciloscopio digital comercial (prestado jeje) que estoy usando para calibrar esta cosa. Su señal de calibracion de 1khz 2vpp se ve exactamente igual en el mio que en el comercial :)

Ahora la mala noticia: Lo unico que pude ver bien fue una señal cuadrada de 500khz. Una de 1mhz se ve pero ya no tan cuadrada (en el comercial se ve perfecta) y mas alla van cada vez peor hasta que una de 4mhz ya no se ve (quedan solo picos abajo).

Creo que es porque sin querer arme un pasabajos en la entrada principal del osciloscopio: Antes del primer operacional tengo una resistencia en serie con el op-amp de 10K en paralelo con un capacitor de 22n y luego de esto, los diodos 1n4148 de proteccion hacia VCC y VEE y ahi si va al + del operacional.

Asi que, antes de proseguir con el soft voy a reparar esta parte del hard. Creo que los operacionales que uso, segun su datasheet y a +-7v deberian ir sobrados para una frecuencia de 4mhz, y por otro lado, el ADC corriendo a 40mhz deberia darme 10 puntos claros bien cuadrados (aclaro: su ancho de banda analogico es de 75mhz) Estoy casi seguro que cometi algun error de diseño y formo un pasabajos accidental por algun lado. Aclaro que en esta prueba no use interpolacion.

De todos modos, estoy conforme con el resultado pero tengo mucho hardware para tan poco asi que lo voy a exprimir al maximo :)

Por otro lado, apenitas resuelva esto me pongo con las mejoras de software que me propones, son excelentes!

asherar: Muchas gracias por el link! Habia leido varias veces tu post sobre la placa de captura a 32mhz y obtuve datos utiles de el para el diseño de esto. Lamentablemente sitio donde tenias detalles hace rato que esta caido.

Tambien podria seguir aumentando la capacidad de esto haciendo muestreo equivalente. De hecho lo hice con un trigger inexacto (aplicando 1 NOP de 83.33~ previo al inicio de captura en la segunda pasada) y luego intercalando los samples de 1 y otra pasada, pero la verdad que el resultado que obtuve con interpolacion 1 matematica fue practicamente el mismo y el hardware se complica bastante si tenemos que generar retrasos variables exactos (de fraccion de la frecuencia de muestreo).
 
Última edición:
Yo también estuve probando las funciones de matlab que ha ido subiendo palurdo y andan de 10.
Es realmente notable lo que se logra con un algoritmo tan sencillo.
Aunque los métodos de interpolación parecen muy enredados si se los ve en forma analítica (como el de la función sinc), pero pueden ser llevados a la práctica con algunos truquitos ingeniosos.

En tu caso, seaarg, trabajando con los datos una vez que están en la PC, no se tiene problemas con la velocidad. Pero si se hicieran a bordo del pic, además de simple, el algoritmo tiene que ser rápido.

Con respecto a mi sitio, ya veré de subir todo otra vez.
Mi intención no era interpolar sino hacer muestreo de tiempo equivalente, y para eso necesitaba un retardo
como el que mencionas al final: ajustable, estable y preciso, con una duración de fracción del retardo (1/32MHz ~ 30 ns), y eso no sé si existe.
Varias veces intenté continuar el proyecto pero algunos temas de hardware me "ganaron" y ya no tengo el tiempo libre que tenía antes. Todo se puede resolver, pero lleva tiempo.

PD: Acá hay algo interesante sobre calcular funciones trigonométricas con numeros enteros
(pero todavía me falta entender cómo es el uso práctico).
En forma de presentación.
En forma de texto plano.
 
Última edición:
Estuve pensando en este tema y me surgieron algunas dudas.

Por lo que se ve en las rutinas que subió palurdo a la cantidad de muestras originales N, la rutina le devuelve un vector de N*M. Usar M = N la verdad es que me parece un poco mucho.
Tal vez con cuadruplicar (M=4) la cantidad de muestras originales alcanzaría para ver una curva suave. Si nó la curva mostrada puede ser demasiado irreal.
Digo esto porque en el intervalo ente dos muestras uno puede intercalar un punto, o dos y ya con eso ganar suavidad en la curva. Pero por la misma cuestión que existe la frecuencia de Nyquist, no tiene sentido agregar más puntos. Si se agregan demasiados puntos se está asumiendo que lo que hay entre medio de dos muestras ES suave.
Además se carga el sistema con cálculos que en realidad resultan innecesarios.
Entiendo que usando un algoritmo sencillo no queda otra, pero tampoco es bueno exagerar con la información que uno agrega a dedo.
Tal vez, la salida elegante sería intercalar más o menos puntos, de modo tal que la curva completa nunca pase de un cierto número, digamos N*M=1000 o algo así.
Pero reitero: que se agregen siempre una cantidad fija (M=N) de puntos ente cada 2 de un conjunto de N no me parece algo conveniente.

Otra cosa.

Cuando te falla la última parte de la curva porque faltan las muestras, es porque te faltan las muestras del "futuro", necesarias para aplicar el algoritmo splines2.
En ese caso (es una sugerencia), y sólo para ese tramo final, se podría probar con la aproximación que tiene en cuenta solamente muestras del "pasado" (la primera versión de splines). Es una idea. No sé qué pueda pasar.

Bueno, no sigo (no molesto) más.

....

Bueno sí, pero espero que no sea molestia.
Estuve haciendo una prueba rápida con la función sinc de Matlab y uno de los ejemplos que viene en el Help.
Les dejo el texto de la ayuda, donde explica que la función sinc es la anti-transformada de Fourier del pulso rectangular que vale 1 en (-pi,pi) y 0 en (-inf,-pi) y (pi,inf).

Copia de pantalla de la ayuda:
Ayuda.JPG

Ahora un código modificado por mí a partir de un ejemplo.
Código:
%
% Reconstruccion de una señal a partir de su muestreo
% usando la funcion sinc de Matlab
%
clear all
clc

N=20;
t = (1:N)';             % Un vector columna de coordenadas de tiempo
s = - t .* t .* cos(t); % Un vector columna de muestras (coseno)
                        % El producto .* opera elemento a elemento
figure(1);
xlabel('tiempo');
ylabel('amplitud');
hold on                 % Para que no se borre 
plot(t,s,'o');          % La grafica de las muestras
texto=sprintf('N=%d',N);text(0,100,texto);

N1 = -2;                % Limite izquierdo de la grafica
N2 = N+2;               % Limite derecho de la grafica
M = 100;                % Numero de puntos a calcular
texto=sprintf('M=%d',M);text(0,-100,texto);

ts = linspace(N1,N2,M)'; % Coordenadas de tiempo interpoladas

% Operacion usando la funcion sinc de Matlab
y = sinc(ts(:,ones(size(t))) - t(:,ones(size(ts)))')*s;

figure(1)
plot(ts,y,'b-')         % La grafica de la funcion reconstruida
Esto da:
reconstruc1.jpg

Lo interesante es que la función sinc que viene implementada usa la misma cantidad de puntos que el vector de muestras dato, o mayor como en el ejemplo.

M es la cantidad de muestras del vector de interpolación que incluye los puntos de la zona inicial y final que serían "puntos desperdiciados".

Si se hace:

ts = linspace(0,N,M)'; % Coordenadas de tiempo interpoladas

la función "linspace" no genera puntos desperdiciados.

reconstruc2.jpg

Acá, además de la curva en rojo se muestran los puntos calculados como x azules.
Es para ver que aunque se agregaron solo 3 puntos por cada uno de muestra la curva se ve suave.

Para dejar este tema redondito quedaría hacer este mismo cálculo sin usar la función sinc de Matlab, es decir recorrer el arreglo elemento por elemento.
 
Última edición:
asherar:

Ante todo, no es molestia! Todo suma al conocimiento y es bienvenido al menos por mi.

En el planteo de la cantidad de muestras inventadas estoy de acuerdo: Estariamos asumiendo que la señal es limpia y la realidad casi siempre tiene espurias por lo tanto, es conveniente no pasarse en cantidad de datos calculados.

En mi caso particular, fabrico 1us/div, 500ns/div, 250ns/div, 100ns/div y 50ns/div. Sin embargo, no me olvido cuando hago pruebas de que hasta 500ns/div tengo una idea mas o menos acertada de que lo que veo "debe" ser como lo real. De ahi para abajo ya no confio tanto jeje, estan ahi, mas que para que sean reales, para poder "hacer zoom" en señales mas rapidas y que sean mas comodas de ver en pantalla. Por otro lado, en mi implementacion hay un checkbox en el soft que decide si aplica interpolacion lineal o splines por lo tanto ante cualquier sospecha se deja lineal.

En lo de la falla en la ultima parte puede que tengas razon, cuestion de probar que el algoritmo anterior se use en ese caso pero creo recordar (no mucho) que hacia lo mismo. Probare y les cuento cuando resuelva el problema que tengo del "pasabajos" en algun lado.

Al respecto de lo que pusiste sobre sinc(x), originalmente antes que palurdo me mostrara splines buscaba informacion precisamente sobre como aplicar esto, ya que el lenguaje de programacion que estoy usando que es vb.net no tiene dicha funcion (y ningun lenguaje de proposito general creo) entonces quise comprender la definicion de la funcion para poder hacerla yo en codigo (como vos decis, recorrer elemento x elemento) y ahi fue cuando el cerebro me hizo division por cero :)

Adelanto que voy a proseguir con esto, no esta abandonado, solamente que tengo que encontrar porque en mi diseño frecuencias cuadradas de 4mhz se ven como triangulo y ya vi que asi estan llegando al ADC. Por lo pronto ya vi que solo la punta de osciloscopio que tengo (dice que es de 20mhz) de por si ya le quita un poco de amplitud a la señal original, lo cual me parece raro pero para nada imposible. Despues, luego del primer operacional de entrada vuelvo a tener la señal como la lee un osciloscopio comercial pero antes de el esta muy reducida en amplitud (algo raro pasa y tengo que enchufar el soldador para encontrar el culpable, me juego que es el conjunto R paralelo a C que esta en serie con la entrada del primer operacional)

Para peor, los cambios que hice para corregir la poca amplitud de entrada disponible funcionan de 10 en cuanto a su objetivo, pero me afectaron el funcionamiento del trigger (ya no dispara bien) y tengo que ver porque razon :confused:

Hoy no pude dedicarme por el trabajo pero se vienen nuevos avances supongo. Por lo pronto tambien intente empezar a hacer esquematicos al menos en proteus para compartir con ustedes, solo que voy poquito a poquito.
 
Me alejo un poco del tema de este tópico pero ¿Has simulado la red RC de entrada con algún programa?.
Podrías subir el esquema de la entrada de tu osciloscopio para ver si surgen ideas para alguna mejora.
 
Estuve pensando en este tema y me surgieron algunas dudas.

Por lo que se ve en las rutinas que subió palurdo a la cantidad de muestras originales N, la rutina le devuelve un vector de N*M. Usar M = N la verdad es que me parece un poco mucho.
Tal vez con cuadruplicar (M=4) la cantidad de muestras originales alcanzaría para ver una curva suave. Si nó la curva mostrada puede ser demasiado irreal.
Digo esto porque en el intervalo ente dos muestras uno puede intercalar un punto, o dos y ya con eso ganar suavidad en la curva. Pero por la misma cuestión que existe la frecuencia de Nyquist, no tiene sentido agregar más puntos. Si se agregan demasiados puntos se está asumiendo que lo que hay entre medio de dos muestras ES suave.
Además se carga el sistema con cálculos que en realidad resultan innecesarios.
Entiendo que usando un algoritmo sencillo no queda otra, pero tampoco es bueno exagerar con la información que uno agrega a dedo.
Tal vez, la salida elegante sería intercalar más o menos puntos, de modo tal que la curva completa nunca pase de un cierto número, digamos N*M=1000 o algo así.
Pero reitero: que se agregen siempre una cantidad fija (M=N) de puntos ente cada 2 de un conjunto de N no me parece algo conveniente.

Gracias por tus apuntes. La verdad es que depende del fin que le des a la interpolación tendrá sentido o no que pongas muchas o pocas muestras. Como ves el vector interpolado es M veces N, donde M el el número de intervalos (puntos+1) a interpolar entre dos puntos reales. Por simplicidad en la función no incluí en el vector de salida el último punto, que sería la última muestra real del vector N, pero no afecta a la interpolación. El M que se utilice ya lo elijes dependiendo de los puntos que necesitas para representar en pantalla y las muestras reales representables. Es decir, que si por ejemplo tienes N muestras representables en pantalla en tu escala de tiempo y tienes disponibles 1000 posiciones en pantalla, entonces para esa escala utilizas 1000/N=M puntos a interpolar entre muestras de forma que M*N=1000. Dejar fijo M sería una pérdida de tiempo para calcular puntos que al final no vas a representar en pantalla porque no caben en los pixeles. Pongamos que tienes 100 puntos en 1us, pues para representar 1000 puntos en pantalla necesitas partir los tramos entre puntos reales en 10 segmentos interpolados (9 puntos intermedios) para tener los 1000 pixeles. Si ahora haces zoom x2, para 500ns, para representar en pantalla sólo tienes la mitad de puntos, por lo que para 1000 pixeles necesitas aumentar al doble el número de puntos interpolados. Hacer una matriz cuadrada M=N es una barbaridad, ya que si tienes por ejemplo 500 puntos, estarías interpolando 500 segmentos entre cada punto, por lo que tendrías 250000 muestras interpoladas, algo completamente innecesario, ya que con M=2, es decir, intercalando un punto interpolado entre 2 reales, ya consigues los 1000 pixeles.

Por lo mismo dejar un M demasiado bajo no es buena idea ya que si tienes pocas muestras, y pocos puntos interpolados, al unir con rectas sigues teniendo una curva irreal, pero con discontinuidades inventadas (esquinas en las uniones de las rectas). Lo ideal es tener un M tal que N*M=Total pixeles a dibujar.

Por otro lado, creo que dices que las curvas interpoladas con muchos puntos quedan demasiado sintéticas. A pesar de que estoy de acuerdo contigo, debo de comentar que discrepo en algunos matices pero propondría alguna solución a esto aunque sería empeorar la calidad de la interpolación. Discrepo porque el que use el osciloscopio debe de tener claro el ancho de banda de éste, de forma que frecuencias superiores al límite no pueden representarse. Por ejemplo, si tienes un ancho de banda de entrada 10MHz, y un muestreador a 200MHz, siempre tendrás curvas suaves de como mínimo de 10 muestras, aunque la señal original tenga transiciones repentinas entre esas 10 muestras, ya que esas transiciones tendrán frecuencia superior al ancho de banda de entrada del osciloscopio. No tiene sentido pensar en un osciloscopio con un ancho de banda de 10MHz y un muestreador a 200MHz, porque desperdicias capacidad de muestreo ya que el ancho de banda es muy pequeño en conmparación con la serie muestreada. Resulta que interplolando, lo que haces al aumentar la cantidad de samples es aumentar la frecuencia de muestreo ya que para el mismo periodo temporal tienes mayor cantidad de samples. Pero esto no aumenta el ancho de banda de la señal de entrada. Por lo tanto, en lugar de tener una entrada de 10MHz y un muestreador a 200MHz, se puede tener una entrada de 10MHz y un muestreador de 20MHz (o 25MHz para no complicarse la vida con el filtro antialiasing), y a partir de los samples a 20MHz interpolar para convertir la señal muestreada a 200MHz con ancho de banda 10MHz lo cual es el mismo resultado que haber muestreado directamente a 200MHz. En todo caso se puede recordar en pantalla que el límite superior a reprentar en la gráfica, ya sea interpolada o no, es el límite superior del ancho de banda de entrada al capturador.

El aspecto de la 'calidez' de las señales reales VS las interpoladas viene a raiz de que en pantalla aparecen componentes frecuenciales de banda ancha que no pertenecen a la señal. Dos motivos ocurren para esto:

-Ruido de captura.
-Ruido de cuantización.

El ruido de cuantización aparece en la señal real al limitar las muestras a 8 bits (LSB a -49dB). Con muestras de 24 bits (LSB a -144dB) esto no es un problema porque el valor mínimo es muy pequeño y la curva muestreada es prácticamente matemática. Cargad con Audacity cualquier archivo de audio directamente extraido a 16 bits de un CD de música, id haciendo zoom hasta ver la onda definida en pantalla, y vereis lo que os digo cuando los samples a 16bits parecen samples calculados matemáticos y sin embargo son samples reales de audio.

El ruido de fondo de captura (noise floor), es una porción de ruido blanco de banda ancha que aparece en las etapas amplificadoras antes de la captura, y ese suelo de ruido cuando es mayor que el ruido de cuantización es cuando aparece representado en la señal (por debajo del ruido de cuantización no tiene efecto ya que el que domina es el de cuantización). El ruido blanco aparece igualmente espaciado en todas las frecuencias, por lo que para saber su magnitud sólo se necesita conocer su valor eficaz RMS.

Reproducir el ruido de cuantización en los puntos interpolados no tiene mayor secreto que truncar (o redondear para eliminar un pequeño sesgo) la parte decimal de los valores interpolados. De hecho al dibujar en pantalla los puntos interpolados ya se está cuantizando porque no existen pixeles fracionales sino enteros.

Reproducir el ruido de fondo captura, a costa de degradar la señal, sería medir el valor RMS del ruido de captura cuando no hay señal, y aplicar un ruido blanco de ese valor a las muestras interpoladas. Este proceso, que empeora la calidad de la señal resultante (añade ruido) pero dependiendo de la aplicación es apropiado para enmascarar ciertos aspectos de una conversión de los datos para hacerlos más naturales, se le conoce como DITHERING.

Otra cosa.

Cuando te falla la última parte de la curva porque faltan las muestras, es porque te faltan las muestras del "futuro", necesarias para aplicar el algoritmo splines2.
En ese caso (es una sugerencia), y sólo para ese tramo final, se podría probar con la aproximación que tiene en cuenta solamente muestras del "pasado" (la primera versión de splines). Es una idea. No sé qué pueda pasar.

No habría problema, ya que cada conjunto de 3 puntos en splines y 4 puntos en splines2 es independiente del resto, así que es como si hasta 0...N-1 calcularas la gráfica en splines2 y de N-1 a N la gráfica para splines 1. Ese tramo seguiría siendo suave ya que la pendiente de la curva anterior a N-1 tiene la misma pendiente que la curva posterior.

De todas formas yo para splines2 asumo que la señal es periódica, es decir que la primera muestra de la señal sigue después de la última. Creo que seaarg la muestra del futuro la hace 0, o igual es por el padding que hace en su señal para rellenar los puntos que le faltan en la pantalla.

Intenté hacer una función de interpolación splines3, donde consideraba las derivadas segundas de los puntos Y[-1] e Y[2], para completar un polinomio de grado 5 con curvas más suaves (dos niveles de derivadas). Los cálculos de los coeficientes A,B,C,D,E,F tuve que hacerlos con Derive ya que resolver el sistema de ecuaciones a mano se hizo una pesadilla. El resultado, como era de esperar, fue una peor interpolación que usando splines de tercer grado. Si quieres comparar, te dejo la función que hice, pero no la uses para interpolaciones reales porque aproxima peor que splines2.

Código:
function salida = splines3(samples, npuntos)

  L=length(samples);
  X=((1:npuntos)-1)/npuntos;

  for i=1:(L-1)

	Y0=samples(rem(i-1+L,L)+1);
	Y1=samples(rem(i-1+L+1,L)+1);
	Y2=samples(rem(i-1+L+2,L)+1);
	Y_1=samples(rem(i-1+L-1,L)+1);
	Y_2=samples(rem(i-1+L-2,L)+1);
	Y3=samples(rem(i-1+L+3,L)+1);

	A1= -(Y_2 -9*Y_1 -7*Y1 +15*Y0)/2;
	B1= 3*(Y_2 -8*Y_1 -6*Y1 +13*Y0)/2;
	C1= -(3*Y_2 -19*Y_1 -13*Y1 +29*Y0)/2;
	D1=(Y_2+Y0-2*Y_1)/2;
	E1=Y0-Y_1;
	F1=Y0;

	A2= (Y3 - 9*Y2 + 15*Y1 - 7*Y0)/2;
	B2= -(2*Y3 - 21*Y2 + 36*Y1 - 17*Y0)/2;
	C2= (Y3 - 13*Y2 + 23*Y1 - 11*Y0)/2;
	D2= (Y2 - 2*Y1 + Y0)/2;
	E2= Y1 - Y0;
	F2= Y0;
	
	A=(A1+A2)/2;
	B=(B1+B2)/2;
	C=(C1+C2)/2;
	D=(D1+D2)/2;
	E=(E1+E2)/2;
	F=(F1+F2)/2;
	
	salida(i,:)=A*X.^5+B*X.^4+C*X.^3+D*X.^2+E*X+F;

	end
 
 salida=salida';
 salida=salida(:)'; 

 return
end


Bueno sí, pero espero que no sea molestia.
Estuve haciendo una prueba rápida con la función sinc de Matlab y uno de los ejemplos que viene en el Help.
Les dejo el texto de la ayuda, donde explica que la función sinc es la anti-transformada de Fourier del pulso rectangular que vale 1 en (-pi,pi) y 0 en (-inf,-pi) y (pi,inf).

Lo interesante es que la función sinc que viene implementada usa la misma cantidad de puntos que el vector de muestras dato, o mayor como en el ejemplo.

M es la cantidad de muestras del vector de interpolación que incluye los puntos de la zona inicial y final que serían "puntos desperdiciados".

Si se hace:

ts = linspace(0,N,M)'; % Coordenadas de tiempo interpoladas

la función "linspace" no genera puntos desperdiciados.

Ver el archivo adjunto 96575

Acá, además de la curva en rojo se muestran los puntos calculados como x azules.
Es para ver que aunque se agregaron solo 3 puntos por cada uno de muestra la curva se ve suave.

Para dejar este tema redondito quedaría hacer este mismo cálculo sin usar la función sinc de Matlab, es decir recorrer el arreglo elemento por elemento.

El problema de sinc es que por cada muestra lo que hace es el sumatorio de toda la serie de puntos para sacar la funcion de onda donde después se remuestrea en la serie interpolada, ten en cuenta que en cálculo sinc(T)*s estás haciendo un producto matricial, lo que viene a ser una convolución de los valores del vector T con el vector S. Esto hace que el algoritmo sea muy lento de implementar. Consigues el mismo resultado implementando la interpolación por FFT que es mucho más eficiente. En matlab/octave existe la implementación de la función de interpolado FFT, llamada intepft. La onda de tu ejemplo usando interpft:

ejemplo 3.png

Por cierto, haz la prueba, pero t=linspace(N1,N2,M) es exáctamente lo mismo que hacer T=(N1:(N2-N1)/(M-1):N2), ya lo verás... (mas que nada para entender la implementación de la función linspace).

De todas formas, la interpolación por splines genera un resultado también bastante decente sin complicar tanto los calculos, aquí abajo la interpolación de dicha señal usando splines2:

ejemplo 4.png

Gráfica generada con las mismas condiciones que las interpolaciones anteriores, lo único es que no se generan los últimos 5 puntos, por lo que el vector interpolado tiene 95 en lugar de 100 puntos.

seaarg:

¿Has probado a atenuar la onda cuadrada de 4MHz al mínimo que te permita capturar aunque sea 1 bit?, más que nada para descartar un problema de Slew-Rate de los operacionales para señales rápidas de niveles grandes. Si pudieras poner unas capturas de lo que te sale con la onda "mala" te lo agradeceríamos. Un saludo y buen trabajo.
 
asherar:

Quería comentarte que cuando me refería que la cantidad de puntos a interpolar dependía de la aplicación, es porque yo inicialmente implementé este sistema de interpolado para otros menesteres.

Hace como cosa de 15 años, me encontré con un problema. Quería pasar por un filtrado de barrido un clip de audio para recrear el efecto de "barrido de filtro resonante" muy popular en muchas muestras que se utiliza en música electrónica. Lo traté de hacer con el filtrado FFT del programa cooledit (ahora adobe audition). El filtro FFT del cooledit es muy bueno en filtrado estático, pero en filtrado de barrido es horrible ya que el "morphing" que hace del filtro a medida que pasa el tiempo no es suave sino que va a tramos, por lo que no se escucha el efecto de barrido sino un efecto como escalonado.

Así que programe un programa que lo que hacía era tener un espacio gráfico donde había una linea horizontal que acababa en 2 vértices, y el usuario podía mover esos vértices entre los niveles de filtrado iniciales y finales, pero también añadir vértices interiores para construir una transición a tramos. Utilizaba la interpolación para generar la transición lo más suave posible. Por ejemplo, si el usuario usaba 5 puntos, se creaban 4 polinomios para crear la transición del filtro (se representaba en pantalla la curva interpolada por pixeles para que el usuario tuviera una idea de como quedaba la función de transición). La interpolación del coeficiente del filtro se hacía cada sample del clip de audio. Pongamos que había 1 segundo de sample a 44100 smp/s, pues con cada sample de entrada se recalculaban los coeficientes del filtro a partir del valor de tiempo que me daba la interpolación dentro del segmento de 2 puntos correspondientes de la gráfica. Al final, había calculado los coeficientes del filtro 44100 veces, de ellas 44095 eran posiciones temporales interpoladas, y 5 reales pertenecientes a la gráfica de transición. La verdad es que el programa funcionaba bastante rápido funcionando en un Pentium I@100MHz y el efecto era el pretendido, tener un filtro de barrido de dos polos movibles con una transición muy suave, al igual que lo hacía el REBIRTH-303 con su resonador.

Cuando quise convertir el código en un plug-in VST, el Norton Antivirus me hizo un desastre en la partición del disco duro y perdí todos los proyectos (no tenía copia de seguridad, en aquella época era jóven y atrevido...)

Como ves, en esta aplicación fue bastante bien interpolar 44095 puntos desde 5 puntos reales, pero claro, poco tiene que ver aquella implementación con esta del osciloscopio, sólo que ambos usan splines.

Saludos.
 
Me alejo un poco del tema de este tópico pero ¿Has simulado la red RC de entrada con algún programa?.
Podrías subir el esquema de la entrada de tu osciloscopio para ver si surgen ideas para alguna mejora.

No hay problema. Si la simule en proteus con un grafico de frecuencia pero no tengo el operacional exacto que estoy usando asi que no es confiable.

No tengo esquematico de la entrada (si una simulacion pero toda desprolija) sin embargo, la misma es casi una copia de esto: http://www.bitscope.com/design/hardware/pdf/Bs11-4.PDF

Solamente que el recuadro verde "vertical input buffers" + el primer mux son reemplazados por un operacional en donde tengo la sospecha que arme un pasabajos sin querer.

Tambien cambie con respecto a este esquematico el ultimo operacional que va al ADC, pero no es el problema (por ahora) porque a partir del 1 operacional de entrada la señal ya esta distorsionada a frecuencias altas.

Esta tarde agarro el soldador y elimino la R limitadora de entrada a ver que pasa



Palurdo, la verdad que no, no probe atenuar aun porque con el osciloscopio real medi que a la salida de mi primer op-amp ya veo distorsionado y eso me confundio pero bien puede ser como sugieren, que el slew rate sea insuficiente (130v/us!)

Esta tarde retomo las pruebas y les envio gustoso unas capturas de pantalla tanto del osciloscopio mio como de un comercial para la misma señal.
 
Última edición:
Atrás
Arriba