autd3_core/gain/
mod.rs

1mod drive;
2mod emit_intensity;
3mod error;
4mod phase;
5
6use std::collections::HashMap;
7
8pub use drive::Drive;
9pub use emit_intensity::Intensity;
10pub use error::GainError;
11pub use phase::Phase;
12
13use crate::{
14    datagram::{DeviceFilter, Segment, TransitionMode},
15    geometry::{Device, Geometry, Transducer},
16};
17
18#[derive(Debug)]
19/// A filter that represents which transducers are enabled.
20pub struct TransducerFilter(Option<HashMap<usize, Option<bit_vec::BitVec<u32>>>>);
21
22impl TransducerFilter {
23    #[doc(hidden)]
24    pub const fn new(filter: HashMap<usize, Option<bit_vec::BitVec<u32>>>) -> Self {
25        Self(Some(filter))
26    }
27
28    /// Returns a new `TransducerFilter` that enables all transducers.
29    pub const fn all_enabled() -> Self {
30        Self(None)
31    }
32
33    /// Creates a `DeviceFilter` where the value at each index is `f(&Device)`
34    pub fn from_fn<FT: Fn(&Transducer) -> bool>(
35        geo: &Geometry,
36        f: impl Fn(&Device) -> Option<FT>,
37    ) -> Self {
38        Self(Some(HashMap::from_iter(geo.iter().filter_map(|dev| {
39            f(dev).map(|f| {
40                (
41                    dev.idx(),
42                    Some(bit_vec::BitVec::from_fn(dev.num_transducers(), |idx| {
43                        f(&dev[idx])
44                    })),
45                )
46            })
47        }))))
48    }
49
50    /// Returns `true` i
51    pub const fn is_all_enabled(&self) -> bool {
52        self.0.is_none()
53    }
54
55    /// Returns `true` if the `Device` is enabled.
56    pub fn is_enabled_device(&self, dev: &Device) -> bool {
57        self.0.as_ref().is_none_or(|f| f.contains_key(&dev.idx()))
58    }
59
60    /// Returns `true` if the `Transducer` is enabled.
61    pub fn is_enabled(&self, tr: &Transducer) -> bool {
62        self.0.as_ref().is_none_or(|f| {
63            f.get(&tr.dev_idx())
64                .map(|f| f.as_ref().map(|f| f[tr.idx()]).unwrap_or(true))
65                .unwrap_or(false)
66        })
67    }
68
69    /// Returns the number of enabled devices.
70    pub fn num_enabled_devices(&self, geometry: &Geometry) -> usize {
71        self.0.as_ref().map_or(geometry.num_devices(), |f| {
72            geometry
73                .iter()
74                .filter(|dev| f.contains_key(&dev.idx()))
75                .count()
76        })
77    }
78
79    /// Returns the number of enabled transducers for the given `Device`.
80    pub fn num_enabled_transducers(&self, dev: &Device) -> usize {
81        self.0.as_ref().map_or(dev.num_transducers(), |f| {
82            f.get(&dev.idx()).map_or(0, |filter| {
83                filter
84                    .as_ref()
85                    .map_or(dev.num_transducers(), |f| f.count_ones() as usize)
86            })
87        })
88    }
89}
90
91impl From<&DeviceFilter> for TransducerFilter {
92    fn from(filter: &DeviceFilter) -> Self {
93        if let Some(filter) = filter.0.as_ref() {
94            Self(Some(
95                filter
96                    .iter()
97                    .enumerate()
98                    .filter_map(|(idx, enable)| enable.then_some((idx, None)))
99                    .collect(),
100            ))
101        } else {
102            Self(None)
103        }
104    }
105}
106
107/// A trait to calculate the phase and intensity for [`Gain`].
108///
109/// [`Gain`]: crate::gain::Gain
110pub trait GainCalculator: Send + Sync {
111    /// Calculates the phase and intensity for the transducer.
112    #[must_use]
113    fn calc(&self, tr: &Transducer) -> Drive;
114}
115
116impl GainCalculator for Box<dyn GainCalculator> {
117    fn calc(&self, tr: &Transducer) -> Drive {
118        self.as_ref().calc(tr)
119    }
120}
121
122/// A trait for generating a calculator for the gain operation.
123pub trait GainCalculatorGenerator {
124    /// The type of the calculator that actually performs the calculation.
125    type Calculator: GainCalculator;
126
127    /// Generate a calculator for the given device.
128    #[must_use]
129    fn generate(&mut self, device: &Device) -> Self::Calculator;
130}
131
132/// Trait for calculating the phase/amplitude of each transducer.
133///
134/// See also [`Gain`] derive macro.
135///
136/// [`Gain`]: autd3_derive::Gain
137pub trait Gain: std::fmt::Debug + Sized {
138    /// The type of the calculator generator.
139    type G: GainCalculatorGenerator;
140
141    /// Initialize the gain and generate the calculator generator.
142    ///
143    /// `filter` is a hash map that holds a bit vector representing the indices of the enabled transducers for each device index.
144    /// If `filter` is `None`, all transducers are enabled.
145    fn init(self, geometry: &Geometry, filter: &TransducerFilter) -> Result<Self::G, GainError>;
146}
147
148#[doc(hidden)]
149pub struct GainOperationGenerator<G: GainCalculatorGenerator> {
150    pub generator: G,
151    pub segment: Segment,
152    pub transition: Option<TransitionMode>,
153}
154
155impl<G: GainCalculatorGenerator> GainOperationGenerator<G> {
156    pub fn new<T: Gain<G = G>>(
157        gain: T,
158        geometry: &Geometry,
159        filter: &DeviceFilter,
160        segment: Segment,
161        transition: Option<TransitionMode>,
162    ) -> Result<Self, GainError> {
163        Ok(Self {
164            generator: gain.init(geometry, &TransducerFilter::from(filter))?,
165            segment,
166            transition,
167        })
168    }
169}
170
171#[derive(Debug, Clone, PartialEq)]
172/// The result of the [`Gain`] inspection.
173pub struct GainInspectionResult {
174    /// The type name of the gain.
175    pub name: String,
176    /// The data of the gain.
177    pub data: Vec<Drive>,
178    /// The segment of the gain.
179    pub segment: Segment,
180    /// The transition mode of the gain.
181    pub transition_mode: Option<TransitionMode>,
182}