lunes, 28 de diciembre de 2009

Capturando fechas de un JDateChooser

Entre los componentes que forman parte del paquete de JCalendar desarrollados por Kai Tödter encontramos uno que es muy útil llamado el JDateChooser. Por lo que he leído en distintas páginas en el internet, muchos tienen problemas para capturar las fechas seleccionadas. Pues en este post vamos a aprender a capturar las fechas del JDateChooser así como darle el formato que uno desee. A lo largo de este post vamos a desarrollar la aplicación que muestro en la siguiente imagen:


En primer lugar para poder dar formato a un JDateChooser, este tiene un atributo el cuál podemos modificar de acuerdo a nuestras necesidades. La forma de cambiarlo es como se muestra en las siguientes imágenes:


Una vez seleccionado el atributo que queremos modificar, le ingresamos el formato que mejor se ajusta a nuestras necesidades, como se muestra en la siguiente imágen:


Pero aún haciendo esto, aún no se ha explicado la forma de capturar la fecha. Bueno, una forma de hacerlo es como muestro en el siguiente bloque de código:
try {
     String formato = comboFormato.getSelectedItem().toString();
     //Formato
     Date date = SelectorFecha.getDate();
     SimpleDateFormat sdf = new SimpleDateFormat(formato);
     txtFechaSeleccionada.setText(sdf.format(date));
} catch(NullPointerException ex) {
     JOptionPane.showMessageDialog(this, "Al menos selecciona una fecha válida!", "Error!", JOptionPane.INFORMATION_MESSAGE);
}
Con eso podremos obtener la fecha y colocarla en una etiqueta de texto o como parte de una cosulta SQL.

Para obtener el día, el mes o el año por separado podemos hacer lo siguiente:
int año = SelectorFecha.getCalendar().get(Calendar.YEAR);
int mes = SelectorFecha.getCalendar().get(Calendar.MONTH) + 1;
int dia = SelectorFecha.getCalendar().get(Calendar.DAY_OF_MONTH);
txtDía.setText("" + dia);
txtMes.setText("" + mes);
txtAño.setText("" + año);
Con eso bastará para poder obtener la fecha y darle el formato que se desee.


Aún así, si no nos gusta usar los componentes de JCalendar podemos escribir nuestro propio calendario. Yo hice uno, el cuál se puede apreciar en la imágen a continuación:


No es la gran cosa, pero con un poco más de tiempo se puede ir mejorando, hasta obtener resultados óptimos.

También podría interesarte este post que muestra cómo manejar los eventos de cambio de fecha en un jcalendar.

Bueno, para cerrar el post les dejo el link de descarga del proyecto que fué realizado en Netbeans IDE 6.8 usando jcalendar-1.3.3

miércoles, 16 de diciembre de 2009

Alumnos de Informática de la Universidad Nacional de Trujillo desarrollan un prototipo de los TALON Military Robots™

Alumnos de la Universidad Nacional de Trujillo lograron desarrollar un primer prototipo, bastante elemental, de los conocidos Robots Talon de Foster Miller Inc. Con motivo de la IV Semana de la Ciencia de la Computación, alumnos de la escuela de Informática de la Universidad Nacional de Trujillo lograron desarrollar un robot para la exploración de terrenos desconocidos mediante telecontrol. La plataforma sobre la que fué desarrollado el proyecto fué Java, gracias a sus altas capacidades de conectividad así como sus constructores de alto nivel que permitieron la transferencia de datos multimedia de una manera eficaz. Para el control de los mecanismos, se escribieron programas para Microcontroladores PIC de Microchip, los cuales gracias a sus manera sencilla de adquirirlos así como las posibilidades de ajustarlos a proyectos tan diversos hicieron de estos los candidatos ideales para esta parte de la arquitectura general del proyecto.

Los recuadros rojos indican las disposiciones de las cámaras en el robot, el recuadro verde indica la ubicación de la placa de control, el recuadro azul es el Modem-Router encargado de la transmisión de datos, y en amarillo se muestra la pantalla del control de mando.


Comunicacion USB, Protocolos de tiempo real así como una diversidad de frameworks y mecanismos que nos provee Java fueron la base para estructurar este proyecto en su primera fase.

El Robot cuenta con cámaras, entre ellas una de alta resolución, un micrófono, una lámpara de leds, un haz láser y dispositivos de control de giro lo cuál le permite tener un conocimiento único del entorno que explora, puesto que la cámara que lleva en la parte superior tiene un giro de 360º sobre su eje z. Este giro está acompañado de una lámpara que le permitirá iluminar terrenos carentes de luz. En la parte delantera cuenta con un dispositivo acoplado a una cámara que tiene una capacidad de giro de 270º en horizontal y 60º en vertical. Todo esto añadido a la transmisión de audio nos permite tener un conocimiento del ambiente explorado casi tan bueno como si estuvieramos presentes ahí.

La imagen que se muestra a continuación es una muestra de lo que se visualiza en la estación de mando.


La transmisión de video en tiempo real de 4 orígenes o fuentes de manera concurrente fué uno de los principales problemas a solucionar. Otro fué el accionar de los mecanismos para lo cual se recurrio a la comunicación USB.

La transmisión de datos se basa en el estándar IEEE 802.11 y el control de los mecanismos del robot están bajo el protocolo USB. El robot lleva consigo una computadora portátil, la cuál en su primera fase se encarga de la emisión de los datos multimedia así como de la comunicación con la placa de control. En una siguiente fase está portátil realizará un tipo de procesamiento que prefiero aún no describir.


Como se recuerda, todo está programado en Java, usando Netbeans 6.7 IDE, pero por el uso de determinadas librerías con JNI no se puede hablar de portabilidad, pero sería interesante desarrollar este tipo de proyectos sobre alguna plataforma libre (Como GNU|Debian, mi favorita).

Para cerrar el post les comento que se está trabajando, a la fecha, en un segundo prototipo que se asemjará más a los Sword robots de Foster Miller Inc.

martes, 15 de diciembre de 2009

Graficador de espectros de audio

El procesamiento digital de señales es un área de la ingeniería que se dedica al análisis y procesamiento de señales (audio, voz, imágenes, video) que son discretas. Aunque comúnmente las señales en la naturaleza nos llegan en forma analógica, también existen casos en que estas son por su naturaleza digitales, por ejemplo, las edades de un grupo de personas, el estado de una válvula en el tiempo (abierta/cerrada), etc.
Se puede procesar una señal para obtener una disminución del nivel de ruido, para mejorar la presencia de determinados matices, como los graves o los agudos y se realiza combinando los valores de la señal para generar otros nuevos.[1] El procesamiento digital de audio es un tipo de procesamiento digital de señales especializado en el tratamiento de la señal de audio.Una señal digital no es audible, ya que requiere ser decodificada antes de su reproducción.[2]

En este post vamos a hablar acerca de la graficación del espectro de audio de un archivo *.wav o *.aif. Pero antes de explicar cómo se realiza la graficación de audio en java, tenemos que tener en cuenta una serie de conceptos que nos ayudarán a comprender mejor la esencia de este proceso.

Primero voy a definir lo que a partir de ahora será Audio Digital.

AUDIO DIGITAL: Proceso de representar una señal de audio como un flujo de
datos numéricos para efectos de almacenamiento, procesamiento o
transmisión. De esta manera prácticamente se elimina la posibilidad de
ruidos o errores en la lectura.

Para poder graficar un archivo de audio lo primero que tenemos que hacer es acceder a los datos numéricos que representan al fichero de audio como una estructura digital. Para eso tendremos que leer el archivo como indico en el siguiente segmento de código:

int totalFramesLeidos = 0;
int totalBytesLeidos = 0;
try {
    AudioInputStream flujoEntradaAudio = AudioSystem.getAudioInputStream(fichero);
    int bytesPorFrame = flujoEntradaAudio.getFormat().getFrameSize();
    int numBytes = 1024 * bytesPorFrame;
    byte[] audioBytes = new byte[numBytes];
    // longitud de archivo de audio en bytes
    int longitudArchivoBytes=(int)flujoEntradaAudio.getFormat().getFrameSize()*(int)flujoEntradaAudio.getFrameLength();
    // objeto datos mas informacion ver clase Datos.java
    Datos datos = new Datos(longitudArchivoBytes,flujoEntradaAudio.getFormat().isBigEndian());
    byte[] datosTemporal=new byte[longitudArchivoBytes];
    int pos=0;
    /* el siguiente procedimiento lee los bytes del archivo de audio a memoria */
    try {
        int numeroBytesLeidos = 0;
        int numeroFramesLeidos = 0;
        while ((numeroBytesLeidos = flujoEntradaAudio.read(audioBytes)) != -1) {
            numeroFramesLeidos = numeroBytesLeidos / bytesPorFrame;
            totalFramesLeidos += numeroFramesLeidos;
            System.arraycopy(audioBytes, 0, datosTemporal, pos, numeroBytesLeidos);
            pos=pos+numeroBytesLeidos;
        }
        datos.llenarByte(datosTemporal);
        //datosVoz=new double[longitudArchivoBytes/bytesPorFrame];
        datosVoz = new ArrayList<Double>();
        datosVoz=datos.convertirByteADouble(longitudArchivoBytes/bytesPorFrame);
        frecuency.setMaximum((int) flujoEntradaAudio.getFrameLength()/100);
        int min = frecuency.getMinimum();
        int max = frecuency.getMaximum();
        frecuency.setValue((min+max)/2);
        ((PanelDeslizable)newContentPane).setIntervalo(frecuency.getValue());
        if(flujoEntradaAudio.getFormat().isBigEndian()) {
            System.out.println("BigEndian");
        } else {
            System.out.println("LittleEndian");
        }
        INFORMACION = flujoEntradaAudio.getFormat().toString();
        //obtiene la frecuencia de sampleo
        FRECUENCIA=(int)flujoEntradaAudio.getFormat().getSampleRate();
        ((PanelDeslizable)newContentPane).setDatos(datosVoz);
        ((PanelDeslizable)newContentPane).repaint();
    } catch (Exception ex) {
    }
}catch(Exception e) {
}

Bueno, en el segmento de código anterior, lo primero que se hace es leer el archivo de audio, luego ir leyendo por frames para poder tener la data en un vector el cual será luego procesado de acuerdo a lo que se quiera obtener.Con eso será suficiente para poder acceder al vector de datos numéricos o sample (Cada uno de los valores que se obtienen del proceso de sampleo. Cada una está cuantizada en una cantidad determinada de bits) que representan un archivo de audio. Se observa también la presencia de una clase, la clase Datos la cuál se encarga de realizar las conversiones respectivas del tipo de datos puesto que un archivo wav es un archivo binario y nosotros procesaremos la data con un tipo de dato más adecuado (Double por ejemplo).

El código que muestro a continuación pertenece a esta clase Datos:

package com.blogspot.rolandopalermo.util;
import java.util.ArrayList;
import java.util.List;
public class Datos {
    byte[] bits ;
    boolean formato;  // para el formato bigEndian y littleEndian
    double mayor, menor;

    public  Datos(int tamano, boolean formato) {
        bits = new byte[tamano];
        this.formato = formato;
        mayor = 0;
        menor = 0;
    }

    public void llenarByte(byte[] bits) {
        this.bits = bits;
    }

    /* ejemplo bits[2]=2 (00000010) bits[3]=3 (00000011)
     se aplica bits[2]<<8 o sea 10 00000000 , luego 11111111(0x000000FF) & bits[3]|bits[2]
     en total da 10 00000011  que es el numero 515 , este es un short de 16 bits , han entrado
     dos bytes en uno (short[i]=contacenar byte[i]+byte[i+1])
     los valores negativos estan en complemento a 2
     */

    public List<Double> convertirByteADouble(int size) {
        List<Double> arrayDouble = new ArrayList<Double>();
        //double[] arrayDouble = new double[bits.length/2];
        if (formato==true) {
            int temp = 0x00000000;
            for (int i = 0, j = 0; j < size ; j++, temp = 0x00000000) {
                temp=(int)bits[i++]<<8;//System.out.println("temp = "+ temp);
                temp |= (int) (0x000000FF & bits[i++]);
                //arrayDouble[j]=(double)temp;
                arrayDouble.add(j, (double)temp);
            }
            return arrayDouble;
        }
        if(formato==false) {  // si el formato es littleEndian
            int temp = 0x00000000;
            for (int i = 0, j = 0; j < size ; j++, temp = 0x00000000) {
                temp=(int)bits[i+1]<<8;//System.out.println("temp = "+ temp);
                temp |= (int) (0x000000FF & bits[(i)]);
                i=i+2;
                arrayDouble.add(j, (double)temp);
                //calcular mayor y menor esto me servira para establecer
                //los parametros en el eje y para la grafica
                if(mayor<arrayDouble.get(j)) {
                    mayor=arrayDouble.get(j);
                }
                if(menor>arrayDouble.get(j)) {
                    menor=arrayDouble.get(j);
                }
            }
            return arrayDouble;
        } else {
            System.out.println("Orden de Bytes desconocido o no soportado");
        }
        return arrayDouble;
    }
}

La forma de graficarlos dependerá de las necesidades que se tenga así como de otros factores como por ejemplo:

FRECUENCIA DE SAMPLEO O MUESTREO: Velocidad, en Hertz, a la cual se extraen las muestras de una señal de audio. Tiene directa relación con el ancho de banda que se obtendrá. Mientras mayor sea la Frecuencia de sampleo, mejor es la respuesta de agudos.

CUANTIZACIÓN: Es el proceso de asignar a una escala "redondeando al peldaño más cercano" el valor de cada muestra. Esta cantidad está determinada por el número de bits utilizados. La cuantización tiene directa relación con el rango dinámico (nivel de ruido) de la señal.

Evidentemente todos estos valores tienen que estar presentes como parámetros al momento de graficar el espectrograma que representará al archivo de audio. Yo recomiendo sean atributos de la clase encargada de mostrar los datos en modo gráfico. En el caso del proyecto que realizé, esta clase tiene el valor de PanelDeslizable (Deslizable puesto que si el gráfico es más grande que la pantalla entonces automáticamente aparecerá un scroll que nos permitirá ubicarnos en la posición que deseemos). El código de esta clase la muestro a continuación:

package com.blogspot.rolandopalermo.gui;
import java.awt.BorderLayout;
import java.awt.Color;
import java.awt.Dimension;
import java.awt.Graphics;
import java.awt.event.ActionEvent;
import java.awt.event.ActionListener;
import java.awt.image.BufferedImage;
import java.io.File;
import java.io.IOException;
import java.util.List;
import javax.imageio.ImageIO;
import javax.swing.JPanel;
import javax.swing.JScrollPane;
import javax.swing.Timer;

//@author Rolando

public class PanelDeslizable extends JPanel {

    private Dimension area; //indicates area taken up by graphics
    //private Vector<Rectangle> circles; //coordinates used to draw graphics
    private JPanel drawingPane;
    private Timer reloj;
    private List<Double> datos;
    private int w;
    private int h;
    private static int x0 = 15;
    private int y0;
    private int intervalo;
    private int temporizador;
    private int fin;
    private double  escalaX;
    private double escalaY;
    private Color gridcolor;
    private Color ejescolor;
    private Color texto;
    private Color espectrogramac;
    private Color background;
    private Color player;
    private boolean dibujargrid;
    private boolean dibujarejes;
    private boolean dibujarespectrograma;
    private String informacion;

    public PanelDeslizable(final int w, final int h) {
        super(new BorderLayout());

        background = Color.BLACK;
        gridcolor = new Color(120, 176, 145);
        ejescolor = Color.YELLOW;
        texto = Color.YELLOW;
        player = Color.RED;
        //espectrogramac = new Color(85, 255, 255);
        espectrogramac = Color.GREEN;
        
        area = new Dimension(0,0);

        //Set up the drawing area.
        drawingPane = new DrawingPane();
        drawingPane.setBackground(background);
        //drawingPane.addMouseListener(this);

        //Put the drawing area in a scroll pane.
        JScrollPane scroller = new JScrollPane(drawingPane);
        scroller.setPreferredSize(new Dimension(200,200));

        add(scroller, BorderLayout.CENTER);

        datos = null;

        this.w  = w;
        this.h  = h;
        this.y0 = h/2;

        intervalo = 1;

        temporizador = 0;
        fin = 0;

        escalaX = 1;
        escalaY = 1;

        dibujargrid = true;
        dibujarejes = true;
        dibujarespectrograma = false;

        informacion = null;

        reloj = new Timer (1, new ActionListener() {
            public void actionPerformed(ActionEvent e) {
                temporizador = temporizador + 1;
            }
        });

    }

    /** The component inside the scroll pane. */
    class DrawingPane extends JPanel {
        @Override
        protected void paintComponent(Graphics g) {
            super.paintComponent(g);
            w  = getSize().width;
            h  = getSize().height;
            y0 = h/2;
            if(dibujargrid) {
                graficarGrid(g);
            }
            if(dibujarejes) {
                graficarEjes(g);
            }
            if(dibujarespectrograma) {
                graficarEscpectrograma(g);
            }
            if(informacion!=null) {
                g.setColor(texto);
                g.drawString(informacion, 20, 20);
            }
        }
    }

    public void graficarGrid(Graphics g) {
        g.setColor(gridcolor);
        for( int i=0; i < w; i+=15) {
            for(int j=0; j<h; j+=40) {
                g.drawLine(i,j,i,h);
                g.drawLine(i,j,w,j);
            }
        }
    }

    public void graficarEjes(Graphics g) {
        g.setColor(ejescolor);
        linea(0,0,w,0,g);
        linea(0,y0,0,-y0,g);
    }

    public void graficarEscpectrograma(Graphics g) {
        g.setColor(espectrogramac);
        int length = datos.size();
        int[] puntoP = new int[2];
        int i, xi=0,xf=0,yi=0,yf=0;
        for(i=0; i<length-intervalo; i+=intervalo) {
            puntoP[0]=(int) (i * escalaX);
            puntoP[1]=(int) (datos.get(i) * escalaY);
            xi = puntoP[0];
            yi = puntoP[1];
            puntoP[0]=(int) ((i + intervalo) * escalaX);
            puntoP[1] = (int) (datos.get(i+intervalo) * escalaY);
            xf = puntoP[0];
            yf = puntoP[1];
            linea(xi, yi, xf, yf, g);
        }
        fin = xf;
        if(xf>w) {
            area.width = xf+100;
            drawingPane.setPreferredSize(area);
            drawingPane.revalidate();
        }
    }
  
    public void iniciarReproduccion() {
        //setTocar(true);
        temporizador = 0;
        reloj.start();
    }

    public void detenerReproduccion() {
        reloj.stop();
    }

    public void reiniciarReproduccion() {
        temporizador = 0;
        reloj.stop();
    }

    public void save(File fichero) {
        BufferedImage imagen = new BufferedImage(w, h, BufferedImage.TYPE_INT_RGB);
        Graphics g = imagen.getGraphics();
        drawingPane.paint(g);
        // Escribimos la imagen en el archivo.
        try {
            ImageIO.write(imagen, "jpg", fichero);
        } catch (IOException e) {
            System.out.println("Error de escritura");
        }
    }

    public void ajustarDimension() {
        area.width=0;
        drawingPane.setPreferredSize(area);
        drawingPane.revalidate();
    }

    public void setDibujargrid(boolean dibujargrid) {
        this.dibujargrid = dibujargrid;
    }

    public void setGridcolor(Color gridcolor) {
        this.gridcolor = gridcolor;
    }

    /**
    *  Dibuja una linea desde (x1,y1) hasta (x2,y2).
    *  @param x1 Coordenada x del punto de origen.
    *  @param y1 Coordenada y del punto de origen.
    *  @param x2 Coordenada x del punto de destino.
    *  @param y2 Coordenada y del punto de destino.
    */
    public void linea(double x1, double y1, double x2, double y2, Graphics g) {
        g.drawLine((int)Math.round(x1+x0),
                (int)Math.round(y0-y1),
                (int)Math.round(x2+x0),
                (int)Math.round(y0-y2));
    }

    public void setInformacion(String informacion) {
        this.informacion = informacion;
    }

    public void setDibujarejes(boolean dibujarejes) {
        this.dibujarejes = dibujarejes;
    }

    public void setDibujarespectrograma(boolean dibujarespectrograma) {
        this.dibujarespectrograma = dibujarespectrograma;
    }

    public void setDatos(List<Double> datos) {
        this.datos = datos;
    }

    public void setIntervalo(int intervalo) {
        this.intervalo = intervalo;
    }

    public void setEscalaY(double escalaY) {
        this.escalaY = escalaY;
    }

    public void setEscalaX(double escalaX) {
        this.escalaX = escalaX;
    }
}

Los archivos que se pueden procesar de esta forma pueden tener el formato WAV o AIF como se había mencionado anteriormente. Acá les dejo algunos screenshots de la aplicación que he escrito en java para graficar espectros de audio:

En Windows:

Photobucket

Photobucket

Photobucket

Photobucket

En Linux:
Photobucket

Photobucket

En la imágen que muestro a continuación se aprecia el árbol de clases del proyecto el cuál fué realizado en netbeans:


A continuación dejo el código fuente para que lo puedan leer y si es posible continuar con el trabajo puesto que hay muchas cosas por mejorar.

Photobucket

Y aquí algunos ejemplos para que puedan probar el programa

Photobucket

Pueden también visitar el blog un gran amigo, Jorge Valverde, quien es un destacado investigador. Ahí podrán encontrar una explicación un poco más detallada de este proceso.

lunes, 7 de diciembre de 2009

Algoritmo de Lamport para la Sincronización de Relojes Lógicos en Sistemas Distribuidos

La sincronización en sistemas distribuidos consiste en garantizar que los procesos se ejecuten en forma cronológica y a la misma vez respetar el orden de los eventos dentro del sistema. En el caso de sistemas de una sola CPU, este problema se resuelve usando semáforos, pero en sistemas de múltiples CPUs la solución ya implica el uso de otros métodos o algoritmos, para garantizar no solo la comunicación entre procesos sino también la forma como estos cooperan entre sí.
Esta sincronización, en sistemas distribuidos, se hace más compleja que en los sistemas centralizados puesto que la información y el procesamiento se mantienen en diferentes nodos. La sincronización de relojes en sistemas distribuidos nos permite garantizar que los procesos se ejecutan cronológicamente y además respetar el orden de los eventos dentro del sistema.

Las computadoras poseen un circuito para el registro del tiempo conocido como dispositivo reloj. Es un cronómetro consistente en un cristal de cuarzo de precisión sometido a una tensión eléctrica.

Para una computadora y un reloj no interesan pequeños desfasajes del reloj porque:

Todos los procesos de la máquina usan el mismo reloj y tendrán consistencia interna.
Importan los tiempos relativos.

Para varias computadoras con sus respectivos relojes:

Es imposible garantizar que los cristales de computadoras distintas oscilen con la misma frecuencia.
Habrá una pérdida de sincronía en los relojes (de software), es decir que tendrán valores distintos al ser leidos.

"La diferencia entre los valores del tiempo se llama distorsión del reloj y podría generar fallas en los programas dependientes del tiempo."

Luego de esta pequeña introducción a la sincronización vamos a hablar acerca del Algoritmo de Lamport. Y es que en este post hablaremos de la propuesta que hizo el científico en computación Dr Leslie Lamport.

Lamport señaló que la sincronización de relojes no tiene que ser absoluta.
Si 2 procesos no interactúan no es necesario que sus relojes estén sincronizados.
Generalmente lo importante no es que los procesos estén de acuerdo en la hora, pero sí importa que coincidan en el orden en que ocurren los eventos.

Y es aquí dónde aparece el concepto de reloj lógico. Un reloj lógico de Lamport es un contador software que se incrementa monótonamente, cuyos valores no necesitan tener ninguna relación particular con ningún reloj físico.

Para sincronizar los relojes lógicos, Lamport definió la relación ocurre antes de(happens-before):

Si “a” y “b” son eventos en el mismo proceso y “a” ocurre antes de “b”, entonces “a –> b” es verdadero.
“Ocurre antes de” es una relación transitiva:
Si “a –> b” y “b –> c”, entonces “a –> c”.
Si dos eventos “x” e “y” están en procesos diferentes que no intercambian mensajes, entonces “x –> y” no es verdadero, pero tampoco lo es “y –> x”:
Se dice que son eventos concurrentes.

Necesitamos una forma de medir el tiempo tal que a cada evento “a”, le podamos asociar un valor del tiempo “C(a)” en el que todos los procesos estén de acuerdo:

Se debe cumplir que:
o Si “a –> b” entonces “C(a) < C(b)”.
o El tiempo del reloj, “C”, siempre debe ir hacia adelante (creciente), y nunca hacia atrás (decreciente).

El algoritmo de Lamport asigna tiempos a los eventos.

Una vez descrito el algoritmo, pasaré a mostrar su implementación en java. La primera imágen corresponde a una simulación similar a la mostrada en la imágen anterior y que puede ayudarnos a comprender mejor el funcionamiento de este algoritmo.


En la imágen siguiente, vemos que al querer enviar un mensaje del proceso 3 en un instante de tiempo 4 al proceso 2 en un instante de tiempo 3, el algoritmo exige la sincronización de los relojes logicos de los CPUs donde se encuentran los procesos anteriormente numerados. Basta dar clic en el botón sincronizar para ver los cambios en los vectores de tiempo de ambos procesos, mientras que el resto de procesos no sufren alteración alguna, tal y como lo describe el algoritmo de Lamport.


Espero que la explicación y esta simulación(que puedes descargar aquí) te sean de utilidad. También pueden revisar este post relacionado a los algoritmos de planificación y paginación de procesos.

jueves, 3 de diciembre de 2009

Cómo configurar Flex en Windows

¿A cuántos de nosotros, durante nuestras carreras en la Universidad, nos han pedido como proyecto hacer un analizador léxico, hacer un compilador o cosas afines?, ¿A cuántos de nosotros se nos pasó el tiempo, y sobre la hora queremos desarrollar estos proyectos desde cero? ¿A cuántos de nosotros nos fascinaría estructurar nuestro propio lenguaje o quizás desarrollar nuestro propio compilador? ... Pues en este post les presentó la herramienta básica de quien se aventura (y también para quién solo está de pasada) en este maravilloso mundo de los compiladores y otros programas que no son exactamente compiladores, pero que presentan algunas características de estos como los coloreadores de código.
Flex es una herramienta para generar escáneres, es decir programas que reconocen patrones léxicos en un texto. En otras palabras, flex se encarga de convertir esos patrones léxicos en tokens que pueden servir para estructurar una gramática (en el caso de un compilador) o para colorear código (En caso de un coloreador de código).
A continuación mostraré un ejemplo de script para flex:

%{
#include <stdio.h>
#include <conio.h>
int num_lineas = 0, num_caracteres = 0;
%}
%option noyywrap
%option yylineno
letra [a-zA-Z]
digito [0-9]
binario [0-1]
ignora " "|\t|\n
operarit *|+|-|/
operlog &|$
comparador <|>|<=|>=|==|!=
%%
{ignora}+                   {;}
{letra}({letra}|{digito})*  {printf("IDENTIFICADOR\n");}
{letra}+                    {printf("CADENA\n");}
{binario}+                  {printf("BOOLEANO\n");} 
{digito}+                   {printf("ENTERO\n");}
{digito}+"."{digito}+       {printf("REAL\n");}
{comparador}                {printf("COMPARADOR\n");}
":="                        {printf("ASIGNADOR\n");}
";"                         {printf("PUNTO_COMA\n");}
"!="                        {printf("DIFERENCIA\n");}
","                         {printf("COMA\n");}
"=="                        {printf("IGUAL\n");}
"."                         {printf("PUNTO\n");}
">="                     {printf("MAYOR_IGUAL\n");}
"<="                     {printf("MENOR_IGUAL\n");}
"("                         {printf("OPEN_PARENTESIS\n");}
")"                         {printf("CLOSE_PARENTESIS\n");}
">"                      {printf("MAYOR\n");}
"<"                      {printf("MENOR\n");}
"{"                         {printf("OPEN_LLAVE\n");}
"}"                         {printf("CLOASE_LLAVE\n");}
"+"                         {printf("SUMA\n");}
"-"                         {printf("RESTA\n");}
"*"                         {printf("MUTIPLICACION\n");}
"/"                         {printf("DIVISION\n");}
"&"                         {printf("AND\n");}
"$"                         {printf("OR\n");}
\n                          ++num_lineas;
.                           {printf("ERROR LEXICO EN LINEA %d \n",yylineno);}
%%
int main(int argc,char *argv[])
{
    char NomArch[30];
    printf("Ingrese nombre de archivo: ");
    gets(NomArch);
    if ((yyin = fopen(NomArch, "rt")) == NULL)
    {
        printf("\nNo se puede abrir el archivo: %s\n", NomArch);
    }
    else
    {
        yylex();
    }
    fclose(yyin);
    getch();
    return 0;
}

Ahora bien, este script debemos enviarlo al Flex para que nos retorne un archivo en lenguaje C el cuál podemos integrar a nuestro proyecto que estamos realizando, de manera sencilla.

Lo primero que debemos hacer es descargar el archivo djgpp.rar, crear una carpeta llamada DJGPP en la unidad D:\ y descomprimir todos los archivos del *.rar aquí.


Luego debemos crear una carpeta en la unidad D:\ llamada PRUEBAS. Con esto será suficiente, pero es bueno recordar que las rutas son relativas. Eso sí, al momento de configurar las variables de entorno debemos tener cuidado de la ubicación de ambas carpetas.

Bueno, el siguiente paso es configurar el Flex para lo cuál haremos lo siguiente:
1. Presionar window+r y escribir cmd. Se abrirá la consola del windows, ahí debemos escribir lo siguiente:

d:
cd PRUEBAS
set djgpp=d:\djgpp\djgpp.env
set path=d:\djgpp\bin
flex -oanalisis.c FLE.L

 

Con esto se generará un archivo llamado analisis.c el cuál podemos integrarlo a nuesto proyecto en C. En este caso el archivo tiene su función main por lo que puede trabajar por si solo. Al ejecutar y enviarle un archivo con patrones léxicos veremos que nos devolverá los tokens correspondientes.

Acá les dejo un proyecto en Dev-C++, en la carpeta hay un archivo llamado test.txt el cuál es la entrada al programa.

Espero les sea de utilidad, y en un siguiente post explicaré como utilizar el Bison para analizar sintácticamente estructuraras más complejas como son las gramáticas.

Pueden revisar este post que explica cómo usar Bison en Windows:
O para algo más aplicativo puedes revisar esto:

miércoles, 2 de diciembre de 2009

Sistema experto para la detección de plagas en sembríos de Tara

Los Sistemas Expertos (SSEE), uno de los campos en que se divide la Inteligencia Artificial, han levantado un gran interés en los últimos cinco años entre los expertos de diversas áreas no relacionadas con la computación, como por ejemplo el sector agroindustrial. Las posibilidades de utilización de los SSEE en control agroindustrial, son amplias y esperanzadoras. Van desde la identificación de plagas que atacan un sembrío hasta la obtención de recomendaciones para el control de las mismas.
SKADEDJUR es un sistema experto diseñado con el fin de proporcionar consejos a los agricultores sobre las diferentes plagas que atacan a los cultivos de Tara. Las tareas implicadas en el cultivo de la Tara, que acotan el contexto de SKADEDJUR son:
  • El diagnóstico de plagas y su tratamiento.
  • El diagnóstico de plagas se realiza a partir de los síntomas observados.
 
 
En función de la plaga diagnosticada y de su grado de levedad, se dictamina un plan de tratamiento para la planta infectada. Un plan de tratamiento debe especificar un conjunto de recursos necesarios, un método de aplicación, un tiempo de aplicación y otros consejos adicionales. En principio pensamos modelar los “recursos necesarios” “métodos y tiempos de aplicación” “consejos adicionales” como conceptos diferenciados del “plan de tratamiento” porque se les supone una cierta complejidad, aunque al profundizar en las descripciones que manejamos decidimos modelarlos como atributos del concepto “plan de tratamiento”.



Evidentemente para poder llegar a un diagnóstico desde los síntomas, se asume la existencia de una relación causa-efecto, formando una estructura más o menos compleja, pero que permitiría por recubrimiento llegar a las causas/diagnóstico de los efectos/síntomas de entrada.

El código fuente del sistema experto ha sido escrito en prolog usando el entorno de SWI Prolog. Presenta una interfaz gráfica sencilla, la cuál fué estructurada gracias a las librerías XPCE que el entorno antes mencionado trae consigo.

El Manual de usuario lo puedes descargar aquí.
El Informe del proyecto lo puedes descargar aquí.
El Artículo referente al proyecto lo puedes descargar aquí.
El código fuente lo puedes descargar aquí.

Recuerden que dentro de la carpeta programa hay un archivo léeme.txt es cuál es muy importante que lo lean, o en todo caso lean estos tips para poder ejecutar el sistema experto y generar su respectivo ejecutable:

1. Primero debes crear una carpeta en tu unidad C:\ llamado programa.
2. Dentro de C:\programa descomprimes todos los archivos de programa.rar
3. Descarga
- Instala primero el swi prolog
- Luego dentro de setup.rar, que es el instalador del swi prolog editor, dale doble clic al archivo setup.exe
- Siguiente, siguiete y listo.
4. Abre el swi prolog editor y asegúrate de cerrar todos los archivos anteriormente trabajados haciendo clic en menú
Archivo y cerrar todo.
5. Abre el archivo proyectofinal.pl que está en C:\ llamado programa y luego en menú iniciar, dar clic a consultar.
6. En la parte inferior, en el editor de consultas escribe lo siguiente sin comillas: "main."
7. Listo, tenemos nuestro sistema experto ejecutándose.

martes, 1 de diciembre de 2009

JInti, una simulación de sistema operativo en java

En este post quiero hablar de Sistemas Operativos, un área de interés para la comunidad informática puesto que es la base de todo lo que, sobre ella, se puede estructurar, desarrollar, implementar, programar o como se quiera decir al hecho de realizar una aplicación informática. Durante el curso de Sistemas Operativos I que se imparte en mi escuela, se desarrolla una serie de algoritmos en sistemas operativos centralizados. Estos algoritmos están orientados a la gestión de procesos; como puede mecanismos de sincronización, priorización de procesos entre muchas otras cosas.
Y es justo la priorización de procesos uno de los temas bases y que se merecen un gran estudio puesto que de los algoritmos que seleccionemos para este hecho dependará en gran medida el rendimiento del sistema operativo que se esté implementando.

Para la gestión de procesos existen muchos algoritmos. La siguiente lista es una muestra de ello:
1. Planificación a Plazo Fijo
2. Planificación Garantizada
3. Planificación del Primero en Entrar Primero en Salir (FIFO)
4. Planificación de Asignación en Rueda (RR: Round Robin)
5. Tamaño del Cuanto o Quantum
6. Planificación del Trabajo Más Corto Primero (SJF)
7. Planificación del Tiempo Restante Más Corto (SRT)
8. Planificación el Siguiente con Relación de Respuesta Máxima (HRN)
9. Planificación por Prioridad
10. Colas de Retroalimentación de Niveles Múltiples
11. Política Versus Mecanismo de Planificación
12. Planificación de Dos Niveles

Ahora otro concepto importante es la paginación de memoria, que consiste en dividir los programas en páginas(pequeños segmentos de programa). Así mismo la memoria es dividida en trozos del mismo tamaño que las páginas llamados marcos de página. De esta forma, la cantidad de memoria desperdiciada por un proceso es el final de su última página, lo que minimiza la fragmentación interna y evita la externa.

Una vez defenidos estos conceptos básicos, paso a explicar lo que es JInti. JInti es una simulación de sistema operativo que, basado en el algoritmo FIFO (First In, First Out "primero en entrar, primero en salir") para la gestión de procesos y en el algoritmo LRU ("Menos usada recientemente" o "Least Recently Used") para la determinación de qué páginas pueden ser sacadas de memoria cuando se necesita cargar una nueva y ya no hay espacio, muestra el funcionamiento de los mencionados algoritmos con procesos semi-reales cargados por el usuario en tiempo de ejecución y de manera concurrente. No es una una simulación completa, por lo que he decido liberar el código de JInti y volverlo OpenSource para que de ese modo alguién más pueda trabajar sobre esto e ir incrementando las capacidades de este simulador. A continuación muestro un screenshot de JInti:

La descarga la puedes realizar aquí, es un proyecto que ha sido realizado usando Netbeans, solo tienes que correr el proyecto y darle clic en los iconos de las aplicaciones que ahí aparecen. Para ver el administrador de procesos solo debes presionar F1 y verás como van cambiado los procesos que acceden al procesador y cómo se va realizando la paginación de los mismos.

domingo, 22 de noviembre de 2009

Semana de la Ciencia de la Computación

Y bueno, un poco tarde pero comentando sobre la SECICOMP. Para los que no saben, SECICOMP es Semana de la Ciencia de la Computación y se realiza anualmente en mi escuela, La Escuela de Informática. Este año se realizó por cuarta vez y bueno, no fué la excepción para que presente algún proyecto (A excepción de la SECICOMP 2007). A diferencia de otros años, la exposición de los trabajos se realizó frente al pabellón de la facultad de derecho con la finalidad de promocionar un poco más lo que se puede hacer en nuestra escuela.
La diversidad de proyectos y las áreas temáticas que estos expusieron dejó entrever la capacidad de los estudiantes de Informática, abordando temas desde puntos de vista tanto ingenieríl como científico, y algunos casos mezclando las capacidades de ambas perspectivas. Si bien es cierto no se logró la afluencia de público que se esperaba, la calidad del trabajo de mis compañeros organizadores y despliegue que este tuvo fué unos de los mejores que se ha visto.

Con ansias espero la SECICOMP 2010, aunque evidentemente ya no podré participar como estudiante y quizás ya no presente ningún proyecto de esos que parecen que van a estallar o que se desarmarán al primer movimiento, pero si espero poder apoyar en la organización, cosa que no hice en las versiones anteriores de la SECICOMP por cuestiones personales.

A través de este post dejo abierta la invitación a la gente que quiera participar en la SECICOMP 2010, para que vayan pensando algún proyecto y ¿por qué no? a los chicos que gustan de hacer cosas como las que solía hacer, para poder trabajar en conjunto o quizás brindándoles algunas ideas.

Cierro este post felicitando a la comisión organizadora de la IV SECICOMP y esperando con ansias la V SECICOMP.

jueves, 19 de noviembre de 2009

Ciencia de la Computación

Por ser este mi primer post quiero hablar de mi escuela, La Escuela de Informática de la Universidad Nacional de Trujillo. Y le dedico el post porque ocurre algo curioso, y es que cuando aún era un estudiante del 5 de secundaria del colegio San Juan estaba en el dilema de miles de jovenes peruanos: "¿Qué estudiar en la universidad?". Lógicamente la tecnología era lo que más me llamaba la atención y habían tres opciones: Ingeniería de Sistemas, Ingeniería Informática o Ingeniería Electrónica. Ya cuando llegó el momento de la decisión la opción fué obviamente Ingeniería Informática en la UNT por supuesto. Al ingresar me di con la sorpresa que no era Ingeniería Informática lo que iba a estudiar, ni siquiera Informática, sino más bien Ciencia de la Computación. ¿Ciencia de la Computación? ... jamás había escuchado de eso, o sea estaba estudiando algo que no sabia que era. Lógicamente mi primera reacción fué informarme más pero la gente de ciclos superiores estaba tan confundida como yo. Luego un grupo de compañeros entro al salón de clases y nos habló de la ACM y de la Ciencia de la Computación. No me pareció mala opción y con tanta diapositiva terminé tranquilizándome y aceptando lo que estudiaría.

Bueno, los ciclos transcurrían y las ideas empezaban a aclararse, cursos por acá, cursos por allá, papers por acá, artículos por allá ... vaya que si empezaba a confundira la situación nuevamente. Y por si fuera poco hasta los mismos docentes se contradecían y se siguen contradiciendo. Cada profesor tiraba para su lado (o "área de investigación" como ellos suelen llamar) y nosotros cada vez más confundidos. Luego se empezó a organizar ferias dentro la escuela y, fiel a mi estilo, me animé a participar. Curiosamente en una de estas ferias llegó una "eminencia" de la Ciencia de la Computación y en una de sus charlas dijo ser Ingeniero de Sistemas pero que se ¡arrepentía! de serlo. Al escuchar esto me sentí avergonzado por los compañeros de ingeniería de sistemas que, estando presentes, no tuvieron el respeto que se merecen, más aún si están colaborando con nuestra feria. sobre todo por parte de este tipo ("científico") que siguió hablando y hablando de la "ciencia de la computación".

Con un montón de experiencias de este tipo ha transcurrido casi toda mi carrera, con compañeros que dicen hacer ciencia y criticando, destructivamente, a quien no siga su línea. Lo curioso de todo esto es que acabando sus tristes carreras no hacen nada de investigación y terminan siendo parte de la masa que tanto criticaban.

Es realmente lamentable todo lo que ocurre en mi escuela, cada vez peor. Quizás haya gente a quien no le guste lo que escribo pero, es la verdad. A este paso no se sabe a donde llegaremos con "investigadores" que solo saben criticar y que no hacen nada concreto por mejorar esta situación, puesto que su pensamiento tan cerrado, y hasta cierto punto tonto, ha sido transmitido a algunos compañeros que dicen hacer ciencia. Si ven un sistema informático dicen que es Ingeniería de Sistemas, si ven un circuito integrado dicen que es electrónica, si ven un motor dicen que es mecánica, para ellos ciencia de la computación es un paper o un algoritmo con entradas predefinidas, para ellos solo existen los paper y sus "complejos algoritmos". Es una pena que gente de este tipo siga contaminando nuestra escuela y siga fomentando sus ideologías a las futuras promociones. Es claro que acabando la universidad gente que se vió arrastrada por estos "personajes" tienen que seguir cursos técnicos puesto que no han recibido la correcta formación como científicos, salvo rescatables excepciones.

A todo esto, yo creo deberíamos empezar por cambiar el nombre de nuestra carrera y la currícula, que a pesar de ya haberse hecho los cambios en esta, está peor que antes, es una ofensa a la "Ciencia de la Computación" y a los alumnos que se basarán en ella.

Como primer post ya fue suficiente. Ya comenté mis ideas y siempre diré que yo estudio Ingeniería Informática.