def main(): tx_im = Image.open("DC4_150x100.pgm") tx_bin = np.unpackbits(np.array(tx_im)) # make sure every modulation has the same energy per symbol bpsk = komm.PSKModulation(2) qam_16 = komm.QAModulation(16, base_amplitudes=1/np.sqrt(10)) qam_256 = komm.QAModulation(256, base_amplitudes=1/np.sqrt(170)) snr = np.arange(0,40,2) ber_bpsk = snr_ber_simulation(tx_bin, snr, bpsk) ber_qam_16 = snr_ber_simulation(tx_bin, snr, qam_16) ber_qam_256 = snr_ber_simulation(tx_bin, snr, qam_256) # plot all snr vs ber curves plt.figure() plt.scatter(snr, ber_bpsk) plt.plot(snr, ber_bpsk, label = 'BPSK') plt.scatter(snr, ber_qam_16) plt.plot(snr, ber_qam_16, label = '16QAM') plt.scatter(snr, ber_qam_256) plt.plot(snr, ber_qam_256, label = '256QAM') plt.xlabel('SNR dB') plt.ylabel('BER percentage') plt.title('SNR vs BER') plt.legend() plt.yscale('log') # image recovery # plt.figure() # rx_im = np.packbits(rx_bin).reshape(tx_im.size[1],tx_im.size[0]) plt.show()
def test_qam_modulation(): qam4 = komm.QAModulation(4) qam8 = komm.QAModulation((4, 2)) qam16 = komm.QAModulation(16) assert np.allclose(qam4.constellation, [-1.0 - 1.0j, 1.0 - 1.0j, -1.0 + 1.0j, 1.0 + 1.0j]) assert np.allclose(qam8.constellation, [ -3.0 - 1.0j, -1.0 - 1.0j, 1.0 - 1.0j, 3.0 - 1.0j, -3.0 + 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, 3.0 + 1.0j ]) assert np.allclose(qam16.constellation, [ -3.0 - 3.0j, -1.0 - 3.0j, 1.0 - 3.0j, 3.0 - 3.0j, -3.0 - 1.0j, -1.0 - 1.0j, 1.0 - 1.0j, 3.0 - 1.0j, -3.0 + 1.0j, -1.0 + 1.0j, 1.0 + 1.0j, 3.0 + 1.0j, -3.0 + 3.0j, -1.0 + 3.0j, 1.0 + 3.0j, 3.0 + 3.0j ])
def create_object(self, x): """ Creates an instance of the corresponding modulation scheme Parameters ---------- x : string containing the name of the modulation scheme Returns ------- instance of the corresponding modulation scheme k : bits per symbol """ if x == 'BPSK': k = 1 obj = komm.PSKModulation(2) if x == 'QPSK': k = 2 obj = komm.PSKModulation(4, phase_offset=np.pi / 4) if x == '4-QAM': k = 2 obj = komm.QAModulation( 4, base_amplitudes=1 / np.sqrt(2.) ) # base_amplitudes is set to a value such that obj.energy_per_symbol becomes unity. if x == '16-QAM': k = 4 obj = komm.QAModulation( 16, base_amplitudes=1 / np.sqrt(10.) ) # base_amplitudes is set to a value such that obj.energy_per_symbol becomes unity. if x == '256-QAM': k = 8 obj = komm.QAModulation( 256, base_amplitudes=1 / np.sqrt(170.) ) # base_amplitudes is set to a value such that obj.energy_per_symbol becomes unity. return obj, k
def __init__(self, nFreqSamples=64, pilotIndices=[-21, -7, 7, 21], pilotAmplitude=1, nData=12, fracCyclic=0.25, mQAM=2): """ nFreqSamples sets the number of frequency coefficients of the FFT. Pilot tones are injected at pilotIndices. The real valued pilot amplitude is pilotAmplitude. For transmission nData bytes are expected in an array. The relative length of the Cyclic prefix is fracCyclic. Number of QAM symbols = 2**mQAM, giving mQAM bits per QAM symbol. Average power is normalised to unity. Default example correspond to 802.11a wifi modulation. """ # the total number of frequency samples self.nIFFT = nFreqSamples # number of data samples in bytes (coded/decoded) self.nData = nData # fracCyclic is relative cyclic prefix/ guard interval length self.nCyclic = int(self.nIFFT * fracCyclic) # indices of pilots self.pilotIndices = np.array(pilotIndices) # amplitudes of the pilot carrier at the beginning self.pilotAmplitude = pilotAmplitude # mQAM bits per QAM symbol self.mQAM = mQAM # normalisation to make average bit energy unity for square QAM norm = 0 for i in range(1, 2**(mQAM // 2), 2): norm = norm + i**2 self.norm = np.sqrt(norm * 2**(2 - mQAM // 2)) # use komm open-source library for QAM mod/demod # pypi.org/project/komm # by Roberto W. Nobrega <*****@*****.**> self.qam = komm.QAModulation(2**self.mQAM, base_amplitudes=1. / self.norm) self.kstart = (8 * self.nData // self.mQAM + self.pilotIndices.size) // 2
def main(): parity = Parity('odd') tx_im = Image.open("DC4_150x100.pgm") tx_bin = np.unpackbits(np.array(tx_im)) modulator = komm.QAModulation(4, base_amplitudes=1 / np.sqrt(2)) # modulator = komm.PSKModulation(2) snr = 4 awgn = komm.AWGNChannel(snr=10**(snr / 10.)) # make the data a multiple of 7 if (len(tx_bin) % 7 != 0): tx_bin = np.int8(np.append(tx_bin, np.zeros(7 - len(tx_bin) % 7))) # transmission rx_bin = [] ARQ_counter = 0 for i in range(0, len(tx_bin), 7): temp = tx_bin[i:i + 7] temp = np.append(temp, parity.parity_cal(temp)) tx_data = modulator.modulate(temp) rx_data = awgn(tx_data) rx_byte = modulator.demodulate(rx_data) while (parity.parity_cal(rx_byte[0:7]) != rx_byte[7]): # parity check fail, need resend rx_data = awgn(tx_data) rx_byte = modulator.demodulate(rx_data) ARQ_counter += 1 rx_bin = np.int8(np.append(rx_bin, rx_byte[0:7])) print("ARQ counter = " + str(ARQ_counter)) print("BER = " + str(BER_cal(tx_bin, rx_bin)))
def qam_constellation_demo(order, base_amplitude, phase_offset, labeling, noise_power_db): qam_modulation = komm.QAModulation(order, base_amplitude, phase_offset, labeling) lim = [-2.125 * np.sqrt(order), 2.125 * np.sqrt(order)] constellation_demo(qam_modulation, noise_power_db, xlim=lim, ylim=lim)
def SimulateBER(snrArray, txBin, Npixels, modulatioInfo): nSNR = len(snrArray) rxDataArray = np.empty(len(txBin)) BitErrorArray = np.empty(2) berArray = np.empty(0) mod = 0 # Create Modulation Scheme Object if (modulatioInfo.get("mod") == "PSK"): mod = komm.PSKModulation(modulatioInfo.get("order")) if (modulatioInfo.get("mod") == 'QAM'): mod = komm.QAModulation(modulatioInfo.get("order")) # Normalize energy per symbol baseAmplitude = 1 / (np.sqrt(mod.energy_per_symbol)) mod = komm.QAModulation(modulatioInfo.get("order"), baseAmplitude) print("Modulation to be used:") print( str(modulatioInfo.get("order")) + " " + str(modulatioInfo.get("mod"))) print("Bits Per Symbol: " + str(mod.bits_per_symbol)) print("Energy Per Symbol: " + str(mod.energy_per_symbol)) print("\n") # Modulate Data txData = mod.modulate(txBin) # For each transmision for i in range(nSNR): # Calculate based on db awgn = komm.AWGNChannel(snr=10**(snrArray[i] / 10.)) # Simulate noise in channel rxData = awgn(txData) # Demodulate Data rxBin = mod.demodulate(rxData) # Append demodulated data as a new row rxDataArray = np.vstack([rxDataArray, rxBin]) awgn = komm.AWGNChannel(snr=10**(snrArray[10] / 10.)) rx_data = awgn(txData) rx_bin = mod.demodulate(rx_data) # Plot few rx bits plt.figure() plt.axes().set_aspect("equal") plt.scatter(rx_data[:10000].real, rx_data[:10000].imag, s=1, marker=".") plt.show() rx_im = np.packbits(rx_bin).reshape(tx_im.size[1], tx_im.size[0]) plt.figure() plt.imshow(np.array(rx_im), cmap="gray", vmin=0, vmax=255) plt.show() # Measuring Bit Error Ratio # For each transmision for j in range(1, nSNR + 1): # Reset number of bit errors BitErrorCount = 0 # Compute bit errors # i.e For each pixel for i in range(Npixels * 8): # If pixel value does not match if (rxDataArray[j][i] != txBin[i]): # Increment error count BitErrorCount += 1 # Calculate bit error rate for transmision ber = BitErrorCount / (Npixels * 8) berArray = np.append(berArray, ber) # Append new dimension containing bit count and bit error rate BitErrorArray = np.vstack([BitErrorArray, [BitErrorCount, ber]]) print("Bit Error Array:") print(BitErrorArray) print("\n") plt.figure() plt.scatter(snrArray, berArray) #plot points plt.plot(snrArray, berArray) #plot lines plt.yscale("log") plt.ylabel('$BER$') plt.xlabel('$SNR$') plt.title((str(modulatioInfo.get("order")) + " " + str(modulatioInfo.get("mod")))) plt.grid(True) #plt.show() # Calculate theoretical BER # Modify k parameter i.e. bits per symbol k = mod.bits_per_symbol errfcDataSet = np.empty(0) # For Each SNR for i in range(nSNR): # Calculate Theorethical BER errfc = 0.5 * scipy.special.erfc( math.sqrt((10**(snrArray[i] / 10)) / k)) errfcDataSet = np.append(errfcDataSet, errfc) plt.plot(snrArray, errfcDataSet, color='r') plt.show() print("Errfc Data Set:") print(errfcDataSet) print("\n") return berArray, errfcDataSet
def SimulateParityBits(snrArray, txBin, Npixels, modulatioInfo): nSNR = len(snrArray) rxBinDecoded = np.empty(0) rxIncorrect = True mod = 0 if (modulatioInfo.get("mod") == "PSK"): mod = komm.PSKModulation(modulatioInfo.get("order")) if (modulatioInfo.get("mod") == 'QAM'): mod = komm.QAModulation( modulatioInfo.get("order")) # add baseAmplitude print("Base Amplitude is: " + str(mod.energy_per_symbol)) # Normalize Enerhy per symbol baseAmplitude = 1 / (np.sqrt(mod.energy_per_symbol)) print("New Base Amplitude is: " + str(baseAmplitude)) mod = komm.QAModulation(modulatioInfo.get("order"), baseAmplitude) print("Modulation to be used:") print( str(modulatioInfo.get("order")) + " " + str(modulatioInfo.get("mod"))) print("Bits Per Symbol: " + str(mod.bits_per_symbol)) print("Energy Per Symbol: " + str(mod.energy_per_symbol)) print("\n") print("Simulating ARQ based on parity bit check!") print("Adding Parity Bits!") # Add parity bits # For each pixel for i in range(Npixels): startIndex = i * 8 # If the sum of on bits is not even if (((np.sum(txBin[startIndex:startIndex + 7])) % 2) != 0): # Change parity bit to 1 txBin[(startIndex + 7)] = 1 # The sum of on bits is even else: # Change parity bit to 0 txBin[(startIndex + 7)] = 0 # Modulate data txDataParity = mod.modulate(txBin) print("Simulating Transmision!") indexFactor = int(8 / mod.bits_per_symbol) berArray = np.empty(0) arqArray = np.empty(0) for c in range(nSNR): print("Simulating SNR: " + str(snrArray[c])) # Set Average Gausian Noise to reflect new SNR awgn = komm.AWGNChannel(snr=10**(snrArray[c] / 10.)) ARQ = 0 # For Each Symbol for i in range(Npixels): # Compute Index of the codeword startIndex = i * indexFactor # Until the Parity bit check is not passed while (rxIncorrect): # Simulate noise in the channel during transmision only rxData = awgn(txDataParity[startIndex:startIndex + indexFactor]) # Demodulate Data rxBin = mod.demodulate(rxData) # Check if parity = 0 if ((np.sum(rxBin) % 2) != 0): # Error During Transmision # Increment Request Counter ARQ += 1 else: # Passed parity check, assume data is correct # Append Data Bits to final binary array rxBinDecoded = np.append(rxBinDecoded, rxBin) # Set while loop flag to false indicating this codeword has been rx without error rxIncorrect = False #Set while loop flag to true to process next codeword rxIncorrect = True # Convert to real int rxBinDecoded = np.real(rxBinDecoded) rxBinDecoded = rxBinDecoded.astype(int) # For SNR 10 Plot graphs if (c == 0): # Plot few rx bits # plt.figure() # plt.axes().set_aspect("equal") # plt.scatter(rxBinDecoded[:10000].real,rxBinDecoded[:10000].imag,s=1,marker=".") # plt.show() rx_im = np.packbits(rxBinDecoded).reshape(tx_im.size[1], tx_im.size[0]) plt.figure() plt.imshow(np.array(rx_im), cmap="gray", vmin=0, vmax=255) plt.show() # Count Bit errors print("Computing BER: " + str(snrArray[c])) BitErrorCount = 0 # For each bit in the rx data for i in range(Npixels * 8): # If bit value does not match if (rxBinDecoded[i] != txBin[i]): # Increment error count BitErrorCount += 1 # Calculate bit error rate for the transmision berArray = np.append(berArray, (BitErrorCount / (Npixels * 8))) arqArray = np.append(arqArray, (ARQ / (Npixels * 8))) print("BER Array:") print(berArray) print("\n") print("ARQ Array:") print(arqArray) print("\n") plt.figure() plt.scatter(snrArray, berArray) #plot points plt.plot(snrArray, berArray) #plot lines plt.yscale("log") plt.ylabel('$BER$') plt.xlabel('$SNR$') plt.title((str(modulatioInfo.get("order")) + " " + str(modulatioInfo.get("mod")) + " BER")) plt.grid(True) # Calculate theoretical BER # Modify k parameter i.e. bits per symbol k = mod.bits_per_symbol errfcDataSet = np.empty(0) # For Each SNR for i in range(nSNR): # Calculate Theorethical BER errfc = 0.5 * scipy.special.erfc( math.sqrt((10**(snrArray[i] / 10)) / k)) errfcDataSet = np.append(errfcDataSet, errfc) plt.plot(snrArray, errfcDataSet, color='r') plt.show() plt.figure() plt.scatter(snrArray, arqArray) #plot points plt.plot(snrArray, arqArray) #plot lines plt.yscale("log") plt.ylabel('$ARQ Rate$') plt.xlabel('$SNR$') plt.title((str(modulatioInfo.get("order")) + " " + str(modulatioInfo.get("mod")) + " ARQ/nBits")) plt.grid(True) return berArray, arqArray, rxBinDecoded
def modulate(self, bits): self.orderCountMethod = "mul" qam = komm.QAModulation(self.orders) return qam.modulate(bits)
def demodulate(self, bods): self.orderCountMethod = "mul" symbols = self.getSymbolsFromSignal(bods) qam = komm.QAModulation(self.orders) return qam.demodulate(symbols)
import pprint as pp import numpy.random as random # sys.path.append("../") import custom_tools.fftplot as fftplot from scipy.fftpack import fft, fftshift, fftfreq, ifft def db(x): # returns dB of number and avoids divide by 0 warnings x = np.array(x) x_safe = np.where(x == 0, 1e-7, x) return 20 * np.log10(np.abs(x_safe)) qam = komm.QAModulation(16) print(f"Constellation: {qam.constellation}") print(f"Symbol Mapping (Gray code): {qam.labeling}") # create dictionary for mapping data words to symbols (matching what we created earlier above # to demonstrate utility of komm library) const_map = dict(zip(qam.labeling, qam.constellation)) print("\n") print("Dictionary for Constellation Mapping for Symbols:") pp.pprint(const_map) sym_rate = 1e3 sym_length = 26 # duration of impulse response oversamp = 4 # samples per symbol