Initial LsPower implementation
This commit is contained in:
217
LLM_readme.md
Normal file
217
LLM_readme.md
Normal file
@@ -0,0 +1,217 @@
|
||||
# LsPower Session Notes
|
||||
|
||||
## Current Goal
|
||||
|
||||
Build a Python tool to estimate electrical power delivered to a DIY active 2-way loudspeaker from measured DSP-output audio. Current measurement point is the analog DSP output / amplifier input, captured through a MOTU UltraLite input. Amplifier output is not measured directly yet; amplifier gain is modeled as an ideal scalar voltage gain in dB.
|
||||
|
||||
## Project Structure
|
||||
|
||||
- `soundcard_input.py`
|
||||
- Single runnable entry point.
|
||||
- Provides console voltage monitor, calibration routine, GUI monitor, and console power estimator mode.
|
||||
- `lspower/audio.py`
|
||||
- Shared sounddevice helpers.
|
||||
- `SoundDeviceManager`
|
||||
- `QueuedInputStream`
|
||||
- channel parsing/formatting helpers.
|
||||
- `lspower/impedance.py`
|
||||
- `ImpedanceCurve`
|
||||
- Loads REW impedance exports with columns: frequency Hz, impedance magnitude ohm, phase degrees.
|
||||
- Interpolates complex impedance to FFT bin frequencies.
|
||||
- `lspower/power.py`
|
||||
- `VoltageSpectrumEstimator`
|
||||
- `PowerEstimator`
|
||||
- `WayConfig`
|
||||
- `PowerFrame`
|
||||
- shared Hann/Welch voltage spectrum scaling helper.
|
||||
- `impedance.txt`
|
||||
- REW impedance export, currently usable directly.
|
||||
- `BC 14NDL76.txt`
|
||||
- Thiele-Small parameters for B&C 14NDL76. Useful later for safety/excursion/thermal modeling, not required for current power calculation.
|
||||
- `dsp_power_estimator.py`
|
||||
- Deleted as source. If an IDE tab still shows it, that is stale.
|
||||
|
||||
## Calibration State
|
||||
|
||||
The project uses a path-specific voltage scale:
|
||||
|
||||
```text
|
||||
voltage = sounddevice_sample * volts_per_sample_unit
|
||||
```
|
||||
|
||||
This is not a MOTU hardware full-scale spec. It includes the Windows/MME capture path, analog gain, routing, and any software gain.
|
||||
|
||||
Built-in reference:
|
||||
|
||||
```python
|
||||
DEFAULT_INPUT_CALIBRATION_REFERENCE_RMS_V = 2.32
|
||||
DEFAULT_INPUT_CALIBRATION_REFERENCE_RMS_SAMPLE = 0.021384357
|
||||
DEFAULT_INPUT_VOLTS_PER_SAMPLE_UNIT ~= 108.490522
|
||||
```
|
||||
|
||||
Later calibration files are saved under:
|
||||
|
||||
```text
|
||||
calibrations/calibration_YYYYMMDD_HHMMSS.json
|
||||
```
|
||||
|
||||
Startup behavior:
|
||||
|
||||
- If `--input-volts-per-sample-unit` is provided, it is used.
|
||||
- Otherwise the newest calibration JSON is loaded.
|
||||
- If no calibration file exists, the built-in default is used.
|
||||
|
||||
CLI calibration example:
|
||||
|
||||
```powershell
|
||||
python soundcard_input.py --device 3 --channels 1 --calibrate-known-rms-v 2.32 --calibrate-only
|
||||
```
|
||||
|
||||
GUI calibration saves the same JSON format.
|
||||
|
||||
## GUI Current Behavior
|
||||
|
||||
Start with:
|
||||
|
||||
```powershell
|
||||
python soundcard_input.py --gui
|
||||
```
|
||||
|
||||
Main sections:
|
||||
|
||||
- Input setup and calibration.
|
||||
- Input-side metrics:
|
||||
- RMS voltage
|
||||
- Peak voltage
|
||||
- Crest factor
|
||||
- Crest dB
|
||||
- Digital peak
|
||||
- Estimated amplifier output power:
|
||||
- LF/HF enable
|
||||
- channel
|
||||
- impedance file
|
||||
- amp gain dB
|
||||
- Vdsp
|
||||
- Vamp
|
||||
- P
|
||||
- Q
|
||||
- Sapp
|
||||
- Input waveform plot:
|
||||
- calibrated voltage y-axis
|
||||
- manual Y limit field, blank means auto
|
||||
- Input PSD plot:
|
||||
- Hann/Welch scaling
|
||||
- dB V^2/Hz
|
||||
- Output power history plot:
|
||||
- P as solid line
|
||||
- Sapp as dashed line
|
||||
- moving window default 30 s, user-editable
|
||||
|
||||
Important GUI detail:
|
||||
|
||||
- If LF and HF are both used, include both channels in `Channels`, e.g. `1,2`.
|
||||
- Power estimation uses the same FFT size, overlap, and smoothing controls as the input PSD.
|
||||
|
||||
## Power Estimation Math
|
||||
|
||||
For each way:
|
||||
|
||||
```text
|
||||
V_amp(f,t) = G_amp * V_DSP(f,t)
|
||||
G_amp = 10^(G_amp_dB / 20)
|
||||
Z(f) = |Z(f)| * exp(j * phase_Z(f))
|
||||
S_k(t) = |V_amp,k(t)|^2 / conj(Z_k)
|
||||
P_k(t) = real(S_k)
|
||||
Q_k(t) = imag(S_k)
|
||||
S_app,k(t) = |V_amp,k(t)|^2 / |Z_k|
|
||||
```
|
||||
|
||||
Totals:
|
||||
|
||||
```text
|
||||
P_total = sum(P_k)
|
||||
Q_total = sum(Q_k)
|
||||
Sapp_total = sum(S_app,k)
|
||||
```
|
||||
|
||||
FFT scaling:
|
||||
|
||||
- DC removed.
|
||||
- Hann window.
|
||||
- rFFT.
|
||||
- Welch scaling to one-sided PSD in `V^2/Hz`.
|
||||
- Multiply by `df` to get bin-integrated RMS voltage squared in `V^2`.
|
||||
|
||||
Synthetic validation already performed:
|
||||
|
||||
```text
|
||||
1 Vrms sine into 8 ohm with 0 dB gain -> 0.125 W
|
||||
```
|
||||
|
||||
## Current Known Hardware Context
|
||||
|
||||
- Audio interface: MOTU UltraLite.
|
||||
- Working input path used so far:
|
||||
|
||||
```text
|
||||
Device 3: Line In 3-4 (UltraLite-mk5) | MME | 2 in | 44100 Hz
|
||||
```
|
||||
|
||||
- WASAPI device 67 previously captured silence for this setup.
|
||||
- REW generator was used for calibration and signal testing.
|
||||
- At one point, generator was running at 50 Hz, 1 Vrms.
|
||||
|
||||
## Commands
|
||||
|
||||
List devices:
|
||||
|
||||
```powershell
|
||||
python soundcard_input.py --list-devices
|
||||
```
|
||||
|
||||
GUI:
|
||||
|
||||
```powershell
|
||||
python soundcard_input.py --gui
|
||||
```
|
||||
|
||||
Console voltage monitor:
|
||||
|
||||
```powershell
|
||||
python soundcard_input.py --device 3 --channels 1 --input-volts-per-sample-unit 108.490522
|
||||
```
|
||||
|
||||
Console power estimator:
|
||||
|
||||
```powershell
|
||||
python soundcard_input.py --device 3 --way LF:1:impedance.txt:34 --input-volts-per-sample-unit 108.490522
|
||||
```
|
||||
|
||||
## Verification Commands
|
||||
|
||||
```powershell
|
||||
.\.venv\Scripts\python.exe -m py_compile soundcard_input.py lspower\audio.py lspower\impedance.py lspower\power.py
|
||||
```
|
||||
|
||||
Synthetic power scaling:
|
||||
|
||||
```powershell
|
||||
.\.venv\Scripts\python.exe -c "import numpy as np; from pathlib import Path; from lspower.impedance import ImpedanceCurve; from lspower.power import PowerEstimator, WayConfig; fs=8192; n=8192; t=np.arange(n)/fs; x=np.sqrt(2)*np.sin(2*np.pi*1000*t); z=ImpedanceCurve(np.array([20.,20000.]), np.array([8.,8.]), np.array([0.,0.])); way=WayConfig('test',0,Path('none'),0.0); frame=PowerEstimator(way,z,fs,n,1.0,0.0).estimate(x); print(frame.rms_input_v, frame.total_p_w, frame.total_s_va)"
|
||||
```
|
||||
|
||||
Expected output approximately:
|
||||
|
||||
```text
|
||||
1.0 0.125 0.125
|
||||
```
|
||||
|
||||
## Likely Next Steps
|
||||
|
||||
- Improve GUI visual polish further if needed.
|
||||
- Add file picker buttons for impedance files.
|
||||
- Add measured amplifier transfer function support `H_amp(f)`.
|
||||
- Add driver safety panel:
|
||||
- compare P against `Pmax`
|
||||
- later estimate excursion against `Xmax`
|
||||
- Use T/S parameters from `BC 14NDL76.txt` only for model-based safety/excursion extensions, not for current impedance-based power estimation.
|
||||
|
||||
Reference in New Issue
Block a user