use crate::room::{Room, RoomAcoustics, RoomSimulator};
use crate::types::Position3D;
use crate::{Error, Result};
use serde::{Deserialize, Serialize};
use std::collections::{HashMap, VecDeque};
use std::time::{Duration, Instant};
pub struct AdaptiveAcousticEnvironment {
current_room: Room,
sensors: EnvironmentSensors,
adaptation_controller: AdaptationController,
ml_adapter: Option<AcousticAdaptationModel>,
config: AdaptiveAcousticsConfig,
metrics: AdaptationMetrics,
adaptation_history: VecDeque<AdaptationAction>,
}
#[derive(Debug, Clone)]
pub struct EnvironmentSensors {
temperature_sensor: TemperatureSensor,
humidity_sensor: HumiditySensor,
noise_sensor: NoiseSensor,
occupancy_sensor: OccupancySensor,
material_detector: MaterialDetector,
acoustic_probe: AcousticProbe,
}
pub struct AdaptationController {
adaptation_state: AdaptationState,
strategies: HashMap<AdaptationTrigger, AdaptationStrategy>,
learning_rate: f32,
thresholds: AdaptationThresholds,
recent_adaptations: VecDeque<AdaptationAction>,
}
pub struct AcousticAdaptationModel {
environment_classifier: EnvironmentClassifier,
parameter_predictor: ParameterPredictor,
user_preference_model: UserPreferenceModel,
training_data: VecDeque<AdaptationTrainingExample>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdaptiveAcousticsConfig {
pub enable_adaptation: bool,
pub update_frequency: f32,
pub min_change_threshold: f32,
pub max_adaptation_rate: f32,
pub sensor_config: SensorConfig,
pub ml_config: Option<MLModelConfig>,
pub adaptation_strategies: Vec<AdaptationStrategyConfig>,
pub enable_preference_learning: bool,
}
#[derive(Debug, Clone)]
pub struct TemperatureSensor {
current_temperature: f32,
temperature_history: VecDeque<SensorReading<f32>>,
calibration_offset: f32,
accuracy: f32,
}
#[derive(Debug, Clone)]
pub struct HumiditySensor {
current_humidity: f32,
humidity_history: VecDeque<SensorReading<f32>>,
calibration_params: HumidityCalibration,
}
#[derive(Debug, Clone)]
pub struct NoiseSensor {
current_level: f32,
spectrum: NoiseSpectrum,
noise_type: NoiseType,
noise_history: VecDeque<NoiseReading>,
}
#[derive(Debug, Clone)]
pub struct OccupancySensor {
occupant_count: usize,
occupant_positions: Vec<Position3D>,
activity_level: ActivityLevel,
confidence: f32,
}
#[derive(Debug, Clone)]
pub struct MaterialDetector {
detected_materials: HashMap<String, MaterialProperties>,
detection_confidence: HashMap<String, f32>,
last_update: Instant,
detection_method: MaterialDetectionMethod,
}
#[derive(Debug, Clone)]
pub struct AcousticProbe {
impulse_responses: HashMap<Position3D, Vec<f32>>,
rt60_measurements: HashMap<String, f32>,
frequency_responses: HashMap<Position3D, Vec<f32>>,
last_probe_time: Instant,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SensorReading<T> {
pub value: T,
pub timestamp: f64,
pub confidence: f32,
}
#[derive(Debug, Clone, Default)]
pub struct AdaptationState {
pub environment_type: EnvironmentType,
pub active_adaptations: HashMap<String, f32>,
pub confidence: f32,
pub last_adaptation_time: Option<Instant>,
pub stability_score: f32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub enum AdaptationTrigger {
TemperatureChange,
HumidityChange,
NoiseChange,
OccupancyChange,
MaterialChange,
ContentChange,
UserFeedback,
TimeAdaptation,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdaptationStrategy {
pub name: String,
pub triggers: Vec<AdaptationTrigger>,
pub parameter_adjustments: HashMap<String, ParameterAdjustment>,
pub adaptation_speed: f32,
pub priority: f32,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Default, Serialize, Deserialize)]
pub enum EnvironmentType {
#[default]
LivingRoom,
Bedroom,
Kitchen,
Office,
Bathroom,
Outdoor,
Vehicle,
ConcertHall,
SmallRoom,
LargeHall,
Unknown,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum NoiseType {
White,
Pink,
Traffic,
HVAC,
Conversation,
Music,
Mechanical,
Natural,
Electronic,
Mixed,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ActivityLevel {
None,
Low,
Medium,
High,
VeryHigh,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum MaterialDetectionMethod {
ComputerVision,
AcousticAnalysis,
LIDAR,
Manual,
MLClassification,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MaterialProperties {
pub name: String,
pub absorption: HashMap<String, f32>,
pub scattering: HashMap<String, f32>,
pub transmission: HashMap<String, f32>,
pub density: f32,
pub roughness: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParameterAdjustment {
pub parameter: String,
pub adjustment_type: AdjustmentType,
pub value: f32,
pub curve: AdjustmentCurve,
pub bounds: (f32, f32),
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AdjustmentType {
Absolute,
Relative,
Additive,
Exponential,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AdjustmentCurve {
Linear,
Exponential,
Logarithmic,
Sigmoid,
Custom,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdaptationThresholds {
pub temperature_threshold: f32,
pub humidity_threshold: f32,
pub noise_threshold: f32,
pub occupancy_threshold: usize,
pub material_threshold: f32,
pub stability_time_threshold: Duration,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdaptationEvent {
pub timestamp: f64,
pub trigger: AdaptationTrigger,
pub environment_snapshot: EnvironmentSnapshot,
pub parameter_changes: HashMap<String, ParameterChange>,
pub result: AdaptationResult,
pub user_feedback: Option<UserFeedback>,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct EnvironmentSnapshot {
pub temperature: f32,
pub humidity: f32,
pub noise_level: f32,
pub occupant_count: usize,
pub materials: HashMap<String, f32>,
pub time_of_day: f32,
}
#[derive(Debug, Clone, Default, Serialize, Deserialize)]
pub struct AdaptationMetrics {
pub total_adaptations: usize,
pub successful_adaptations: usize,
pub average_adaptation_time: Duration,
pub user_satisfaction: f32,
pub classification_accuracy: f32,
pub prediction_accuracy: f32,
pub adaptation_frequency: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct SensorConfig {
pub temperature: TemperatureSensorConfig,
pub humidity: HumiditySensorConfig,
pub noise: NoiseSensorConfig,
pub occupancy: OccupancySensorConfig,
pub material_detector: MaterialDetectorConfig,
pub acoustic_probe: AcousticProbeConfig,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct TemperatureSensorConfig {
pub update_frequency: f32,
pub calibration_offset: f32,
pub accuracy: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HumiditySensorConfig {
pub update_frequency: f32,
pub calibration: HumidityCalibration,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct NoiseSensorConfig {
pub update_frequency: f32,
pub frequency_bands: Vec<(f32, f32)>,
pub enable_classification: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct OccupancySensorConfig {
pub detection_method: OccupancyDetectionMethod,
pub update_frequency: f32,
pub enable_position_tracking: bool,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MaterialDetectorConfig {
pub detection_method: MaterialDetectionMethod,
pub update_frequency: f32,
pub confidence_threshold: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AcousticProbeConfig {
pub probe_frequency: f32,
pub probe_signal: ProbeSignalType,
pub analysis_window: Duration,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum ProbeSignalType {
SineSweep,
WhiteNoise,
PinkNoise,
MLS,
TSP,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum OccupancyDetectionMethod {
ComputerVision,
Infrared,
Ultrasonic,
WiFi,
Bluetooth,
AudioAnalysis,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct HumidityCalibration {
pub linear_coeff: f32,
pub offset: f32,
pub temp_compensation: f32,
}
#[derive(Debug, Clone)]
pub struct NoiseSpectrum {
pub frequency_bands: Vec<f32>,
pub power_levels: Vec<f32>,
pub centroid: f32,
pub rolloff: f32,
}
#[derive(Debug, Clone)]
pub struct NoiseReading {
pub level: f32,
pub spectrum: NoiseSpectrum,
pub noise_type: NoiseType,
pub timestamp: f64,
pub confidence: f32,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdaptationAction {
pub timestamp: f64,
pub parameter: String,
pub old_value: f32,
pub new_value: f32,
pub trigger: AdaptationTrigger,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct ParameterChange {
pub parameter: String,
pub change: f32,
pub change_type: AdjustmentType,
pub success: bool,
}
#[derive(Debug, Clone, Copy, PartialEq, Eq, Serialize, Deserialize)]
pub enum AdaptationResult {
Success,
Failed,
Partial,
Cancelled,
Skipped,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct UserFeedback {
pub rating: f32,
pub comment: Option<String>,
pub parameter_preferences: HashMap<String, f32>,
pub timestamp: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdaptationTrainingExample {
pub environment_features: Vec<f32>,
pub target_parameters: HashMap<String, f32>,
pub satisfaction_score: f32,
pub context: EnvironmentSnapshot,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct MLModelConfig {
pub enable_classification: bool,
pub enable_prediction: bool,
pub enable_preference_learning: bool,
pub update_frequency: Duration,
pub batch_size: usize,
pub learning_rate: f64,
}
#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct AdaptationStrategyConfig {
pub name: String,
pub triggers: Vec<AdaptationTrigger>,
pub parameters: HashMap<String, ParameterAdjustment>,
pub weight: f32,
}
#[derive(Debug, Clone)]
pub struct EnvironmentClassifier {
weights: Vec<f32>,
}
#[derive(Debug, Clone)]
pub struct ParameterPredictor {
weights: Vec<f32>,
}
#[derive(Debug, Clone)]
pub struct UserPreferenceModel {
preferences: HashMap<String, f32>,
}
impl Default for AdaptiveAcousticsConfig {
fn default() -> Self {
Self {
enable_adaptation: true,
update_frequency: 1.0, min_change_threshold: 0.05,
max_adaptation_rate: 10.0, sensor_config: SensorConfig::default(),
ml_config: None,
adaptation_strategies: vec![
AdaptationStrategyConfig {
name: "Temperature Compensation".to_string(),
triggers: vec![AdaptationTrigger::TemperatureChange],
parameters: HashMap::new(),
weight: 1.0,
},
AdaptationStrategyConfig {
name: "Occupancy Adjustment".to_string(),
triggers: vec![AdaptationTrigger::OccupancyChange],
parameters: HashMap::new(),
weight: 1.0,
},
],
enable_preference_learning: true,
}
}
}
impl Default for SensorConfig {
fn default() -> Self {
Self {
temperature: TemperatureSensorConfig {
update_frequency: 0.1, calibration_offset: 0.0,
accuracy: 0.5, },
humidity: HumiditySensorConfig {
update_frequency: 0.1,
calibration: HumidityCalibration {
linear_coeff: 1.0,
offset: 0.0,
temp_compensation: 0.01,
},
},
noise: NoiseSensorConfig {
update_frequency: 10.0, frequency_bands: vec![
(20.0, 200.0), (200.0, 2000.0), (2000.0, 20000.0), ],
enable_classification: true,
},
occupancy: OccupancySensorConfig {
detection_method: OccupancyDetectionMethod::AudioAnalysis,
update_frequency: 1.0, enable_position_tracking: false,
},
material_detector: MaterialDetectorConfig {
detection_method: MaterialDetectionMethod::AcousticAnalysis,
update_frequency: 0.01, confidence_threshold: 0.7,
},
acoustic_probe: AcousticProbeConfig {
probe_frequency: 0.01, probe_signal: ProbeSignalType::SineSweep,
analysis_window: Duration::from_secs(5),
},
}
}
}
impl Default for AdaptationThresholds {
fn default() -> Self {
Self {
temperature_threshold: 2.0, humidity_threshold: 0.1, noise_threshold: 5.0, occupancy_threshold: 1, material_threshold: 0.2, stability_time_threshold: Duration::from_secs(30),
}
}
}
impl AdaptiveAcousticEnvironment {
fn get_current_timestamp() -> f64 {
use std::time::{SystemTime, UNIX_EPOCH};
SystemTime::now()
.duration_since(UNIX_EPOCH)
.expect("SystemTime should be after UNIX_EPOCH")
.as_secs_f64()
}
pub fn new(initial_room: Room, config: AdaptiveAcousticsConfig) -> Result<Self> {
let sensors = EnvironmentSensors::new(&config.sensor_config)?;
let adaptation_controller = AdaptationController::new(&config)?;
let ml_adapter = if config.ml_config.is_some() {
Some(AcousticAdaptationModel::new()?)
} else {
None
};
Ok(Self {
current_room: initial_room,
sensors,
adaptation_controller,
ml_adapter,
config,
metrics: AdaptationMetrics::default(),
adaptation_history: VecDeque::new(),
})
}
pub fn update(&mut self) -> Result<Vec<AdaptationAction>> {
if !self.config.enable_adaptation {
return Ok(Vec::new());
}
self.sensors.update()?;
let triggers = self.detect_environmental_changes()?;
let mut actions = Vec::new();
for trigger in triggers {
if let Some(new_actions) = self.perform_adaptation(trigger)? {
actions.extend(new_actions);
}
}
self.update_metrics(&actions);
for action in &actions {
self.adaptation_history.push_back(action.clone());
}
if self.adaptation_history.len() > 1000 {
self.adaptation_history.pop_front();
}
Ok(actions)
}
pub fn manual_adaptation(&mut self, parameter: &str, value: f32) -> Result<AdaptationAction> {
let old_value = self.get_parameter_value(parameter)?;
self.set_parameter_value(parameter, value)?;
let action = AdaptationAction {
timestamp: Self::get_current_timestamp(),
parameter: parameter.to_string(),
old_value,
new_value: value,
trigger: AdaptationTrigger::UserFeedback,
};
self.adaptation_history.push_back(action.clone());
self.metrics.total_adaptations += 1;
Ok(action)
}
pub fn provide_user_feedback(&mut self, feedback: UserFeedback) -> Result<()> {
let total_feedback = self.metrics.total_adaptations as f32;
self.metrics.user_satisfaction = (self.metrics.user_satisfaction * (total_feedback - 1.0)
+ feedback.rating)
/ total_feedback;
if self.config.enable_preference_learning {
let snapshot = self.get_current_environment_snapshot();
if let Some(ref mut ml_adapter) = self.ml_adapter {
ml_adapter.learn_from_feedback(&feedback, &snapshot)?;
}
}
for (param, preferred_value) in &feedback.parameter_preferences {
let current_value = self.get_parameter_value(param)?;
if (current_value - preferred_value).abs() > self.config.min_change_threshold {
self.manual_adaptation(param, *preferred_value)?;
}
}
Ok(())
}
pub fn metrics(&self) -> &AdaptationMetrics {
&self.metrics
}
pub fn adaptation_history(&self) -> &VecDeque<AdaptationAction> {
&self.adaptation_history
}
pub fn get_current_environment_snapshot(&self) -> EnvironmentSnapshot {
EnvironmentSnapshot {
temperature: self.sensors.temperature_sensor.current_temperature,
humidity: self.sensors.humidity_sensor.current_humidity,
noise_level: self.sensors.noise_sensor.current_level,
occupant_count: self.sensors.occupancy_sensor.occupant_count,
materials: self
.sensors
.material_detector
.detected_materials
.iter()
.map(|(name, props)| (name.clone(), props.density))
.collect(),
time_of_day: {
use std::time::SystemTime;
let now = SystemTime::now()
.duration_since(SystemTime::UNIX_EPOCH)
.expect("SystemTime should be after UNIX_EPOCH")
.as_secs()
% 86400; now as f32 / 86400.0 },
}
}
fn detect_environmental_changes(&self) -> Result<Vec<AdaptationTrigger>> {
let mut triggers = Vec::new();
let thresholds = &self.adaptation_controller.thresholds;
if let Some(recent_temp) = self.sensors.temperature_sensor.temperature_history.back() {
let temp_change =
(recent_temp.value - self.sensors.temperature_sensor.current_temperature).abs();
if temp_change > thresholds.temperature_threshold {
triggers.push(AdaptationTrigger::TemperatureChange);
}
}
if let Some(recent_humidity) = self.sensors.humidity_sensor.humidity_history.back() {
let humidity_change =
(recent_humidity.value - self.sensors.humidity_sensor.current_humidity).abs();
if humidity_change > thresholds.humidity_threshold {
triggers.push(AdaptationTrigger::HumidityChange);
}
}
if let Some(recent_noise) = self.sensors.noise_sensor.noise_history.back() {
let noise_change = (recent_noise.level - self.sensors.noise_sensor.current_level).abs();
if noise_change > thresholds.noise_threshold {
triggers.push(AdaptationTrigger::NoiseChange);
}
}
Ok(triggers)
}
fn perform_adaptation(
&mut self,
trigger: AdaptationTrigger,
) -> Result<Option<Vec<AdaptationAction>>> {
if let Some(strategy) = self.adaptation_controller.strategies.get(&trigger).cloned() {
let mut actions = Vec::new();
for (param_name, adjustment) in &strategy.parameter_adjustments {
let current_value = self.get_parameter_value(param_name)?;
let new_value = self.apply_parameter_adjustment(current_value, adjustment)?;
let bounded_value = new_value.clamp(adjustment.bounds.0, adjustment.bounds.1);
if (bounded_value - current_value).abs() > self.config.min_change_threshold {
self.set_parameter_value(param_name, bounded_value)?;
actions.push(AdaptationAction {
timestamp: Self::get_current_timestamp(),
parameter: param_name.clone(),
old_value: current_value,
new_value: bounded_value,
trigger,
});
}
}
Ok(Some(actions))
} else {
Ok(None)
}
}
fn apply_parameter_adjustment(
&self,
current_value: f32,
adjustment: &ParameterAdjustment,
) -> Result<f32> {
let adjusted = match adjustment.adjustment_type {
AdjustmentType::Absolute => adjustment.value,
AdjustmentType::Relative => current_value * adjustment.value,
AdjustmentType::Additive => current_value + adjustment.value,
AdjustmentType::Exponential => current_value * adjustment.value.exp(),
};
let final_value = match adjustment.curve {
AdjustmentCurve::Linear => adjusted,
AdjustmentCurve::Exponential => adjusted.exp(),
AdjustmentCurve::Logarithmic => adjusted.ln(),
AdjustmentCurve::Sigmoid => 1.0 / (1.0 + (-adjusted).exp()),
AdjustmentCurve::Custom => adjusted, };
Ok(final_value)
}
fn get_parameter_value(&self, parameter: &str) -> Result<f32> {
match parameter {
"reverb_time" => Ok(1.5), "early_reflection_level" => Ok(-12.0), "diffusion" => Ok(0.7),
"absorption" => Ok(0.3),
_ => Err(Error::processing(&format!(
"Unknown parameter: {parameter}"
))),
}
}
fn set_parameter_value(&mut self, parameter: &str, value: f32) -> Result<()> {
match parameter {
"reverb_time" | "early_reflection_level" | "diffusion" | "absorption" => {
Ok(())
}
_ => Err(Error::processing(&format!(
"Cannot set unknown parameter: {parameter}"
))),
}
}
fn update_metrics(&mut self, actions: &[AdaptationAction]) {
self.metrics.total_adaptations += actions.len();
}
}
impl EnvironmentSensors {
fn new(_config: &SensorConfig) -> Result<Self> {
Ok(Self {
temperature_sensor: TemperatureSensor::new(),
humidity_sensor: HumiditySensor::new(),
noise_sensor: NoiseSensor::new(),
occupancy_sensor: OccupancySensor::new(),
material_detector: MaterialDetector::new(),
acoustic_probe: AcousticProbe::new(),
})
}
fn update(&mut self) -> Result<()> {
self.temperature_sensor.update()?;
self.humidity_sensor.update()?;
self.noise_sensor.update()?;
self.occupancy_sensor.update()?;
self.material_detector.update()?;
self.acoustic_probe.update()?;
Ok(())
}
}
impl AdaptationController {
fn new(config: &AdaptiveAcousticsConfig) -> Result<Self> {
let mut strategies = HashMap::new();
for strategy_config in &config.adaptation_strategies {
let strategy = AdaptationStrategy {
name: strategy_config.name.clone(),
triggers: strategy_config.triggers.clone(),
parameter_adjustments: strategy_config.parameters.clone(),
adaptation_speed: 0.5,
priority: strategy_config.weight,
};
for trigger in &strategy.triggers {
strategies.insert(*trigger, strategy.clone());
}
}
Ok(Self {
adaptation_state: AdaptationState::default(),
strategies,
learning_rate: 0.01,
thresholds: AdaptationThresholds::default(),
recent_adaptations: VecDeque::new(),
})
}
}
impl AcousticAdaptationModel {
fn new() -> Result<Self> {
Ok(Self {
environment_classifier: EnvironmentClassifier {
weights: vec![0.0; 10],
},
parameter_predictor: ParameterPredictor {
weights: vec![0.0; 20],
},
user_preference_model: UserPreferenceModel {
preferences: HashMap::new(),
},
training_data: VecDeque::new(),
})
}
fn learn_from_feedback(
&mut self,
_feedback: &UserFeedback,
_snapshot: &EnvironmentSnapshot,
) -> Result<()> {
Ok(())
}
}
impl TemperatureSensor {
fn new() -> Self {
Self {
current_temperature: 22.0, temperature_history: VecDeque::new(),
calibration_offset: 0.0,
accuracy: 0.5,
}
}
fn update(&mut self) -> Result<()> {
let reading = SensorReading {
value: self.current_temperature + fastrand::f32() * 0.1 - 0.05, timestamp: AdaptiveAcousticEnvironment::get_current_timestamp(),
confidence: 0.95,
};
self.temperature_history.push_back(reading);
if self.temperature_history.len() > 100 {
self.temperature_history.pop_front();
}
Ok(())
}
}
impl HumiditySensor {
fn new() -> Self {
Self {
current_humidity: 0.45, humidity_history: VecDeque::new(),
calibration_params: HumidityCalibration {
linear_coeff: 1.0,
offset: 0.0,
temp_compensation: 0.01,
},
}
}
fn update(&mut self) -> Result<()> {
let reading = SensorReading {
value: self.current_humidity + fastrand::f32() * 0.02 - 0.01,
timestamp: AdaptiveAcousticEnvironment::get_current_timestamp(),
confidence: 0.9,
};
self.humidity_history.push_back(reading);
if self.humidity_history.len() > 100 {
self.humidity_history.pop_front();
}
Ok(())
}
}
impl NoiseSensor {
fn new() -> Self {
Self {
current_level: 35.0, spectrum: NoiseSpectrum {
frequency_bands: vec![125.0, 250.0, 500.0, 1000.0, 2000.0, 4000.0, 8000.0],
power_levels: vec![30.0, 32.0, 34.0, 35.0, 33.0, 31.0, 29.0],
centroid: 800.0,
rolloff: 2000.0,
},
noise_type: NoiseType::HVAC,
noise_history: VecDeque::new(),
}
}
fn update(&mut self) -> Result<()> {
let reading = NoiseReading {
level: self.current_level + fastrand::f32() * 2.0 - 1.0,
spectrum: self.spectrum.clone(),
noise_type: self.noise_type,
timestamp: AdaptiveAcousticEnvironment::get_current_timestamp(),
confidence: 0.8,
};
self.noise_history.push_back(reading);
if self.noise_history.len() > 1000 {
self.noise_history.pop_front();
}
Ok(())
}
}
impl OccupancySensor {
fn new() -> Self {
Self {
occupant_count: 1,
occupant_positions: vec![Position3D::new(0.0, 0.0, 1.7)], activity_level: ActivityLevel::Low,
confidence: 0.85,
}
}
fn update(&mut self) -> Result<()> {
Ok(())
}
}
impl MaterialDetector {
fn new() -> Self {
let mut detected_materials = HashMap::new();
detected_materials.insert(
"carpet".to_string(),
MaterialProperties {
name: "Carpet".to_string(),
absorption: [
("125Hz", 0.02),
("250Hz", 0.04),
("500Hz", 0.08),
("1000Hz", 0.12),
("2000Hz", 0.22),
("4000Hz", 0.35),
]
.iter()
.map(|(k, v)| (k.to_string(), *v))
.collect(),
scattering: HashMap::new(),
transmission: HashMap::new(),
density: 400.0,
roughness: 0.3,
},
);
Self {
detected_materials,
detection_confidence: HashMap::new(),
last_update: Instant::now(),
detection_method: MaterialDetectionMethod::AcousticAnalysis,
}
}
fn update(&mut self) -> Result<()> {
self.last_update = Instant::now();
Ok(())
}
}
impl AcousticProbe {
fn new() -> Self {
Self {
impulse_responses: HashMap::new(),
rt60_measurements: [
("125Hz", 1.2),
("250Hz", 1.1),
("500Hz", 0.9),
("1000Hz", 0.8),
("2000Hz", 0.7),
("4000Hz", 0.6),
]
.iter()
.map(|(k, v)| (k.to_string(), *v))
.collect(),
frequency_responses: HashMap::new(),
last_probe_time: Instant::now(),
}
}
fn update(&mut self) -> Result<()> {
if self.last_probe_time.elapsed() > Duration::from_secs(60) {
self.last_probe_time = Instant::now();
}
Ok(())
}
}
#[cfg(test)]
mod tests {
use super::*;
use crate::room::Room;
#[test]
fn test_adaptive_environment_creation() {
let room = Room::new(
"test_room".to_string(),
(5.0, 4.0, 3.0),
1.2,
Position3D::new(0.0, 0.0, 0.0),
)
.unwrap();
let config = AdaptiveAcousticsConfig::default();
let environment = AdaptiveAcousticEnvironment::new(room, config);
assert!(environment.is_ok());
}
#[test]
fn test_sensor_updates() {
let mut temp_sensor = TemperatureSensor::new();
assert!(temp_sensor.update().is_ok());
assert_eq!(temp_sensor.temperature_history.len(), 1);
}
#[test]
fn test_adaptation_triggers() {
let trigger = AdaptationTrigger::TemperatureChange;
assert_eq!(trigger, AdaptationTrigger::TemperatureChange);
}
#[test]
fn test_parameter_adjustment() {
let adjustment = ParameterAdjustment {
parameter: "reverb_time".to_string(),
adjustment_type: AdjustmentType::Relative,
value: 1.2,
curve: AdjustmentCurve::Linear,
bounds: (0.1, 3.0),
};
assert_eq!(adjustment.parameter, "reverb_time");
assert_eq!(adjustment.value, 1.2);
}
#[test]
fn test_environment_snapshot() {
let snapshot = EnvironmentSnapshot {
temperature: 22.5,
humidity: 0.45,
noise_level: 35.0,
occupant_count: 2,
materials: HashMap::new(),
time_of_day: 0.5,
};
assert_eq!(snapshot.temperature, 22.5);
assert_eq!(snapshot.occupant_count, 2);
}
#[test]
fn test_user_feedback() {
let mut preferences = HashMap::new();
preferences.insert("reverb_time".to_string(), 1.2);
let feedback = UserFeedback {
rating: 0.8,
comment: Some("Sounds good".to_string()),
parameter_preferences: preferences,
timestamp: AdaptiveAcousticEnvironment::get_current_timestamp(),
};
assert_eq!(feedback.rating, 0.8);
assert!(feedback.comment.is_some());
}
#[test]
fn test_noise_spectrum() {
let spectrum = NoiseSpectrum {
frequency_bands: vec![125.0, 250.0, 500.0],
power_levels: vec![30.0, 32.0, 28.0],
centroid: 400.0,
rolloff: 800.0,
};
assert_eq!(spectrum.frequency_bands.len(), 3);
assert_eq!(spectrum.power_levels.len(), 3);
}
#[test]
fn test_adaptation_metrics() {
let mut metrics = AdaptationMetrics::default();
metrics.total_adaptations = 50;
metrics.successful_adaptations = 45;
let success_rate = metrics.successful_adaptations as f32 / metrics.total_adaptations as f32;
assert_eq!(success_rate, 0.9);
}
}