Skip to content

Commit f161159

Browse files
committed
simple synced capture
Signed-off-by: PopPaul2021 <Paul.Pop@analog.com>
1 parent 8ed7577 commit f161159

File tree

1 file changed

+7
-230
lines changed

1 file changed

+7
-230
lines changed

examples/sharkbyte_example.py

Lines changed: 7 additions & 230 deletions
Original file line numberDiff line numberDiff line change
@@ -21,21 +21,21 @@
2121
print("uri: " + str(my_uri))
2222

2323
# Individual device access (for first plot demonstration)
24-
hmcad15xx_dev1 = adi.hmcad15xx(uri=my_uri,device_name="axi_adc1_hmcad15xx")
25-
hmcad15xx_dev2 = adi.hmcad15xx(uri=my_uri,device_name="axi_adc2_hmcad15xx")
26-
ad5696_dev = adi.ad5686(uri=my_uri)
24+
hmcad15xx_dev1 = adi.hmcad15xx(uri=my_uri,device_name="axi_adc1_hmcad15xx")
25+
hmcad15xx_dev2 = adi.hmcad15xx(uri=my_uri,device_name="axi_adc2_hmcad15xx")
2726
gpio_controller = adi.one_bit_adc_dac(uri=my_uri, name="one-bit-adc-dac")
27+
ad5696_dev = adi.ad5686(uri=my_uri)
28+
tddn = adi.tddn(my_uri)
2829

2930
tddn_channel_on_raw = 0
3031
tddn_channel_off_raw = 10
3132
tddn_channel_polarity = 0
3233
tddn_channel_enable = 1
33-
34-
tddn = adi.tddn(my_uri)
3534
tddn.burst_count = 0
3635
tddn.startup_delay_ms = 0
3736
tddn.frame_length_ms = 1
3837

38+
3939
tddn.enable = 0
4040

4141
tddn.channel[0].on_ms = 0
@@ -79,34 +79,6 @@
7979
ramp_pattern = 0x40
8080
pattern_disabled = 0x00
8181

82-
hmcad15xx_dev1.rx_buffer_size = 2**18
83-
hmcad15xx_dev2.rx_buffer_size = 2**18
84-
85-
hmcad15xx_dev1.rx_enabled_channels = [0]
86-
hmcad15xx_dev2.rx_enabled_channels = [0]
87-
88-
print("RX1 rx_enabled_channels: " + str(hmcad15xx_dev1.rx_enabled_channels))
89-
print("RX2 rx_enabled_channels: " + str(hmcad15xx_dev2.rx_enabled_channels))
90-
91-
hmcad15xx_dev1.hmcad15xx_register_write(0x42, 0x0000) # Phase DDR
92-
hmcad15xx_dev2.hmcad15xx_register_write(0x42, 0x0000) # Phase DDR
93-
hmcad15xx_dev1.hmcad15xx_register_write(0x26, custom_pattern)
94-
hmcad15xx_dev2.hmcad15xx_register_write(0x26, custom_pattern)
95-
hmcad15xx_dev1.hmcad15xx_register_write(0x25, ramp_pattern)
96-
hmcad15xx_dev2.hmcad15xx_register_write(0x25, ramp_pattern)
97-
98-
#input_select_available value: IP1_IN1 IP2_IN2 IP3_IN3
99-
100-
hmcad15xx_dev1.channel[0].input_select = "IP1_IN1"
101-
hmcad15xx_dev1.channel[1].input_select = "IP1_IN1"
102-
hmcad15xx_dev1.channel[2].input_select = "IP1_IN1"
103-
hmcad15xx_dev1.channel[3].input_select = "IP1_IN1"
104-
105-
hmcad15xx_dev2.channel[0].input_select = "IP1_IN1"
106-
hmcad15xx_dev2.channel[1].input_select = "IP1_IN1"
107-
hmcad15xx_dev2.channel[2].input_select = "IP1_IN1"
108-
hmcad15xx_dev2.channel[3].input_select = "IP1_IN1"
109-
11082
# Enable TDD and configure sync for synchronized multi-ADC capture
11183
tddn.enable = 1
11284
tddn.sync_external = False
@@ -120,7 +92,7 @@
12092

12193
# Configure buffer size and enabled channels
12294
multi.rx_buffer_size = 2**17
123-
multi.rx_enabled_channels = [0] # Apply to both devices
95+
multi.rx_enabled_channels = [3] # Apply to both devices
12496

12597
print("Multi-ADC rx_enabled_channels: " + str(multi.rx_enabled_channels))
12698

@@ -154,205 +126,10 @@
154126
plt.title('ADC Data - Channel 0 from Both Devices (TDD Synchronized)')
155127
plt.legend()
156128
plt.grid(True)
157-
plt.savefig("Data channels 0 of both devices - Synchronized")
129+
plt.show()
158130
plt.close() # Close the figure to free memory
159131

160132
print("Synchronized data capture complete!")
161133

162-
num_captures = 1000
163-
phase_shifts_samples = []
164-
phase_shifts_degrees = []
165-
correlation_peaks = []
166-
167-
# Phase Shift Analysis using Cross-Correlation
168-
print("\n--- Phase Shift Analysis ---")
169-
print(f"Performing {num_captures} captures for cross-correlation analysis...")
170-
171-
sampling_rate = multi.dev1.sampling_rate
172-
print(f"Sampling rate: {sampling_rate} Hz")
173-
174-
for i in range(num_captures):
175-
if (i + 1) % 10 == 0:
176-
print(f"Progress: {i + 1}/{num_captures} captures")
177-
178-
# Capture synchronized data
179-
data1, data2 = multi.rx()
180-
181-
# Normalize signals (remove DC offset and normalize amplitude)
182-
data1_norm = (data1 - np.mean(data1)) / np.std(data1)
183-
data2_norm = (data2 - np.mean(data2)) / np.std(data2)
184-
185-
# Compute cross-correlation using FFT (much faster for large arrays)
186-
# This is equivalent to np.correlate(data1_norm, data2_norm, mode='full')
187-
# but uses FFT for O(N log N) complexity instead of O(N^2)
188-
fft1 = np.fft.fft(data1_norm, n=2*len(data1_norm))
189-
fft2 = np.fft.fft(data2_norm, n=2*len(data2_norm))
190-
correlation = np.fft.ifft(fft1 * np.conj(fft2)).real
191-
192-
# Rearrange to match 'full' mode output (shift zero-lag to center)
193-
correlation = np.concatenate([correlation[len(data1):], correlation[:len(data1)]])
194-
195-
# Find the lag with maximum correlation
196-
max_corr_idx = np.argmax(correlation)
197-
lag = max_corr_idx - (len(data1) - 1) # Offset to center
198-
199-
# Store results
200-
phase_shifts_samples.append(lag)
201-
correlation_peaks.append(correlation[max_corr_idx])
202-
203-
# Calculate phase shift in degrees (if signal is periodic)
204-
# For a sinusoidal signal, we can estimate phase shift
205-
# Phase shift in samples / samples per period * 360 degrees
206-
# We'll store the sample shift for now and convert later if needed
207-
208-
# Convert to numpy arrays for analysis
209-
phase_shifts_samples = np.array(phase_shifts_samples)
210-
correlation_peaks = np.array(correlation_peaks)
211-
212-
# Statistical analysis
213-
mean_shift = np.mean(phase_shifts_samples)
214-
std_shift = np.std(phase_shifts_samples)
215-
median_shift = np.median(phase_shifts_samples)
216-
217-
print(f"\nPhase Shift Statistics (in samples):")
218-
print(f" Mean: {mean_shift:.3f} samples")
219-
print(f" Std Dev: {std_shift:.3f} samples")
220-
print(f" Median: {median_shift:.3f} samples")
221-
print(f" Min: {np.min(phase_shifts_samples)} samples")
222-
print(f" Max: {np.max(phase_shifts_samples)} samples")
223-
224-
# Time delay in seconds
225-
time_delay_mean = mean_shift / sampling_rate
226-
time_delay_std = std_shift / sampling_rate
227-
print(f"\nTime Delay:")
228-
print(f" Mean: {time_delay_mean*1e9:.3f} ns")
229-
print(f" Std Dev: {time_delay_std*1e9:.3f} ns")
230-
231-
# Create comprehensive analysis plots
232-
fig = plt.figure(figsize=(16, 12))
233-
234-
# Plot 1: Histogram of phase shifts
235-
ax1 = plt.subplot(3, 2, 1)
236-
plt.hist(phase_shifts_samples, bins=50, edgecolor='black', alpha=0.7)
237-
plt.axvline(mean_shift, color='red', linestyle='--', linewidth=2, label=f'Mean: {mean_shift:.2f}')
238-
plt.axvline(median_shift, color='green', linestyle='--', linewidth=2, label=f'Median: {median_shift:.2f}')
239-
plt.xlabel('Phase Shift (samples)')
240-
plt.ylabel('Frequency')
241-
plt.title('Distribution of Phase Shifts Across 1000 Captures')
242-
plt.legend()
243-
plt.grid(True, alpha=0.3)
244-
245-
# Plot 2: Time series of phase shift
246-
ax2 = plt.subplot(3, 2, 2)
247-
plt.plot(phase_shifts_samples, alpha=0.6, linewidth=0.5)
248-
plt.axhline(mean_shift, color='red', linestyle='--', linewidth=2, label=f'Mean: {mean_shift:.2f}')
249-
plt.fill_between(range(num_captures),
250-
mean_shift - std_shift,
251-
mean_shift + std_shift,
252-
alpha=0.2, color='red', label=f'±1σ: {std_shift:.2f}')
253-
plt.xlabel('Capture Number')
254-
plt.ylabel('Phase Shift (samples)')
255-
plt.title('Phase Shift Over Time')
256-
plt.legend()
257-
plt.grid(True, alpha=0.3)
258-
259-
# Plot 3: Correlation peak values
260-
ax3 = plt.subplot(3, 2, 3)
261-
plt.plot(correlation_peaks, alpha=0.6, linewidth=0.5)
262-
plt.axhline(np.mean(correlation_peaks), color='red', linestyle='--', linewidth=2, label=f'Mean: {np.mean(correlation_peaks):.2f}')
263-
plt.xlabel('Capture Number')
264-
plt.ylabel('Correlation Peak Value')
265-
plt.title('Cross-Correlation Peak Strength')
266-
plt.legend()
267-
plt.grid(True, alpha=0.3)
268-
269-
# Plot 4: Example cross-correlation function
270-
ax4 = plt.subplot(3, 2, 4)
271-
# Perform one final capture to show the correlation function
272-
data1_ex, data2_ex = multi.rx()
273-
data1_norm_ex = (data1_ex - np.mean(data1_ex)) / np.std(data1_ex)
274-
data2_norm_ex = (data2_ex - np.mean(data2_ex)) / np.std(data2_ex)
275-
# Use FFT-based cross-correlation for speed
276-
fft1_ex = np.fft.fft(data1_norm_ex, n=2*len(data1_norm_ex))
277-
fft2_ex = np.fft.fft(data2_norm_ex, n=2*len(data2_norm_ex))
278-
correlation_ex = np.fft.ifft(fft1_ex * np.conj(fft2_ex)).real
279-
correlation_ex = np.concatenate([correlation_ex[len(data1_ex):], correlation_ex[:len(data1_ex)]])
280-
lags_ex = np.arange(-len(data1_ex) + 1, len(data1_ex))
281-
282-
# Plot only around the peak for clarity
283-
max_idx = np.argmax(correlation_ex)
284-
window = 1000 # Show ±1000 samples around peak
285-
start_idx = max(0, max_idx - window)
286-
end_idx = min(len(correlation_ex), max_idx + window)
287-
288-
plt.plot(lags_ex[start_idx:end_idx], correlation_ex[start_idx:end_idx], linewidth=1)
289-
plt.axvline(lags_ex[max_idx], color='red', linestyle='--', linewidth=2, label=f'Peak at lag={lags_ex[max_idx]}')
290-
plt.xlabel('Lag (samples)')
291-
plt.ylabel('Cross-Correlation')
292-
plt.title('Example Cross-Correlation Function')
293-
plt.legend()
294-
plt.grid(True, alpha=0.3)
295-
296-
# Plot 5: Example synchronized signals (zoomed in)
297-
ax5 = plt.subplot(3, 2, 5)
298-
zoom_samples = min(1000, len(data1_ex)) # Show first 1000 samples
299-
plt.plot(data1_ex[:zoom_samples], label='Device 1', alpha=0.7, linewidth=1)
300-
plt.plot(data2_ex[:zoom_samples], label='Device 2', alpha=0.7, linewidth=1)
301-
plt.xlabel('Sample Index')
302-
plt.ylabel('ADC Value')
303-
plt.title('Example Synchronized Signals (Zoomed)')
304-
plt.legend()
305-
plt.grid(True, alpha=0.3)
306-
307-
# Plot 6: Phase shift distribution (box plot)
308-
ax6 = plt.subplot(3, 2, 6)
309-
plt.boxplot(phase_shifts_samples, vert=True)
310-
plt.ylabel('Phase Shift (samples)')
311-
plt.title('Phase Shift Distribution (Box Plot)')
312-
plt.grid(True, alpha=0.3, axis='y')
313-
plt.text(0.5, mean_shift, f'Mean: {mean_shift:.2f}\nStd: {std_shift:.2f}',
314-
transform=ax6.get_yaxis_transform(), ha='left', va='center',
315-
bbox=dict(boxstyle='round', facecolor='wheat', alpha=0.5))
316-
317-
plt.tight_layout()
318-
plt.savefig("Phase_Shift_Analysis_1000_Captures")
319-
plt.close()
320-
321-
print("\nPhase shift analysis complete!")
322-
print(f"Analysis plot saved as: Phase_Shift_Analysis_{num_captures}_Captures.png")
323-
324-
# Summary report
325-
print("\n" + "="*60)
326-
print("PHASE SHIFT ANALYSIS SUMMARY")
327-
print("="*60)
328-
print(f"Number of captures: {num_captures}")
329-
print(f"Sampling rate: {sampling_rate} Hz")
330-
print(f"\nPhase alignment:")
331-
if abs(mean_shift) < 1.0:
332-
print(f" ✓ Excellent alignment (mean shift: {mean_shift:.3f} samples)")
333-
elif abs(mean_shift) < 5.0:
334-
print(f" ✓ Good alignment (mean shift: {mean_shift:.3f} samples)")
335-
else:
336-
print(f" ⚠ Measurable shift detected (mean shift: {mean_shift:.3f} samples)")
337-
338-
print(f"\nConsistency:")
339-
if std_shift < 0.5:
340-
print(f" ✓ Very consistent (σ = {std_shift:.3f} samples)")
341-
elif std_shift < 2.0:
342-
print(f" ✓ Consistent (σ = {std_shift:.3f} samples)")
343-
else:
344-
print(f" ⚠ Variable phase shift (σ = {std_shift:.3f} samples)")
345-
346-
print(f"\nCorrelation quality:")
347-
mean_corr = np.mean(correlation_peaks)
348-
print(f" Mean correlation peak: {mean_corr:.3f}")
349-
if mean_corr > 0.9:
350-
print(f" ✓ Excellent correlation")
351-
elif mean_corr > 0.7:
352-
print(f" ✓ Good correlation")
353-
else:
354-
print(f" ⚠ Moderate correlation")
355-
print("="*60)
356134

357-
# Cleanup buffers
358135
multi.rx_destroy_buffer()

0 commit comments

Comments
 (0)