1029 lines
52 KiB
Python
1029 lines
52 KiB
Python
''' ----------------------------------------------------------------------------------------------------------------
|
||
|
||
Shannon Equation for Dummies - JPC Feb 2021
|
||
|
||
Educational Application
|
||
|
||
Exploration from Claude's Shannon initial theory to its practical application to satellite communications
|
||
|
||
The application Runs either in local windows or in web pages
|
||
|
||
The Web version via localhost is fully functional although not as convenient as the windowed version (only 1 plot open)
|
||
|
||
The Web version in remote does work for a single user (all users connected can send command but see the same page)
|
||
|
||
--------------------------------------------------------------------------------------------------------------------'''
|
||
|
||
''' ------------------------------------------ Imports ---------------------------------------------------
|
||
|
||
The GUI has been designed to be compatible with both PySimpleGUIWeb and PySimpleGUI
|
||
|
||
The PySimpleGUi version takes full benefit of the matplotlib windowing whereas the Web version is constrained to use
|
||
a web compatible method with only one graph at a time
|
||
|
||
'''
|
||
from math import *
|
||
import matplotlib.pyplot as plt
|
||
import numpy as np
|
||
import webbrowser
|
||
import Shannon_Dict as Shd
|
||
import sqlite3
|
||
import os
|
||
import binascii
|
||
import itur
|
||
from astropy.units import imperial
|
||
# Python Program to Get IP Address
|
||
import socket
|
||
hostname = socket.gethostname()
|
||
IPAddr = socket.gethostbyname(hostname)
|
||
|
||
Web_Version=True #
|
||
Web_Remote=True #
|
||
imperial.enable()
|
||
|
||
if Web_Version :
|
||
import PySimpleGUIWeb as sg
|
||
from matplotlib.backends.backend_tkagg import FigureCanvasTkAgg, FigureCanvasAgg
|
||
import io
|
||
def draw_matfig(fig, element):
|
||
canv = FigureCanvasAgg(fig)
|
||
buf = io.BytesIO()
|
||
canv.print_figure(buf, format='png')
|
||
if buf is None:
|
||
return None
|
||
buf.seek(0)
|
||
data = buf.read()
|
||
element.update(data=data)
|
||
def window_matfig(fig, title_fig, title_win):
|
||
matlayout = [[sg.T(title_fig, font='Any 20')],
|
||
[sg.Image(key='-IMAGE-')],
|
||
[sg.B('Exit')]]
|
||
winmat = sg.Window(title_win, matlayout, finalize=True)
|
||
draw_matfig(fig, winmat['-IMAGE-'])
|
||
while True:
|
||
event, values = winmat.read()
|
||
if event == 'Exit' or event == sg.WIN_CLOSED:
|
||
break
|
||
plt.close()
|
||
winmat.close()
|
||
else:
|
||
import PySimpleGUI as sg
|
||
|
||
if Web_Version and Web_Remote :
|
||
web_cfg={"web_ip":IPAddr,"web_port":8080,"web_start_browser":False}
|
||
else:
|
||
web_cfg={}
|
||
|
||
''' ------------------------------------------ Core Functions ---------------------------------------------------
|
||
|
||
These functions are mainly application of formulas given in the first panel and formatting functions
|
||
|
||
'''
|
||
|
||
def Combine_CNR(*CNR):
|
||
''' Combination of Carrier to Noise Ratio '''
|
||
NCR_l = 0
|
||
for CNR_dB in CNR:
|
||
NCR_l += 10 ** (-CNR_dB / 10) # Summation of normalized noise variances
|
||
return -10 * log(NCR_l, 10)
|
||
|
||
def Shannon(BW=36.0, CNR=10.0, Penalty=0.0):
|
||
''' Shannon Limit, returns Bit Rate '''
|
||
CNR_l = 10 ** ((CNR - Penalty) / 10)
|
||
return BW * log(1 + CNR_l, 2)
|
||
|
||
def BR_Multiplier(BW_mul=1.0, P_mul=2.0, CNR=10.0):
|
||
''' Returns BR multiplier '''
|
||
CNR_l = 10 ** (CNR / 10)
|
||
return BW_mul * log(1 + CNR_l * P_mul / BW_mul, 2) / log(1 + CNR_l, 2)
|
||
|
||
def Shannon_Points(BW=36.0, CNR=10.0):
|
||
''' Returns CNR_l, BR_inf, C/N0 and BR(BW,CNR) '''
|
||
CNR_l = 10 ** (CNR / 10)
|
||
C_N0_l = CNR_l * BW
|
||
BR_infinity = C_N0_l / log(2)
|
||
BR_constrained = Shannon(BW, CNR)
|
||
return CNR_l, BR_infinity, C_N0_l, BR_constrained
|
||
|
||
def Shannon_Sp_Eff(Sp_Eff=0.5, BW=36.0, CNR=10.0):
|
||
''' Returns values at required Spe : CNR, BW, BR '''
|
||
C_N0_l = 10 ** (CNR / 10) * BW
|
||
BW_Spe_1 = C_N0_l
|
||
BW_Spe = C_N0_l / (2 ** Sp_Eff - 1)
|
||
BR_Spe = BW_Spe * Sp_Eff
|
||
CNR_Spe = 10 * log(BW_Spe_1 / BW_Spe, 10)
|
||
return CNR_Spe, BW_Spe, BR_Spe
|
||
|
||
def BR_Format(BR=100):
|
||
return "{:.1f}".format(BR) + ' Mbps'
|
||
|
||
def Power_Format(Pow=100):
|
||
Pow_dB=10*log(Pow,10)
|
||
if Pow > 1 and Pow < 1e4 :
|
||
return "{:.1f}".format(Pow) + ' W .. ' + "{:.1f}".format(Pow_dB) + ' dBW'
|
||
elif Pow <= 1 and Pow > 1e-3 :
|
||
return "{:.4f}".format(Pow) + ' W .. ' + "{:.1f}".format(Pow_dB) + ' dBW'
|
||
else :
|
||
return "{:.1e}".format(Pow) + ' W .. ' + "{:.1f}".format(Pow_dB) + ' dBW'
|
||
|
||
def PFD_Format(Pow=1): # PSD in W per m2
|
||
Pow_dB=10*log(Pow,10)
|
||
return "{:.1e}".format(Pow) + ' W/m\N{SUPERSCRIPT TWO} .. ' + "{:.1f}".format(Pow_dB) + ' dBW/m\N{SUPERSCRIPT TWO}'
|
||
|
||
def PSD_Format(Pow=1): # PSD in W per MHz
|
||
Pow_dB=10*log(Pow,10)
|
||
return "{:.1e}".format(Pow) + ' W/MHz .. ' + "{:.1f}".format(Pow_dB) + ' dBW/MHz'
|
||
|
||
|
||
def Gain_Format(Gain=1000):
|
||
Gain_dB=10*log(Gain,10)
|
||
return "{:.1f}".format(Gain) + ' .. ' + "{:.1f}".format(Gain_dB) + ' dBi'
|
||
|
||
def PLoss_Format(Loss=10):
|
||
Loss_dB=10*log(Loss,10)
|
||
return "{:.2}".format(Loss) + ' m\N{SUPERSCRIPT TWO} .. ' + "{:.1f}".format(Loss_dB) + ' dBm\N{SUPERSCRIPT TWO}'
|
||
|
||
|
||
''' ------------------------------------------ Database Functions ---------------------------------------------------
|
||
|
||
Functions for management of users' contributions
|
||
|
||
'''
|
||
|
||
def Contribution_Write (DB_File) :
|
||
|
||
Sh_DB=sqlite3.connect(DB_File)
|
||
Sh_DB_c=Sh_DB.cursor()
|
||
|
||
Sh_DB_c.execute("CREATE TABLE IF NOT EXISTS contributions "
|
||
"(num INTEGER, name TEXT, title TEXT, keywords TEXT, text TEXT, date TEXT, password TEXT)")
|
||
Sh_DB.commit()
|
||
|
||
Sh_DB_c.execute("SELECT MAX(num) FROM contributions")
|
||
ID_Contrib=Sh_DB_c.fetchall()[0][0]
|
||
|
||
if ID_Contrib == None:
|
||
ID_Contrib = 0
|
||
|
||
print (ID_Contrib)
|
||
|
||
layout3 = [ [sg.Text('Initials / name',size=(20,1), justification='center'),
|
||
sg.Input('',size=(45,1), key='-Name-')],
|
||
[sg.Text('Title ', size=(20, 1), justification='center'),
|
||
sg.Input('', size=(45, 1), key='-Title-')],
|
||
[sg.Text('Keywords ',size=(20,1), justification='center'),
|
||
sg.Input('', size=(45,1), key='-Keywords-')],
|
||
[sg.Text('Password ', size=(20, 1), justification='center'),
|
||
sg.Input('', size=(45, 1), key='-Password-')],
|
||
[sg.Frame('Write your text here',
|
||
[[sg.Multiline('', size=(80, 15), key='-Text-')],
|
||
[sg.Button('Validate'),
|
||
sg.Button('Exit'),
|
||
sg.Button('Help')]],
|
||
element_justification='center')]
|
||
]
|
||
window3 = sg.Window('Write Contribution', layout3, finalize=True)
|
||
|
||
while True:
|
||
event3, values = window3.read()
|
||
print(event3)
|
||
|
||
if event3 == sg.WIN_CLOSED or event3 == 'Exit' : # if user closes window
|
||
break
|
||
|
||
elif event3 == 'Validate' :
|
||
|
||
ID_Contrib += 1
|
||
|
||
Sh_DB_c.execute("INSERT INTO contributions VALUES ( " + str (ID_Contrib) + ", '" + values['-Name-'] +
|
||
"', '" + values['-Title-'] + "', '" + values['-Keywords-'] + "', '" + values['-Text-'] +
|
||
"', " + "Date('now')" + ", '" + values['-Password-'] + "' )")
|
||
Sh_DB.commit()
|
||
|
||
window3['-Text-'].Update('Thank you, your contribution has been successfully stored, ID #'+str(ID_Contrib))
|
||
|
||
elif event3 == 'Help':
|
||
window3['-Text-'].Update('Write your contribution here as a free text. Edit it in the text window until you'
|
||
' are happy with the result and then Validate. \n\nContributions should be candid observations'
|
||
' about the technical subject, references to relevant material (ideally as web pointers), open '
|
||
' discussion items about adjacent subjects, suggestion for improvement... \n\nYou can retrieve'
|
||
' your contribution via a search from the Read Panel and delete them there with the relevant '
|
||
'password. Keeping the "no password" default will allow anyone to delete.')
|
||
|
||
Sh_DB.close()
|
||
|
||
window3.close()
|
||
|
||
return ID_Contrib
|
||
|
||
def Contribution_Read (DB_File) :
|
||
|
||
layout4 = [ [sg.Text('Filter on Name',size=(20,1), justification='center'),
|
||
sg.Input('',size=(45,1), key='-Name-')],
|
||
[sg.Text('Filter on Title ', size=(20, 1), justification='center'),
|
||
sg.Input('', size=(45, 1), key='-Title-')],
|
||
[sg.Text('Filter on Keywords ',size=(20,1), justification='center'),
|
||
sg.Input('', size=(45,1), key='-Keywords-')],
|
||
[sg.Text('Filter on Content ', size=(20, 1), justification='center'),
|
||
sg.Input('', size=(45, 1), key='-Content-')],
|
||
[sg.Frame('Contribution',
|
||
[[sg.Multiline('', size=(80, 15), key='-Text-')],
|
||
[sg.Button('Load / Filter', key='-Filter-'),
|
||
sg.Button('Read Next', key='-Next-'),
|
||
sg.Button('Delete', key='-Del-'),
|
||
sg.Button('Exit'),
|
||
sg.Button('Help')]],
|
||
element_justification='center')]
|
||
]
|
||
|
||
if os.path.isfile(DB_File):
|
||
Sh_DB = sqlite3.connect(DB_File)
|
||
Sh_DB_c = Sh_DB.cursor()
|
||
else:
|
||
sg.popup('No Database Found', keep_on_top=True)
|
||
return 0
|
||
|
||
window4 = sg.Window('Read Contributions', layout4)
|
||
DB_ind = 0
|
||
|
||
while True:
|
||
|
||
event4, values = window4.read()
|
||
|
||
print(event4)
|
||
|
||
if event4 == sg.WIN_CLOSED or event4 == 'Exit': # if user closes window
|
||
break
|
||
|
||
elif event4 == '-Filter-':
|
||
|
||
Name = "'%" + values['-Name-'] + "%'"
|
||
Title = "'%" + values['-Title-'] + "%'"
|
||
Keywords = "'%" + values['-Keywords-'] + "%'"
|
||
Content = "'%" + values['-Content-'] + "%'"
|
||
Sh_DB_c.execute("SELECT num, name, title, keywords, text, date, password FROM contributions WHERE " +
|
||
"name LIKE " + Name +
|
||
" AND title LIKE " + Title +
|
||
" AND keywords LIKE " + Keywords +
|
||
" AND text LIKE " + Content +
|
||
" ORDER BY num DESC "
|
||
" LIMIT 50 ")
|
||
DB_Extract = Sh_DB_c.fetchall()
|
||
|
||
print(len(DB_Extract))
|
||
|
||
if len(DB_Extract) > 0 : # First Contribution read automatically
|
||
|
||
window4['-Text-'].Update( DB_Extract[0][2] + ' , ' + DB_Extract[0][1]
|
||
+ '\n\n' + DB_Extract[0][4] + '\n\n Keywords : ' + DB_Extract[0][3]
|
||
+ '\n\n ID #' + str(DB_Extract[0][0]) + ' - ' + str(DB_Extract[0][5]) )
|
||
DB_ind = 1
|
||
|
||
elif event4 == '-Next-' and DB_ind>0 :
|
||
|
||
if DB_ind < len(DB_Extract):
|
||
window4['-Text-'].Update(DB_Extract[DB_ind][2] + ' , ' + DB_Extract[DB_ind][1]
|
||
+ '\n\n' + DB_Extract[DB_ind][4] + '\n\n Keywords : ' + DB_Extract[DB_ind][3]
|
||
+ '\n\n ID #' + str(DB_Extract[DB_ind][0]) + ' - ' + str(DB_Extract[DB_ind][5]))
|
||
DB_ind +=1
|
||
|
||
elif event4 == '-Del-':
|
||
Password = sg.popup_get_text('Enter Item\'s Password')
|
||
print (Password)
|
||
DB_ind -= 1
|
||
if DB_Extract[DB_ind][6] == Password :
|
||
Item_num=DB_Extract[DB_ind][0]
|
||
Sh_DB_c.execute("DELETE FROM contributions WHERE num = " + str(Item_num))
|
||
window4['-Text-'].Update('Item ID# '+ str(Item_num) + ' deleted')
|
||
else:
|
||
window4['-Text-'].Update('Incorrect password, item unaffected')
|
||
|
||
elif event4 == 'Help':
|
||
window4['-Text-'].Update('To read contributions you have to load them first. If the search fields are empty'
|
||
', all contributions will be loaded. You should only enter 1 item per search field.'
|
||
'\n\n You can delete items if you know the associated password. Items are not encrypted'
|
||
' in the Database and can be removed by the admin.')
|
||
|
||
Sh_DB.commit()
|
||
Sh_DB.close()
|
||
window4.close()
|
||
|
||
return DB_ind
|
||
|
||
|
||
''' ------------------------------------------ GUI Functions---------------------------------------------------
|
||
|
||
LEDs from PySimpleGUI demos
|
||
|
||
'''
|
||
|
||
|
||
def LEDIndicator(key=None, radius=30):
|
||
return sg.Graph(canvas_size=(radius, radius),
|
||
graph_bottom_left=(-radius, -radius),
|
||
graph_top_right=(radius, radius),
|
||
pad=(0, 0), key=key)
|
||
|
||
def SetLED(window, key, color):
|
||
graph = window[key]
|
||
graph.erase()
|
||
graph.draw_circle((0, 0), 12, fill_color=color, line_color='black')
|
||
|
||
|
||
''' ------------------------------------------ Main Program ---------------------------------------------------
|
||
|
||
The program has 2 main panels associated with events collection loops
|
||
|
||
As the loops are build, when the second panel is open, events are only collected for this panel
|
||
|
||
In the windowed version, matplotlib plots don't interfere with the event loops : as many as desired can be open
|
||
|
||
'''
|
||
|
||
# ---------------- First Panel : Shannon's Equation -------------------
|
||
|
||
form_i = {"size":(22,1),"justification":'left',"enable_events":True} # input label format
|
||
form_iv = {"size":(8,1),"justification":'center'} # imput value format
|
||
form_ov = {"size":(20,1),"justification":'center'} # output value format
|
||
form_o = {"size":(65,1),"justification":'right',"enable_events":True} # output label format, also using input elements
|
||
form_CRC = {"size":(8,1),"justification":'center',"enable_events":True} # CRC Format
|
||
|
||
sg.set_options(auto_size_buttons=False, button_element_size=(14,1))
|
||
|
||
col1=sg.Column([[sg.Frame('Theoretical Exploration',
|
||
[[sg.Text(' Reference C/N [dB] ', **form_i,key='-iCNR-'),sg.Input('12', **form_iv, key='-CNR-')],
|
||
[sg.Text(' Reference BW [MHz] ', **form_i,key='-iBW-'),sg.Input('36', **form_iv, key='-BW-'),
|
||
sg.Text('',size=(34,1)),sg.Text('', **form_CRC, key='-CRC-'), LEDIndicator('-OK-')],
|
||
[sg.Text('Carrier Power to Noise Power Density Ratio : C/N\N{SUBSCRIPT ZERO}', **form_o,key='-iC_N0-'),
|
||
sg.Input(**form_ov,key='-C_N0-')],
|
||
[sg.Text('Theoretical BR at infinite BW : 1.44 C/N\N{SUBSCRIPT ZERO}', **form_o,key='-iBRinf-'),
|
||
sg.Input(**form_ov,key='-BRinf-')],
|
||
[sg.Text('Theoretical BR at Spectral Efficiency = 1 : C/N\N{SUBSCRIPT ZERO}', **form_o,key='-iBRunit-'),
|
||
sg.Input(**form_ov,key='-BRunit-')],
|
||
[sg.Text('Theoretical BR at Reference (BW,C/N)', **form_o,key='-iBRbw-'),
|
||
sg.Input(**form_ov, key='-BRbw-')],
|
||
[sg.Text('Carrier to Noise Ratio : C / N = C / (N\N{SUBSCRIPT ZERO}.B)', **form_o,key='-iCNRlin-'),
|
||
sg.Input(**form_ov, key='-CNRlin-')],
|
||
[sg.Text(' BW Increase Factor ',**form_i,key='-iBWmul-'), sg.Input('1', **form_iv, key='-BWmul-')],
|
||
[sg.Text(' Power Increase Factor ',**form_i,key='-iCmul-'), sg.Input('2', **form_iv, key='-Cmul-')],
|
||
[sg.Text('Bit Rate Increase Factor', **form_o,key='-iBRmul-'), sg.Input(**form_ov, key='-BRmul-')],
|
||
[sg.Button('Evaluation', visible=False, key='-Evaluation-', bind_return_key = True),
|
||
sg.Button('BW Sensitivity', pad=((60,5),(2,2)), key='-BW_Graph-'),
|
||
sg.Button('Power Sensitivity',key='-Pow_Graph-'),
|
||
sg.Button('BR Factor Map', key='-Map-'),
|
||
sg.Button('Go to Real World', key='-Real-')]])]])
|
||
|
||
col2=sg.Column([[sg.Frame('Background Information (click on items)',
|
||
[[sg.Multiline('Click on parameter\'s label to get information',size=(80,15),key='-Dialog-')],
|
||
[sg.Button('Advanced'), sg.Button('Write Contribution', key='-Write_Ct-'),
|
||
sg.Button('Read Contributions',key='-Read_Ct-'),sg.Button('Help')]], element_justification='center')]])
|
||
|
||
layout=[
|
||
[sg.Button('Wiki : Claude_Shannon',size=(25,1), key='-Wiki-')],
|
||
[sg.Image(filename='Shannon.png',key='-iShannon-',enable_events=True, background_color='black')],
|
||
[col1,col2]
|
||
]
|
||
|
||
window = sg.Window('Shannon\'s Equation for Dummies', layout, disable_close=True, finalize=True, element_justification='center', **web_cfg)
|
||
|
||
# Needed for the Web version (on a finalized window)
|
||
window['-CNR-'].Update('12')
|
||
window['-BW-'].Update('36')
|
||
window['-BWmul-'].Update('1')
|
||
window['-Cmul-'].Update('2')
|
||
|
||
File_CRC=hex(binascii.crc32(open('Shannon.py', 'rb').read()) & 0xFFFFFFFF)[2:].upper()
|
||
print("File's CRC : ", File_CRC)
|
||
|
||
Win_time_out = 500 # Time out approach required for enter capture in the Web version
|
||
First_Pass = True
|
||
Err_msg = False
|
||
|
||
while True:
|
||
|
||
event, values = window.read(timeout=Win_time_out, timeout_key='__TIMEOUT__')
|
||
|
||
if event != '__TIMEOUT__' : print (event)
|
||
|
||
try:
|
||
|
||
if event == sg.WIN_CLOSED: # if user closes window
|
||
break
|
||
|
||
elif event == '-Evaluation-' or event == '__TIMEOUT__' :
|
||
|
||
if First_Pass :
|
||
window['-Dialog-'].Update(Shd.Help['-iShannon-'])
|
||
First_Pass = False
|
||
|
||
CNR_List=values['-CNR-'] # CNR can be a combination of comma separated CNRs
|
||
CNR_Nyq=Combine_CNR(*[float(val) for val in CNR_List.split(',')])
|
||
|
||
BW_Nyq=float(values['-BW-'])
|
||
|
||
CNR_l, BRinf, C_N0_l, BRbw = Shannon_Points(BW_Nyq,CNR_Nyq)
|
||
|
||
BRunit = C_N0_l # Mbps / MHz : Sp Eff =1
|
||
|
||
window['-C_N0-'].Update("{:.1f}".format(C_N0_l) + ' MHz')
|
||
window['-BRinf-'].Update(BR_Format(BRinf))
|
||
window['-BRunit-'].Update(BR_Format(BRunit))
|
||
window['-BRbw-'].Update(BR_Format(BRbw))
|
||
window['-CNRlin-'].Update("{:.1f}".format(CNR_Nyq)+" [dB] .. "+"{:.1f}".format(CNR_l)+' [Linear]')
|
||
|
||
BWmul=float(values['-BWmul-'])
|
||
Cmul=float(values['-Cmul-'])
|
||
|
||
BRmul=BR_Multiplier(BWmul,Cmul,CNR_Nyq)
|
||
window['-BRmul-'].Update("{:.2f}".format(BRmul))
|
||
|
||
Params = str(CNR_Nyq)+','+str(BW_Nyq)+','+str(BWmul)+','+str(Cmul)
|
||
Params_CRC = (hex(binascii.crc32(Params.encode('ascii')) & 0xFFFFFFFF)[2:].upper()) # Params' CRC
|
||
|
||
elif event == '-Wiki-':
|
||
webbrowser.open('https://en.wikipedia.org/wiki/Claude_Shannon')
|
||
|
||
elif event in ('-iC_N0-','-iCNR-','-iBRinf-','-iBRunit-','-iBRbw-','-iCNRlin-','-iBRmul-','-iCmul-',
|
||
'-iBWmul-','-iBW-','-iShannon-', '-CRC-', 'Advanced','Help' ):
|
||
window['-Dialog-'].Update(Shd.Help[event])
|
||
|
||
elif event == '-BW_Graph-':
|
||
BW = np.zeros(20)
|
||
BR = np.zeros(20)
|
||
CNR = np.zeros(20)
|
||
CNR[0] = CNR_Nyq + 10 * log(8, 10)
|
||
BW[0] = BW_Nyq / 8
|
||
BR[0] = Shannon(BW[0], CNR[0])
|
||
for i in range(1, 20):
|
||
BW[i] = BW[i - 1] * 2 ** (1 / 3)
|
||
CNR[i] = CNR[i - 1] - 10 * log(BW[i] / BW[i - 1], 10)
|
||
BR[i] = Shannon(BW[i], CNR[i])
|
||
fig = plt.figure(figsize=(6, 4))
|
||
ax = fig.add_subplot(111)
|
||
plt.plot(BW, BR, 'b')
|
||
Mark = ('D', 's', 'p', 'h', 'x')
|
||
for i in range(5):
|
||
ind = 3 * (i + 1)
|
||
BR_norm = BR[ind] / BR[9]
|
||
plt.plot(BW[ind], BR[ind], Mark[i] + 'b', label="{:.1f}".format(BW[ind]) + " MHz" +
|
||
" , {:.1f}".format(BR[ind]) + " Mbps" + " : {:.0%}".format(BR_norm))
|
||
plt.title('Theoretical Bit Rate at Constant Power\nC/N\N{SUBSCRIPT ZERO} = ' +
|
||
"{:.1f}".format(C_N0_l) + " MHz" )
|
||
plt.xlabel('Bandwidth [MHz]')
|
||
plt.ylabel('Bit Rate [Mbps]')
|
||
plt.grid(True)
|
||
plt.legend(loc='lower right')
|
||
|
||
if Web_Version:
|
||
window_matfig(fig, title_fig='Bandwidth Sensitivity', title_win='Shannon for Dummies')
|
||
else:
|
||
plt.show(block=False)
|
||
|
||
elif event == '-Pow_Graph-':
|
||
P_mul = np.zeros(20)
|
||
BR = np.zeros(20)
|
||
CNR = np.zeros(20)
|
||
P_mul[0] = 1 / 8
|
||
CNR[0] = CNR_Nyq - 10 * log(8, 10)
|
||
BR[0] = Shannon(BW_Nyq, CNR[0])
|
||
for i in range(1, 20):
|
||
P_mul[i] = P_mul[i-1] * 2 ** ( 1 / 3 )
|
||
CNR[i] = CNR[i - 1] + 10 * log( 2 ** ( 1 / 3 ), 10 )
|
||
BR[i] = Shannon(BW_Nyq, CNR[i])
|
||
fig = plt.figure(figsize=(6, 4))
|
||
ax = fig.add_subplot(111)
|
||
plt.plot(P_mul, BR, 'b')
|
||
Mark = ('D', 's', 'p', 'h', 'x')
|
||
for i in range(5):
|
||
ind = 3 * (i + 1)
|
||
BR_norm = BR[ind] / BR[9]
|
||
plt.plot(P_mul[ind], BR[ind], Mark[i] + 'b', label='{:.2f}'.format(P_mul[ind]) +
|
||
'x , {:.1f}'.format(BR[ind]) + ' Mbps' + ' : {:.0%}'.format(BR_norm))
|
||
plt.title('Theoretical Bit Rate at Constant Bandwidth : ' + '{:.1f}'.format(BW_Nyq) + ' MHz \n'
|
||
'Reference : C/N = {:.1f}'.format(CNR_l) + ' [Linear Format]')
|
||
plt.xlabel('Power Multiplying Factor')
|
||
plt.ylabel('Bit Rate [Mbps]')
|
||
plt.grid(True)
|
||
plt.legend(loc='lower right')
|
||
|
||
if Web_Version:
|
||
window_matfig(fig, title_fig='Power Sensitivity', title_win='Shannon for Dummies')
|
||
else:
|
||
plt.show(block=False)
|
||
|
||
elif event == '-Map-' :
|
||
BR_mul=np.zeros((21,21))
|
||
BW_mul=np.zeros((21,21))
|
||
P_mul=np.zeros((21,21))
|
||
for i in range(21):
|
||
for j in range(21):
|
||
BW_mul[i, j] = (i + 1)/4
|
||
P_mul[i, j] = (j + 1)/4
|
||
BR_mul[i, j] = BR_Multiplier(BW_mul[i, j], P_mul[i, j], CNR_Nyq)
|
||
fig = plt.figure(figsize=(6, 4))
|
||
ax = fig.add_subplot(111)
|
||
Map = plt.contour(BW_mul,P_mul,BR_mul, 20)
|
||
plt.clabel(Map, inline=1, fontsize=8,fmt='%.2f')
|
||
plt.title('Bit Rate Multiplying Factor, \n Reference : C/N = {:.1f}'.format(CNR_Nyq) + ' dB, BW = ' +
|
||
'{:.1f}'.format(BW_Nyq) + ' MHz , C/N\N{SUBSCRIPT ZERO} = ' + '{:.1f}'.format(C_N0_l) +
|
||
' MHz, BR = {:.1f}'.format(BRbw) + ' Mbps', fontsize=10)
|
||
plt.xlabel('Bandwidth Multiplying Factor')
|
||
plt.ylabel('Power Multiplying Factor')
|
||
plt.grid(True)
|
||
|
||
if Web_Version:
|
||
window_matfig(fig, title_fig='Multiplying Factors Map', title_win='Shannon for Dummies')
|
||
else:
|
||
plt.show(block=False)
|
||
|
||
elif event == '-Write_Ct-' :
|
||
Contribution_Write('Shannon_Theory.db')
|
||
|
||
elif event == '-Read_Ct-' :
|
||
Contribution_Read('Shannon_Theory.db')
|
||
|
||
elif event == '-Real-': # ---------------- Second Panel : Real World -------------------
|
||
|
||
P_i1, P_i2, P_i3 = '', '', ''
|
||
|
||
fr1 = sg.Frame('Satellite Link',[
|
||
[sg.Text('Satellite Altitude [km] ', **form_i, key='-iSatAlt-'),
|
||
sg.Input('35786', **form_iv, key='-SatAlt-'),
|
||
sg.Text('Satellite Lat, Long [\N{DEGREE SIGN}]', **form_i, key='-iSatLatLong-'),
|
||
sg.Input('0.0, 19.2', **form_iv, key='-SatLatLong-'),
|
||
sg.Text('Ground Station Lat, Long [\N{DEGREE SIGN}]', **form_i, key='-iGSLatLong-'),
|
||
sg.Input('49.7, 6.3', **form_iv, key='-GSLatLong-')],
|
||
[sg.Text('HPA Output Power [W]',**form_i,key='-iHPA-'),
|
||
sg.Input('120', **form_iv, key='-HPA_P-'),
|
||
sg.Text('Output Losses [dB]',**form_i,key='-iLoss-'),
|
||
sg.Input('2', **form_iv, key='-Losses-'),
|
||
sg.Text('TX Impairments, C/I [dB]', **form_i, key='-iSCIR-'),
|
||
sg.Input('25, 25', **form_iv, key='-Sat_CIR-')],
|
||
[sg.Text('Beam Diameter [\N{DEGREE SIGN}]', **form_i, key='-iSBeam-'),
|
||
sg.Input('3', **form_iv, key='-Sat_Beam-'),
|
||
sg.Text('Offset from Peak [dB] ', **form_i, key='-iGOff-'),
|
||
sg.Input('0', **form_iv, key='-Gain_Offset-'), sg.Text('', size=(7, 1)),
|
||
sg.Text('', **form_CRC, key='-CRC1-'), LEDIndicator('-OK1-')],
|
||
[sg.Text('Frequency [GHz]', **form_i, key='-iFreq-'),
|
||
sg.Input('12', **form_iv, key='-Freq-'),
|
||
sg.Text('Link Availability [%]', **form_i, key='-iAvail-'),
|
||
sg.Input('99.9', **form_iv, key='-Avail-')],
|
||
[sg.Text('Output Power', **form_o,key='-iOPow-'),
|
||
sg.Input('', size=(35, 1), key='-Feed_P-', justification='center')],
|
||
[sg.Text('Satellite Antenna Gain', **form_o,key='-iSGain-'),
|
||
sg.Input('', size=(35, 1), key='-Sat_G-', justification='center')],
|
||
[sg.Text('Equivalent Isotropic Radiated Power', **form_o,key='-iEIRP-'),
|
||
sg.Input('', size=(35, 1), key='-EIRP-', justification='center')],
|
||
[sg.Text('Path Length @ Elevation', **form_o, key='-iPathLength-'),
|
||
sg.Input('', size=(35, 1), key='-PathLength-', justification='center')],
|
||
[sg.Text('Path Dispersion Loss', **form_o, key='-iPLoss-'),
|
||
sg.Input('', size=(35, 1), key='-PLoss-', justification='center')],
|
||
[sg.Text('Atmospheric Attenuation', **form_o, key='-iAtmLoss-'),
|
||
sg.Input('', size=(35, 1), key='-AtmLoss-', justification='center')],
|
||
[sg.Text('Power Flux Density', **form_o,key='-iPFD-'),
|
||
sg.Input('', size=(35, 1), key='-PFD-', justification='center')],
|
||
], key='-SatLink-')
|
||
|
||
fr2=sg.Frame('Radio Front End ',[
|
||
[sg.Text('Receive Antenna Size [m]',**form_i,key='-iCPE-'),
|
||
sg.Input('0.6', **form_iv, key='-CPE_Ant-'),
|
||
sg.Text('Noise Temperature [K] ', **form_i, key='-iCPE_T-'),
|
||
sg.Input('140', **form_iv, key='-CPE_T-'), sg.Text('',size=(7, 1)),
|
||
sg.Text('', **form_CRC, key='-CRC2-'),LEDIndicator('-OK2-')],
|
||
[sg.Text('Customer Antenna Effective Area and G/T', **form_o,key='-iCGain-'),
|
||
sg.Input('', size=(35, 1), key='-CPE_G-', justification='center')],
|
||
[sg.Text('RX Power at Antenna Output', **form_o,key='-iRXPow-'),
|
||
sg.Input('', size=(35, 1), key='-RX_P-', justification='center')],
|
||
[sg.Text('Noise Power Density Antenna Output', **form_o, key='-iN0-'),
|
||
sg.Input('', size=(35, 1), key='-N0-', justification='center')],
|
||
[sg.Text('Bit Rate at infinite Bandwidth', **form_o,key='-iBRinf-'),
|
||
sg.Input('', size=(35, 1), key='-BRinf-', justification='center')],
|
||
[sg.Text('Bit Rate at Spectral Efficiency=1', **form_o,key='-iBRUnit-'),
|
||
sg.Input('', size=(35, 1), key='-BRUnit-', justification='center')],
|
||
[sg.Text('Bit Rate at Spectral Efficiency=2', **form_o,key='-iBRdouble-'),
|
||
sg.Input('', size=(35, 1), key='-BRdouble-', justification='center')]
|
||
], key='-iRadio-')
|
||
|
||
fr3=sg.Frame('Baseband Unit',[
|
||
[sg.Text('Occupied Bandwidth [MHz]',**form_i,key='-iBW-'),
|
||
sg.Input('36', **form_iv, key='-BW-'),
|
||
sg.Text('Nyquist Filter Rolloff [%]',**form_i,key='-iRO-'),
|
||
sg.Input('5', **form_iv, key='-RO-'),
|
||
sg.Text('Higher Layers Overhead [%]', **form_i, key='-iOH-'),
|
||
sg.Input('5', **form_iv, key='-OH-')],
|
||
[sg.Text('RX Impairments, C/I [dB]',**form_i,key='-iCIR-'),
|
||
sg.Input('20', **form_iv, key='-CIR-'),
|
||
sg.Text('Implementation Penalty [dB]',**form_i,key='-iPenalty-'),
|
||
sg.Input('1.5', **form_iv, key='-Penalty-'), sg.Text('',size=(7, 1)),
|
||
sg.Text('', **form_CRC, key='-CRC3-'), LEDIndicator('-OK3-')],
|
||
[sg.Text('Signal to Noise Ratio in Available BW', **form_o,key='-iCNRbw-'),
|
||
sg.Input('', size=(35, 1), key='-CNRbw-', justification='center')],
|
||
[sg.Text('Signal to Noise Ratio in Nyquist BW', **form_o,key='-iCNRnyq-'),
|
||
sg.Input('', size=(35, 1), key='-CNRnyq-', justification='center')],
|
||
[sg.Text('Signal to Noise Ratio at Receiver Output', **form_o,key='-iCNRrcv-'),
|
||
sg.Input('', size=(35, 1), key='-CNRrcv-', justification='center')],
|
||
[sg.Text('Theoretical Bit Rate', **form_o,key='-iBRnyq-'),
|
||
sg.Input('', size=(35, 1), key='-BRnyq-', justification='center')],
|
||
[sg.Text('Practical Bit Rate', **form_o,key='-iBRrcv-'),
|
||
sg.Input('', size=(35, 1), key='-BRrcv-', justification='center')],
|
||
[sg.Text('Practical Higher Layers Bit Rate', **form_o,key='-iBRhigh-'),
|
||
sg.Input('', size=(35, 1), key='-BRhigh-', justification='center')],
|
||
[sg.Button('Evaluation', key='-Evaluation-',visible=False, bind_return_key = True),
|
||
sg.Button('BW Sensitivity', pad=((100,5),(2,2)), key='-BW_Graph-'),
|
||
sg.Button('Power Sensitivity',key='-Pow_Graph-'),
|
||
sg.Button('BR Factor Map', key='-Map-'),
|
||
sg.Button('Back to Theory', key='-Back-')],
|
||
], key='-Baseband-')
|
||
|
||
fr4 = sg.Frame('Background Information (click on items)',
|
||
[[sg.Multiline('Click on parameter\'s label to get information', size=(80, 15),key='-Dialog-')],
|
||
[sg.Button('Advanced'), sg.Button('Write Contribution', key='-Write_Ct-'),
|
||
sg.Button('Read Contributions',key='-Read_Ct-'), sg.Button('Help')]],element_justification='center')
|
||
|
||
layout2 =[
|
||
[sg.Column([[fr1],[fr2],[fr3]]),
|
||
sg.Column([[sg.Text('', size=(55, 1), justification='center', key='-FCRC-')],
|
||
[sg.Button('Wiki : Harry Nyquist', size=(25,1), key='-W_Nyquist-'),
|
||
sg.Button('Wiki : Richard Hamming', size=(25,1), key='-W_Hamming-')],
|
||
[sg.Button('Wiki : Andrew Viterbi', size=(25,1), key='-W_Viterbi-'),
|
||
sg.Button('Wiki : Claude Berrou', size=(25,1), key='-W_Berrou-')],
|
||
[sg.Image(filename='Satellite.png', key='-Satellite-',background_color='black', enable_events=True)],
|
||
[fr4]], element_justification='center')]]
|
||
|
||
window2 = sg.Window('Shannon and Friends in the Real World', layout2, finalize=True)
|
||
|
||
window2['-FCRC-'].Update('Program\'s CRC: ' + File_CRC)
|
||
|
||
# Needed for the Web version (on a finalized window)
|
||
window2['-Freq-'].Update('12')
|
||
window2['-Losses-'].Update('2')
|
||
window2['-SatAlt-'].Update('35786')
|
||
window2['-SatLatLong-'].Update('0.0, 19.2')
|
||
window2['-Avail-'].Update('99.9')
|
||
window2['-GSLatLong-'].Update('49.7, 6.3')
|
||
window2['-HPA_P-'].Update('120')
|
||
window2['-Sat_CIR-'].Update('25, 25')
|
||
window2['-Sat_Beam-'].Update('3')
|
||
window2['-Gain_Offset-'].Update('0')
|
||
window2['-CPE_Ant-'].Update('0.6')
|
||
window2['-CPE_T-'].Update('120')
|
||
window2['-Penalty-'].Update('1.5')
|
||
window2['-BW-'].Update('36')
|
||
window2['-CIR-'].Update('25')
|
||
window2['-RO-'].Update('5')
|
||
window2['-OH-'].Update('5')
|
||
window2['-AtmLoss-'].Update(' ... LOADING ...')
|
||
|
||
First_Pass = True
|
||
while True:
|
||
|
||
event2, values = window2.read(timeout=Win_time_out,timeout_key = '__TIMEOUT__')
|
||
|
||
if event2 != '__TIMEOUT__' : print(event2)
|
||
|
||
P_err = 0 # Error ID
|
||
|
||
try:
|
||
|
||
if event2 == sg.WIN_CLOSED or event2 == '-Back-': # closes window
|
||
break
|
||
|
||
elif event2 == '-Evaluation-'or event2 == '__TIMEOUT__' :
|
||
|
||
if First_Pass :
|
||
window2['-Dialog-'].Update(Shd.Help2['-Satellite-'])
|
||
First_Pass = False
|
||
|
||
P_err = 1 # Error ID
|
||
Freq = float(values['-Freq-']) # GHz
|
||
HPA_Power = float(values['-HPA_P-']) # Watts
|
||
Sat_Loss = float(values['-Losses-']) # dB
|
||
Sat_CIR_List = values['-Sat_CIR-'] # list if comma separated CIR contributions in dB
|
||
Sat_CIR = Combine_CNR(*[float(val) for val in Sat_CIR_List.split(',')])
|
||
Sig_Power = HPA_Power * 10 ** (-Sat_Loss / 10) # Watts
|
||
Sat_Beam = float(values['-Sat_Beam-']) #dB
|
||
Gain_Offset = float(values['-Gain_Offset-']) #dB
|
||
Sat_Ant_eff = 0.65 # Factor
|
||
|
||
window2['-Feed_P-'].Update(Power_Format(Sig_Power))
|
||
|
||
Lambda = 300e6 / Freq / 1e9 # meter
|
||
Sat_Gain_l = Sat_Ant_eff * ( pi * 70 / Sat_Beam ) ** 2
|
||
Sat_Gain_l = Sat_Gain_l * 10**(-Gain_Offset/10)
|
||
Sat_Ant_d = 70 * Lambda / Sat_Beam
|
||
Sat_Gain_dB = 10 * log(Sat_Gain_l, 10)
|
||
|
||
window2['-Sat_G-'].Update(Gain_Format(Sat_Gain_l))
|
||
|
||
EIRP_l = Sig_Power * Sat_Gain_l
|
||
EIRP_dB = 10 * log(EIRP_l, 10)
|
||
window2['-EIRP-'].Update(Power_Format(EIRP_l))
|
||
|
||
Avail = float(values['-Avail-'])
|
||
|
||
R_earth=6378
|
||
|
||
[lat_GS, lon_GS] = [float(val) for val in values['-GSLatLong-'].split(',')]
|
||
[lat_sat, lon_sat] = [float(val) for val in values['-SatLatLong-'].split(',')]
|
||
|
||
h_sat = float(values['-SatAlt-'])
|
||
|
||
Path_Length = sqrt (h_sat**2 + 2 * R_earth * (R_earth + h_sat ) *
|
||
( 1 - cos(np.radians(lat_sat-lat_GS)) * cos(np.radians(lon_sat-lon_GS))))
|
||
|
||
# elevation = itur.utils.elevation_angle(h_sat, lat_sat, lon_sat, lat_GS, lon_GS) # non signed
|
||
|
||
Phi = acos(cos(np.radians(lat_sat-lat_GS)) * cos(np.radians(lon_sat-lon_GS)))
|
||
|
||
if Phi > 0 :
|
||
elevation = np.degrees(atan((cos(Phi)-R_earth/(R_earth+h_sat))/sqrt(1-cos(Phi)**2)))
|
||
else :
|
||
elevation = 90
|
||
|
||
if elevation <= 0 :
|
||
Atm_Loss = 999
|
||
else:
|
||
Atm_Loss = itur.atmospheric_attenuation_slant_path(lat_GS, lon_GS, Freq,
|
||
elevation, 100-Avail, 1).value
|
||
|
||
window2['-AtmLoss-'].Update("{:.1f}".format(10 ** (Atm_Loss/10)) + ' [Linear] .. ' +
|
||
"{:.1f}".format(Atm_Loss) + " [dB]")
|
||
window2['-PathLength-'].Update("{:.1f}".format(Path_Length) + " [km] @ " +
|
||
"{:.1f}".format(elevation) + " [\N{DEGREE SIGN}]")
|
||
|
||
Free_Space_Loss_l = (4 * pi * Path_Length * 1000 / Lambda) ** 2
|
||
Free_Space_Loss_dB = 10 * log(Free_Space_Loss_l, 10)
|
||
|
||
Path_Loss_l = 4 * pi * (Path_Length * 1000) ** 2
|
||
Path_Loss_dB = 10 * log(Path_Loss_l, 10)
|
||
window2['-PLoss-'].Update(PLoss_Format(Path_Loss_l))
|
||
|
||
PFD_l = EIRP_l / Path_Loss_l * 10 ** (-Atm_Loss/ 10)
|
||
PFD_dB = 10 * log(PFD_l, 10)
|
||
window2['-PFD-'].Update(PFD_Format(PFD_l))
|
||
|
||
P_err = 2 # Error ID
|
||
CPE_Ant_d = float(values['-CPE_Ant-']) # meter
|
||
CPE_T_Clear= float(values['-CPE_T-']) # K
|
||
CPE_Ant_eff = 0.6
|
||
CPE_T_Att = (CPE_T_Clear - 40) + 40 * 10 ** (-Atm_Loss/10) + 290 * (1 - 10 ** (-Atm_Loss/10))
|
||
k_Boltz = 1.38e-23 # J/K
|
||
|
||
P_err = 3 # Error ID
|
||
Penalties = float(values['-Penalty-']) # dB, overall implementation penalty
|
||
Bandwidth = float(values['-BW-']) # MHz
|
||
CNR_Imp_List = values['-CIR-'] # List of comma separated CNR impairments in dB
|
||
CNR_Imp = Combine_CNR(*[float(val) for val in CNR_Imp_List.split(',')])
|
||
Rolloff = float(values['-RO-']) # percent
|
||
Overheads = float(values['-OH-']) # percent
|
||
|
||
CPE_Ae = pi * CPE_Ant_d ** 2 / 4 * CPE_Ant_eff
|
||
CPE_Gain_l = (pi * CPE_Ant_d / Lambda) ** 2 * CPE_Ant_eff
|
||
CPE_Gain_dB = 10 * log(CPE_Gain_l, 10)
|
||
CPE_Beam = 70 * Lambda / CPE_Ant_d # diameter in degrees
|
||
CPE_G_T = 10 * log(CPE_Gain_l / CPE_T_Att, 10)
|
||
window2['-CPE_G-'].Update(
|
||
"{:.1f}".format(CPE_Ae)+" m\N{SUPERSCRIPT TWO} .. {:.1f}".format(CPE_G_T)+" dB/K")
|
||
|
||
RX_Power_l = PFD_l * CPE_Ae
|
||
# Alternative : RX_Power_l=EIRP_l/Free_Space_Loss_l*CPE_Gain_l
|
||
RX_Power_dB = 10 * log(RX_Power_l,10)
|
||
N0 = k_Boltz * CPE_T_Att # W/Hz
|
||
C_N0_l = RX_Power_l / N0 # Hz
|
||
C_N0_dB = 10 * log(C_N0_l, 10) # dBHz
|
||
window2['-RX_P-'].Update('C : ' + Power_Format(RX_Power_l))
|
||
window2['-N0-'].Update('N\N{SUBSCRIPT ZERO} : ' + PSD_Format(N0*1e6))
|
||
|
||
BW_Spe_1 = C_N0_l / 1e6 # C_N0 without Penalty in MHz
|
||
BW_Spe_1half = BW_Spe_1 / (2 ** 0.5 - 1) # MHz
|
||
BW_Spe_1quarter = BW_Spe_1 / (2 ** 0.25 - 1)
|
||
BW_Spe_double = BW_Spe_1 / (2 ** 2 - 1)
|
||
|
||
BR_Spe_1 = BW_Spe_1 # Mbps
|
||
BR_Spe_1half = BW_Spe_1half / 2
|
||
BR_Spe_1quarter = BW_Spe_1quarter / 4
|
||
BR_Spe_double= BW_Spe_double * 2
|
||
BR_infinity = BW_Spe_1 / log(2)
|
||
BR_Spe_1_Norm = BR_Spe_1 / BR_infinity
|
||
BR_Spe_1half_Norm = BR_Spe_1half / BR_infinity
|
||
BR_Spe_1quarter_Norm = BR_Spe_1quarter / BR_infinity
|
||
BR_Spe_double_Norm = BR_Spe_double / BR_infinity
|
||
window2['-BRinf-'].Update('1.443 C/N\N{SUBSCRIPT ZERO} : ' +
|
||
BR_Format(BR_infinity)+" .. {:.0%}".format(1))
|
||
window2['-BRUnit-'].Update('C/N\N{SUBSCRIPT ZERO} : ' +
|
||
BR_Format(BR_Spe_1)+" .. {:.0%}".format(BR_Spe_1_Norm))
|
||
window2['-BRdouble-'].Update('0.667 C/N\N{SUBSCRIPT ZERO} : ' +
|
||
BR_Format(BR_Spe_double)+" .. {:.0%}".format(BR_Spe_double_Norm))
|
||
|
||
CNR_Spe_1 = 0 # dB
|
||
CNR_Spe_1half = -10 * log(BW_Spe_1half / BW_Spe_1, 10)
|
||
CNR_Spe_1quarter = -10 * log(BW_Spe_1quarter / BW_Spe_1, 10)
|
||
CNR_Spe_double = -10 * log(BW_Spe_double/ BW_Spe_1, 10)
|
||
|
||
CNR_BW = CNR_Spe_1 + 10 * log(BW_Spe_1 / Bandwidth, 10) # dB
|
||
BW_Nyq = Bandwidth / (1 + Rolloff / 100) # MHz
|
||
CNR_Nyq = CNR_Spe_1 + 10 * log(BW_Spe_1 / BW_Nyq, 10) # dBB
|
||
CNR_Rcv = Combine_CNR (CNR_Nyq, CNR_Imp, Sat_CIR) #
|
||
BR_BW = Shannon (Bandwidth, CNR_BW) # Mbps
|
||
BR_Nyq = Shannon (BW_Nyq, CNR_Nyq) # Mbps
|
||
BR_Rcv = Shannon (BW_Nyq, CNR_Rcv,Penalties) # Mbps
|
||
BR_Rcv_Higher = BR_Rcv / (1 + Overheads / 100) # Mbps
|
||
BR_BW_Norm = BR_BW / BR_infinity
|
||
BR_Nyq_Norm = BR_Nyq / BR_infinity
|
||
BR_Rcv_Norm = BR_Rcv / BR_infinity
|
||
BR_Rcv_H_Norm = BR_Rcv_Higher / BR_infinity
|
||
Spe_BW = BR_BW / Bandwidth
|
||
Spe_Nyq = BR_Nyq / Bandwidth # Efficiency in available bandwidth
|
||
Bits_per_Symbol = BR_Nyq / BW_Nyq # Efficiency in Nyquist bandwidth
|
||
Spe_Rcv = BR_Rcv / Bandwidth
|
||
Spe_Higher = BR_Rcv_Higher / Bandwidth
|
||
|
||
window2['-CNRbw-'].Update("{:.1f}".format(CNR_BW)+" dB in "+"{:.1f}".format(Bandwidth)+" MHz")
|
||
window2['-CNRnyq-'].Update("{:.1f}".format(CNR_Nyq)+" dB in "+"{:.1f}".format(BW_Nyq)+" MHz")
|
||
window2['-CNRrcv-'].Update("{:.1f}".format(CNR_Rcv)+" dB")
|
||
window2['-BRnyq-'].Update(BR_Format(BR_Nyq) + " .. {:.0%}".format(BR_Nyq_Norm)+
|
||
" .. {:.1f}".format(Spe_Nyq)+" bps/Hz .. {:.1f}".format(Bits_per_Symbol)+" b/S")
|
||
window2['-BRrcv-'].Update(BR_Format(BR_Rcv) + " .. {:.0%}".format(BR_Rcv_Norm)+
|
||
" .. {:.1f}".format(Spe_Rcv)+" bps/Hz")
|
||
window2['-BRhigh-'].Update(BR_Format(BR_Rcv_Higher)+" .. {:.0%}".format(BR_Rcv_H_Norm)+
|
||
" .. {:.1f}".format(Spe_Higher)+" bps/Hz")
|
||
|
||
Params1 = str(Freq) + ',' + str(Path_Length) + ',' + str(Atm_Loss) + ',' + \
|
||
str(HPA_Power) + ',' + str(Sat_Loss) + ',' + str(Sat_CIR) + ',' + \
|
||
str(Sat_Beam) + ',' + str(Gain_Offset)
|
||
Params2 = str(CPE_Ant_d) + ',' + str(CPE_T_Clear)
|
||
Params3 = str(Bandwidth) + ',' + str(Rolloff) + ',' + str(Overheads) + ',' + \
|
||
str(CNR_Imp) + ',' + str(Penalties)
|
||
|
||
Params1_CRC=hex(binascii.crc32(Params1.encode('ascii')) & 0xFFFFFFFF)[2:].upper()
|
||
Params2_CRC = hex(binascii.crc32(Params2.encode('ascii')) & 0xFFFFFFFF)[2:].upper()
|
||
Params3_CRC = hex(binascii.crc32(Params3.encode('ascii')) & 0xFFFFFFFF)[2:].upper()
|
||
|
||
elif event2 in ('-iFreq-','-iHPA-','-iSBeam-','-iLoss-', '-iGOff-','-iFade-', '-iSCIR-',
|
||
'-iOPow-','-iSGain-', '-iEIRP-', '-iPFD-', '-iCPE-','-iCGain-','-iRXPow-',
|
||
'-iBRinf-','-iBRhalf-', '-iBRUnit-','-iBRdouble-','-iBW-','-iRO-','-iCIR-',
|
||
'-iPenalty-', '-iOH-','-iNBW-', '-iCNRbw-','-iCNRnyq-','-iCNRrcv-','-iBRbw-',
|
||
'-iBRnyq-','-iBRrcv-','-iBRhigh-','-Satellite-','-iPLoss-','Advanced','Help',
|
||
'-CRC1-', '-CRC2-', '-CRC3-', '-iN0-','-iCPE_T-', '-iSatAlt-','-iSatLatLong-',
|
||
'-iGSLatLong-', '-iAvail-', '-iPathLength-','-iAtmLoss-'):
|
||
window2['-Dialog-'].Update(Shd.Help2[event2])
|
||
|
||
elif event2 == '-BW_Graph-' :
|
||
BW = np.zeros(20)
|
||
BR = np.zeros(20)
|
||
CNR = np.zeros(20)
|
||
CNR[0] = CNR_Nyq+10*log(8,10)
|
||
BW[0] = Bandwidth/8
|
||
BR[0] = Shannon(BW[0]/(1+Rolloff/100), CNR[0], Penalties) / (1 + Overheads / 100)
|
||
for i in range(1, 20):
|
||
BW[i] = BW[i - 1] * 2 ** (1 / 3)
|
||
CNR[i] = CNR[i - 1] - 10 * log(BW[i] / BW[i - 1], 10)
|
||
CNR_Rcv_i = Combine_CNR(CNR[i], CNR_Imp, Sat_CIR)
|
||
BR[i] = Shannon(BW[i]/(1+Rolloff/100), CNR_Rcv_i, Penalties) / (1 + Overheads / 100)
|
||
|
||
fig = plt.figure(figsize=(6, 4))
|
||
ax = fig.add_subplot(111)
|
||
plt.plot(BW, BR, 'b')
|
||
Mark = ('D', 's', 'p', 'h', 'x')
|
||
for i in range(5):
|
||
ind = 3 * (i + 1)
|
||
BR_norm = BR[ind] / BR[9]
|
||
plt.plot(BW[ind], BR[ind], Mark[i] + 'b',label="{:.1f}".format(BW[ind]) +
|
||
" MHz" + " , {:.1f}".format(BR[ind]) + " Mbps" + " : {:.0%}".format(BR_norm))
|
||
plt.title('Higher Layers Bit Rate at Constant HPA Output Power : ' +
|
||
"{:.1f}".format(HPA_Power) + " W")
|
||
plt.xlabel('Occupied Bandwidth [MHz]')
|
||
plt.ylabel('Bit Rate [Mbps]')
|
||
plt.grid(True)
|
||
plt.legend(loc='lower right')
|
||
|
||
if Web_Version:
|
||
window_matfig(fig, title_fig='Bandwidth Sensitivity',
|
||
title_win='Shannon and Friends in the Real World')
|
||
else:
|
||
plt.show(block=False)
|
||
|
||
elif event2 == '-Pow_Graph-' :
|
||
Power = np.zeros(20)
|
||
BR = np.zeros(20)
|
||
CNR = np.zeros(20)
|
||
Power[0] = HPA_Power / 8
|
||
CNR[0] = CNR_Nyq-10*log(8,10)
|
||
CNR_Rcv_i = Combine_CNR(CNR[0], CNR_Imp, Sat_CIR)
|
||
BR[0] = Shannon(BW_Nyq, CNR_Rcv_i, Penalties) / (1 + Overheads / 100)
|
||
for i in range(1, 20):
|
||
Power[i] = Power[i-1] * 2 ** (1 / 3)
|
||
CNR[i] = CNR[i - 1] + 10 * log( 2 ** (1 / 3) , 10 )
|
||
CNR_Rcv_i = Combine_CNR(CNR[i], CNR_Imp, Sat_CIR)
|
||
BR[i] = Shannon(BW_Nyq, CNR_Rcv_i, Penalties) / (1 + Overheads / 100)
|
||
fig = plt.figure(figsize=(6, 4))
|
||
ax = fig.add_subplot(111)
|
||
plt.plot(Power, BR, 'b')
|
||
Mark = ('D', 's', 'p', 'h', 'x')
|
||
for i in range(5):
|
||
ind = 3 * (i + 1)
|
||
BR_norm=BR[ind]/BR[9]
|
||
plt.plot(Power[ind], BR[ind], Mark[i] + 'b', label="{:.1f}".format(Power[ind]) + " W" +
|
||
" , {:.1f}".format(BR[ind]) + " Mbps"+" : {:.0%}".format(BR_norm))
|
||
plt.title('Higher Layers Bit Rate at Constant Occupied Bandwidth : ' +
|
||
"{:.1f}".format(Bandwidth) + " MHz")
|
||
plt.xlabel('HPA Output Power @ Operating Point [Watts]')
|
||
plt.ylabel('Bit Rate [Mbps]')
|
||
plt.grid(True)
|
||
plt.legend(loc='lower right')
|
||
|
||
if Web_Version:
|
||
window_matfig(fig, title_fig='Power Sensitivity',
|
||
title_win='Shannon and Friends in the Real World')
|
||
else:
|
||
plt.show(block=False)
|
||
|
||
elif event2 == '-Map-':
|
||
BR_mul = np.zeros((21, 21))
|
||
BW_mul = np.zeros((21, 21))
|
||
P_mul = np.zeros((21, 21))
|
||
BR_00 = BR_Rcv_Higher
|
||
for i in range(21):
|
||
for j in range(21):
|
||
BW_mul[i, j] = (i + 1) / 4
|
||
P_mul[i, j] = (j + 1) / 4
|
||
CNR_ij = CNR_Nyq + 10 * log( P_mul[i, j] / BW_mul[i, j] , 10 )
|
||
CNR_Rcv_ij = Combine_CNR (CNR_ij, CNR_Imp, Sat_CIR)
|
||
BW_ij = BW_Nyq * BW_mul[i, j]
|
||
BR_ij = Shannon( BW_ij / (1 + Rolloff / 100), CNR_Rcv_ij, Penalties) / (1 + Overheads / 100)
|
||
BR_mul[i, j] = BR_ij / BR_00
|
||
fig = plt.figure(figsize=(6, 4))
|
||
ax = fig.add_subplot(111)
|
||
Map = plt.contour(BW_mul, P_mul, BR_mul, 20)
|
||
plt.clabel(Map, inline=1, fontsize=8, fmt='%.2f')
|
||
plt.title('Bit Rate Multiplying Factor, \n Reference : Power = {:.1f}'.format(HPA_Power) +
|
||
' W , BW = ' + '{:.1f}'.format(Bandwidth) +
|
||
' MHz , BR = {:.1f}'.format(BR_Rcv_Higher) + ' Mbps')
|
||
plt.xlabel('Bandwidth Multiplying Factor')
|
||
plt.ylabel('Power Multiplying Factor')
|
||
plt.grid(True)
|
||
|
||
if Web_Version:
|
||
window_matfig(fig, title_fig='Multiplying Factors Map',
|
||
title_win='Shannon and Friends in the Real World')
|
||
else:
|
||
plt.show(block=False)
|
||
|
||
elif event2 == '-W_Nyquist-':
|
||
webbrowser.open('https://en.wikipedia.org/wiki/Harry_Nyquist')
|
||
elif event2 == '-W_Hamming-':
|
||
webbrowser.open('https://en.wikipedia.org/wiki/Richard_Hamming')
|
||
elif event2 == '-W_Viterbi-':
|
||
webbrowser.open('https://en.wikipedia.org/wiki/Andrew_Viterbi')
|
||
elif event2 == '-W_Berrou-':
|
||
webbrowser.open('https://en.wikipedia.org/wiki/Claude_Berrou')
|
||
|
||
elif event2 == '-Write_Ct-':
|
||
Contribution_Write('Shannon_Real.db')
|
||
|
||
elif event2 == '-Read_Ct-':
|
||
Contribution_Read('Shannon_Real.db')
|
||
|
||
else:
|
||
print("Untrapped event : "+event2)
|
||
|
||
|
||
except :
|
||
window2['-Dialog-'].Update('Invalid input fields')
|
||
if P_err == 1 :
|
||
window2['-CRC1-'].Update('-')
|
||
SetLED(window2, '-OK1-', 'red')
|
||
if P_err == 2 :
|
||
window2['-CRC2-'].Update('-')
|
||
SetLED(window2, '-OK2-', 'red')
|
||
if P_err == 3 :
|
||
window2['-CRC3-'].Update('-')
|
||
SetLED(window2, '-OK3-', 'red')
|
||
Err_msg=True
|
||
else:
|
||
window2['-CRC1-'].Update(Params1_CRC)
|
||
window2['-CRC2-'].Update(Params2_CRC)
|
||
window2['-CRC3-'].Update(Params3_CRC)
|
||
SetLED(window2, '-OK1-', 'green')
|
||
SetLED(window2, '-OK2-', 'green')
|
||
SetLED(window2, '-OK3-', 'green')
|
||
if Err_msg :
|
||
window2['-Dialog-'].Update('Input Validated')
|
||
Err_msg = False
|
||
|
||
window2.close()
|
||
|
||
except :
|
||
window['-Dialog-'].Update('Invalid input fields')
|
||
window['-CRC-'].Update('-')
|
||
SetLED(window, '-OK-', 'red')
|
||
Err_msg = True
|
||
else:
|
||
window['-CRC-'].Update(Params_CRC)
|
||
SetLED(window, '-OK-', 'green')
|
||
if Err_msg:
|
||
window['-Dialog-'].Update('Input Validated')
|
||
Err_msg = False
|
||
|
||
window.close()
|