Reducir ruido usando la media y la desviación típica

Este metido es para detectar y reducir los ruidos intensos y poco frecuentes. La idea principal es que el valor leído más el ruido de baja intensidad se comportan como una función de normal. Se podría ver como que a mayor intensidad del ruido menos probable es que aparezca. Visto en forma de gráfica:

Standard deviation diagram micro.svg
De AinaliTrabajo propio, CC BY-SA 3.0, Enlace

En la imagen se puede ver que según un valor se aleja de la media (μ) menos probable es que pertenezca a la muestra. Así que según su distancia a la muestra podemos saber lo probable que es que pertenezca. Sabiendo esto se ponen una distancia máxima a la media de tal forma que habrá dos umbrales (μ+distancia y μ-distancia) los valores que queden fuera de esos umbrales de eliminan. Valores habituales de filtrado corresponde a μ±σμ±2σ y μ±3σ. O aproximadamente dejan fuera el 16%, 2% y 0.1% de los valores (a cada lado del umbral). Para filtrar valores fijamos la probabilidad de pertenencia a la muestra que les «exigimos». Por ejemplo si un valor solo puede pertenecer a la muestra con una seguridad del 5% lo descartamos.

Este proceso lo podemos aplica una vez o varias, repitiéndolo hasta que no se elimine ninguno de los valores.

Una vez eliminados los valores que quedan fuera del umbral podemos aplicar alguno de los filtros ya vista como la moda, mediana o media para calcular el valor.

Ejemplo:

Usamos como limite 2σ. repetiremos el filtrado hasta que no haya descartes en las muestras

Iteración 1

muestras iniciales: [23, 4, 5, 5, 6, 4, 5, 4, 5, 6, 4, 12]

media: 6.9167

desviación estándar: 5.5179

tolerancias: 6.9167+(2 * 5.5179) = 17.953         6.9167-(2 * 5.5179) = -4.1191

muestras admitidas: [4, 5, 5, 6, 4, 5, 4, 5, 6, 4, 12]

Iteración 2

muestras iniciales: [4, 5, 5, 6, 4, 5, 4, 5, 6, 4, 12]

media: 5.4545

desviación estándar: 2.2962

tolerancias: 5.4545 + (2 * 2.2962) = 10.047       5.4545 – (2 * 2.2962) = 0.8621

muestras admitidas: [4, 5, 5, 6, 4, 5, 4, 5, 6, 4]

Iteración 3

muestras iniciales: [4, 5, 5, 6, 4, 5, 4, 5, 6, 4]

media: 4.8

desviación estándar: 0.7888

tolerancia: 4.8 + (2 * 0.7888) = 6.3776        4.8 – (2 * 0.7888) = 3.2224

muestras admitidas: [4, 5, 5, 6, 4, 5, 4, 5, 6, 4]

Ahora calculamos los distintos valores usando al media, moda y mediana

media: 4.8 

moda: 4

mediana: 5

Comparamos entre los resultados entre los datos filtrados y sin filtrar:

Filtrado Sin filtrar
Media 4.8 6.9167
Mediana 5 5
Moda 4 4

Es normal que solo se haya visto afectada la media, ya que tanto la moda como la mediana están libres de la influencia de los valores en los extremos.

Reducir ruido usando la mediana

Otra idea para reducir el ruido es ordenar todos los valores y coger el central. La idea es muy parecida a la de la media. Se considera el ruido como la suma de una pequeña cantidad aleatoria cuyo valor oscila entre -e y e. Si el valor real es V las muestras se dividirán entre la que sumen el ruido (V+e) y la que lo resten (V-e) . Quedando el valor real V mas o menos en el centro de todos los valores. La mediana es precisamente eso, el valor en el centro de todos los valores. Para calcularlo es necesario ordenar la lista de muestras. Este es su punto débil ya que aumenta el coste computacional de calcular la mediana.

Tiene varias ventajas:

  • Es sencillo
  • Es insensible al ruido intenso pero poco frecuente.

También tiene sus inconvenientes:

  • Ordenar las muestras puede ser una tarea costosa a nivel computacional
  • Solo se puede usar cuando se puedan tomar varias muestras de la misma medida

Ejemplo:

Partimos de las siguientes muestras [23, 4, 5, 5, 6, 4, 5, 4, 5, 6, 4, 12]

Mediana: 5

El resultado no se ha visto influido por los valores extremos (12 y 23)

Reducir ruido usando la moda

El uso de la moda para evitar el ruido es parecida al caso de la media, pero en lugar de sumar todos los valores se selecciona el que más veces se repite. La idea en que se basa en que la mayoría del ruido es pequeño así que el valor que más veces aparezca es el más cercano al real.

Al igual que la media, esta técnica solo sirve si se pueden capturar suficiente numero de muestras sin que el valor cambie de forma apreciable. En este caso necesitamos mas valores que en caso de la media.

Tiene varias ventajas:

  • Es sencillo
  • Requiere poco «coste computacional»
  • Es insensible al ruido intenso pero poco frecuente.

También tiene sus inconvenientes:

  • Solo se puede usar cuando se puedan tomar varias muestras de la misma medida
  • Requiere muchas medidas para ser exacto
  • Por lo general supone perder «resolución» en la medida para poder «agrupar» las medidas y calcular la moda. Por ejemplo si tenemos los valores 4,13 y 4,18 hay que eliminar el último decimal para poder contar ambos como el mismo valor 4,1

Ejemplo:

Partimos de las siguientes muestras [23, 4, 5, 5, 6, 4, 5, 4, 5, 6, 4, 12]

Moda: 4

El resultado no se ha visto influido por los valores extremos (12 y 23)

Reducir ruido usando la media

Vamos a ver una técnica para ocuparnos del ruido habitual pero de baja intensidad. En el caso de que podamos tomar varias medidas sin que haya a penas variación del valor a medir. Es decir, estamos midiendo un valor que no cambia o lo hace tan lentamente que podemos capturar varias muestras sin que cambie.

Podemos ver el ruido como la suma de una pequeña cantidad aleatoria cuyo valor oscila entre -e y e. Eso significa que si tomamos suficiente muestras y las sumamos entre ellas lo mas probable es que los diferentes incrementos y decrementos que el ruido produce al valor medido se «neutralice» entre si. Ese calculo, sumar varios valores y dividir la suma entre el número de valores es precisamente la media.

Tiene varias ventajas:

  • Es sencillo
  • Requiere poco «coste computacional»
  • Se puede aplicar a cualquier número de muestras, aunque a mayor número de muestras mejores resultados.

También tiene sus inconvenientes:

  • Solo se puede usar cuando se puedan tomar varias muestras de la misma medida.
  • Hay que filtrar primero los valores de ruido más intenso ya que «desplazan» el valor de la media y son tan poco habituales que no se «neutralizan» al sumar las medidas
  • No todos los ruidos siguen el modelo propuesto de valor aleatorio entre e y -e

Ejemplo:

Partimos de las siguientes muestras [23, 4, 5, 5, 6, 4, 5, 4, 5, 6, 4, 12]

Media: 6.9167

Se puede ver como el 12 y el 23 han influido «desplazando» la media hacia su lado.

Combinar varias metaheurísticas

Si ajustar una metaheurísticas ya cuesta. ¿Por qué querríamos sufrir el doble para hacerlo con dos?. Hay varios motivos, el principal es que una metaheurística no se comportan bien en todo el espacio de soluciones del problema y por ello se usan varias.

Un caso es que una metaheurística se puede comportar muy bien para calcular parte de la solución pero no toda. Entonces algunos de sus valores los calcularemos usando una metaheurística dejando intactos aquellas partes de la solución para los que no funciona a los que posteriormente aplicaremos la segunda metaheurística que al igual que la anterior no alterará la parte para la que no funciona. Este proceso tiene que repetirse varias veces permitiendo que ambas partes evolucionen de forma conjunta.

Otro caso en que resulta útil aplicar una segunda metaheurística es cuando tenemos una que funciona muy bien explorando el espacio de soluciones y encontrando la zona donde se encuentra el máximo pero muy mal para precisar el valor de este. En ese caso se usa una metaheurística para acercarnos al máximo y cuando ha terminado aplicamos otra para precisar el resultado.

Ahora el problema es como combinar varias metaheurísticas ya que algunas funcionan con mutiles soluciones y otras con una sola.

Empezamos por el caso más intuitivo, el de que ambas metaheurísticas recurran a una población de varios individuos. Aquí las opciones son varias:

  • Cada metaheurística se ejecuta de forma separa con sus propia población de soluciones y cada cierto tiempo se intercambian soluciones entre ellas.
  • Ambas metaheurística actúan sobre las mismas soluciones y compiten entre ellas. Solo las mejores soluciones pasan a formar parte de la población
  • Intercalar metaheurísticas. Aplicamos una durante varias iteracciones  una y luego iteramos varias veces con la otra.

Para el caso de combinar dos metaheurísticas que trabajan con un solo resultado todas las opciones se limitan a usar primero una y luego la otra. Este proceso puede repetirse varias veces o realizarse solo una vez.

Para el caso de combinar metaheurísticas con población y las que trabajan mejorando una única solución:  

  • Tras cada ciclo de la metaheurística orientada a población se aplica la otra metaheurística a los individuos nuevos tratando de mejorarlos
  • Otra opción es usar la metaheristica individual como función de modificación/creación de nuevo individuos.

Un ejemplo muy habitual de combinar metahurísticas es en el caso de los algoritmos genéticos, tras haber generado los nuevos individuos usando los operadores de mutación y/o cruce  y antes de que compitan con el resto de la población se trata de mejorar los nuevos individuos usando alguna metaheurísticas que explore el espacio cercano a cada individuo tratando de encontrar el máximo local.

Trilateralización

Tras que medir la distancia al emisor no diera el resultado deseado pensé en no escribir esta entrada, pero como puede ser útil y ya la tenia medio escrita he decidido terminarla.

Ya hemos visto cómo calcular (más o menos) la distancia a un emisor. Si conocemos la situación del emisor podemos situarnos en algún punto de una circunferencia de radio r1 (r1 es igual a la distancia al emisor). Si añadiéramos un segundo emisor de coordenadas conocidas y al que calculamos la distancia r2. Esto nos sitúa en una segunda circunferencia que corta a la primera en dos puntos. Ahora ya sabemos que estamos situados en uno de esos dos puntos. Para saber en cual exactamente necesitamos un tercer emisor cuya posición conozcamos y del que podamos calcular la distancia r3. Esta tercera circunferencia coincidirá con las otras dos en un solo punto. En la imagen se ve mejor

Trilateration.svg
De Braindrain0000 de la Wikipedia en inglés, CC BY-SA 3.0, Enlace

Ahora toca ponerlo todo en lenguaje matemático. En lugar de usar circunferencias vamos a usar esferas, los cálculos son los mismo y nos permite no tener los tres emisores y el receptor en el mismo plano. La ecuación de una esfera cuyo centro está en las coordenadas (a,b,c) es:

(x ─ a) 2 + (y ─ b) 2 + (z ─ c) 2= r2

Esta ecuación representa a todos los puntos de la súperficie de una esfera. Cómo tenemos tres esferas que coinciden en un punto de sus superficies hay que buscar un punto (x,y,z) que cumpla las ecuaciones de las tres esferas.

Esfera1, vamos a ser amables con nosotros mismo y vamos a colocar esta esfera en el origen de coordenadas (0,0,0) por lo que su ecuación es:

x 2 + y 2 + z 2 = r12

Esfera2, también por simplificar nos la vida, colocamos el centro de esta esfera en línea con la anterior en las coordenadas (d,0,0). Su ecuación es:

(x – d)2 + y 2 + z 2 = r22

La tercer esfera la colocamos con el centro en el mismo plano pero con ambas coordenadas distintas.

(x – i)2 + (y – j) 2 + z 2 = r3

En el articulo de la wikipedia esta la resolución completa de las ecuaciones paso a paso, yo salto a la conclusión:

x = (r1 2 – r2 2 + d 2 ) / 2d

y = (r1 2 – r3 2 + i 2 + j 2) / 2j + (x * i / j)

z = √(r1 x 2 – y 2 )

Con estos cálculos ya tienes localizado el punto exacto. Desgraciadamente en la vida real las mediciones no suelen ser tan exactas por eso la mejor solución es detectar donde cortan dos circunferencias (por ejemplo la 1 con la 2 y la 1 con la 3) Buscar los puntos mas cercano y tomar el punto medo entre ambos, teniendo en cuenta que es una aproximación y que no será el punto exacto.

Medir distancia al emisor WiFi.

La idea es sencilla, mides la potencia de la señal de varias estaciones cuya posición conoces, con la potencia calculas la distancia a cada estación y a partir de ahí con geometría básica calculas tu posición. Parece fácil, hasta que lo intentas y vas viendo como todo se complica.

Como estación vamos a usar un emisor WiFi, eso nos permitirá realizar pruebas fácilmente ya que podemos usar cualquier router WiFi como estación y como receptor cualquier móvil. Vamos a empezar por lo mas sencillo, medir la distancia a un solo nodo cuya localización conocemos. En nuestro receptor podemos ver la potencia. ¿Como convertimos la potencia en distancia?. Las malas noticias es que no es lineal. Las buenas es que hay fórmula (Free-space path loss) para hacerlo de manera aproximada

dB = 20log10(d) + 20log10(f) + K

K varia segun las unidades de medida de la distancia d y la frecuencia f, siendo:

  • K = 92.45 si d está en km y f en Ghz
  • K = -87.55 si d está en m y f en Khz
  • K = -27.55 si d está en m y f en Mhz
  • K = 32.45 si d está en km y f en Mhz

Lo que nos interesa son metros y Mhz. Como frecuencia de la seña WiFi se puede usar siempre 2400 Mhz sin temer cometer un gran error (aunque ya hay algunas redes que operan a otras frecuencias como 5 Ghz)

Aunque no es del todo exacta en muchas aplicaciones usan directamente esta formula para calcular la distancia. En el receptor podemos conocer  la atenuación (dB), la frecuencia (f) y la constante (K). Ahora podemos resolver la distancia (d).

dB – (20log10(f) + K) = 20log10(d)

Cómo ni f ni K van a variar en nuestro caso vamos a remplazarlos por una constante C

dB – C = 20log10(d)

Despejando d

d = 10^((dB – C)/20)

Si queremos ser mas exactos no basta con leer la potencia de señal que se recibe en el receptor ya que la formula esta expresada en decibelios (dB) y la potencia de la señal WiFi nos la devuelve el sistema en decibelios-miliwatio (dBm). Que aunque aparentan ser lo mismo no lo son. Los dB son una medida relativa de potencia entre dos valores (en este caso serian la potencia de emisión del nodo WiFi y la potencia percibida en el receptor). Sin embargo los dBm indican un valor de potencia expresado en relación a 1 mW. Que para los que no estamos acostumbrados a este campo todo esto nos suena a chino y lo único que queremos saber es: ¿Como se convierte de una unidad a la otra?. Pues no es tan sencillo porque cada unidad mide cosas diferentes. Voy a tratar de explicarlo para este caso y perdonarme si meto mucho la pata, ya os digo que no es un tema que domine. Los dB serian la diferencia de potencia entre la señal original y el punto donde estas recibiéndola y se calcula como:

dB = 10log10(P/P0)

Siendo P la potencia medida y P0 la emitida o de referencia. Necesitamos obtener esas dos potencias. Para ello podemos usar los dBm, que son los dB medidos tomando como potencia de referencia 1mW por lo que la formula queda:

dBm = 10 log10(P/1mW)

Podemos calcular P en mW fácilmente.

P = 10 ^ (dBm/10)

¿Pero de donde sacamos P0?. Los que esperéis complicados cálculos siento decepcionaros. La forma de calcular P0 (de forma aproximada) es acercarse lo más posible al emisor y medir la potencia en dBm, despejar la formula anterior y usar ese valor como P0.

Con todo esto podemos calcular el valor en dB de la atenuación de la señal. Así que ahora podemos volver a la primera formula para calcular la distancia.

En javascript

function dBm2dB(dBm0, dBm){
  var P0 = Math.pow(10, dBm0/10);
  var P = Math.pow(10, dBm/10);
  var dB = 10 * Math.log10(P/P0);
  return dB;
}

function fspl(dB,f,K){
  var logF = 20*Math.log10(f) + K;
  var d = Math.pow(10, (Math.abs(dB) - logF)/20);
  return d;
}

//ejmeplo
fspl(dBm2dB(-29, -58), 2400, -27.55)*10;

¿Que tal resultado da? Pues por alguna extraña metedura de pata que no logro localizar necesito multiplicar el resultado por 100 para que las cifras tengan sentido. La aproximación es buena pero no lo suficiente, incluso sin moverse los valores de la señal varían mucho. Como sistema de localización, la potencia de la señal WiFi deja mucho que desear

Derivada numérica y gradiente

Derivada

La derivada df de una función f es otra función que expresa la tasa de cambio de f. Por ejemplo si tenemos una función que calcula la velocidad en el punto X y calculamos su derivada tendremos una función que calcula la aceleración (cambio de la velocidad) en el punto X. Otra forma de entenderla es como la pendiente en un punto. Si calculamos la derivada de la función fitness en un punto tendremos una función que nos dice cuánto varía y si aumenta o disminuye. Es decir nos da una pista clara de en qué sentido hay que moverse para aumentar o disminuir el valor de la función.

Esto también quiere decir que si la pendiente es 0 ya estás en un máximo o en un mínimo. Si calculas todos los puntos donde la derivada es 0 seguro que uno de ellos es el máximo o el mínimo que estás buscando. Desgraciadamente en muchos casos no es sencillo hallar esos puntos.

Siendo una herramienta tan útil vamos a ver cómo calcularlo. A muchos os sonará de haberlo estudiado y haber tenido que memorizar un montón de derivadas y luego aprender reglas de derivación (por partes, cambio de variables,…) Incluso puede que tener pesadillas con ellas. Pero los ordenadores no saben hacer ese tipo de derivadas. Con ellos hay que recurrir derivadas numéricas que son mucho más simples.

df(x) = f(x+h) – f(x-h) / 2*h

¿Cuanto es h? Lo ideal es que sea una cantidad lo más pequeña posible. Pero ojo con cantidades muy pequeñas y la precisión numérica de los lenguajes de programación que puede dar sorpresa. Cómo se puede ver en el código más abajo yo he fijado el valor por defecto a 0,001.

this.epsilon = epsilon || 0.001;

this.diff = function(x, f){
  return (f(x+this.epsilon)-f(x-this.epsilon))/(this.epsilon*2);
}

Para ir más allá de la primera derivada también hay fórmulas para calcularla numéricamente que son más exactas que el método que vamos a usar nosotros pero en este caso me ha parecido más interesante el siguiente método.

Tenemos una función diff(x,f) que calcula la derivada de f en el punto x. Si hacemos diff(3,diff(3,f)) calcularíamos la segunda derivada de la función f en el punto 3. Para la tercera tendríamos que hacer diff(3,diff(3,diff(3,f))). Para las siguientes derivadas creo que ya habéis entendido como funciona.

En lugar de escribir todas las funciones una detrás de otra en una larga cadena vamos a usar una función que lo haga por nosotros. Siendo el parámetro n el número de derivada que calculará.

this.diffN = function(n, x, f){
  if(n == 1)
    return this.diff(x,f);
  else
    return this.diffN(n-1, x, function(x){return that.diff(x,f)});
}

Gradiente

Ya hemos visto como funciona la derivada para una función f(x) en un punto A, ahora os estaréis preguntando «¿Cómo funciona la derivada para una función con más variables como f(x1, x2)?» ¿A qué os he leído la mente?. Esta vez el punto donde se calcula tiene dos coordenadas [A,B]. Se calculan dos derivadas respecto de x1 y respecto de x2. Lo de «respecto» significa que solo se va a calcular modificando esa varíable, la otra será estática.

df(x1,x2)/dx1 = f(x1-h,x2)-f(x1+h,x2)/2*h

Es decir dejamos el resto de las «equis» inalteradas.

El gradiente es el cálculo de la derivada respecto a «cada equis». Es decir que

G = [df(x1,x2)/dx1, df(x1,x2)/dx2];

Podemos calcular el segundo, tercer,…. gradiente calculando la correspondiente derivada.

Nuestra función para calcular el gradiente usando la función anterior para calcular la derivada numérica queda así:

this.gradN = function(n, x, f){
  G = [];
  for(var i = 0; i < x.length; ++i){
    var auxX = x.slice(0);
    var fdx = function(x){auxX[i] = x; return f(auxX);}
    G.push(this.diffN(n, auxX[i], fdx));
  }
  return G;
}

Para que el uso sea más intuitivo vamos a hacer una versión del primer gradiente sin el parámetro n (n=1)

this.grad = function(x, f){
return this.gradN(1,x,f);
}

Puedes ver todo el código en este repositorio de github.

Condición de parada

Si ya hemos elegido nuestro algoritmo favorito y la función fitness que vamos a usar, lanzamos nuestro programa y surge un problema ¿Cuando páramos?.

Lo fácil sería decir que cuando alcancemos el resultado deseado, pero eso no es siempre posible o al menos no en un tiempo que sea razonable. Así que tendremos que quedarnos con una buena aproximación. ¿Pero cual es una buen aproximación? Hay veces que lo sabemos, sabemos que resultado nos tiene que dar al función fitness para que la solución sea suficiente para nosotros. ¿Pero que pasa si no sabemos cuando ha llegado al máximo o al mínimo de la misma?. Con las metaheurísticas siempre nos quedaremos con la duda. No podemos saber si hemos encontrado el punto optimo o nos hemos quedados atrapados en un máximo/mínimo local. Todo dependerá de nuestras necesidades y conocimiento del espacio de búsqueda.

Para reducir este problema hay que intentar explorar lo máximo posible el espacio de búsqueda. El punto optimo puede esconderse en cualquier rincón que nos dejemos sin mirar. Pero claro si estamos usando una metaheurística es porque no conocemos el espacio de búsqueda y es muy grande como para que lo exploremos.

Una de las condiciones más usadas en el caso de desconocimiento total es fijar de antemano un número de iteracciones. Es útil cuando tenemos un tiempo o recursos limitados para calcular la solución. Sin embargo puede darse el caso de que el tiempo no sea tan limitante, aunque tampoco nos apetezca tener al algoritmo iterando durante varias veces la vida del universo. En ese caso se puede fijar un umbral de «mejora». De tal manera que si durante un número determinado de iteracciones el resultado no ha mejorado la solución por encima de ese umbral se para la ejecución ya que se considera que el tiempo invertido no compensa la mejora obtenida.

Por último la que me atrevería a decir que es la condición más usada pero que ningún libro habla de ella. Ir mostrando datos en pantalla y que el usuario decida cuando terminar la ejecución. Puede parecer una solución «poco inteligente» pero durante las pruebas de un algoritmo para ver qué tal se comporta con un problema o viendo si se puede afinar su configuración puede ahorrar mucho de tiempo.

De todas formas muchas veces nos obsesionamos con encontrar el resultado optimo y en la vida real muchas veces basta con una aproximación que ni siquiera sea muy buena.
 

Descenso del gradiente

Si hay una metaheurística de ascender montañas tiene que haber otra de bajarlas. El descenso del gradiente se basa en usar el gradiente de guía para encontrar el mínimo de una función. El gradiente indica la pendiente máxima en un punto y hacia donde tenemos que dirigirnos para ascender (a favor del gradiente) o descender (en contra del gradiente). Sabiendo eso solo hay que moverse en la dirección indicada por el gradiente. ¿Cuanto? Ahí está el problema. Si el paso es muy grande podrías pasarte el mínimo y si es muy corto puedes acabar dando un gran número de pasos. Cómo lo de dar un gran número de pasos solo es un problema cuando lo haces con papel y lápiz y los ordenadores no se cansan de caminar (siendo cada paso una iteración del algoritmo) es preferible el segundo caso. Cada vez que se llega a un nuevo punto se calcula el gradiente en ese punto y se avanza en esa nueva dirección.

Supongamos que aún con nuestras precauciones de dar pasitos pequeños nos pasamos del mínimo. ¿Cómo podemos saberlo?. En la imagen de debajo se puede ver un ejemplo. Primero empezamos a «rebotar» de un lado a otro de la función, mientras el valor decrezca vamos bien. El problema surge si el valor aumenta (en la imagen el paso del punto f al g) . En ese caso hemos de volver al punto anterior, reducir el tamaño del paso y seguir probando hasta que se obtenga un valor fitness menor.

descensoGradienateProblema

 

Lo ideal sería llegar a un punto donde la pendiente sea 0 (eso indica que es un máximo o un mínimo). Pero en la practica no siempre es posible y al final hemos de depender de las condiciones habituales, llegar a una solución lo suficientemente próxima a la ideal, alcanzar cierto numero de iteraciones o llegar a un tamaño de paso tan pequeño que no merezca la pena continuar.

Ya hemos visto como calcular de forma numérica la derivada y el gradiente. Ahora hemos de aplicar ese conocimiento para calcular el gradiente de la función fitness. Como el descenso del gradiente esta pensado para minimizar, hemos de elegir una función fitness que a menor valor mejor resultado.

Cada nueva coordenada seria la antigua coordenada menos el valor de la derivada de la funcion para esa coordenada multiplicado por el tamaño del paso Kstep.

cordX = cordX – (Kstep * dF/dx)

O lo que es lo mismo en código:

var grad = diff.grad(cords, this.model.calculateFitness);
for(var i = 0; i < this.parameters.dimensions; ++i){
  cords[i] -= this.parameters.step*grad[i];
}

Si el nuevo valor de fitness es menor adoptamos esas coordenadas como nueva solución, si es mayor reducimos el tamaño del paso y volvemos a probar:

if(newFitness < this.fitness){
this.cords = newCords;
this.fitness = newFitness;
} else {
this.parameters.step *= this.parameters.reduceStep;
}

El código completo puede verse aqui.