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