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