Source Code
Infrared Signal Coding Schemes
home top contents previous up next

import java.awt.Color;
import java.awt.Dimension;
import java.awt.Image;


final public class PAPM extends MultiPathConvolution{
	public PAPM (Dimension dim, Image img, String problemName){
		super(dim,img,problemName);
	}

    int NIPoints;
	
	//==========================================
	//  Parameter initializations
	//------------------------------------------
	protected void initPreconstructor_Variables(){
		initPreconstructorInMPLevel();

		L=2;
		Amax=2;
	    subModel=3;
		tapsSimulationLimit=10000;
        NIPoints=100;
        shotNoisePresented=1;
		amInteferenceSummationPoints=2;
        flgDrawNumbers=-1;

		modelDescription[0]="Program 1. Draft in progress. Model: PAPM with ISI, Noise, and Ambient Light. Graph: BER(SNR).";
		modelDescription[2]="       ";
		modelDescription[3]="       "+"Horizontal axis stands for SNR, db.  "+
				                    "Vertical axis stands for log(BER)/log(10).";
		
		
		functionCOUNT=4;
        functionTitle[0]="BER.     SNR=2. Rb=100 MHz";        
        functionTitle[1]="BER,db.  Rb=0.05 Mhz";
        functionTitle[2]="BER,db.  Rb=10 Mhz";
        functionTitle[3]="BER,db.  Rb=100 Mhz";
		
        dmnRangeF=20.0;
        dmnRangeFDown=19.0;
        dmnRangeX=10.0;
        grPoints=10;

        drawGrid=true;
        drawLengenOnCurve=false;
        gridStepY=1.0;
        grStartF=120;
        
    	functionColor=new Color[]{
    			new Color(150,0,0),
    			new Color(0,40,0),
    			new Color(150,0,150),
    			new Color(0,0,255),
    			new Color(255,0,0),
    			new Color(0,0,255)
    	};

	}
	
	//-----------------------------------------------
    // User Input Prompts
    //- - - - - - - - - - - - - - - - - - - - - - - - 
    protected int setParsToStrings(){
         int i=0;
        
         String decription="";
         for(int j=0; j<subModelTitle.length; j++){
        	 decription += ", "+j+" - " + subModelTitle[j];
         }
         
         strParsCrr[i][0]=String.valueOf(subModel);   strParsCrr[i][1]="Sub Model: "+decription; strParsCrr[i++][2]="int"; 
         strParsCrr[i][0]=String.valueOf(shotNoisePresented);   strParsCrr[i][1]="shotNoisePresented, 0 or 1"; strParsCrr[i++][2]="int"; 
         //strParsCrr[i][0]=String.valueOf(SNR);  strParsCrr[i][1]="SNR, dB"; strParsCrr[i++][2]="double"; 
         strParsCrr[i][0]=String.valueOf(amSAR);  strParsCrr[i][1]="SAR, Signal to Ambient Light Ratio"; strParsCrr[i++][2]="double"; 
         strParsCrr[i][0]=String.valueOf(amInterferencePeriodTi);  strParsCrr[i][1]="Ti, Ambient Light Interference Period, sec"; strParsCrr[i++][2]="double"; 
		 strParsCrr[i][0]=String.valueOf(amInteferenceSummationPoints);   strParsCrr[i][1]="NTi, Ambient Light Interf. Sum. Points Numb., 1 for no Interference."; strParsCrr[i++][2]="int";
         
         strParsCrr[i][0]=String.valueOf(dmnRangeX);  strParsCrr[i][1]="Argument Range"; strParsCrr[i++][2]="double"; 
         strParsCrr[i][0]=String.valueOf(dmnRangeF);  strParsCrr[i][1]="Function Range"; strParsCrr[i++][2]="double";
         strParsCrr[i][0]=String.valueOf(dmnStartF);  strParsCrr[i][1]="Function Start"; strParsCrr[i++][2]="double";

         //strParsCrr[i][0]=String.valueOf(Rb);   strParsCrr[i][1]="Bit Rate, Rb"; strParsCrr[i++][2]="double";
         strParsCrr[i][0]=String.valueOf(ceilingHeight);   strParsCrr[i][1]="Room Height, meters"; strParsCrr[i++][2]="double";

         strParsCrr[i][0]=String.valueOf(L);   strParsCrr[i][1]="Maximum symbol length, L"; strParsCrr[i++][2]="int"; 
         strParsCrr[i][0]=String.valueOf(Amax);   strParsCrr[i][1]="Non-zero levels in chip amplitude, A"; strParsCrr[i++][2]="int";
         strParsCrr[i][0]=String.valueOf(NIPoints);   strParsCrr[i][1]="Numerical integration via primary slot gap, NIPoints"; strParsCrr[i++][2]="int";

         return i;
    }
    public String setParsFromStrings(){
         int i=0;
         try{
        	 subModel =Integer.parseInt(strParsCrr[i][0]);  i++;
        	 shotNoisePresented =Integer.parseInt(strParsCrr[i][0]);  i++;
        	 //SNR =Double.parseDouble(strParsCrr[i][0]);  i++;
        	 amSAR =Double.parseDouble(strParsCrr[i][0]);  i++;
        	 amInterferencePeriodTi = Double.parseDouble(strParsCrr[i][0]);  i++;
        	 amInteferenceSummationPoints = Integer.parseInt(strParsCrr[i][0]);  i++;
        	 
        	 dmnRangeX =Double.parseDouble(strParsCrr[i][0]);  i++;
        	 dmnRangeF =Double.parseDouble(strParsCrr[i][0]);  i++;
        	 dmnStartF =Double.parseDouble(strParsCrr[i][0]);  i++;
        	 //Rb =Double.parseDouble(strParsCrr[i][0]);  i++;
        	 ceilingHeight =Double.parseDouble(strParsCrr[i][0]);  i++;
        	 L =Integer.parseInt(strParsCrr[i][0]);  i++;
        	 Amax =Integer.parseInt(strParsCrr[i][0]);  i++;
        	 NIPoints =Integer.parseInt(strParsCrr[i][0]);  i++;
         }catch(Exception e){
            return "Exception when (re)setting parameters.\n" + e;    
         }
         return "";
    }
    //- - - - - - - - - - - - - - - - - - - - - - - - 
    // User Input Prompts
	//================================================================
	
	protected void spawnParametersAfterUserApplied(){
		 tapsSimulationLimit=10000;
         simulationBlocked=false;
         userImputCheckOrCorrectionBeforeBasic();
		 if(!simulationBlocked)spanParsInMPLevel();
		 if(!simulationBlocked)userImputCheckOrCorrectionAfterBasic();
		 if(!simulationBlocked)displySpawnedPars();
		 simulateThresholding();
         if(simulationBlocked){
  	  	   for(int i=20; i<modelDescription.length; i++){
  	  		   modelDescription[i]=null;
  	  	   }
		   //Set B to 1.0 to attract attention:
  	  	   BAmb=1.0;
  	  	   con("Simulation blocked.");
         }
	}
	
	private void userImputCheckOrCorrectionBeforeBasic(){
	  	   for(int i=4; i<modelDescription.length; i++){
	  		   modelDescription[i]=null;
	  	   }
           if(L<2){
			   modelDescription[10]="L must be > 1";
			   //Set B to 1.0 to attract attention:
			   simulationBlocked=true;
		   }
	}
	private void userImputCheckOrCorrectionAfterBasic(){
	  	   for(int i=20; i<modelDescription.length; i++){
	  		   modelDescription[i]=null;
	  	   }
	  	   
	  	   if(tapsNumber<1 || avLength<=0.0){
	  		   modelDescription[1]="Taps < 1 or average Length<=0. Unknown exception.";
			   //Set B to 1.0 to attract attention:
			   simulationBlocked=true;
			   return;
	  	   }
		   if(tapsSimulationLimit<=tapsNumber){
			   modelDescription[1]="BER for sub Model " + subModelTitle[subModel]+". Taps Number exceeded limit.";
			   //Set B to 1.0 to attract attention:
			   simulationBlocked=true;
			   return;
		   }
		   if(3!=subModel){
			   modelDescription[1]="Sub model  " + subModelTitle[subModel]+
			                        " requested, but only " + subModelTitle[subModel]+ 
			                        " is implemented in this window.";
			   //Set B to 1.0 to attract attention:
			   simulationBlocked=true;
			   return;
		   }
	}
	
	//---------------------------------------------------------
	//To display this strings in graph background: 
	//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
    private void displySpawnedPars(){
	    //con("subModelTile[0]="+subModelTitle[0]+" " + subModel);
		modelDescription[1]="Sub Model = "+subModelTitle[subModel];
		modelDescription[4]="A="+Amax;
		modelDescription[5]="L="+L;
		//modelDescription[6]="SNR="+SNR+",db     SNR="+SN;
		
		modelDescription[7]="Symbols in Alphabet="+aphabetCount;
		modelDescription[8]="M="+M;
		//modelDescription[9]="BitRate, Rb="+Rb+", bits/second.";
		
		modelDescription[10]="Average Length="+avLength;
		modelDescription[11]="Bits per chip="+bitsPerChip;
		//modelDescription[12]="Chip Length="+T+", seconds.";
		modelDescription[13]="Room Height="+ceilingHeight+", meters.";
		modelDescription[14]="Dispersion Length Scale, a="+a+", seconds.";
		modelDescription[15]="Lambda="+lambda;
		
		modelDescription[16]="Recent tapsNumber="+tapsNumber;
    }
	//- - - - - - - - - - - - - - - - - - - - - - - - - - - - - 
	//  To display this strings in graph background: 
	//------------------------------------------
	//  Parameter initializations
	//==========================================

	
	
	
	//==========================================
	//  Simulation
	//------------------------------------------
    final protected void simulateThresholding(){
       if(simulationBlocked)return;

	   //First, find out number of slots of symbols which  
	   //precede primary symbol and can interfere with primary symbol:
	   int preSymbolSlots=0;
	   while(preSymbolSlots*L<tapsNumber)preSymbolSlots=preSymbolSlots+1;
	   //Recalculated taps number which fits preceding symbols:
	   int pastTaps=preSymbolSlots*L;
	   modelDescription[17]="RecentConvolving symbol slots number="+preSymbolSlots;

	   //Recalculate tapsNumber including primary symbol:
	   int symTapsNumber=pastTaps+L;
	   modelDescription[18]="Recent preceding taps + L ="+symTapsNumber;

       b=new int[symTapsNumber];
	   result=new double[symTapsNumber];
	   //Convolved primary symbol's ambient contribution for each chip: 
	   double[] V=new double[L];
	   
	   double overFlowProtector; 


   	   //------------------------------------
   	   //Generate symbols and chip sequences.
   	   //- - - - - - - - - - - - - - - - - - -
	   int AAmax=Amax;  //Active number of levels.
	   //For PAM Amax+1.
	   overFlowProtector=1.0*L*AAmax;
	   if(overFlowProtector>2.0E9){
			  modelDescription[20]="L*AAmax>2E9, ~ 32 bit limit.";
              simulationBlocked=true;
              return;
	   }
	   int symSlotWeight=L*AAmax;

	   
	   int symbol_events=1;
	   overFlowProtector=1.0; 
	   for(int i=0; i<preSymbolSlots; i++){
		   overFlowProtector=overFlowProtector*symSlotWeight;
		   if(overFlowProtector>2.0E9){
				  modelDescription[20]="symSlotWeight^preSymbolSlots>2E9, ~ 32 bit limit";
	              simulationBlocked=true;
	              return;
		   }
		   symbol_events=symbol_events*symSlotWeight;
	   }
	
	   //Now, symbol_events=symSlotWeight^preSymbolSlots
	   int PPMSymbolSimulationLimit=1000000;
	   //Protect against long calculations:
	   if(PPMSymbolSimulationLimit<=symbol_events){
			  modelDescription[20]="BER for sub Model " + subModelTitle[subModel]+
			                       ". Symbol Slots Limit exceeded.";
			  simulationBlocked=true;
			  return;
       }
	   modelDescription[19]="Recent symbol events="+symbol_events;
   	   //- - - - - - - - - - - - - - - - - - -
       //Generate symbols and chip sequences.
   	   //------------------------------------
	   
	   //We are about ready to summarize ...

	   boolean HeavisideMode=0==shotNoisePresented;

	   //Shortcuts:
       double amK=1.0/amSAR;  //Parameter K-declared in [7, Wong, ...]
       double weight_ISI_NOISE=1.0/symbol_events/(symSlotWeight*M);

       //Prepare constants for numerical integration:
       double GaussNorm=1.0/Math.sqrt(2.0*Math.PI);
       
 	   BAmb=0.0; //Full BER
 	   double amInterferenceStep=amInterferencePeriodTi/amInteferenceSummationPoints;
       for(int iXAm=0; iXAm<amInteferenceSummationPoints; iXAm++){
    	    double tt=amInterferenceStep*iXAm;
            double BB=0.0; //BER under integration by time.
            
            //Prepare ambient contributions to current symbol:
            for(int i=0; i<L; i++){
            	V[i]=amK*am_vi(tt+T*i, T);
            }                             
            
            for(int e=0; e<symbol_events; e++){
            	
            	//------------------------------------
            	//Generate symbols and chip sequences.
            	//- - - - - - - - - - - - - - - - - - -
            	//
            	//   Symbol is encoded as couple
            	//          (d,A) = (PostionOfPrimaryChip, AmplitudeLevelOfPrimaryChip).
            	//   0<=d<=L-1, 0<A<=Amax
            	//
            	//   (d,A) is encoded as number sym:
            	//   sym=d*Amax+(A-1)
            	//
            	//   Hence, sym has range 0<=sym<symSlotWeight=L*Amax.
                //   In turn, for sequence of Lps symbols, the full number      
            	//   of possible sequences is
            	//
            	//   symbol_events = Lps ^ symSlotWeight 
            	//
            	//   Notations in program:
            	//     preSymbolSlots=Lps
            	//     primaryChip=d
            	//
            	int mask=symbol_events;
          	    for(int slot=0; slot<preSymbolSlots; slot++){
          	    	int sym=mask%symSlotWeight;
          	        mask=(mask-sym)/symSlotWeight;
          	        //do1 hard coded for PAPM. Not for PAM:
          	        int amplitude=sym%L;
          	        int primaryChip=(sym-amplitude)/L;
          	        amplitude=amplitude+1;
       	        	for(int i=0; i<L; i++){
       	        		b[slot*L+i]=0;
                        if(primaryChip==i)b[slot*L+i]=amplitude;
       	        	}
          	    }
            	//- - - - - - - - - - - - - - - - - - -
            	//Generate symbols and chip sequences.
            	//------------------------------------

          	    
          	    //Cycle through primary chips:
          	    for(int i=0; i<L; i++){
          	    	//Fill primary symbol's chips with zeros:
          	    	for(int k=0; k<L; k++)b[preSymbolSlots*L+k]=0;
           	    for(int ia=1; ia<=Amax; ia++){
          	    	//Make i-th primary chip non-zero:
          	    	b[preSymbolSlots*L+i]=ia;
          	    	//Calculate convolved chips from the top-1 to
              	    //top-L-1 chip which are chips of current symbol:
          	    	//do1 apparently overcalculating chips after primary chips:
              	    convolve(pastTaps,b,result,false);
                    double Zi=lambda*result[pastTaps+i];
                    //con("Zi="+Zi);
                    if(amInteferenceSummationPoints>1)Zi=Zi+V[i];

                    double Gplus=lambda*(ia+0.5)-Zi;
                    double Gminus=lambda*(ia-0.5)-Zi;
                    
                    //con(" Zi="+Zi+" Gplus="+Gplus+" Gminus="+Gminus);
                    
                    
                    //Setup integration over y.
                    
                    boolean skipSummation = false;
                    double normedGplus=0.0;
                    double normedGminus=0.0;
                    //We have no processor power to integrate numerically.
                    //Deploy tricks ... 
                    if(HeavisideMode){
                    	if(Gplus<0.0 || Gminus>0.0 ) skipSummation=true;
                    }else{
                    	normedGplus=Gplus*SN;
                    	normedGminus=Gminus*SN;

                    	//Set limits for extreme levels for PAPM:
                        if(1==ia)normedGminus=-100.0;
                        if(Amax==ia)normedGplus=100.0;
                        //Hence, when Amax==1, then limit of integration for
                        //y is -oo to +oo.
                    	
                    	normedGplus=Math.min(10.0,normedGplus);
                    	normedGminus=Math.max(-10.0,normedGminus);
                    	if(normedGplus<-9.0)skipSummation=true;
                    	if(normedGminus>9.0)skipSummation=true;
                    	//Now, we excluded infinite trunks ...
                    }
                    //con("skip="+skipSummation+" nGPlus"+normedGplus);
                    if(skipSummation)continue;
                    
                    double PSuccess=0.0;
                    //Now, do integrate numerically ...
                    double NIStep= (normedGplus-normedGminus)/NIPoints;
                    
                    int NIWithHeavisideMode=NIPoints;
                    if(HeavisideMode){
                    	NIWithHeavisideMode=1;
                    	NIStep=1;
                    }
                    for(int iNIy=0; iNIy<NIWithHeavisideMode; iNIy++){
                        //Take values in the middle of intervals: add 0.5 to index:
                    	double y=(iNIy+0.5)*NIStep+normedGminus;
                        double yWeight=GaussNorm*Math.exp(-y*y*0.5)*NIStep;

                        if(HeavisideMode){
                        	y=0;
                        	yWeight=1.0;
                        }
                        
                        //con(" iNIy="+iNIy+" y="+y+" yWeight="+yWeight);
                        //Cycle through competing chips:
                    	double PRODUCT=1.0;
              	        for(int j=0; j<L; j++){
          	    	        if(i==j)continue;
                            double Zj=lambda*result[pastTaps+j];
                            if(amInteferenceSummationPoints>1)Zj=Zj+V[j];
                            double G=Zi-Zj;
                            //BB=BB+UFun.erfh(G);
                            //BB=BB+UFun.erfh(G*SNR_PPM,HeavisideMode);
                            //Recall, y is already normed:
                            double qq=Math.max(0.0, (1-UFun.erfh(y+G*SN,HeavisideMode)));
                            //con(" j="+j+" SN="+SN+"  G="+G+" arg="+(y+G*SN)+" 1-Q="+qq);
                            PRODUCT=PRODUCT*qq;
                            //con("Binstant="+BB+" G="+G);
              	        }    
              	        //con(" PRODUCT="+PRODUCT);
                        PSuccess=PSuccess+yWeight*PRODUCT;
                    }//iNIy - numerical integration ...
           	        BB=BB+1.0-PSuccess;
           	        //con("BB="+BB);
          	    }//primary levels
          	    }//primary chips
          	    //con("e="+e+"  BB="+BB);
        	} //for(e
            BAmb=BAmb+weight_ISI_NOISE*BB;
            //con("iXAm="+iXAm+"  BB="+BB+"  BAmb="+BAmb);
       } //for(int iXAm=0; 
       
       BAmb=BAmb/amInteferenceSummationPoints;
	   //do1 Wrong way. These values printed before calculations:
       modelDescription[20]="Recent BER "+BAmb;
       //con("Recent BER "+BAmb);
	}
	//------------------------------------------
	//  Simulation
	//==========================================
	
	//Accuracy is restricted by 1e-16.
	private double LogBERonSNR(double SNR, double Rb){
		this.SNR=SNR;
		this.Rb=Rb;
		spawnParametersAfterUserApplied();
		//simulateThresholding();
		if(1.0e-16>BAmb)return -16.0; //Blind return. Assumed accuracy limit in Java.
		return Math.log(BAmb)/Math.log(10);
	}
	private double BERonSNR(double SNR, double Rb){
		this.SNR=SNR;
		this.Rb=Rb;
		spawnParametersAfterUserApplied();
		//simulateThresholding();
		if(1.0e-16>BAmb)return 1.0e-16; //Blind return. Assumed accuracy limit in Java.
		return BAmb;
	}

	
	//UCFun ftest=new UCFun();	
	protected double functionSwitchX(int fIx, double t) {return 0;}
	protected double functionSwitch(int fIx, double x){
	    switch(fIx){
	    case 0: return BERonSNR(2.0, 100.0E6);
	    case 1: return LogBERonSNR(x, 0.05E6);
	    case 2: return LogBERonSNR(x, 50.0E6);
	    case 3: return LogBERonSNR(x, 100.0E6);
	    }
	    return 0;
    }
}


Copyright (C) 2009 Konstantin Kirillov