Document EDFA max-power characterisation; restore safe pump clamp

Swept pump-1 to find real output: 1 W (30.1 dBm) at 4000 mA, 1.22 W at
4500 mA still unsaturated. External Thorlabs meter read 1.05 W vs 1.22 W
internal PD -> telemetry is ~0.5-0.6 dB optimistic, path-dependent; treat
amp/output*_power_dbm as indicative, not calibrated.

- README: full pump-vs-output table, PD-vs-meter calibration note, >1 W
  output-connector warning, ramp/overshoot guidance
- config.h: PUMP_CURRENT_MAX_MA back to 4000 mA (1 W rating) after the
  supervised over-rating sweep; added get_thresholds probe to agiltron driver
This commit is contained in:
James Bateman (hp-laptop)
2026-06-19 10:34:46 +01:00
parent 58475386ba
commit 61f4526d09
5 changed files with 62 additions and 12 deletions
+35 -11
View File
@@ -46,23 +46,47 @@ The rack is a **MOPA** (master-oscillator power-amplifier) at 1550 nm:
Run the booster in **ACC (constant-current)** mode — APC stepping quantises the
output. Below transparency the booster erbium fibre *absorbs* the pre-amp
output, so output stays at the PD floor (−60 dBm) until the pump is high
enough. Measured 2026-06-17 with ~6 mW (7.8 dBm) seed into the EDFA:
enough.
| Pump-1 | Output-1 | note |
|-------:|---------:|------|
### Pump-1 vs output characterisation (2026-06-17)
Two sweeps. The transparency sweep used ~6 mW (7.8 dBm) seed into the EDFA; the
high-power sweep added a 3 dB pad (input 3.2 dBm, within the ≤5 dBm benchtop
spec) and a direct output-to-power-meter connection.
| Pump-1 | Output-1 (internal PD) | note |
|-------:|------------------------|------|
| 500–900 mA | −60 dBm | below transparency, signal absorbed |
| 1200 mA | 21.0 dBm | booster turns on |
| 1500 mA | 23.3 dBm | |
| 1500 mA | 23.1 dBm | |
| 2000 mA | 25.9 dBm | |
| 2500 mA | 27.1 dBm | documented operating point, ~515 mW |
| 2500 mA | 27.1 dBm / 514 mW | documented 0.5 W operating point |
| 3000 mA | 28.3 dBm / 679 mW | |
| 3500 mA | 29.3 dBm / 857 mW | |
| 4000 mA | 30.1 dBm / 1026 mW | **1 W rated ceiling** |
| 4500 mA | 30.85 dBm / 1216 mW | over-rating; curve still ~linear (not saturated) |
Pump current overshoots ~2× briefly on each step up and settles in 2–4 s, so
**ramp gradually** rather than jumping straight to the setpoint.
The unit (factory APC setpoint 30 dBm) comfortably exceeds 1 W: 1.22 W at
4500 mA with the output still climbing ~0.74 dB/500 mA and module temp only
~30 °C — so its true saturated maximum is higher, but driving a 1 W-rated pump
diode past rating trades lifetime for diminishing return. Pump current
overshoots ~2× briefly on each step up and settles in 2–4 s, so **ramp
gradually** rather than jumping to the setpoint.
> **Safety:** this is a Class 4, ~1 W, invisible 1550 nm source. The firmware
> clamps pump-1 to `PUMP_CURRENT_MAX_MA` (3000 mA) and seed current to
> `SEED_CURRENT_MAX_MA`, but those are not interlocks — treat the output as
> hazardous unless it terminates in a power meter / beam dump / closed system.
> **Internal PD vs external power meter:** at 4500 mA the internal PD reported
> 1.22 W while a Thorlabs meter measured **1.05 W** at the output (~0.6 dB
> high / residual loss). Treat the `amp/output*_power_dbm` telemetry as
> indicative, ~0.5–0.6 dB optimistic, not a calibrated power reading. (The
> earlier lab notes saw the opposite sign through a different connection, so
> the offset is path-dependent.)
> **Safety:** Class 4, >1 W, invisible 1550 nm. The firmware clamps pump-1 to
> `PUMP_CURRENT_MAX_MA` (4000 mA ≈ the 1 W rating) and seed current to
> `SEED_CURRENT_MAX_MA` — guardrails against accidental over-drive, **not
> interlocks**. Above 1 W the Agiltron manual requires matched high-power
> connectors or a splice on the output, else the output fibre/amplifier can be
> damaged. Always drop the pump to 0 before unmating any fibre. Treat the
> output as hazardous unless it terminates in a power meter / beam dump.
## Hardware
+4 -1
View File
@@ -26,7 +26,10 @@
// HA number sliders are capped here. The hardware allows 8000 mA pump, but
// the lab notes report ~2500 mA pump-1 -> ~27 dBm (~515 mW). Keep a margin.
#define SEED_CURRENT_MAX_MA 300 // CTL200 ilmax default is 1000; seed DFB is low-power
#define PUMP_CURRENT_MAX_MA 3000 // firmware clamps amp pump-1 to this
// Pump-1 clamp = the 1 W rated operating point (~4000 mA, measured 2026-06-17).
// Raise deliberately only for supervised over-rating characterisation; it is a
// guardrail against accidental over-drive, not a safety interlock.
#define PUMP_CURRENT_MAX_MA 4000
// ── Serial links to the instruments (wired in later increments) ─────
// UART0 stays the USB console. The classic ESP32 has 3 hardware UARTs.
+19
View File
@@ -79,6 +79,25 @@ int Agiltron::getPumpEnabled() {
return (u16(r[8], r[9]) == 0) ? 1 : 0; // edfa.py: ==0 means enabled
}
long Agiltron::logThresholds() {
uint8_t r[64];
size_t n = transact(0x5F, nullptr, 0, r, sizeof(r));
if (!validate(r, n, 0x5F) || n < 48) return -1;
auto u32 = [&](int o) -> uint32_t {
return ((uint32_t)r[o] << 24) | ((uint32_t)r[o+1] << 16) |
((uint32_t)r[o+2] << 8) | r[o+3];
};
uint32_t maxPreampI = u32(8);
uint32_t maxPump1 = u32(24);
uint32_t maxPump2 = u32(32);
uint32_t maxPumpT = u32(44); // /10 = degC
Serial.printf("[agiltron] thresholds: max_preamp=%lu mA, max_pump1=%lu mA, "
"max_pump2=%lu mA, max_pump_temp=%.1f C\n",
(unsigned long)maxPreampI, (unsigned long)maxPump1,
(unsigned long)maxPump2, maxPumpT / 10.0);
return (long)maxPump1;
}
String Agiltron::getSn() {
uint8_t r[64];
size_t n = transact(0x1F, nullptr, 0, r, sizeof(r));
+3
View File
@@ -50,6 +50,9 @@ public:
// Authoritative pump-enable from get_settings (0x2E): byte[8:9]==0 => enabled.
// Returns -1 on no/invalid reply, 0 = disabled, 1 = enabled.
int getPumpEnabled();
// Factory safety thresholds (0x5F). Logs to Serial; returns max pump-1 mA
// (the device's own ceiling), or -1 on no/invalid reply.
long logThresholds();
// Control (return true if the device ACKed)
bool pumpOn() { return cmdAck(0x20, (const uint8_t[]){0x00,0x00}, 2); }
+1
View File
@@ -300,6 +300,7 @@ void setup() {
AGILTRON_UART_NUM, AGILTRON_RX_PIN, AGILTRON_TX_PIN);
String sn = agiltron.getSn(), pn = agiltron.getPn();
Serial.printf(" SN=\"%s\" PN=\"%s\"\n", sn.c_str(), pn.c_str());
agiltron.logThresholds();
if (sn.length() == 0)
Serial.println(" (no reply — Agiltron not wired? RX/TX swapped? wrong dev ID? GND?)");
#endif