graphs.py 3.1 KB

12345678910111213141516171819202122232425262728293031323334353637383940414243444546474849505152535455565758596061626364656667686970717273747576777879808182838485868788
  1. import math
  2. import os
  3. from multiprocessing import Pool
  4. from sklearn.metrics import accuracy_score
  5. from defs import Modulator, Demodulator, Channel
  6. from models.basic import AWGNChannel
  7. from misc import generate_random_bit_array
  8. from models.optical_channel import OpticalChannel
  9. import matplotlib.pyplot as plt
  10. import numpy as np
  11. CPU_COUNT = os.environ.get("CPU_COUNT", os.cpu_count())
  12. def show_constellation(mod: Modulator, chan: Channel, demod: Demodulator, samples=1000):
  13. x = generate_random_bit_array(samples)
  14. x_mod = mod.forward(x)
  15. x_chan = chan.forward(x_mod)
  16. x_demod = demod.forward(x_chan)
  17. plt.plot(x_chan.rect_x[x], x_chan.rect_y[x], '+')
  18. plt.plot(x_chan.rect_x[:, 0][~x], x_chan.rect_y[:, 1][~x], '+')
  19. plt.plot(x_mod.rect_x[:, 0], x_mod.rect_y[:, 1], 'ro')
  20. axes = plt.gca()
  21. axes.set_xlim([-2, +2])
  22. axes.set_ylim([-2, +2])
  23. plt.grid()
  24. plt.show()
  25. print('Accuracy : ' + str())
  26. def get_ber(mod, chan, demod, samples=1000):
  27. if samples % mod.N:
  28. samples += mod.N - (samples % mod.N)
  29. x = generate_random_bit_array(samples)
  30. x_mod = mod.forward(x)
  31. x_chan = chan.forward(x_mod)
  32. x_demod = demod.forward(x_chan)
  33. return 1 - accuracy_score(x, x_demod)
  34. def get_AWGN_ber(mod, demod, samples=1000, start=-8., stop=5., steps=30):
  35. ber_x = np.linspace(start, stop, steps)
  36. ber_y = []
  37. for noise in ber_x:
  38. ber_y.append(get_ber(mod, AWGNChannel(noise), demod, samples=samples))
  39. return ber_x, ber_y
  40. def __calc_ber(packed):
  41. # This function has to be outside get_Optical_ber in order to be pickled by pool
  42. mod, demod, noise, length, pulse_shape, samples = packed
  43. tx_channel = OpticalChannel(noise_level=noise, dispersion=-21.7, symbol_rate=10e9, sample_rate=400e9,
  44. length=length, pulse_shape=pulse_shape, sqrt_out=True)
  45. return get_ber(mod, tx_channel, demod, samples=samples)
  46. def get_Optical_ber(mod, demod, samples=1000, start=-8., stop=5., steps=30, length=100, pulse_shape='rect'):
  47. ber_x = np.linspace(start, stop, steps)
  48. ber_y = []
  49. print(f"Computing Optical BER.. 0/{len(ber_x)}", end='')
  50. with Pool(CPU_COUNT) as pool:
  51. packed_args = [(mod, demod, noise, length, pulse_shape, samples) for noise in ber_x]
  52. for i, ber in enumerate(pool.imap(__calc_ber, packed_args)):
  53. ber_y.append(ber)
  54. i += 1 # just offset by 1
  55. print(f"\rComputing Optical BER.. {i}/{len(ber_x)} ({i * 100 / len(ber_x):6.2f}%)", end='')
  56. print()
  57. return ber_x, ber_y
  58. def get_SNR(mod, demod, ber_func=get_Optical_ber, samples=1000, start=-5, stop=15, **ber_kwargs):
  59. """
  60. SNR for optics and RF should be calculated the same, that is A^2
  61. Because P∝V² and P∝I²
  62. """
  63. x_mod = mod.forward(generate_random_bit_array(samples * mod.N))
  64. sig_power = [A ** 2 for A in x_mod.amplitude]
  65. av_sig_pow = np.mean(sig_power)
  66. av_sig_pow = math.log(av_sig_pow, 10)
  67. noise_start = -start + av_sig_pow
  68. noise_stop = -stop + av_sig_pow
  69. ber_x, ber_y = ber_func(mod, demod, samples, noise_start, noise_stop, **ber_kwargs)
  70. SNR = -ber_x + av_sig_pow
  71. return SNR, ber_y