Guest User

Untitled

a guest
Aug 1st, 2025
8
0
Never
Not a member of Pastebin yet? Sign Up, it unlocks many cool features!
text 7.65 KB | None | 0 0
  1. import streamlit as st
  2. import numpy as np
  3. import matplotlib.pyplot as plt
  4. from scipy import signal
  5. import pandas as pd
  6.  
  7. # Set page config
  8. st.set_page_config(
  9. page_title="Signal Generator Calculator",
  10. page_icon="📊",
  11. layout="wide"
  12. )
  13.  
  14. # Custom CSS for styling
  15. st.markdown("""
  16. <style>
  17. .main-header {
  18. font-size: 2.5rem;
  19. color: #1f77b4;
  20. text-align: center;
  21. margin-bottom: 30px;
  22. }
  23. .sub-header {
  24. font-size: 1.5rem;
  25. color: #ff7f0e;
  26. margin-top: 20px;
  27. margin-bottom: 10px;
  28. }
  29. .info-box {
  30. background-color: #f0f2f6;
  31. padding: 20px;
  32. border-radius: 10px;
  33. margin: 10px 0;
  34. }
  35. .warning-box {
  36. background-color: #ffe6e6;
  37. padding: 15px;
  38. border-radius: 5px;
  39. margin: 10px 0;
  40. border-left: 5px solid #ff4444;
  41. }
  42. </style>
  43. """, unsafe_allow_html=True)
  44.  
  45. st.markdown('<h1 class="main-header">🔧 AD9833 Signal Generator Design Calculator</h1>', unsafe_allow_html=True)
  46. st.markdown("*For Reddit user Schniedelholz*")
  47.  
  48. # Sidebar for inputs
  49. with st.sidebar:
  50. st.header("⚙️ Input Parameters")
  51.  
  52. clock_freq = st.number_input(
  53. "Clock Frequency (MHz)",
  54. min_value=1.0,
  55. max_value=50.0,
  56. value=24.0,
  57. step=0.1
  58. )
  59.  
  60. max_output_freq = st.number_input(
  61. "Maximum Output Frequency (MHz)",
  62. min_value=0.01,
  63. max_value=clock_freq/2,
  64. value=1.0,
  65. step=0.1
  66. )
  67.  
  68. st.markdown("### Filter Design")
  69. filter_type = st.selectbox(
  70. "Filter Type",
  71. ["Butterworth", "Chebyshev", "Elliptic", "Bessel"]
  72. )
  73.  
  74. filter_order = st.slider("Filter Order", 3, 9, 5, 2)
  75.  
  76. st.markdown("### Output Stage")
  77. supply_voltage = st.number_input("Op-Amp Supply (±V)", 5.0, 20.0, 15.0, 0.5)
  78. output_impedance = st.selectbox("Output Impedance", ["50Ω", "75Ω", "High-Z"])
  79.  
  80. # Main content area
  81. col1, col2 = st.columns(2)
  82.  
  83. with col1:
  84. st.markdown('<h2 class="sub-header">📐 Calculated Parameters</h2>', unsafe_allow_html=True)
  85.  
  86. # Calculate key parameters
  87. nyquist_freq = clock_freq / 2
  88. recommended_cutoff = max_output_freq * 2.5
  89.  
  90. if recommended_cutoff > nyquist_freq * 0.8:
  91. recommended_cutoff = nyquist_freq * 0.8
  92.  
  93. # AD9833 specific calculations
  94. freq_resolution = clock_freq * 1e6 / (2**28)
  95. max_theoretical_freq = clock_freq / 2
  96.  
  97. # Display results in styled boxes
  98. st.markdown('<div class="info-box">', unsafe_allow_html=True)
  99. st.write(f"**Nyquist Frequency:** {nyquist_freq:.2f} MHz")
  100. st.write(f"**Recommended Filter Cutoff:** {recommended_cutoff:.2f} MHz")
  101. st.write(f"**Frequency Resolution:** {freq_resolution:.3f} Hz")
  102. st.write(f"**Phase Resolution:** {360/4096:.3f}°")
  103. st.markdown('</div>', unsafe_allow_html=True)
  104.  
  105. # Filter component values (example for Butterworth)
  106. if filter_type == "Butterworth":
  107. st.markdown('<div class="info-box">', unsafe_allow_html=True)
  108. st.write("**Example Component Values (1kΩ impedance):**")
  109. # Simplified calculation for demonstration
  110. C = 1 / (2 * np.pi * recommended_cutoff * 1e6 * 1000)
  111. st.write(f"Capacitor: {C*1e12:.0f} pF")
  112. st.write(f"Resistor: 1 kΩ")
  113. st.markdown('</div>', unsafe_allow_html=True)
  114.  
  115. # Warnings
  116. if max_output_freq > nyquist_freq * 0.4:
  117. st.markdown('<div class="warning-box">', unsafe_allow_html=True)
  118. st.warning("⚠️ Output frequency is close to Nyquist limit. Consider lower frequencies for better signal quality.")
  119. st.markdown('</div>', unsafe_allow_html=True)
  120.  
  121. with col2:
  122. st.markdown('<h2 class="sub-header">📊 Filter Response</h2>', unsafe_allow_html=True)
  123.  
  124. # Create filter
  125. if filter_type == "Butterworth":
  126. b, a = signal.butter(filter_order, 2*recommended_cutoff/clock_freq)
  127. elif filter_type == "Chebyshev":
  128. b, a = signal.cheby1(filter_order, 0.5, 2*recommended_cutoff/clock_freq)
  129. elif filter_type == "Elliptic":
  130. b, a = signal.ellip(filter_order, 0.5, 40, 2*recommended_cutoff/clock_freq)
  131. else: # Bessel
  132. b, a = signal.bessel(filter_order, 2*recommended_cutoff/clock_freq)
  133.  
  134. # Frequency response
  135. w, h = signal.freqz(b, a, worN=2000)
  136. freq = w * clock_freq / (2 * np.pi)
  137.  
  138. # Plot
  139. fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(8, 6))
  140.  
  141. # Magnitude
  142. ax1.plot(freq, 20 * np.log10(abs(h)), 'b', linewidth=2)
  143. ax1.axvline(max_output_freq, color='g', linestyle='--', label='Max Output')
  144. ax1.axvline(recommended_cutoff, color='r', linestyle='--', label='Filter Cutoff')
  145. ax1.set_ylabel('Magnitude (dB)')
  146. ax1.set_xlim(0, nyquist_freq)
  147. ax1.grid(True, alpha=0.3)
  148. ax1.legend()
  149. ax1.set_title(f'{filter_type} Filter Response')
  150.  
  151. # Phase
  152. ax2.plot(freq, np.angle(h) * 180/np.pi, 'r', linewidth=2)
  153. ax2.set_xlabel('Frequency (MHz)')
  154. ax2.set_ylabel('Phase (degrees)')
  155. ax2.set_xlim(0, nyquist_freq)
  156. ax2.grid(True, alpha=0.3)
  157.  
  158. plt.tight_layout()
  159. st.pyplot(fig)
  160.  
  161. # Additional calculations section
  162. st.markdown('<h2 class="sub-header">🔢 Additional Calculations</h2>', unsafe_allow_html=True)
  163.  
  164. col3, col4 = st.columns(2)
  165.  
  166. with col3:
  167. st.markdown("### Digital Potentiometer Settings")
  168. desired_gain = st.slider("Desired Voltage Gain", 0.1, 10.0, 1.0, 0.1)
  169.  
  170. # Calculate pot settings (assuming 10kΩ digital pot)
  171. pot_steps = 256 # 8-bit pot
  172. pot_max_r = 10000 # 10kΩ
  173.  
  174. # For non-inverting amp: Gain = 1 + (Rf/Rin)
  175. if desired_gain >= 1:
  176. rf_ratio = desired_gain - 1
  177. pot_setting = int(rf_ratio * pot_steps / 10) # Assuming max gain of 10
  178. pot_resistance = pot_setting * pot_max_r / pot_steps
  179.  
  180. st.markdown('<div class="info-box">', unsafe_allow_html=True)
  181. st.write(f"**Digital Pot Setting:** {pot_setting}/256")
  182. st.write(f"**Resistance:** {pot_resistance:.0f} Ω")
  183. st.write(f"**Actual Gain:** {1 + pot_resistance/1000:.2f}")
  184. st.markdown('</div>', unsafe_allow_html=True)
  185.  
  186. with col4:
  187. st.markdown("### Output Protection")
  188. max_current = st.slider("Maximum Output Current (mA)", 10, 100, 25, 5)
  189.  
  190. # Protection resistor calculation
  191. short_circuit_r = (supply_voltage / (max_current / 1000))
  192. power_rating = (max_current / 1000)**2 * short_circuit_r
  193.  
  194. st.markdown('<div class="info-box">', unsafe_allow_html=True)
  195. st.write(f"**Series Protection Resistor:** {short_circuit_r:.0f} Ω")
  196. st.write(f"**Minimum Power Rating:** {power_rating:.2f} W")
  197. st.write(f"**Suggested Resistor:** {short_circuit_r*1.2:.0f} Ω, {power_rating*2:.1f} W")
  198. st.markdown('</div>', unsafe_allow_html=True)
  199.  
  200. # Summary table
  201. st.markdown('<h2 class="sub-header">📋 Design Summary</h2>', unsafe_allow_html=True)
  202.  
  203. summary_data = {
  204. "Parameter": [
  205. "Clock Frequency",
  206. "Max Output Frequency",
  207. "Filter Type",
  208. "Filter Order",
  209. "Filter Cutoff",
  210. "Frequency Resolution",
  211. "Output Impedance",
  212. "Supply Voltage"
  213. ],
  214. "Value": [
  215. f"{clock_freq} MHz",
  216. f"{max_output_freq} MHz",
  217. filter_type,
  218. str(filter_order), # Convert to string
  219. f"{recommended_cutoff:.2f} MHz",
  220. f"{freq_resolution:.3f} Hz",
  221. output_impedance,
  222. f"±{supply_voltage} V"
  223. ]
  224. }
  225.  
  226. df = pd.DataFrame(summary_data)
  227. st.table(df)
  228.  
  229. # Footer
  230. st.markdown("---")
  231. st.markdown("*Happy building! Remember to use proper decoupling capacitors and a good PCB layout.*")
Advertisement
Add Comment
Please, Sign In to add comment