package interference;
import math.Complex;
import math.FFT;
public class WiFiTransceiver {
public static double getNumberOfReceivedErrorBits(String inputMsg, int noNeghboringNodes, int radioRange, int perActiveNodes) {
// The number of received error bits to return
double errBits = 0;
// ------------------------------------------------------
// Wi-Fi Parameters
// ------------------------------------------------------
int signalConstellation = 16;
int symbolSize = signalConstellation/4; //number of bits per symbol
int subChannels = 64;
int cp = 2; //cyclic prefix length
int sizeout = subChannels * 2 + cp;
// ------------------------------------------------------
// Binary Source Generation
//number of bits to be generated in WiFi are = subChannels*symbolLen*2
byte [] binaryData = getStringToBinary(inputMsg);
byte [] binarySource = new byte [subChannels*symbolSize*2];
if (binaryData.length>=subChannels*symbolSize*2)
System.out.print("Too Long Message");
else {
for(int i=0; i<subChannels*symbolSize*2; i++){
if (i<binaryData.length)
binarySource[i]=binaryData[i];
else
binarySource[i] = 0;
}
// ------------------------------------------------------
// Wi-Fi Transmitter
// ------------------------------------------------------
int lengthDecNo = binarySource.length / symbolSize; // length of decimal numbers
int[] DecNumbers = new int[lengthDecNo];
int j = 0;
for (int i = 0; i < binarySource.length; i += 4) {
String s = "" + binarySource[i] + binarySource[i + 1] + binarySource[i + 2] + binarySource[i + 3];
DecNumbers[j] = Integer.parseInt(s, 2);
j++;
}
// ------------------------------------------------------
// Mapping of Decimal Numbers on complex numbers // QAM Modulation
Complex[] qMapping = new Complex[16];
qMapping[0] = new Complex(-3, -3);
qMapping[1] = new Complex(-3, -1);
qMapping[2] = new Complex(-3, 3);
qMapping[3] = new Complex(-3, 1);
qMapping[4] = new Complex(-1, -3);
qMapping[5] = new Complex(-1, -1);
qMapping[6] = new Complex(-1, 3);
qMapping[7] = new Complex(-1, 1);
qMapping[8] = new Complex(3, -3);
qMapping[9] = new Complex(3, -1);
qMapping[10] = new Complex(3, 3);
qMapping[11] = new Complex(3, 1);
qMapping[12] = new Complex(1, -3);
qMapping[13] = new Complex(1, -1);
qMapping[14] = new Complex(1, 3);
qMapping[15] = new Complex(1, 1);
Complex[] modulatedSource = new Complex[lengthDecNo];
for (int i = 0; i < lengthDecNo; i++) {
modulatedSource[i] = qMapping[DecNumbers[i]];
}
// ------------------------------------------------------
// Taking subChannels*2 point IFFT then adding Cyclic Preix
Complex[] IFFTsource = FFT.ifft(modulatedSource, subChannels*2);
Complex[] cyclicPrefixedSource = new Complex[IFFTsource.length + cp];
for (int i = 0; i < IFFTsource.length; i++) {
cyclicPrefixedSource[i + cp] = IFFTsource[i];
}
cyclicPrefixedSource[0] = IFFTsource[IFFTsource.length - 2];
cyclicPrefixedSource[1] = IFFTsource[IFFTsource.length - 1];
// ------------------------------------------------------
// Alpha-Stable Channel
// ------------------------------------------------------
// generating alpha-stable random variables
double [] alpharnd1 = AlphaStableRandom.generateNext(noNeghboringNodes, radioRange, perActiveNodes, sizeout);
double [] alpharnd2 = AlphaStableRandom.generateNext(noNeghboringNodes, radioRange, perActiveNodes, sizeout);
Complex [] alpharnd = new Complex[sizeout];
// generating them twice and then adding them as complex function
for (int i = 0; i < sizeout; i++) {
alpharnd[i] = new Complex(alpharnd1[i], alpharnd2[i]);
}
Complex [] rx = new Complex[sizeout];
double [] noise_real = new double[sizeout];
double [] noise_imag = new double[sizeout];
for (int i = 0; i < sizeout; i++) {
noise_real[i] = cyclicPrefixedSource[i].re() + alpharnd[i].re();
noise_imag[i] = cyclicPrefixedSource[i].im() + alpharnd[i].im();
rx[i] = new Complex(noise_real[i], noise_imag[i]);
}
// ------------------------------------------------------
// Wi-Fi Receiver
// ------------------------------------------------------
// Removing Cyclic Prefix
Complex[] rx_rcp = new Complex[rx.length - cp];
for (int i = 0; i < IFFTsource.length; i++) {
rx_rcp[i] = rx[i + cp];
}
// ------------------------------------------------------
// Taking FFT
Complex[] FFTsignal = FFT.fft(rx_rcp, subChannels*2); // round these values
int[] deModulatedSignal = new int[FFTsignal.length];
for (int i = 0; i < FFTsignal.length; i++) {
for (int h = 0; h < qMapping.length; h++) {
if ((Math.round(FFTsignal[i].im()) == Math.round(qMapping[h].im())) && (Math.round(FFTsignal[i].re()) == Math.round(qMapping[h].re()))) {
deModulatedSignal[i] = h;
}
}
}
// ------------------------------------------------------
// De-Mapping or Demodulation
String[] qDeMapping = new String[deModulatedSignal.length * 4];
for (int i = 0; i < deModulatedSignal.length; i++) {
switch (deModulatedSignal[i]) {
case 0:
deModulatedSignal[i] = 0;
qDeMapping[i] = "0000"; // binary zero
break;
case 1:
deModulatedSignal[i] = 1;
qDeMapping[i] = "0001"; // binary 1
break;
case 2:
deModulatedSignal[i] = 2;
qDeMapping[i] = "0010"; // binary 2
break;
case 3:
deModulatedSignal[i] = 3;
qDeMapping[i] = "0011"; // binary 3
break;
case 4:
deModulatedSignal[i] = 4;
qDeMapping[i] = "0100"; // binary 4
break;
case 5:
deModulatedSignal[i] = 5;
qDeMapping[i] = "0101"; // binary 5
break;
case 6:
deModulatedSignal[i] = 6;
qDeMapping[i] = "0110"; // binary 6
break;
case 7:
deModulatedSignal[i] = 7;
qDeMapping[i] = "0111"; // binary 7
break;
case 8:
deModulatedSignal[i] = 8;
qDeMapping[i] = "1000"; // binary 8
break;
case 9:
deModulatedSignal[i] = 9;
qDeMapping[i] = "1001"; // binary 9
break;
case 10:
deModulatedSignal[i] = 10;
qDeMapping[i] = "1010"; // binary 10
break;
case 11:
deModulatedSignal[i] = 11;
qDeMapping[i] = "1011"; // binary 11
break;
case 12:
deModulatedSignal[i] = 12;
qDeMapping[i] = "1100"; // binary 12
break;
case 13:
deModulatedSignal[i] = 13;
qDeMapping[i] = "1101"; // binary 13
break;
case 14:
deModulatedSignal[i] = 14;
qDeMapping[i] = "1110"; // binary 14
break;
case 15:
deModulatedSignal[i] = 15;
qDeMapping[i] = "1111"; // binary 15
break;
}
}
// ------------------------------------------------------
// Decimal to Binary Conversion
byte[] decimalToBin = new byte[deModulatedSignal.length * 4];
for (int i = 0; i < deModulatedSignal.length * 4; i++) {
decimalToBin[i] = getNthBit(qDeMapping, i);
}
// ------------------------------------------------------
// Calculating number of Errored Bits
byte[] cb = new byte[decimalToBin.length];
for (int i = 0; i < decimalToBin.length; i++) {
cb[i] = binarySource[i];
errBits += (cb[i] == decimalToBin[i]) ? 0 : 1;
}
}
// errBits = Error Bits in the received data
// if errBits == 0 -> Packet Received Correctly
// otherwise -> Packet Not Received Correctly
return errBits ;
}
// ------------------------------------------------------
// Other Functions
// ------------------------------------------------------
public static byte getNthBit(String[] t, int n) {
byte bit = (byte) Integer.parseInt((t[n / 4].charAt(n % 4)) + "");
return bit;
}
// ------------------------------------------------------
// GammaFunction
static double logGamma(double x) {
double tmp = (x - 0.5) * Math.log(x + 4.5) - (x + 4.5);
double ser = 1.0 + 76.18009173 / (x + 0) - 86.50532033 / (x + 1)
+ 24.01409822 / (x + 2) - 1.231739516 / (x + 3)
+ 0.00120858003 / (x + 4) - 0.00000536382 / (x + 5);
return tmp + Math.log(ser * Math.sqrt(2 * Math.PI));
}
static double gamma(double x) { return Math.exp(logGamma(x)); }
// ------------------------------------------------------
// converting Input String to Binary bits Function
public static byte [] getStringToBinary(String inputMsg) {
String s2 = "";
for(int i=0; i<inputMsg.length(); i++) {
char c = inputMsg.charAt(i);
s2 += String.format("%8s", Integer.toBinaryString(c)).replaceAll(" ", "0");
}
s2 = s2.replaceAll("0", "\0");
s2 = s2.replaceAll("1", "\1");
byte [] binarySource = s2.getBytes();
return binarySource;
}
}