6 votos

Resultados incorrectos de corrección atmosférica 6S

Estoy usando 6s para corregir datos de sentinel, pero hay una pequeña desviación que me dice que estoy haciendo algo mal.

Este es el resultado, por ejemplo, de un escenario:

*******************************************************************************
*                        resultado de corrección atmosférica                        *
*                        -----------------------------                        *
*       reflectancia aparente de entrada            :    0.100                      *
*       radiación medida [w/m2/sr/mic]       :   37.699                      *
*       reflectancia corregida atmosféricamente                                 *
*       caso lambertiano :      0.02879                                        *
*       caso BRDF       :      0.02879                                        *
*       coeficientes xa xb xc                 :  0.00346  0.10170  0.14026    *
*       y=xa*(radiación medida)-xb;  acr=y/(1.+xc*y)                         *
*******************************************************************************

El problema es que si calculo la reflectancia corregida atmosféricamente (acr) usando las fórmulas proporcionadas con una radiación medida de 37.699, obtengo un valor de 0.02862 que no coincide con el resultado presentado = 0.02879. Sé que es solo un error del 0,6%, pero es matemática... no debería haber error.

Sospecho que estoy haciendo algo mal y necesito orientación en cuanto a cómo usar estos valores para corregir datos de sentinel, ya que parece que me estoy saltando un paso tal vez, que no encuentro en la documentación de 6s. Necesito hacer el cálculo píxel por píxel, por lo que ejecutar el algoritmo n veces (una vez por cada píxel) no es una opción.

10voto

Bill Puntos 7824

Respuesta corta: Es un problema de precisión numérica: el xa , xb y xc Los coeficientes no se muestran en el archivo de salida 6S con la suficiente precisión para producir la respuesta correcta cuando se utiliza la fórmula. Es posible modificar el 6S para que imprima los coeficientes con una mayor precisión, lo que resuelve el problema.

Respuesta larga: Me intrigó esta pregunta, ya que he utilizado 6S durante mucho tiempo (y he escrito una interfaz de Python para ello) y nunca me había dado cuenta de esto... ¡extrañamente, nunca había pensado en comprobarlo!

En un principio pensé que podría tratarse de un problema con tu parametrización del 6S, pero probé algunas parametrizaciones diferentes y me encontré con el mismo problema: obtenía una reflectancia corregida atmosféricamente ligeramente diferente al pasar los coeficientes por la fórmula, en comparación con la reflectancia que arrojaba el modelo 6S directamente.

El manual del 6S es muy detallado, pero de alguna manera nunca parece responder a las preguntas que tengo - por ejemplo, no explica en ninguna parte cómo se calculan los tres coeficientes. Sin embargo, tiene un archivo de salida de ejemplo que incluye los resultados de la corrección atmosférica (ver la página final de Parte 1 del manual ). Esto incluye las siguientes salidas:

*******************************************************************************
* atmospheric correction result *
* ----------------------------- *
* input apparent reflectance : 0.100 *
* measured radiance [w/m2/sr/mic] : 38.529 *
* atmospherically corrected reflectance *
* Lambertian case : 0.22180 *
* BRDF case : 0.22180 *
* coefficients xa xb xc : 0.00685 0.03885 0.06835 *
* y=xa*(measured radiance)-xb; acr=y/(1.+xc*y) *
*******************************************************************************

Si se trabaja en el cálculo utilizando la fórmula dada se encuentra que el resultado del cálculo no coincide con la salida del 6S. Permítanme decirlo de nuevo: en el ejemplo proporcionado por los autores del 6S, ¡la salida del modelo y la fórmula no coinciden! No podía creer esto...

Así que me pregunté si la fórmula era algún tipo de ajuste de curva simple a algunas salidas del 6S, y por lo tanto se esperaría que tuviera un pequeño error en comparación con las salidas reales del modelo. Como ya he mencionado, el manual explica muchas cosas con gran detalle, pero no dice nada sobre el cálculo de estos coeficientes. Por suerte, el código fuente del 6S está disponible para descargar . Y lo que es menos conveniente, el código fuente está escrito en Fortran 77.

No soy en absoluto un experto en Fortran 77 (de hecho, nunca he escrito ningún código Fortran en la vida real), pero he indagado en el código para intentar averiguar cómo se calculan los coeficientes.

Si quieres seguirlo, el código para calcular los coeficientes comienza en la línea 3382 de main.f . Los coeficientes reales se fijan en las líneas 3393-3397:

 xa=pi*sb/xmus/seb/tgasm/sutott/sdtott
 xap=1./tgasm/sutott/sdtott
 xb=ainr(1,1)/sutott/sdtott/tgasm
 xb=ainr(1,1)/sutott/sdtott/tgasm
 xc=sast

(extrañamente xb se fija dos veces, con el mismo valor, y otro coeficiente xap que parece que nunca se utiliza (¡no tengo ni idea de por qué!).

A partir de este código es bastante obvio que no se utiliza ningún algoritmo complicado de ajuste de curvas: los coeficientes son simplemente manipulaciones algebraicas de otras variables utilizadas en el modelo. Por ejemplo, xc se establece el valor de la variable sast que, con un poco de trabajo de detective, resulta ser el albedo esférico total (ver línea 3354). Puede comprobarlo en la salida del 6S: el valor de xc es siempre el mismo que el albedo esférico total que se muestra unas líneas más arriba en el archivo de salida. Del mismo modo, xb se calcula en función de diversas variables, entre ellas tgasm que es la transmitancia global total del gas y sdtott que es la transmitancia total de la dispersión hacia abajo, y así sucesivamente. (Estas variables son difíciles de descifrar, porque Fortran 77 tiene un límite de seis caracteres para los nombres de las variables, por lo que no son muy descriptivas).

Estaba perplejo en este punto, hasta que pensé en la precisión numérica. Me di cuenta de que el xa El coeficiente tiene un número de ceros después del punto decimal, y se pregunta si no hay suficientes cifras significativas para producir un resultado preciso al utilizar la fórmula. Resultó que este era el caso, pero voy a ir a través de cómo he alterado el código 6S para probar esto.

Línea 3439 de main.f se encarga de escribir los coeficientes en el archivo. Se compone de:

write(iwr, 944)xa,xb,xc

Esto le dice a Fortran que escriba la salida en el flujo de archivo/salida iwr utilizando el código de formato especificado en la línea 944 y escribir las tres variables xa , xb y xc . Si miramos la línea 944 (es decir, la línea a la que se le ha dado un número de línea Fortran de 944, que en realidad es la línea 3772 del archivo... ¡sólo para mantenerte alerta!

  944 format(1h*,6x,40h coefficients xa xb xc                 :, 
     s           1x, 3(f8.5,1x),t79,1h*,/,1h*,6x,
     s           ' y=xa*(measured radiance)-xb;  acr=y/(1.+xc*y)',
     s               t79,1h*,/,79(1h*))

Esta línea bastante complicada explica cómo formatear la salida. El bit clave es 3(f8.5,1x) que le dice a Fortran que escriba un número de punto flotante ( f ) con una anchura máxima de 8 caracteres y 5 decimales ( 8.5 ) seguido de un espacio ( 1x ), y repetirlo tres veces (el 3(...) ). Podemos modificar esto para imprimir más decimales - por ejemplo, yo lo cambié a 3(f10.8,1x) , lo que nos da 8 decimales. Si hacemos esto, entonces encontramos que la salida va hacia el * que están al final de cada línea, por lo que tenemos que modificar un poco el resto de la línea para reducir el número de espacios después del texto coefficients xa xb xc . La línea final, que funciona, tiene este aspecto:

  944 format(1h*,6x,35h coefficients xa xb xc            :, 
 s           1x, 3(f10.8,1x),t79,1h*,/,1h*,6x,
 s           ' y=xa*(measured radiance)-xb;  acr=y/(1.+xc*y)',
 s               t79,1h*,/,79(1h*))

Si se modifica esta línea en main.f y recompilar el 6S, verá que su salida se parece a esto:

*******************************************************************************
*                        atmospheric correction result                        *
*                        -----------------------------                        *
*       input apparent reflectance            :    0.485                      *
*       measured radiance [w/m2/sr/mic]       :  240.000                      *
*       atmospherically corrected reflectance                                 *
*       Lambertian case :      0.45439                                        *
*       BRDF       case :      0.45439                                        *
*       coefficients xa xb xc            : 0.00297362 0.20291930 0.24282509   *
*       y=xa*(measured radiance)-xb;  acr=y/(1.+xc*y)                         *
*******************************************************************************

Si a continuación se aplica la fórmula, se comprobará que el resultado de la fórmula y el resultado del modelo coinciden, al menos hasta el número de decimales del resultado del modelo.

En mis pruebas de esto, obtuve lo siguiente para el código original 6S:

  • Modelo: 0.4543900000
  • Fórmula: 0.4537049078
  • Perc Diff: 0.1507718536%

(la diferencia porcentual que yo obtenía era menor que la que tú encontraste, pero eso dependerá de la parametrización utilizada)

y esto para mi código 6S alterado:

  • Modelo: 0.4543900000
  • Fórmula: 0.4543942552
  • Perc Diff: -0.0009364659%

Mucho mejor.

Como referencia, para investigar esto he utilizado Py6S la interfaz de Python para el modelo 6S que escribí. Usé las siguientes funciones para calcular automáticamente los resultados usando la fórmula de un Py6S SixS y calcular automáticamente la diferencia porcentual:

def calc_acr(radiance, xa, xb, xc):
    y = xa * radiance - xb
    acr = y/(1.0 + xc * y)

    return acr

def calc_acr_from_obj(radiance, s):
    return calc_acr(radiance, s.outputs.coef_xa, s.outputs.coef_xb, s.outputs.coef_xc)

def difference_between_formula_and_model(s):
    formula = calc_acr_from_obj(s.outputs.measured_radiance, s)
    model = s.outputs.atmos_corrected_reflectance_lambertian

    diff = model - formula

    perc_diff = (diff / model) * 100

    print("Model: %.10f" % model)
    print("Formula: %.10f" % formula)
    print("Perc Diff: %.10f%%" % perc_diff)

y mis errores de ejemplo anteriores provienen de ejecutar Py6S utilizando la siguiente parametrización:

s = SixS()
s.altitudes.set_sensor_satellite_level()
s.atmos_corr = AtmosCorr.AtmosCorrLambertianFromRadiance(240)
s.wavelength = Wavelength(PredefinedWavelengths.LANDSAT_OLI_B1)
s.run()

Sólo como una pequeña adición, si usted está corrigiendo atmosféricamente los datos de Sentinel-2 con 6S entonces usted podría considerar el uso de ARCSI - una herramienta de corrección atmosférica que utiliza Py6S internamente, pero que hace gran parte del trabajo duro por ti. La mejor manera de aprender ARCSI es con su documento tutorial .

0 votos

¡Wow! gracias @robintw por tomarte el tiempo para responder tan detalladamente, estaré utilizando Py6S (también gracias por eso). ¡Intentaré recompilar 6S siguiendo tus pasos para resolver esto!

1 votos

Otra cosa a considerar es el tipo de precisión de los datos. Al revisar rápidamente main.f, todos los tipos son real / precisión simple / float32. Python utiliza nativamente la doble precisión, por lo que siempre obtendrá una mejor respuesta con una mayor precisión.

i-Ciencias.com

I-Ciencias es una comunidad de estudiantes y amantes de la ciencia en la que puedes resolver tus problemas y dudas.
Puedes consultar las preguntas de otros usuarios, hacer tus propias preguntas o resolver las de los demás.

Powered by:

X