rf-funcitons-py 0.1.2__py3-none-any.whl → 0.1.5__py3-none-any.whl

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
rafpy/__init__.py CHANGED
@@ -1 +1,3 @@
1
- from .logic import id_signal_candidates
1
+ from .logic import id_signal_candidates
2
+ from .filters import RF_filter, bpf_kernel, get_acf_amplitude, plot_frequency_response
3
+ from .bpf_filter import create_bpf_kernel
rafpy/filters.py ADDED
@@ -0,0 +1,102 @@
1
+ def RF_filter(signal_array, filter_kernel, caption_text1, caption_text2, sampling_rate=1.0, show_graph=True):
2
+ normalized_kernel = filter_kernel / np.sum(filter_kernel)
3
+ filtered_signal = signal.fftconvolve(signal_array, normalized_kernel, mode='same')
4
+ if show_graph:
5
+ N = len(signal_array)
6
+ t = np.arange(N) / sampling_rate
7
+ M = len(filter_kernel)
8
+ t_kernel = np.arange(M) / sampling_rate
9
+ fig, (ax1, ax2) = plt.subplots(2, 1, figsize=(10, 10))
10
+ plt.subplots_adjust(bottom=0.1, hspace=0.6)
11
+ ax1.set_title("Fig 1. Input 1: Signal & Filter Kernel", fontweight='bold')
12
+ ax1.plot(t, signal_array, color='steelblue', alpha=0.6, label='Input Signal (Left Axis)')
13
+ ax1.tick_params(axis='y', labelcolor='steelblue')
14
+ ax1_twin = ax1.twinx()
15
+ ax1_twin.plot(t_kernel, normalized_kernel, color='#D62728', linewidth=2, label='Filter Kernal (Right Axis)')
16
+ ax1_twin.fill_between(t_kernel, 0, normalized_kernel, color='#D62728', alpha=0.3)
17
+ ax1_twin.tick_params(axis='y', labelcolor='#D62728')
18
+ ax1_twin.set_ylim(bottom=0)
19
+ ax1_twin.set_ylabel("Normalized Amplitude", color='#D62728')
20
+ lines_1, labels_1 = ax1.get_legend_handles_labels()
21
+ lines_2, labels_2 = ax1_twin.get_legend_handles_labels()
22
+ ax1.legend(lines_1 + lines_2, labels_1 + labels_2, loc='upper right')
23
+ ax1.set_xlabel(f"Time (s)if Fs={sampling_rate} Hz")
24
+ ax1.set_ylabel("Amplitude", color = 'steelblue')
25
+ desc_1 = caption_text1
26
+ desc_2 = caption_text2
27
+ ax1.text(0.5, -0.25, textwrap.fill(desc_1, width = 100), transform=ax1.transAxes, ha='center', va='top', fontsize=10, color='darkred', bbox=dict(boxstyle="round,pad=0.3", fc="white", ec="gray", alpha=0.5))
28
+ ax2.set_title("Fig 2. Output: Convolved Result", fontweight='bold')
29
+ ax2.plot(t, signal_array, color='gray', alpha=0.3, label='(Original Input)')
30
+ ax2.plot(t, filtered_signal, color='green', linewidth=2, label='Filtered Output')
31
+ ax2.set_xlabel(f"Time (seconds) if Fs={sampling_rate}Hz")
32
+ ax2.set_ylabel("Amplitude")
33
+ ax2.legend(loc='upper right')
34
+ ax2.grid(True, alpha=0.3)
35
+ ax2.text(0.5, -0.3, textwrap.fill(desc_2, width = 100), transform=ax2.transAxes, ha='center', va='top', fontsize=10, color='darkgreen', bbox=dict(boxstyle="round,pad=0.3", fc="white", ec="gray", alpha=0.5))
36
+
37
+ plt.show()
38
+ return filtered_signal
39
+
40
+ def get_acf_amplitude(signal_array):
41
+ # 1. Remove DC offset (Center the signal at 0)
42
+ centered_signal = signal_array - np.mean(signal_array)
43
+
44
+ # 2. Calculate the Autocorrelation
45
+ # 'same' mode keeps the output the same length as the input
46
+ acf = np.correlate(centered_signal, centered_signal, mode='full')
47
+
48
+ # 3. Get the value at zero lag (the center of the 'full' correlation)
49
+ zero_lag_index = len(acf) // 2
50
+ r_0 = acf[zero_lag_index] / len(centered_signal) # Normalize by length
51
+
52
+ # 4. Calculate RMS and Peak Amplitude
53
+ rms = np.sqrt(r_0)
54
+ peak_amplitude = rms * np.sqrt(2)
55
+
56
+ return peak_amplitude
57
+
58
+ def create_bpf_kernel(low_kb, high_kb, fs, num_taps=101):
59
+ """Utility to generate a Band-Pass Filter kernel."""
60
+ return sp_signal.firwin(num_taps, [low_kb, high_kb], fs=fs, pass_zero=False)
61
+
62
+ def plot_frequency_response(data_list, use_acf=True):
63
+ """
64
+ Plots Max Voltage vs Frequency, handling 1.5MHz and 3MHz separately.
65
+ data_list: list of (freq_hz, filename, fs_hz)
66
+ """
67
+ data_1_5 = []
68
+ data_3_0 = []
69
+
70
+ for freq, filename, fs in data_list:
71
+ try:
72
+ data_file = np.load(filename)
73
+ signal_data = data_file["arr_0"][2]
74
+
75
+ # Choose amplitude method
76
+ val = get_acf_amplitude(signal_data) if use_acf else np.max(np.abs(signal_data))
77
+
78
+ if fs == 1500000:
79
+ data_1_5.append((freq / 1000, val))
80
+ else:
81
+ data_3_0.append((freq / 1000, val))
82
+ except Exception as e:
83
+ print(f"Error loading {filename}: {e}")
84
+
85
+ # Sort to prevent the 'sawtooth' lines
86
+ data_1_5.sort()
87
+ data_3_0.sort()
88
+
89
+ plt.figure(figsize=(10, 6))
90
+ if data_1_5:
91
+ x15, y15 = zip(*data_1_5)
92
+ plt.plot(x15, y15, 'bo-', label='1.5 MHz Fs', alpha=0.8)
93
+ if data_3_0:
94
+ x30, y30 = zip(*data_3_0)
95
+ plt.plot(x30, y30, 'ro-', label='3.0 MHz Fs', alpha=0.8)
96
+
97
+ plt.title(f"Frequency Response ({'ACF' if use_acf else 'Raw'} Peak)")
98
+ plt.xlabel("Signal Frequency (kHz)")
99
+ plt.ylabel("Amplitude (V)")
100
+ plt.legend()
101
+ plt.grid(True, alpha=0.3)
102
+ plt.show()
rafpy/logic.py CHANGED
@@ -56,12 +56,6 @@ def id_signal_candidates(fig_num, observed, current_fs, filter_range=None, show_
56
56
  ax.set_title(f"Fig {fig_num}. Signal Identification (Observed: {observed} Hz | $f_s$: {current_fs} Hz | Bandpass {np.min(filter_range)}-{np.max(filter_range)} Hz)", fontweight='bold')
57
57
  ax.set_xlabel("Frequency (Hz)", fontweight='bold')
58
58
  ax.set_ylim(0, 1.6)
59
- desc = (
60
- f"""Fig {fig_num}. You saw a signal at {observed} Hz with a sampling rate of {current_fs} Hz. If you used a bandpass filter then the highlighted frequency is the original frequency considering any aliasing observed and which Nyquist zone it resides in. If you did not use a bandpass filter, then this lists the possible frequencies associated with the sampled signal, which can be filtered manually using known physics of your source."""
61
- )
62
- wrapped_desc = textwrap.fill(desc, width=90)
63
- plt.figtext(0.5, 0.05, wrapped_desc, ha='center', fontsize=10,
64
- bbox=dict(boxstyle="round,pad=0.3", fc="#f0f0f0", ec="black", alpha=0.5))
65
59
  plt.legend(loc='upper right')
66
60
  print("-" * 30)
67
61
  print(f"ANALYSIS FOR {observed} Hz (Fs = {current_fs} Hz)")
@@ -1,10 +1,13 @@
1
1
  Metadata-Version: 2.4
2
2
  Name: rf_funcitons_py
3
- Version: 0.1.2
3
+ Version: 0.1.5
4
4
  Summary: First package from a notebook
5
5
  Author-email: Avery Books <abooks104@gmail.com>
6
6
  Requires-Python: >3.8
7
7
  Description-Content-Type: text/markdown
8
+ Requires-Dist: numpy
9
+ Requires-Dist: matplotlib
10
+ Requires-Dist: scipy
8
11
 
9
12
  #My First Package
10
13
  This package contains my alias source signal identification function
@@ -0,0 +1,7 @@
1
+ rafpy/__init__.py,sha256=uAUmFifm3o5-_PpU6mYsLqJWqkNeId6rp53mmHvKbt8,170
2
+ rafpy/filters.py,sha256=xFXy_SIV7GdAT3fX72fEimuSHetja5O0EYzEGC6LDsU,4754
3
+ rafpy/logic.py,sha256=UMsdbz0s30P7ojoNHi22_oLoIm-f1gxp9YplSej4eeA,3277
4
+ rf_funcitons_py-0.1.5.dist-info/METADATA,sha256=0QzsHHPT8TaKqKrQzD8JvWouQK0wVTEUq75CbLX0a9Q,377
5
+ rf_funcitons_py-0.1.5.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
6
+ rf_funcitons_py-0.1.5.dist-info/top_level.txt,sha256=4q_MXcdbMykJYGFjd_1IVwHk_V3unZSegNAYAUumMnw,6
7
+ rf_funcitons_py-0.1.5.dist-info/RECORD,,
@@ -1,6 +0,0 @@
1
- rafpy/__init__.py,sha256=YJ7WwLTtUPL2cl7hNS_I75dwn4MiCSuXmjbPVYw0c60,39
2
- rafpy/logic.py,sha256=_bjpKKMS93SO8UpJDEoPCUWyM8Fn8pXO4GjLnIQ8qKA,3974
3
- rf_funcitons_py-0.1.2.dist-info/METADATA,sha256=EM5qzvPt6if5KUdEZ4Cl9IKlSjl5FP3E6W2PWW3FNJc,306
4
- rf_funcitons_py-0.1.2.dist-info/WHEEL,sha256=wUyA8OaulRlbfwMtmQsvNngGrxQHAvkKcvRmdizlJi0,92
5
- rf_funcitons_py-0.1.2.dist-info/top_level.txt,sha256=4q_MXcdbMykJYGFjd_1IVwHk_V3unZSegNAYAUumMnw,6
6
- rf_funcitons_py-0.1.2.dist-info/RECORD,,