/*
This source file is part of the edu.wisc.ssec.mcidas package and is
Copyright (C) 1998 - 2017 by Tom Whittaker, Tommy Jasmin, Tom Rink,
Don Murray, James Kelly, Bill Hibbard, Dave Glowacki, Curtis Rueden
and others.
This library is free software; you can redistribute it and/or
modify it under the terms of the GNU Library General Public
License as published by the Free Software Foundation; either
version 2 of the License, or (at your option) any later version.
This library is distributed in the hope that it will be useful,
but WITHOUT ANY WARRANTY; without even the implied warranty of
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
Library General Public License for more details.
You should have received a copy of the GNU Library General Public
License along with this library; if not, write to the Free
Software Foundation, Inc., 59 Temple Place - Suite 330, Boston,
MA 02111-1307, USA
*/
package edu.wisc.ssec.mcidas;
import java.io.IOException;
/**
* @author tommyj
* Adapted from the McIDAS-X module kbxfy2.dlm
* NOT TESTED YET, USE AT YOUR OWN RISK!
*
*/
public class CalibratorFY2 extends CalibratorDefault implements Calibrator {
private boolean isVis = false;
/**
* Current cal type as set by <code>setCalType</code>
*/
private int curCalType = Calibrator.CAL_RAW;
private int numFY2Bands = 4;
private int[] visDetectorId = { 0x6C6C0000, 0xB4B40000, 0xD8D80000, 0xFCFC0000 };
private int[] prefix;
private int[] calBlock;
private static final int VIS_BAND_OFFSET = 192;
private int[][] albedoFromRaw = new int[numFY2Bands][256];
private int[][] britFromAlbedo = new int[numFY2Bands][256];
private int[] tempTable = new int[1024];
private int[] radTable = new int[1024];
private int[] britTable = new int[1024];
private int lastBand = -1;
public CalibratorFY2(int[] prefix, int[] areaDir, int[] calBlock)
throws IOException {
super(null, null);
if(calBlock != null)
initFY2(prefix, areaDir, calBlock);
else
setIsPreCalibrated(true);
}
public void initFY2(int[] prefix, int[] areaDir, int[] calBlock){
this.prefix = prefix;
this.calBlock = calBlock;
// initialize tables
int visOffset = 0;
float albedo = 0.0f;
for (int i = 0; i < numFY2Bands; i++) {
visOffset = VIS_BAND_OFFSET + (i * 64);
for (int j = 0; j < 256; j+=4) {
albedo = calBlock[visOffset + ((j + 1) / 4)] / 10000.0f;
britFromAlbedo[i][j] = (int) Math.round(0.5 + 25.5 * Math.sqrt(albedo));
albedoFromRaw[i][j] = (int) Math.round(albedo * 100.0f);
britFromAlbedo[i][j + 1] = (int) Math.round(0.5 + 25.5 * Math.sqrt(albedo));
albedoFromRaw[i][j + 1] = (int) Math.round(albedo * 100.0f);
britFromAlbedo[i][j + 2] = (int) Math.round(0.5 + 25.5 * Math.sqrt(albedo));
albedoFromRaw[i][j + 2] = (int) Math.round(albedo * 100.0f);
britFromAlbedo[i][j + 3] = (int) Math.round(0.5 + 25.5 * Math.sqrt(albedo));
albedoFromRaw[i][j + 3] = (int) Math.round(albedo * 100.0f);
}
}
}
public int[] calibratedList( final int band, final boolean isPreCal ) {
int[] cList;
if(isPreCal){
if (band == 1) {
// Visible
cList = new int[]{CAL_RAW, CAL_BRIT};
} else {
// IR Channel
cList = new int[]{CAL_RAW, CAL_TEMP, CAL_BRIT};
}
} else {
if (band == 1) {
// Visible
cList = new int[]{CAL_RAW, CAL_ALB, CAL_BRIT};
} else {
// IR Channel
cList = new int[]{CAL_RAW, CAL_TEMP, CAL_RAD, CAL_BRIT};
}
}
return cList;
}
/* (non-Javadoc)
* @see edu.wisc.ssec.mcidas.CalibratorDefault#calibrate(float, int, int)
*/
@Override
public float calibrate(float inVal, int band, int calTypeOut) {
int detector = 0;
int irOffset = 0;
float radiance = 0.0f;
float temperature = 0.0f;
float outVal = 0.0f;
// first set the vis-or-ir flag
if (band == 1) {
isVis = true;
} else {
isVis = false;
}
if (isVis) {
// read the detector number from line prefix
detector = 1;
for (int i = 0; i < numFY2Bands; i++) {
if (visDetectorId[i] == prefix[1]) {
detector = i + 1;
}
}
}
// for IR data, we will generate new tables when the band changes
if (! isVis) {
if (band != lastBand) {
irOffset = calBlock[(band - 2) * 2 + 8] / 4;
for (int i = 0; i < 1024; i++) {
temperature = calBlock[irOffset] / 1000.0f;
radiance = tempToRad(temperature, band);
tempTable[i] = Math.round(temperature * 100.f);
radTable[i] = Math.round(radiance * 1000.f);
if (temperature >= 242.0f) {
britTable[i] = Math.max(660 - (int) (2 * temperature), 0);
} else {
britTable[i] = Math.min(418 - (int) (temperature), 255);
}
}
}
}
// update last band seen
lastBand = band;
// finally, do the calibration
if (calTypeOut == curCalType) {
outVal = inVal;
} else {
if (isVis) {
if (calTypeOut == Calibrator.CAL_ALB) {
outVal = albedoFromRaw[detector][(int) inVal];
}
if (calTypeOut == Calibrator.CAL_BRIT) {
outVal = britFromAlbedo[detector][(int) inVal];
}
} else {
if (calTypeOut == Calibrator.CAL_RAD) {
outVal = radTable[(int) inVal];
}
if (calTypeOut == Calibrator.CAL_TEMP) {
outVal = tempTable[(int) inVal];
}
if (calTypeOut == Calibrator.CAL_BRIT) {
outVal = britTable[(int) inVal];
}
}
}
return outVal;
}
/**
*
* calibrate from temperature to radiance
*
* @param inVal
* input data value
* @param band
* channel/band number
*
*/
public float tempToRad(float inVal, int band) {
float outVal = -1f;
// derived constants for each band
float[] fk1 = { 9280.38f, 7136.31f, 37258.20f, 224015.00f };
float[] fk2 = { 1323.95f, 1212.95f, 2104.22f, 3826.28f };
// derived temp constants for each band
float[] tc1 = { 0.72122f, 1.00668f, 3.76883f, 4.00279f };
float[] tc2 = { 0.99750f, 0.99621f, 0.99108f, 0.99458f };
// temperature adjusted by derived constants
float adjustedTemp;
adjustedTemp = tc1[band - 1] + tc2[band - 1] * inVal;
outVal = (float) (fk1[band - 1] /
(Math.exp(fk2[band - 1] / adjustedTemp) - 1.0f));
return (outVal);
}
public String calibratedUnit(int calType){
String unitStr = null;
switch (calType) {
case CAL_RAW:
unitStr = null;
break;
case CAL_RAD:
unitStr = "MW**";
break;
case CAL_ALB:
unitStr = "%";
break;
case CAL_TEMP:
unitStr = "K";
break;
case CAL_BRIT:
unitStr = null;
break;
}
return unitStr;
}
}