# AC Small-Signal Transfer Function Analysis

`anacxf.h`/`coreacxf.h` (with `lib/anacxf.cpp`/`lib/coreacxf.cpp`) implement AC small-signal transfer function analysis: across a swept frequency range, for one or more independent sources in turn, it computes the complex transfer function from that source's magnitude to a chosen output, and the complex small-signal input impedance/admittance seen at the source's terminals. It combines the frequency sweep of [AC Analysis](anac.md) with the per-source unity-excitation approach of [DC Transfer Function Analysis](andcxf.md).

## Class and Data Structures

`ACXF` is the typedef `SmallSignal<ACXFCore, ACXFData>` ([Small-Signal Analysis Template](ansmsig.md)), pairing an `OperatingPointCore` ([Operating Point Analysis](anop.md)) with `ACXFCore`. `ACXFData` (`anacxf.h`) supplies the `DataMixin` slot's storage - the union of what AC analysis and DC transfer function analysis each need:

- `acMatrix`, `acSolution` - the complex system matrix and phasor solution vector, as in [AC Analysis](anac.md).
- `sourceIndex`, `sources` - the source-instance index map and resolved `Instance*` list, as in [DC Transfer Function Analysis](andcxf.md).
- `tf`, `yin`, `zin` - one complex entry per source: transfer function, input admittance, input impedance (complex here, unlike the real-valued `DCXFData` equivalents).

`ACXFCore` (`coreacxf.h`) is the concrete `AnalysisCore`, holding references to the op core's real Jacobian/solution/states plus its own complex matrix and per-source vectors. `ACXFParameters` embeds `OperatingPointParameters opParams`, the output selector `out`, and the same frequency-sweep fields as `ACParameters` (`from`, `to`, `step`, `mode`, `points`, `values`).

`SmallSignal<ACXFCore, ACXFData>` is specialized in `anacxf.cpp` for its constructor, `resolveSave()`, and `dump()`.

## Core Algorithm

Same governing equation as the rest of this section (comment block in `coreacxf.h`):

```
            d
   f(x(t)) + ---- q(x(t)) = 0
            dt
```

AC transfer function analysis assumes `t=0`, solves the operating point `f(x0) = 0` via `opCore_`, computes the resistive Jacobian `Jr` (from the op core) and reactive Jacobian `Jc` once, then at each swept frequency (`omega = 2 pi f`) forms

```
   (Jr + omega Jc) X = U
```

and solves it **once per independent source** listed in `sources`, with `U` set to that source's unity excitation (magnitude 1, phase 0 - `inst->scaledUnityExcitation()` at the source's excitation equations from `inst->sourceExcitation()`), all other sources silent. `ACXFCore::coroutine()`, per frequency point:

1. Zeroes and reloads only the imaginary part of `acMatrix` (`reactiveJacobianFactor = omega`) - the real part, copied from `Jr` once before the sweep starts, does not change with frequency.
2. Refactors (or, on failure, fully factors) `acMatrix`, optionally checking `rcondcheck`.
3. For each source `i` in `sources`: builds `U` from that source alone, solves for `X`, then:
   - **Transfer function** `tf[i] = X[up] - X[un]`, the response at the output node pair given by `out` (resolved once via `getDiffNodePair()`, [Analysis Core Base Class](core.md)).
   - **Input impedance/admittance**, read at the source's response unknowns (`inst->sourceResponse()`), scaled by `inst->responseScalingFactor()/inst->scaledUnityExcitation()`. A voltage source's natural response is current, giving `yin` directly (`zin = 1/yin`, guarded against a zero `yin` with `zin = 1e20`); a current source's natural response is voltage, giving `zin` directly (`yin = 1/zin` likewise guarded).
4. Writes an output point, advances the frequency sweeper.

The frequency sweep mechanics (`ScalarSweep` set up directly from `from`/`to`/`step`/`mode`/`points`/`values`) are identical to [AC Analysis](anac.md); see [Sweep Support](answeep.md) for the four supported shapes. See [Operating Point Analysis](anop.md) for how nodesets seed the initial op solve.

## Parameters

`ACXFParameters` (`coreacxf.h`), registered for introspection in `coreacxf.cpp`:

| Parameter | Type | Description |
|---|---|---|
| `out` | Value (string or 2-element string vector) | Output node, or output node pair for a differential output. |
| `from` | Real | Start frequency (step and `lin`/`dec`/`oct` sweeps). |
| `to` | Real | Stop frequency (step and `lin`/`dec`/`oct` sweeps). |
| `step` | Real | Step size for a stepped sweep. |
| `mode` | Id | `lin` (linearly spaced, `points` intervals), `dec` (points per decade), or `oct` (points per octave). |
| `points` | Int | Interval/point-per-decade/point-per-octave count for `mode`-based sweeps. |
| `values` | Value | Explicit vector or list of frequency values, instead of `from`/`to`/`step`/`mode`/`points`. |
| `write` | Int | Write the transfer-function results to a file (default 1). |
| `writeop` | Int | Exposes `opParams.write`: write the operating-point results to a separate `<name>.op` file (default 0). |
| `nodeset` | Value | Exposes `opParams.nodeset`: stored-solution slot name to read, or a list of nodesets for the op solve. |
| `store` | String | Exposes `opParams.store`: stored-solution slot name to write after the op solve. |

## Recognized Save Directives

Resolved in `SmallSignal<ACXFCore, ACXFData>::resolveSave()` (`anacxf.cpp`), using the same `tf`/`zin`/`yin` helpers as [DC Transfer Function Analysis](andcxf.md). Anything not below falls through to `resolveOpSave()` (shared operating-point saves, written to the separate `.op` output file).

| Save directive | Arguments | Description |
|---|---|---|
| `default` | none | `tf` and `zin` for every independent source in the circuit (`addAllTfZin()`); the fallback when no save directive produces any descriptor. |
| `tf` | one source instance name | Complex transfer function from that source to `out`, versus frequency. |
| `zin` | one source instance name | Complex input impedance felt at that source's terminals, versus frequency. |
| `yin` | one source instance name | Complex input admittance felt at that source's terminals, versus frequency. |

Regardless of `save` directives, `ACXFCore::addCoreOutputDescriptors()` always adds a `frequency` descriptor (unless output is suppressed).

| OP save directive (via `resolveOpSave()`) | Arguments | Description |
|---|---|---|
| `opdefault` | none | All circuit unknowns, operating-point values. |
| `opfull` | none | Every non-ground node, operating-point values. |
| `v` | one node name | Operating-point voltage at the given node. |
| `i` | one instance name | Operating-point branch current of the given instance. |
| `p` | instance name, outvar name | One instance output variable's operating-point value. |

An instance named by `tf`/`zin`/`yin` (or picked up by `default`) that is not found, or that is found but is not a source, is an error under strict resolution.

## Related Documentation

- [Small-Signal Analysis Template](ansmsig.md) - the `SmallSignal<CoreClass, DataMixin>` template this analysis instantiates.
- [Operating Point Analysis](anop.md) - the dependency core providing the DC bias point and nodeset mechanism.
- [Analysis Core Base Class](core.md) - `AnalysisCore`, the `tf`/`zin`/`yin` save-directive helpers, and the core pipeline.
- [Sweep Support](answeep.md) - `ScalarSweep`, reused here directly for the frequency axis.
- [KLU Matrix](klumatrix.md) - `KluComplexMatrix`, the complex system matrix factored at each frequency.
- [AC Analysis](anac.md) - the all-sources-at-once, all-unknowns counterpart of this analysis.
- [DC Transfer Function Analysis](andcxf.md) - the single-operating-point counterpart of this analysis (no frequency dependence).
