Skip to content

Commit

Permalink
add adc conversion
Browse files Browse the repository at this point in the history
  • Loading branch information
jelenakhlr committed Jan 18, 2024
1 parent 3bd72d0 commit 02fe723
Show file tree
Hide file tree
Showing 2 changed files with 126 additions and 1 deletion.
104 changes: 104 additions & 0 deletions grand/sim/ADCconverter.py
Original file line number Diff line number Diff line change
@@ -0,0 +1,104 @@
#!/usr/bin/env python3
# author: Jelena & Pablo

import numpy as np

# Step 1: Convert voltage to ADC
def voltage_to_adc(trace,
adc_sampling_rate=2, # ns
adc_to_voltage=0.9e6/2**13):
'''
Description
-----------
Performs the virtual digitization of voltage traces at the ADC level:
- downsamples the simulated signal to the ADC sampling rate.
Parameters
----------
trace : np.ndarray[float]
Input voltage traces at the ADC level with dimensions (3, N_simu_samples).
Units: µV.
adc_sampling_rate : float, optional
Sampling rate of the ADC. Default is 2 ns (500 MHz).
Units: ns.
adc_to_voltage : float, optional
Conversion factor from ADC counts to voltage. Default is 0.9e6/2**13.
Units: µV.
Returns
-------
trace : np.ndarray[float]
The digitized array of voltage traces, with the ADC sampling rate and in ADC counts.
Units: LSB.
'''

# round the trace (by flooring)
trace = np.floor(trace / adc_to_voltage)

# Obtain downsampling factor
downsampling_factor = 1 / adc_sampling_rate # Adjusted to directly use adc_sampling_rate
# for the standard values, this would be a factor of 1/4, so we "keep" every 4th sample
if not downsampling_factor.is_integer():
raise ValueError("Downsampling factor must be an integer. Please check your settings.")

# Select all rows from the array and every downsampling_factor-th column, effectively downsampling the array along the second axis:
downsampled_trace = trace[:, ::int(downsampling_factor)]

return downsampled_trace



# Step 2: Pad the trace with a constant value and adjust its length to 2048
def padding(trace, padding_value=800):
'''
Description
-----------
Pads the trace with a constant value before the trace and adjusts its length to 2048.
Converts the voltage traces to ADC counts.
Arguments
---------
`trace`
type : np.ndarray[float]
units : LSB
description : The digitized array of voltage traces, with the ADC sampling rate and in ADC counts.
`padding_value`
type : int or float
units : LSB
description : Constant value used for padding the trace before.
Returns
-------
`trace`
type : np.ndarray[float]
units : LSB
description : The padded and adjusted array of voltage traces in ADC counts.
'''
# Pad the trace before with a constant value (800 in this case)
trace = np.concatenate([np.full(padding_value, 800), trace])

# Calculate the remaining padding needed after the trace
padding_after = max(0, 2048 - len(trace))

# Pad with zeros after the trace
if padding_after > 0:
trace = np.concatenate([trace, np.zeros(padding_after)])

# Ensure the length is 2048
trace = trace[:2048]

# Return trace in ADC counts, with the ADC sampling rate, and peak in the center
return trace

# Example usage:
# Assuming you have a trace
your_trace = np.random.rand(1000) # Replace this with your actual trace

# Step 1: Sample reduction & conversion to ADC
downsampled_trace = voltage_to_adc(your_trace)

# Step 2: add padding
final_trace = padding(downsampled_trace)
23 changes: 22 additions & 1 deletion grand/sim/efield2voltage.py
Original file line number Diff line number Diff line change
Expand Up @@ -18,6 +18,8 @@
from .shower.gen_shower import ShowerEvent
from .noise.galaxy import galactic_noise

from ADCconverter import voltage_to_adc, padding

logger = getLogger(__name__)

def get_fastest_size_fft(sig_size, f_samp_mhz, padding_factor=1):
Expand Down Expand Up @@ -58,7 +60,8 @@ def __init__(self, f_input, f_output="", seed=None, padding_factor=1.0):
self.events_list = self.events.get_list_of_events() # [[evt0, run0], [evt1, run0], ...[evt0, runN], ...]
self.rf_chain = RFChain() # loads RF chain. # RK: TODO: load this only if we want to add RF Chain.
self.ant_model = AntennaModel() # loads antenna models. time consuming. du_type='GP300' (default), 'Horizon'
self.params = {"add_noise": True, "lst": 18.0, "add_rf_chain":True}
self.params = {"add_noise": True, "lst": 18.0, "add_rf_chain":True,
"add_ADC_conversion": True, "add_downsampler_and_paddings": True}
self.previous_run = -1 # Not to load run info everytime event info is loaded.

def get_event(self, event_idx=None, event_number=None, run_number=None):
Expand Down Expand Up @@ -148,6 +151,15 @@ def get_event(self, event_idx=None, event_number=None, run_number=None):
if self.params["add_rf_chain"]:
self.rf_chain.compute_for_freqs(self.freqs_mhz)

# Add ADC conversion
if self.params["add_adc_conversion"]:
#! TODO: is self.traces what we want here?
downsampled_trace = self.voltage_to_adc(self.traces)

# Add downsampler and padding
if self.params["add_downsampler_and_padding"]:
self.padding(downsampled_trace)

def get_leff(self, du_idx):
"""
Define for each antenna in DU du_idx an object AntennaProcessing according its position
Expand Down Expand Up @@ -332,6 +344,15 @@ def compute_voltage_du(self, du_idx):
# ----- Add RF chain -----
if self.params["add_rf_chain"]:
self.vout_f[du_idx] *= self.rf_chain.get_tf()

# ----- Add ADC conversion -----
if self.params["add_adc_conversion"]:
# Add ADC conversion
self.vout_f[du_idx] += self.voltage_to_adc

if self.params["add_downsampler_and_padding"]:
# Add downsampler and padding
self.vout_f[du_idx] += self.padding

# Final voltage output for antenna with index du_idx
if self.params["add_noise"] or self.params["add_rf_chain"]:
Expand Down

0 comments on commit 02fe723

Please sign in to comment.