Code Segment

PolarShow 0.70

Jan 29 2010 by csegura @ 23:29

Mi pequeño proyecto PolarShow ha tomado un poquito más de cuerpo, estoy ya en la versión 0.70 y prácticamente tiene ya todas las características que se pueden encontrar en polarpersonaltrainer.com

En esta versión hay un calendario con un resumen semanal de las sesiones de entrenamiento

También he ajustado algunos de los gráficos para que se muestren más claramente, el gráfico de sesiones por defecto muestra las 10 últimas sesiones salvo que se seleccionen otras

Una cosa interesante es la agregación, en el momento que hemos seleccionado un conjunto de sesiones podemos ver agregados los resultados, mostrando el total de Km, el total de entrenamiento y las medias de velocidad y pulsaciones,

Las “Auto Laps” quedan agregadas de modo que podemos ver un gráfico completo por ejemplo de una semana completa.

Una cosa interesante es que ahora se pueden editar los archivos xml que hemos extraído del reloj pudiendo añadir notas, una clasificación de cómo te has sentido en el entrenamiento y una url (por ejemplo a GPSSies) con la ruta que has seguido.

También como no he solucionado un montonazo de bugs…

Podeís descargar esta versión desde aquí.

Comments (0)

Fuzzy Logic y expresiones lambda

Jan 16 2010 by csegura @ 01:33

Para un proyecto que estoy realizando, he realizado una prueba de concepto probado a aplicar lógica difusa con el fin de realizar ciertas acciones a partir de una serie de datos imprecisos.


A la hora de expresar las reglas encargadas de modelar nuestro sistema de lógica difusa, (IF-THEN) la mayoría de los sistemas que he visto requerían de un pequeño y simple analizador sintáctico para interpretar las reglas, en este punto me he preguntado si en vez de un analizador sintáctico, podríamos usar expresiones lambda y una interfaz fluida.

FuzzySystem (improvisado)

De modo que he construido un pequeño motor de lógica difusa que tiene la particularidad de usar expresiones lambda y una interfaz fluida para definir el conjunto de reglas.
Este pequeño motor incorpora un par de funciones miembro, una de tipo Trapezoide y otra Triangular, básicamente su uso es el siguiente.
Definimos el sistema, añadimos las variables con sus estados y funciones miembro…

    public class FuzzyTest
    {
        private readonly FuzzySystem _engine = new FuzzySystem();

        public FuzzyTest()
        {
            FuzzyVariable varA = new FuzzyVariable("A");
            varA.Memberships.Add(new TrapezoidMembership("Cerrado", 0, 0, 5, 5));
            varA.Memberships.Add(new TrapezoidMembership("Medio", 4, 4, 6, 6));
            varA.Memberships.Add(new TrapezoidMembership("Abierto", 7, 7, 9, 9));
            _engine.Variables.Add(varA);

            FuzzyVariable varB = new FuzzyVariable("B");
            varB.Memberships.Add(new TrapezoidMembership("Cerrado", 0, 0, 5, 5));
            varB.Memberships.Add(new TrapezoidMembership("Medio", 4, 4, 6, 6));
            varB.Memberships.Add(new TrapezoidMembership("Abierto", 7, 7, 9, 9));
            _engine.Variables.Add(varB);

            FuzzyVariable varR = new FuzzyVariable("R");
            varR.Memberships.Add(new TrapezoidMembership("Frio", 0, 0, 3, 3));
            varR.Memberships.Add(new TrapezoidMembership("Templado", 3, 3, 6, 6));
            varR.Memberships.Add(new TrapezoidMembership("Caliente", 7, 7, 9, 9));
            _engine.Variables.Add(varR);

 

La definición de reglas mediante expresiones Lambda

El beneficio en este punto es que el sistema no requiere del analizador sintáctico para evaluar las expresiones si no que será el CLR quien se encargue de ello.
Para llevar a cabo esta evaluación de las reglas he definido una clase FuzzyExpresion que tiene definidos  los operadores && y || para así como el true y el false para poder evaluar las reglas en consecuencia.

    public class FuzzyExpression
    {
        private readonly FuzzyVariable _variable;
        private string _state;
        private double? _value;

        public double Value
        {
            get
            {
                if (_value.HasValue)
                    return _value.Value;
                _value = _variable.Fuzzify(State);
                return _value.Value;
            }
        }

        public string State
        {
            get { return _state; }
        }
      
        public FuzzyExpression(FuzzySystem engine, string literal)
        {
            _variable = engine.Variables[literal];
            
            if (_variable == null)
            {
                throw new FuzzyException("variable not found.");
            }
        }

        public FuzzyExpression(double value)
        {
            _value = value;
        }

        public FuzzyExpression Is(string state)
        {
            _state = state;
            _value = _variable.Fuzzify(_state);
            return this;
        }

        public FuzzyExpression Set(string newState)
        {
            _state = newState;
            return this;
        }

        public static FuzzyExpression operator |(FuzzyExpression a, FuzzyExpression b)
        {
            return new FuzzyExpression(Math.Max(a.Value, b.Value));
        }

        public static FuzzyExpression operator &(FuzzyExpression a, FuzzyExpression b)
        {
            return new FuzzyExpression(Math.Min(a.Value, b.Value));
        }

        public static bool operator false(FuzzyExpression a)
        {
            return 0 > a.Value;
        }

        public static bool operator true(FuzzyExpression a)
        {
            return a.Value > 0;
        }
    }

 

Las reglas en la lógica difusa sirven para combinar las distintas proposiciones, no son reglas excesivamente complicadas, y son del tipo IF-THEN, básicamente hay 4 reglas (Implicación Conjunción, Disyunción  y negación) que se corresponden con:

-    Implicación IF variable==estado THEN variable = estado
-    Conjunción, equivalente al AND, si dos proposiciones son ciertas simultáneamente
-    Disyunción, cualquiera de las dos proposiciones es cierta OR
-    Negación, invierte la proposición

Finalmente podemos definir las reglas de este modo

            _engine.AddRule(x =>
                            x.Variable("A").Is("Abierto") &&
                            x.Variable("B").Is("Abierto"))
                            .Then(x => x.Variable("R").Set("Caliente"));

            _engine.AddRule(x =>
                            x.Variable("A").Is("Abierto") &&
                            (x.Variable("B").Is("Cerrado") || x.Variable("B").Is("Medio")))
                            .Then(x => x.Variable("R").Set("Templado"));

            _engine.AddRule(x =>
                            x.Variable("B").Is("Abierto") &&
                            (x.Variable("A").Is("Cerrado") || x.Variable("A").Is("Medio")))
                            .Then(x => x.Variable("R").Set("Templado"));

            _engine.AddRule(x =>
                            x.Variable("A").Is("Cerrado") &&
                            x.Variable("B").Is("Cerrado"))
                            .Then(x => x.Variable("R").Set("Frio"));

¿Cómo funciona?

Una regla tiene una condición (IF) y una consecuencia (THEN), la condición es una función que recibe el sistema y debe devolver una FuzzyExpresion, (Func<FuzzySystem,FuzzyExpression>), esto es parte de la magia ya que una expresión condicional es siempre reducida a una única expresión y finalmente a un único valor.
Y curiosamente la consecuencia de la regla, es exactamente igual, solo que en este caso la expresión no devuelve nada porque la consecuencia es una acción, aquí hay otro pequeño truco que es que la propia regla contiene los dos elementos separados (condición y consecuencia) fijaros en que:

   _engine.AddRule(x =>
                        x.Variable("A").Is("Abierto") &&
                        x.Variable("B").Is("Abierto"))

Está devolviendo una regla y el método Then es aplicado sobre la regla, y cuando se evalúa la regla si la condición es cierta se evalúa la consecuencia, que lo que hace es únicamente cambiar el estado (ver el método Set de FuzzyExpression)

    public class FuzzyRule
    {
        private readonly FuzzySystem _engine;
        private readonly Func _condition;
        private Func _then;


        public double Value { get; set; }

        public FuzzySystem Engine
        {
            get { return _engine; }
        }

        public FuzzyRule(FuzzySystem engine, Func condition)
        {
            _engine = engine;
            _condition = condition;
        }

        public FuzzyExpression Eval()
        {
            Value = _condition(Engine).Value;

            if (Value > 0)
            {
                return _then(Engine);
            }

            return null;
        }

        public void Then(Func then)
        {
            _then = then;
        }     
    }

Defuzzyficando

Para evaluar nuestro sistema ..

 

            for (int a = 0; a < 10; a++)
            {
                for (int b = 0; b < 10; b++)
                {
                    _engine.Variables["A"].InputValue = a;
                    _engine.Variables["B"].InputValue = b;
                    _engine.Consecuent = "R";

                    var r = _engine.Defuzzy();

                    Console.WriteLine(string.Format("A {0} - B {1} = {2,-6} [{3,-10}][{4,-10}] = {5}", 
                        a, 
                        b, 
                        r, 
                        _engine.GetVariableState("A",a),
                        _engine.GetVariableState("B",b),
                        _engine.GetVariableState("R", r)));
                }
            }
        }

Mejoras de diseño

Hay una cosa que no me gusta mucho y es el hecho de que mi clase FuzzyExpression, tiene tanto el método Is como el método Set y esto habría que dividirlo en dos para no llevar a errores a la hora de la usar la interfaz fluida.

Errores de diseño

Pero no todo es de color de rosa, cuando planifique el sistema, pensé en la posibilidad de guardar las expresiones lambda como texto y después compilarlas usando CodeDom, bien tengo que deciros que cuando me he puesto a ello me he llevado la desagradable sorpresa de que CodeDom no soporta expresiones lambda, de modo que mi gozo en un pozo.

Y digo esto porque es de vital importancia el poder mantener las reglas fuera del código, bien un archivo de configuración, un archivo XML, lo que sea… de este modo podemos realizar ajustes sin tener que recompilar todo …

Para una futura versión

Completar estas cositas …

 

Comments (0)

Polar Rs300x - GUI

Jan 8 2010 by csegura @ 14:34

Estas navidades el Olentzero, Santa Claus, Papa Noel ó uno mismo, vaya ud. a saber … me dejo un pulsometro Polar RS300x, uno de esos aparatitos que te miden las pulsaciones (para evitar que a los que nos vamos haciendo mayores nos dé un chunguito)



La verdad es que no está nada mal, viene con el transmisor WearLink que es la cinta que te atas en el pecho que se encarga de enviar la frecuencia cardiaca al reloj, con un sensor S1 que es un podómetro que te pones en la zapatilla y una vez calibrado, mide la distancia y la velocidad, y finalmente con el FlowLink que es un dispositivo USB a través del cual puedes enviar la información a una web para (www.polarpersonaltrainer.com) para mantener un histórico de las sesiones de entrenamiento.

El domingo día 3 calibre el sensor S1 recorriendo una distancia de 1km y después probé por los alrededores de mi casa a correr una distancia conocida y me quede impresionado, tan solo medio metro de diferencia. Una maravilla.

El lunes día 4 realice una sesión de entrenamiento y después subí los datos la web, usando el FlowLink y el software de sincronización que viene con el aparato.

Bueno, no es que este mal del todo, pero no se puede decir que la web sea una pasada. La cosa es que me pico el gusanito ese “f-geek” (freak-geek) que llevo dentro ..

De modo que me puse a buscar todo tipo de información acerca de cómo sacar los datos del dichoso relojito … y no encontré absolutamente nada (y mira que ha sido fácil)

Revisando el software de sincronización di con unas .dlls curiosas .. Polar.Transport.dll y Polar.Monitor.dll … que curiosamente están en .Net … también hay una biblioteca de más bajo nivel llamada libpolar.dll a la que las otras dos hacen refencia (Interop) ..

Bueno tras una revisión con el reflector encontré muchas, muchas cosas interesantes .. lo mejor es que me podía conectar al relojito y obtener los datos de las sesiones, de modo que en un primer paso realice un sencillo programita para exportar los datos a XML

Que bonito … en poco más de una hora tenía los datos …

Básicamente basta con crear un proyecto en VS y referenciar Polar.Monitor.dll (como internamente usa libpolar.dll) debéis aseguraros que libpolar.dll está también localizable.

Pero para no perder detalle aquí os dejo un video de cómo hacerlo…



La cosa es que me he liado un poco (¿Cómo no?) y me he metido a hacer un GUI que por el momento tiene este aspecto.

Permite ver un resumen de las sesiones



Permite analizar cada sesión (yo le he activado el modo Auto Lap, de modo que el pulsometro toma datos a cada KM) me muestra el tiempo empleado, la velocidad, la FC Max, y la FC Media. Además emparejo cada dato de FC con la Zona de trabajo.

En el gráfico, se puede ver la FC , la FC Max (puntitos rojos) y ambas dentro de sus zonas correspondientes. En el gráfico de velocidad, se puede ver la velocidad en Km/h y en min/km además la vuelta más rápida queda en verde y la más lenta en rojo.



Por último el gráfico de las Zonas, con el tiempo empleado en cada una de ellas en la sesión de entrenamiento.



Os dejo otro bonito video del programita … (que me he emocionaooo ...)


Ya sabes si eres un f-geek de los ordenadores que además te gusta el running el Rs300x es una magnifica opción

Comments (6)

ASP.NET Mvc Delete Link usando DELETE method

Nov 1 2009 by csegura @ 11:53
Realmente he llegado tarde (seguro que estaba haciendo alguna que otra mala cosa) al MVC de ASP.Net, lo digo porque aunque había jugueteado un poco no me había tenido que poner a hacer cosas un poco serias.

Bueno, la verdad es que estoy encantado ya voy haciendo mis pinitos poco a poco … una de las cosas con las que estaba más a disgusto ha sido el tema de hacer las eliminaciones vía POST (cosas de los que hemos jugado con Ruby)

Sthephen Walter (autor de ASP.NET MVC Framework Unleashed) tiene un post en su blog con una muy buena descripción del problema en su blog.  Resumo.
  • Realizar un borrado mediante HTTP GET es un error de seguridad como la copa de un pino.
  • Realizar un borrado usando Ajax y HTTP DELETE es dependiente del JavaScript.
  • Realizar un borrado usando HTTP POST, según Sthephen es la manera más idónea para no ser dependiente de JavaScript.
  • Problema, un link no puede hacer un HTTP POST
  • Tenemos que usar una imagen o un botó
  • Propone una solución para realizar la eliminación mediante AJAX y java script (demasiado dependiente)
Mi problema (y seguro que el de otros) - Requisitos
  • Quiero realizar un borrado
  • Quiero hacerlo usando un link
  • Quiero que sea seguro
  • Quiero que use HTTP DELETE
  • Quiero poder validar “¿Esta Ud. Seguro?”
  • Quiero poder personalizar el mensaje
  • Quiero que tras borrar pueda dirigirme a una página concreta
  • Quiero controlar los errores
  • Quiero que sea versátil y no tener que escribir JavaScript cada vez
Extendiendo jQuery

Ya está más que dicho, pero jQuery es grande, muy grande. Y una de las cosas que más me gustan es la facilidad con que puede extenderse, básicamente hay dos formas de hacerlo, una añadiendo nuevos métodos que son aplicables a los elementos (jQuery.fn.extend) y otra a través de la cual se pueden añadir nuevos métodos a  jQuery (jQuery.extend).

En este caso, vamos a extender jQuery añadiéndole un nuevo método, un método llamado mvcDelete que podremos usar desde el onclick de un link.

He preferido la este modo de extensión para poder escribir un sencillo HtmlHelper que me ayude a no tener que escribir prácticamente nada de JavaScript cada vez que quiero poner un link para eliminar un elemento.

<%= Html.DeleteLink(“Delete”, new { action=”Delete”, controller=”Page”, id=Model.Id, redirectToController=”Page”}, null) %>

   1:  jQuery.extend({
   2:          mvcDelete: function(options) {
   3:              var defaults = {
   4:                  controller: "",
   5:                  action: "delete",
   6:                  onComplete: function(xhr, status) { },
   7:                  onSuccess: function(data) { },
   8:                  onError: function(xhr, status) { alert("Error"); },
   9:                  message: "Are you sure you wish to delete this item?",
  10:                  confirmAlert: true,
  11:                  id: 0,
  12:                  redirectToController: "",
  13:                  redirectToAction: "index"
  14:              }
  15:              var ajaxError = false;
  16:              var opt = $.extend(defaults, options);
  17:              var deleteRequest = function() {
  18:                  var deleteUrl = '/' + opt.controller + '/' + opt.action + '/' + opt.id;
  19:                  $.ajax({
  20:                      type: "DELETE",
  21:                      url: deleteUrl,
  22:                      async: false,
  23:                      success: opt.onSuccess(data),
  24:                      complete: opt.onComplete(xhr,status),
  25:                      error: function(xhr, status) { opt.onError(xhr, status); ajaxError = true; }                    
  26:                  });
  27:              };
  28:   
  29:              if (opt.controller.length > 0 && opt.id > 0) {
  30:                  if (opt.confirmAlert) {
  31:                      if (confirm(opt.message))
  32:                          deleteRequest();
  33:                      else
  34:                          return false;
  35:                  } else
  36:                      deleteRequest();
  37:   
  38:                  if (!ajaxError && opt.redirectToController.length > 0) {
  39:                      var redirect = '/' + opt.redirectToController + '/' + opt.redirectToAction;
  40:                      window.location.replace(redirect);
  41:                  }
  42:              }
  43:              return false;
  44:          }
  45:   
  46:      });

En donde vamos a poder pasar:

controller -> controlador de la acción de borrado (requerido)
action -> acción de borrado, por defecto delete
id -> elemento a borrar (requerido)
onComplete -> una función a realizar tras completarse el borrado
onError -> una función a realizar si se producen errores
confirmAlert -> si se mostrará o no el mensaje de advertencia
message -> el mensaje de seguridad
redirectToController -> el controlador de salida (por defecto el mismo que de entrada)
redirectToAction -> la acción de la salida por defecto (Index)

Después el helper que se encargará de realizar el link será

   1:  public static string DeleteLink(this HtmlHelper helper,
   2:                                  string text,
   3:                                  object deleteOptions,
   4:                                  object linkHtmlAttributes)
   5:  {
   6:      var linkTagBuilder = new TagBuilder("a");
   7:   
   8:      linkTagBuilder.Attributes.Add("href", "#");
   9:      linkTagBuilder.SetInnerText(text);
  10:   
  11:      var serializer = new JavaScriptSerializer();
  12:      var mvcDeleteOptions = serializer.Serialize(deleteOptions);
  13:   
  14:      linkTagBuilder.MergeAttribute("onclick", 
  15:                                    string.Format("$.mvcDelete({0}); return false;", mvcDeleteOptions));
  16:      linkTagBuilder.MergeAttributes(new RouteValueDictionary(linkHtmlAttributes));
  17:   
  18:      return linkTagBuilder.ToString();
  19:  }
Aquí lo más destacable es como pasamos las opciones a nuestro plugin, usando un método anónimo, convertimos el objeto usando el serializador de javascript de este modo nuestro plugin, recibe los parámetros.


Comments (2)

NavarraDotNet - Independencia

Oct 21 2009 by csegura @ 16:40

Ayer tuvimos una sesión de arquitectura que dedicamos por completo a la inyección de dependencias (la llamamos Independencia), en esta ocasión contamos con gente que está trabajando con Java, e incluso con PHP, la verdad es que fue una autentica pasada ya que tras ver algunas demos, (yo flipo con la gente de PHP) mantuvimos una conversación realmente interesante, buen rollito a pasar de las diferentes tecnologías.

•    En Java vimos PicoContainer, NanoContainer, Spring y MicroSpring.
•    En PHP vimos como ejemplo Substrate (y Manu, se llevo el premio arquitecto-friki del día)
•    En .Net vimos StructureMap, Unity, Ninject, Autofac y más….

No obstante y para variar, terminamos con algunas discusiones un poco más acaloradas, y es que hay que ver como se ponen algunos.
Haciendo un resumen discutimos sobre:

-    Cuando se debe usar IoC.
-    Pros y contras
-    Alternativas de configuración XML/Código
-    Sugerencias para la elección de un framework
-    Rendimiento

En cuanto al rendimiento, pudimos hacer una serie de benchmarks con las herramientas de .Net, usamos un sencillo test preparado por (gracias Torkel [http://www.codinginstinct.com]), en donde lo más destacable fue el poder ver cómo se comportan los distintos frameworks, dejo los enlaces abajo, esta prueba es realmente interesante

•    http://www.codinginstinct.com/2008/04/ioc-container-benchmark-unity-windsor.html
•    http://www.codinginstinct.com/2008/04/ioc-benchmark-revisited-ninject.html
•    http://www.codinginstinct.com/2008/05/ioc-container-benchmark-rerevisted.html

Os sugiero variar el número de objetos que se crean y el modo en que se instanciaran.

Bueno, lo próximo serán los talleres de integración continua que haremos en el CES, estos se han llenado en apenas 24 horas. De modo que tendremos que pensar en organizar más

Calendario de eventos del CES para Noviembre


Comments (3)