-
Notifications
You must be signed in to change notification settings - Fork 13
Commit
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.
First step at including the ADC in the detector simulation chain
- Loading branch information
Pablo Correa
committed
Feb 21, 2024
1 parent
cec0dcc
commit 38050fe
Showing
3 changed files
with
162 additions
and
0 deletions.
There are no files selected for viewing
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,122 @@ | ||
""" | ||
Master module for the ADC in GRAND | ||
""" | ||
import numpy as np | ||
|
||
|
||
class ADC: | ||
''' | ||
Class that represents the analog-to-digital converter (ADC) of GRAND. | ||
The ADC digitizes an analog voltage that has been processed through the entire RF chain. | ||
For GRAND, the ADC has: | ||
- a sampling rate of 500 MHz | ||
- 14 bits centered around 0 V <-> 0 ADC counts, with 13 positive and 13 negative bits | ||
- a saturation at an input voltage of +/- 0.9 V | ||
''' | ||
|
||
def __init__(self): | ||
self.sampling_rate = 500 # [MHz] | ||
self.max_bit_value = 8192 # 14 bit ADC; 2 x 2^13 bits for negative and positive ADC values | ||
self.max_voltage = 9e5 # [µV]; saturation voltage of ADC (absolute value) | ||
|
||
|
||
def _digitize(self, | ||
voltage_trace): | ||
''' | ||
Performs the digitization of voltage traces at the ADC input: | ||
- converts voltage to ADC counts | ||
- quantizes the values | ||
Arguments | ||
--------- | ||
`voltage_trace` | ||
type : np.ndarray[float] | ||
units : µV | ||
description : Array of voltage traces at the ADC level, with shape (N_du,3,N_samples) | ||
Returns | ||
------- | ||
`adc_trace` | ||
type : np.ndarray[int] | ||
units : ADC counts (least significant bits) | ||
description : The digitized array of voltage traces, with shape (N_du,3,N_samples) | ||
''' | ||
|
||
# Convert voltage to ADC | ||
adc_trace = voltage_trace * self.max_bit_value / self.max_voltage | ||
|
||
# Quantize the trace | ||
adc_trace = np.trunc(adc_trace).astype(int) | ||
|
||
return adc_trace | ||
|
||
|
||
def _saturate(self, | ||
adc_trace): | ||
''' | ||
Simulates the saturation of the ADC | ||
Arguments | ||
--------- | ||
`adc_trace` | ||
type : np.ndarray[int] | ||
units : ADC counts (least significant bits) | ||
description : Array of ADC traces, with shape (N_du,3,N_samples) | ||
Returns | ||
------- | ||
`saturated_adc_trace` | ||
type : np.ndarray[int] | ||
units : ADC counts (least significant bits) | ||
description : Array of saturated ADC traces, with shape (N_du,3,N_samples) | ||
''' | ||
|
||
saturated_adc_trace = np.where(np.abs(adc_trace)<self.max_bit_value, | ||
adc_trace, | ||
np.sign(adc_trace)*self.max_bit_value) | ||
|
||
return saturated_adc_trace | ||
|
||
|
||
def process(self, | ||
voltage_trace, | ||
noise_trace=None): | ||
''' | ||
Processes an analog voltage trace to a digital ADC trace, | ||
with an option to add measured noise | ||
Arguments | ||
--------- | ||
`voltage_trace` | ||
type : np.ndarray[float] | ||
units : µV | ||
description : Array of voltage traces at the ADC level, with shape (N_du,3,N_samples) | ||
`noise_trace` (optional) | ||
type : np.ndarray[int] | ||
units : ADC counts (least significant bits) | ||
description : Array of measured noise traces, with shape (N_du,3,N_samples) | ||
Returns | ||
------- | ||
`adc_trace` | ||
type : np.ndarray[int] | ||
units : ADC counts (least significant bits) | ||
description : Array of ADC traces with shape (N_du,3,N_samples) | ||
''' | ||
|
||
assert isinstance(voltage_trace,np.ndarray) | ||
|
||
adc_trace = self._digitize(voltage_trace) | ||
|
||
# Add measured noise to the trace if requested | ||
if noise_trace is not None: | ||
assert isinstance(noise_trace,np.ndarray) | ||
assert noise_trace.shape == adc_trace.shape | ||
assert noise_trace.dtype == adc_trace.dtype | ||
adc_trace += noise_trace | ||
|
||
# Make sure the saturation occurs AFTER adding noise | ||
adc_trace = self._saturate(adc_trace) | ||
|
||
return adc_trace |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Original file line number | Diff line number | Diff line change |
---|---|---|
@@ -0,0 +1,38 @@ | ||
#! /usr/bin/env python3 | ||
|
||
import numpy as np | ||
np.set_printoptions(threshold = 3000) | ||
from grand import ADC | ||
import grand.dataio.root_trees as rt | ||
|
||
''' | ||
This will be an equivalent file to `convert_efield2voltage.py`. For now it's just a sandbox to test the ADC module. | ||
Goal of this script: | ||
- read voltage simulation file, containing a TVoltage tree with voltage traces processed through the RF chain | ||
- convert analog voltage traces to digital ADC traces | ||
- include an option to add measured noise to the ADC traces | ||
- save the (noisy) ADC traces in a TADC tree | ||
''' | ||
|
||
f_input = '../sim2root/Common/sim_Xiaodushan_20221026_180000_RUN0_CD_DC2Alpha_0000/voltage_-1_L0_0000_with-rf_no-noise.root' | ||
#f_input = '/sps/grand/tueros/DC2Alpha/GP300_Xi_Sib_Proton_1.53_82.1_101.7_8550/tvoltage_8550-8550_L0_0000_with-rf_no-noise.root' | ||
|
||
df = rt.DataFile(f_input) | ||
tvoltage = df.tvoltage | ||
tvoltage.get_entry(0) | ||
|
||
voltage_trace = np.array(tvoltage.trace) | ||
|
||
adc = ADC() | ||
|
||
adc_trace = adc.process(voltage_trace) | ||
|
||
adc_trace_noise = adc.process(voltage_trace,noise_trace=adc_trace) | ||
# adc_trace = adc.digitize(voltage_trace) | ||
# print(adc_trace[10][0]) | ||
# adc_trace = adc.saturate(adc_trace) | ||
# print(adc_trace[10][0]) | ||
|
||
|
||
print('done') |