123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219 |
- import math
- import streamlit as st
- import matplotlib.pyplot as plt
- import numpy as np
- XLIM = [-1.1, 1.1]
- YLIM = [-1.1, 1.1]
- def round_up(x, n=7):
- if x == 0:
- return 0
- deg = math.floor(math.log(abs(x), 10))
- return (10 ** deg) * round(x / (10 ** deg), n - 1)
- def circle(ax, x, y, radius, color='#1946BA'):
- from matplotlib.patches import Ellipse
- drawn_circle = Ellipse((x, y), radius * 2, radius * 2, clip_on=False,
- zorder=2, linewidth=2, edgecolor=color, facecolor=(0, 0, 0, .0125))
- ax.add_artist(drawn_circle)
- def plot_data(r, i, g):
- fig = plt.figure(figsize=(10, 10))
- ax = fig.add_subplot()
- major_ticks = np.arange(-1.0, 1.1, 0.25)
- minor_ticks = np.arange(-1.1, 1.1, 0.05)
- ax.set_xticks(major_ticks)
- ax.set_xticks(minor_ticks, minor=True)
- ax.set_yticks(major_ticks)
- ax.set_yticks(minor_ticks, minor=True)
- ax.grid(which='major', color='grey', linewidth=1.5)
- ax.grid(which='minor', color='grey', linewidth=0.5, linestyle=':')
- plt.xlabel(r'$Re(\Gamma)$', color='gray', fontsize=16, fontname="Cambria")
- plt.ylabel('$Im(\Gamma)$', color='gray', fontsize=16, fontname="Cambria")
- plt.title('Smith chart', fontsize=24, fontname="Cambria")
- # circle approximation
- radius = abs(g[1] - g[0] / g[2]) / 2
- x = ((g[1] + g[0] / g[2]) / 2).real
- y = ((g[1] + g[0] / g[2]) / 2).imag
- circle(ax, x, y, radius, color='#FF8400')
- #
- # unit circle
- circle(ax, 0, 0, 1)
- #
- # data
- ax.plot(r, i, '+', ms=10, mew=2, color='#1946BA')
- #
- ax.set_xlim(XLIM)
- ax.set_ylim(YLIM)
- st.pyplot(fig)
- from streamlit_echarts import st_echarts, JsCode
- interval_range = (0,100)
- interval_start,interval_end=0,0
- def plot_interact_abs_from_f(f,r,i):
- abs_S = list((r[n] ** 2 + i[n] ** 2)**0.5 for n in range(len(r)))
- global interval_range,interval_start,interval_end
- # echarts for datazoom https://discuss.streamlit.io/t/streamlit-echarts/3655
- # datazoom https://echarts.apache.org/examples/en/editor.html?c=line-draggable&lang=ts
- # axis pointer values https://echarts.apache.org/en/option.html#axisPointer
- options = {
- "xAxis": {
- "type": "category",
- "data": f,
- },
- "yAxis": {
- "type": "value",
- "name":"abs(S)",
- },
- "series": [{"data": abs_S, "type": "line", "name":"abs(S)"}],
- "dataZoom": [{"type": "slider", "start": 0, "end": 100}],
- "tooltip": {
- "trigger":"axis",
- "axisPointer": {
- "type": 'cross',
- # "label": {
- # "show":"true",
- # "formatter": JsCode(
- # "function(info){return info.value;};"
- # ).js_code
- # }
- }
- },
- "toolbox":{
- "feature": {
- "dataView": { "show": "true", "readOnly": "true" },
- "restore": { "show": "true" },
- }
- },
- }
- events = {
- "dataZoom": "function(params) { return [params.start, params.end] }",
- }
- interval_range = st_echarts(
- options=options, events=events, height="500px", key="render_basic_bar_events"
- )
- if interval_range is None:
- interval_range = (0, 100)
- n=len(f)
- interval_start,interval_end=(int(n*interval_range[id]*0.01) for id in (0,1))
- def plot_ref_from_f(f, r, i):
- fig = plt.figure(figsize=(10, 10))
- abs_S = list((r[n] ** 2 + i[n] ** 2)**0.5 for n in range(len(r)))
- xlim = [min(f) - abs(max(f) - min(f)) * 0.1, max(f) + abs(max(f) - min(f)) * 0.1]
- ylim = [min(abs_S) - abs(max(abs_S) - min(abs_S)) * 0.5, max(abs_S) + abs(max(abs_S) - min(abs_S)) * 0.5]
- ax = fig.add_subplot()
- ax.set_xlim(xlim)
- ax.set_ylim(ylim)
- ax.grid(which='major', color='k', linewidth=1)
- ax.grid(which='minor', color='grey', linestyle=':', linewidth=0.5)
- plt.xlabel(r'$f,\; 1/c$', color='gray', fontsize=16, fontname="Cambria")
- plt.ylabel('$|\Gamma|$', color='gray', fontsize=16, fontname="Cambria")
- plt.title('Modulus of reflection coefficient from frequency', fontsize=24, fontname="Cambria")
-
- ax.plot(f, abs_S, '+', ms=10, mew=2, color='#1946BA')
- st.pyplot(fig)
- def run(calc_function):
- global interval_range,interval_start, interval_end
- data = []
- uploaded_file = st.file_uploader('Upload a csv')
- if uploaded_file is not None:
- data = uploaded_file.readlines()
- col1, col2 = st.columns(2)
- select_data_format = col1.selectbox('Choose data format from a list',
- ['Frequency, Re(S11), Im(S11)', 'Frequency, Re(Zin), Im(Zin)'])
- select_separator = col2.selectbox('Choose separator', ['" "', '","', '";"'])
- select_coupling_losses = st.checkbox('Apply corrections for coupling losses (lossy coupling)')
-
- def is_float(element) -> bool:
- try:
- float(element)
- val = float(element)
- if math.isnan(val) or math.isinf(val):
- raise ValueError
- return True
- except ValueError:
- return False
- def unpack_data(data):
- nonlocal select_separator
- nonlocal select_data_format
- f, r, i = [], [], []
- if select_data_format == 'Frequency, Re(S11), Im(S11)':
- for x in range(len(data)):
- # print(select_separator)
- select_separator = select_separator.replace('\"', '')
- if type(data[x])==bytes:
- # print('f')
- try:
- data[x]=data[x].decode('utf-8-sig', 'ignore')
- except:
- return f, r, i, 'Not an utf-8-sig line №: ' + str(x)
- if select_separator == " ":
- tru = data[x].split()
- else:
- data[x] = data[x].replace(select_separator, ' ')
- tru = data[x].split()
- if len(tru) != 3:
- return f, r, i, 'Can\'t parse line №: ' + str(x)
- a, b, c = (y for y in tru)
- if not ((is_float(a)) or (is_float(b)) or (is_float(c))):
- return f, r, i, 'Your data isn\'t numerical type. Error on line: ' + str(x)
- f.append(float(a)) # frequency
- r.append(float(b)) # Re of S11
- i.append(float(c)) # Im of S11
- else:
- return f, r, i, 'Wrong data format'
- return f, r, i, 'data parsed'
- validator_status = '...'
- # calculate
- circle_params = []
- if len(data) > 0:
- f, r, i, validator_status = unpack_data(data)
- plot_interact_abs_from_f(f, r, i)
- f_cut=f[interval_start:interval_end]
- r_cut=r[interval_start:interval_end]
- i_cut=i[interval_start:interval_end]
- if validator_status == 'data parsed':
- Q0, sigmaQ0, QL, sigmaQl, circle_params = calc_function(f_cut, r_cut, i_cut, select_coupling_losses)
- # Q0 = round_up(Q0)
- # sigmaQ0 = round_up(sigmaQ0)
- # QL = round_up(QL)
- # sigmaQl = round_up(sigmaQl)
- if select_coupling_losses:
- st.write("Lossy coupling")
- else:
- st.write("Cable attenuation")
- out_precision='0.7f'
- st.latex(r'Q_0 =' + f'{format(Q0, out_precision)} \pm {format(sigmaQ0, out_precision)}, ' +
- r'\;\;\varepsilon_{Q_0} =' + f'{format(sigmaQ0 / Q0, out_precision)}')
- st.latex(r'Q_L =' + f'{format(QL, out_precision)} \pm {format(sigmaQl, out_precision)}, ' +
- r'\;\;\varepsilon_{Q_L} =' + f'{format(sigmaQl / QL, out_precision)}')
- st.write("Status: " + validator_status)
- if len(data) > 0:
- f, r, i, validator_status = unpack_data(data)
- if validator_status == 'data parsed':
- plot_ref_from_f(f_cut, r_cut, i_cut)
- plot_data(r_cut, i_cut, circle_params)
|