Browse Source

Add demo;

Correct smith chart:
1. Fitted circle is cropped (no large pyplot image exception)
2. Better points plotting

Correct Docker:
Make uploaded file size smaller (20 Mb is more than enough)
ricet8ur 1 year ago
parent
commit
1c838f1a92
5 changed files with 109 additions and 48 deletions
  1. 2 1
      .gitignore
  2. 1 1
      Dockerfile
  3. 1 0
      TODO.md
  4. 26 0
      resource/data/8_default_demo.s1p
  5. 79 46
      source/frontend/front.py

+ 2 - 1
.gitignore

@@ -1,2 +1,3 @@
 **/__pycache__
-.idea/
+.idea/
+**/.ipynb_checkpoints

+ 1 - 1
Dockerfile

@@ -5,6 +5,6 @@ RUN pip install -r requirements.txt
 EXPOSE 8501
 COPY . /app
 ENTRYPOINT ["streamlit", "run"]
-CMD ["./source/main.py", "--browser.serverAddress=0.0.0.0", "--browser.gatherUsageStats=false"]
+CMD ["./source/main.py", "--browser.serverAddress=0.0.0.0", "--browser.gatherUsageStats=false", "--server.maxUploadSize = 20"]
 # docker build -t calc-q-factor:latest .
 # docker run -p 8501:8501 calc-q-factor:latest

+ 1 - 0
TODO.md

@@ -28,5 +28,6 @@
 11. Advanced file preview: .snp support for .s2p (or more) 
 12. [x] Make charts more interactive
 13. Make an option to pass the whole program to .html site via iframe? - It works, but where to host?
+14. Add support lines for smith chart?
 <!-- Add direct support for output files from different vna models? Supported formats: .snp, .csv or similar -->
 <!-- Do we need to calculate systematic errors? - yes, if its not too hard. After some considerations... Rather not -->

+ 26 - 0
resource/data/8_default_demo.s1p

@@ -0,0 +1,26 @@
+# Hz S MA R 50
+11414028125 0.4301177 93.203987
+11414715625 0.40031707 92.644608
+11415403125 0.37010744 92.47802
+11416090625 0.33831283 92.906929
+11416778125 0.3069371 94.03318
+11417465625 0.27716747 96.86544
+11418153125 0.25166345 100.84904
+11418840625 0.22895016 106.31691
+11419528125 0.21294561 113.55509
+11420215625 0.20525002 121.82249
+11420903125 0.20573099 130.26067
+11421590625 0.21451311 137.88812
+11422278125 0.22832666 144.17075
+11422965625 0.24686199 149.12198
+11423653125 0.26650944 152.45326
+11424340625 0.28751916 154.89363
+11425028125 0.30911326 156.45076
+11425715625 0.33000126 157.51169
+11426403125 0.35029748 158.05258
+11427090625 0.36924407 158.25481
+11427778125 0.38721535 158.16319
+11428465625 0.40406558 158.07317
+11429153125 0.42126176 157.74857
+11429840625 0.43520793 157.26349
+11430528125 0.44878739 156.78369

+ 79 - 46
source/frontend/front.py

@@ -1,21 +1,20 @@
 from streamlit_ace import st_ace
-from streamlit_echarts import st_echarts
+from streamlit_echarts import st_echarts, JsCode
 import math
 import streamlit as st
 import matplotlib.pyplot as plt
 import numpy as np
 
-XLIM = [-1.1, 1.1] # why global...
-YLIM = [-1.1, 1.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,
+    drawn_circle = Ellipse((x, y), radius * 2, radius * 2, clip_on=True,
                            zorder=2, linewidth=2, edgecolor=color, facecolor=(0, 0, 0, .0125))
-    ax.add_artist(drawn_circle)
-
+    try:
+        ax.add_artist(drawn_circle)
+    except:
+        raise
 
-def plot_data(r, i, g):
+def plot_smith(r, i, g, r_cut, i_cut):
     fig = plt.figure(figsize=(10, 10))
     ax = fig.add_subplot()
 
@@ -30,25 +29,28 @@ def plot_data(r, i, g):
     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
+
+    # unit circle
+    circle(ax, 0, 0, 1)
+
+    # input data points
+    ax.plot(r, i, '+', ms=8, mew=2, color='#b6c7f4')
+    
+    # choosen data points
+    ax.plot(r_cut, i_cut, '+', ms=8, mew=2, color='#1946BA')
+
+    # circle approximation by calc
     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')
-    #
+
+    XLIM = [-1.1, 1.1]
+    YLIM = [-1.1, 1.1]
     ax.set_xlim(XLIM)
     ax.set_ylim(YLIM)
-    # sometimes throws exception
-    try:
-        st.pyplot(fig)
-    except:
-        st.write("Plot size is too big. There are some problems with fitting. Check your input")
+    st.pyplot(fig)
+
 
 
 interval_range = (0, 100) # in percents
@@ -67,28 +69,37 @@ def plot_interact_abs_from_f(f, r, i):
             "data": f,
             "name": "Hz",
             "nameTextStyle": {"fontSize": 16},
-            "axisLabel": {"fontSize": 16}
+            "axisLabel": {"fontSize": 16},
         },
         "yAxis": {
             "type": "value",
             "name": "abs(S)",
             "nameTextStyle": {"fontSize": 16},
-            "axisLabel": {"fontSize": 16}
+            "axisLabel": {"fontSize": 16},
+            # "axisPointer": {
+            #     "type": 'cross',
+            #     "label": {
+            #     "show":"true",
+            #     "formatter": JsCode(
+            #     "function(info){console.log(info);return 'line ' ;};"
+            #     ).js_code
+            #     }
+            # }
         },
         "series": [{"data": abs_S, "type": "line", "name": "abs(S)"}],
         "height": 300,
         "dataZoom": [{"type": "slider", "start": 0, "end": 100, "height": 100, "bottom": 10}],
         "tooltip": {
-            "trigger": "axis",
-            "axisPointer": {
-                "type": 'cross',
-                # "label": {
-                # "show":"true",
-                # "formatter": JsCode(
-                # "function(info){return info.value;};"
-                # ).js_code
-                # }
-            }
+                "trigger": "axis",
+                "axisPointer": {
+                    "type": 'cross',
+                    # "label": {
+                    # "show":"true",
+                    # "formatter": JsCode(
+                    # "function(info){console.log(info);return 'line ' ;};"
+                    # ).js_code
+                    # }
+                }
         },
         "toolbox": {
             "feature": {
@@ -131,7 +142,7 @@ def plot_ref_from_f(f, r, i):
     plt.title('Absolute value of reflection coefficient from frequency',
               fontsize=24, fontname="Cambria")
 
-    ax.plot(f, abs_S, '+', ms=10, mew=2, color='#1946BA')
+    ax.plot(f, abs_S, '+', ms=8, mew=2, color='#1946BA')
     st.pyplot(fig)
 
 
@@ -237,13 +248,31 @@ def run(calc_function):
     global interval_range, interval_start, interval_end
 
     # file upload button
-    data = []
-    uploaded_file = st.file_uploader('Upload a csv')
-    if uploaded_file is not None:
-        data_format_snp = False
+    uploaded_file = st.file_uploader('Upload a file from your vector analizer. ' +
+        'Make sure the file format is .snp or it has a similar inner structure.')
+    
+    # check .snp
+    data_format_snp = False
+    if uploaded_file is None:
+        st.write("Demonstration: ")
+        # display DEMO
+        data_format_snp = True
+        try:
+            with open('./resource/data/8_default_demo.s1p') as f:
+                data = f.readlines()
+        except:
+            # 'streamlit run' call in the wrong directory. Display smaller demo:
+            data =[line.strip()+'\n' for line in '''# Hz S MA R 50
+                11415403125 0.37010744 92.47802
+                11416090625 0.33831283 92.906929
+                11416778125 0.3069371 94.03318
+                '''.split('\n')]
+    else:
         data = uploaded_file.readlines()
+
         if uploaded_file.name[-4:-2]=='.s' and uploaded_file.name[-1]== 'p':
             data_format_snp = True
+            
     
     validator_status = '...'
     ace_preview_markers = []
@@ -317,20 +346,24 @@ def run(calc_function):
             plot_interact_abs_from_f(f, r, i)
 
             select_coupling_losses = st.checkbox(
-                'Apply corrections for coupling losses (lossy coupling)')
+                'Apply corrections for coupling losses')
+
+            if select_coupling_losses:
+                st.write("Option: Lossy coupling")
+            else:
+                st.write("Option: Cable attenuation")
+
             f_cut, r_cut, i_cut = (x[interval_start:interval_end]
                                    for x in (f, r, i))
-            # for x in range(len(f_cut)):
-                # print(f_cut[x], r_cut[x], i_cut[x])
+
             if validator_status == 'data parsed':
                 Q0, sigmaQ0, QL, sigmaQl, circle_params = calc_function(
                     f_cut, r_cut, i_cut, select_coupling_losses)
-                if select_coupling_losses:
-                    st.write("Lossy coupling")
-                else:
-                    st.write("Cable attenuation")
 
                 out_precision = '0.7f'
+                if Q0 <= 0 or QL <= 0:
+                    st.write("Negative Q detected, fitting may be inaccurate!")
+
                 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)},  ' +
@@ -341,4 +374,4 @@ def run(calc_function):
     if len(data) > 0 and validator_status == 'data parsed':
         with st.expander("Show static abs(S) plot"):
             plot_ref_from_f(f_cut, r_cut, i_cut)
-        plot_data(r_cut, i_cut, circle_params)
+        plot_smith(r, i, circle_params, r_cut, i_cut)