// // CalibratorGvar.java // /* 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.DataInputStream; import java.io.IOException; import java.nio.ByteBuffer; /** * CalibratorGvar creates a Calibrator object designed specifically * to deal with GVAR data. Not fully implemented at present - some * calibrations remain to be done. * * @version 1.5 16 Nov 1998 * @author Tommy Jasmin, SSEC */ public abstract class CalibratorGvar implements Calibrator { protected static final int NUM_BANDS_IMAGER = 5; protected static final int NUM_BANDS_SOUNDER = 18; protected static final int NUM_VIS_DETECTORS = 8; protected static final int NUM_IR_DETECTORS = 2; protected static final int NUM_IR_BANDS = 4; protected static final int LOOKUP_TABLE_SZ_IMGR = 1024; protected static final int LOOKUP_TABLE_SZ_SNDR = 32768; // var to store current cal type protected static int curCalType = 0; protected static int index = 0; protected float [] visBiasCoef = new float [NUM_VIS_DETECTORS]; protected float [] visGain1Coef = new float [NUM_VIS_DETECTORS]; protected float [] visGain2Coef = new float [NUM_VIS_DETECTORS]; protected float visBiasCoefAVG = 0.f; protected float visGain1CoefAVG = 0.f; protected float visGain2CoefAVG = 0.f; protected float visRadToAlb = 0.0f; protected float [][] irBiasCoef = new float [NUM_IR_DETECTORS][NUM_IR_BANDS]; protected float [][] irGainCoef = new float [NUM_IR_DETECTORS][NUM_IR_BANDS]; protected float [] sBiasCoef = new float [NUM_BANDS_SOUNDER]; protected float [] sGainCoef = new float [NUM_BANDS_SOUNDER]; protected float [][] lookupTable; // used in calibrator method private static float gain = 0.0f; private static float bias = 0.0f; private static int scale = 1; private static int bandNum = 0; private static int sid = 0; // public boolean isPreCalibrated = false; /** * * constructor * * @param dis data input stream * @param ad AncillaryData object * @param calBlock calibration parameters array * */ public CalibratorGvar ( DataInputStream dis, AncillaryData ad, int [] calBlock) throws IOException { sid = ad.getSensorId(); if(calBlock != null) initGvar(ad.getSensorId(), calBlock); } public CalibratorGvar ( int sensorId, int [] calBlock) { sid = sensorId; if(calBlock != null) initGvar(sensorId, calBlock); else setIsPreCalibrated(true); } public void initGvar(final int sensorId, int[] calBlock) { int calIndex = 0; sid = sensorId; // now, correct for satellites starting with G12 (sid = 78) int irOffset = 2; if (sid > 77) irOffset = 0; //System.out.println("xxx sid = "+sid); if ((sid % 2) == 0) { // initialize lookup table lookupTable = new float [NUM_BANDS_IMAGER] [LOOKUP_TABLE_SZ_IMGR]; for (int i = 0; i < NUM_BANDS_IMAGER; i++) { for (int j = 0; j < LOOKUP_TABLE_SZ_IMGR; j++) { lookupTable [i][j] = Float.NaN; } } // read in an imager format cal block for (int i = 0; i < NUM_VIS_DETECTORS; i++) { visBiasCoef[i] = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); visBiasCoefAVG = visBiasCoefAVG + visBiasCoef[i]; calIndex++; } visBiasCoefAVG = visBiasCoefAVG/NUM_VIS_DETECTORS; for (int i = 0; i < NUM_VIS_DETECTORS; i++) { visGain1Coef[i] = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); visGain1CoefAVG = visGain1CoefAVG + visGain1Coef[i]; calIndex++; } visGain1CoefAVG = visGain1CoefAVG/NUM_VIS_DETECTORS; for (int i = 0; i < NUM_VIS_DETECTORS; i++) { visGain2Coef[i] = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); visGain2CoefAVG = visGain2CoefAVG + visGain2Coef[i]; calIndex++; } visGain2CoefAVG= visGain2CoefAVG/NUM_VIS_DETECTORS; visRadToAlb = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); calIndex++; for (int i = 0; i < NUM_IR_BANDS; i++) { irBiasCoef[0][(i + irOffset) % NUM_IR_BANDS] = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); calIndex++; } for (int i = 0; i < NUM_IR_BANDS; i++) { irBiasCoef[1][(i + irOffset) % NUM_IR_BANDS] = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); calIndex++; } for (int i = 0; i < NUM_IR_BANDS; i++) { irGainCoef[0][(i + irOffset) % NUM_IR_BANDS] = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); calIndex++; } for (int i = 0; i < NUM_IR_BANDS; i++) { irGainCoef[1][(i + irOffset) % NUM_IR_BANDS] = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); calIndex++; } } else { // initialize lookup table lookupTable = new float [NUM_BANDS_SOUNDER + 1] [LOOKUP_TABLE_SZ_SNDR]; for (int i = 0; i < NUM_BANDS_SOUNDER + 1; i++) { for (int j = 0; j < LOOKUP_TABLE_SZ_SNDR; j++) { lookupTable [i][j] = Float.NaN; } } // read in a sounder format cal block for (int i = 0; i < NUM_VIS_DETECTORS / 2; i++) { visBiasCoef[i] = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); visBiasCoefAVG = visBiasCoefAVG + visBiasCoef[i]; calIndex++; } visBiasCoefAVG = visBiasCoefAVG/(NUM_VIS_DETECTORS/2); for (int i = 0; i < NUM_VIS_DETECTORS / 2; i++) { visGain1Coef[i] = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); visGain1CoefAVG = visGain1CoefAVG + visGain1Coef[i]; calIndex++; } visGain1CoefAVG = visGain1CoefAVG/(NUM_VIS_DETECTORS/2); for (int i = 0; i < NUM_VIS_DETECTORS / 2; i++) { visGain2Coef[i] = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); visGain2CoefAVG = visGain2CoefAVG + visGain2Coef[i]; calIndex++; } visGain2CoefAVG= visGain2CoefAVG/(NUM_VIS_DETECTORS/2); visRadToAlb = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); calIndex++; for (int i = 0; i < NUM_BANDS_SOUNDER; i++) { sBiasCoef[i] = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); calIndex++; } for (int i = 0; i < NUM_BANDS_SOUNDER; i++) { sGainCoef[i] = (float) ConversionUtility.GouldToNative(calBlock[calIndex]); calIndex++; } } } /** * * set calibration type of current (input) data * * @param calType one of the types defined in Calibrator interface * */ public int setCalType(int calType) { if ((calType < Calibrator.CAL_MIN) || (calType > Calibrator.CAL_MAX)) { return -1; } curCalType = calType; return 0; } /** * * calibrate from radiance to temperature * * @param inVal input data value * @param band channel/band number * @param sId sensor id number * */ public abstract float radToTemp(float inVal, int band, int sId); /** * * calibrate data buffer to specified units. * * @param inputData input data buffer * @param band channel/band number * @param calTypeOut units to convert input buffer to * */ public float[] calibrate ( float[] inputData, int band, int calTypeOut ) { // create the output data buffer float[] outputData = new float[inputData.length]; // just call the other calibrate routine for each data point for (int i = 0; i < inputData.length; i++) { outputData[i] = calibrate(inputData[i], band, calTypeOut); } // return the calibrated buffer return outputData; } /** * * calibrate single value to specified units. * * @param inputPixel input data value * @param band channel/band number * @param calTypeOut units to convert input buffer to * */ public float calibrate ( float inputPixel, int band, int calTypeOut ) { float outputData = 0.0f; //System.out.println("#### input pixel="+inputPixel); //System.out.println("#### cal band = "+band); //System.out.println("#### len lookup = "+lookupTable.length+" "+lookupTable[3].length); // load gain and bias constants based on band requested // If this is imager and band 6, change to band 5 if (band != bandNum) { bandNum = band; if ((sid % 2) == 0) { if (band == 1) { gain = visGain1Coef[0]; bias = visBiasCoef[0]; } else { if( band == 6) { band = 5; } gain = irGainCoef[0][band - 2]; bias = irBiasCoef[0][band - 2]; //System.out.println("#### band="+band+" gain="+gain+" bias"+bias); } scale = 32; } else { if (band == 19) { gain = visGain1Coef[0]; bias = visBiasCoef[0]; } else { gain = sGainCoef[band - 1]; bias = sBiasCoef[band - 1]; } scale = 2; } } // check lookup table first, if there is an entry, use it if (curCalType == CAL_BRIT) { // one byte values are signed, so take absolute value for index index = (int) inputPixel + 128; } else { // otherwise scale down the 1K possible 15 bit values to an index index = (int) inputPixel / scale; } //System.out.println("xxx band = "+band+" index = "+index+" scale="+scale+ " inputPixel"+inputPixel); //if (!(Float.isNaN(lookupTable[band - 1][index]))) { // return (lookupTable[band - 1][index]); // } // validate, then calibrate for each combination starting with cur type switch (curCalType) { case CAL_RAW: outputData = inputPixel; // if they want raw, just break right away if (calTypeOut == CAL_RAW) { break; } if(band == 1 || band == 19){ // convert to albedo //int tmp = (int)inputPixel; //int tmp1 = tmp >> 4; float f = (inputPixel)/scale; //float f = tmp1; float G2TERM = 1.0f; if(Math.abs(visGain2CoefAVG) > 0.0001){ G2TERM = (float)Math.pow(f, visGain2CoefAVG); } outputData = (G2TERM + (f * visGain1CoefAVG) + visBiasCoefAVG) * visRadToAlb; if(outputData < 0.0) outputData = 0.0f; if (calTypeOut == CAL_ALB) { outputData = outputData * 100.0f; break; } // convert to brightness outputData = Math.round(Math.sqrt(100.0 * outputData) * 25.5); if (calTypeOut == CAL_BRIT) { break; } // } else { // convert to radiance if ((sid % 2) == 0) { outputData = inputPixel / scale; } outputData = (outputData - bias) / gain; // if they want radiance we are done if (calTypeOut == CAL_RAD) { break; } // otherwise, convert to temperature outputData = radToTemp(outputData, band, sid); // if they want temperature, break here if (calTypeOut == CAL_TEMP) { break; } // compute brightness from temperature if (outputData >= 242.0f) { outputData = Math.max(660 - (int) (outputData * 2), 0); } else { outputData = Math.min(418 - (int) outputData, 255); } // if they want brightness, break here if (calTypeOut == CAL_BRIT) { break; } } break; case CAL_RAD: outputData = inputPixel; break; case CAL_ALB: outputData = inputPixel; break; case CAL_TEMP: outputData = inputPixel; break; case CAL_BRIT: outputData = inputPixel; break; } // lookupTable[band - 1][index] = outputData; return outputData; } public int[] calibratedList( final int band, final boolean isPreCal ) { int[] cList; if(isPreCal){ if (band == 1 || band == 12) { // Visible cList = new int[]{CAL_RAW, CAL_BRIT}; } else { // IR Channel cList = new int[]{CAL_RAW, CAL_TEMP, CAL_BRIT}; } } else { if (band == 1 || band == 12) { // Visible and near-visible (VIS006, VIS008, IR016, HRV) 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; } public String calibratedUnit(int calType){ String unitStr = null; switch (calType) { case CAL_RAW: unitStr = null; break; case CAL_RAD: unitStr = "mW/m^2/sr/cm-1"; break; case CAL_ALB: unitStr = "%"; break; case CAL_TEMP: unitStr = "K"; break; case CAL_BRIT: unitStr = null; break; } // lookupTable[band - 1][index] = outputData; return unitStr; } /** * * convert a gray scale value to brightness temperature * * @param inVal input data value * */ public float convertBritToTemp(int inVal) { int con1 = 418; int con2 = 660; int ilim = 176; float outVal; if(inVal > ilim){ outVal = con1 - inVal; } else { outVal = (con2 - inVal)/2; } return (outVal); } /** * * convert a gray scale value to brightness temperature * * @param inputData input data array * */ public float[] convertBritToTemp (float[] inputData) { // create the output data buffer float[] outputData = new float[inputData.length]; // just call the other calibrate routine for each data point for (int i = 0; i < inputData.length; i++) { outputData[i] = convertBritToTemp((int) inputData[i]); } // return the calibrated buffer return outputData; } public boolean getIsPreCalibrated(){ return isPreCalibrated; } public void setIsPreCalibrated(boolean isPrecalibrated){ this.isPreCalibrated = isPrecalibrated; } }