File size: 5,123 Bytes
acb1e49
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
145
146
147
148
// Room Acoustics Calculator Logic

class RoomAcousticsCalculator {
    constructor() {
        this.speedOfSound = 343; // m/s
        this.roomDimensions = { length: 5, width: 4, height: 3 };
        this.subwooferPosition = { x: 2.5, y: 2, z: 1.5 };
        this.modes = [];
        this.init();
    }

    init() {
        this.calculateModes();
    }

    setRoomDimensions(dimensions) {
        this.roomDimensions = dimensions;
        this.calculateModes();
    }

    setSubwooferPosition(position) {
        this.subwooferPosition = position;
        this.calculatePressureDistribution();
    }

    calculateModes(maxFrequency = 200) {
        const { length, width, height } = this.roomDimensions;
        this.modes = [];
        
        // Maximum mode numbers based on max frequency
        const maxN = Math.ceil((2 * maxFrequency * length) / this.speedOfSound);
        const maxM = Math.ceil((2 * maxFrequency * width) / this.speedOfSound);
        const maxP = Math.ceil((2 * maxFrequency * height) / this.speedOfSound);
        
        for (let n = 0; n <= maxN; n++) {
            for (let m = 0; m <= maxM; m++) {
                for (let p = 0; p <= maxP; p++) {
                    if (n === 0 && m === 0 && p === 0) continue;
                    
                    const frequency = (this.speedOfSound / 2) * 
                        Math.sqrt(
                            Math.pow(n / length, 2) + 
                            Math.pow(m / width, 2) + 
                            Math.pow(p / height, 2)
                        );
                    
                    if (frequency <= maxFrequency) {
                        let modeType = 'oblique';
                        if ((n > 0 && m === 0 && p === 0) || 
                            (n === 0 && m > 0 && p === 0) || 
                            (n === 0 && m === 0 && p > 0)) {
                            modeType = 'axial';
                        } else if ((n > 0 && m > 0 && p === 0) || 
                                   (n > 0 && m === 0 && p > 0) || 
                                   (n === 0 && m > 0 && p > 0)) {
                            modeType = 'tangential';
                        }
                        
                        this.modes.push({
                            n, m, p,
                            frequency: parseFloat(frequency.toFixed(2)),
                            type: modeType
                        });
                    }
                }
            }
        }
        
        // Sort by frequency
        this.modes.sort((a, b) => a.frequency - b.frequency);
        return this.modes;
    }

    calculatePressureAtPosition(x, y, z) {
        const { length, width, height } = this.roomDimensions;
        let pressure = 0;
        
        // Simplified pressure calculation based on mode shapes
        this.modes.forEach(mode => {
            const { n, m, p, frequency } = mode;
            if (frequency >= 20 && frequency <= 200) {
                // Mode shape function
                const modeShape = Math.cos((n * Math.PI * x) / length) *
                                  Math.cos((m * Math.PI * y) / width) *
                                  Math.cos((p * Math.PI * z) / height);
                
                // Pressure contribution (simplified)
                pressure += Math.abs(modeShape) / (frequency * frequency);
            }
        });
        
        return pressure;
    }

    calculatePressureDistribution() {
        // This would normally generate a full 3D pressure map
        // For now we'll just return pressure at subwoofer position
        return this.calculatePressureAtPosition(
            this.subwooferPosition.x,
            this.subwooferPosition.y,
            this.subwooferPosition.z
        );
    }

    getCriticalFrequencies() {
        const { length, width, height } = this.roomDimensions;
        return [
            {
                name: "Length Axial",
                frequency: parseFloat(((this.speedOfSound / 2) / length).toFixed(2)),
                dimension: "length"
            },
            {
                name: "Width Axial",
                frequency: parseFloat(((this.speedOfSound / 2) / width).toFixed(2)),
                dimension: "width"
            },
            {
                name: "Height Axial",
                frequency: parseFloat(((this.speedOfSound / 2) / height).toFixed(2)),
                dimension: "height"
            }
        ];
    }
}

// Global calculator instance
const calculator = new RoomAcousticsCalculator();

// Utility functions
function updateResults() {
    document.dispatchEvent(new CustomEvent('calculatorUpdated', {
        detail: {
            modes: calculator.modes,
            criticalFrequencies: calculator.getCriticalFrequencies(),
            pressure: calculator.calculatePressureDistribution()
        }
    }));
}

// Initialize when DOM is loaded
document.addEventListener('DOMContentLoaded', () => {
    updateResults();
});

// Export for use in components
window.calculator = calculator;
window.updateResults = updateResults;