# NI analog write task

> Write command channel values to the analog outputs of an NI device.

An NI analog write task writes the values of command channels to the analog outputs of one NI device. For example, a setpoint on a schematic can drive a proportional valve from `ao0` of a USB-6343.

Each output has a command channel and a [state channel](https://docs.synnaxlabs.com/reference/hardware/tasks#write-tasks). Each command writes the last value of every output of the task in one call. A [function generator](https://docs.synnaxlabs.com/reference/hardware/ni/analog-write-task#ao_func_gen) is different: it has no command or state channel, and it runs while the task runs.

Before you start, you need a [configured device](https://docs.synnaxlabs.com/reference/hardware/ni/configure-device).

The Console gives the analog write tasks of a device one state index channel, and only one writer can hold an index channel. So only one of these tasks can run on a device at a time, even when the tasks use different ports. A second task stops right after it starts, with an error that names the running task. Tasks from a client library have this limit only when they share an index channel.

## Create an NI analog write task

[Enterprise](https://docs.synnaxlabs.com/reference/get-started/editions "Needs Synnax Enterprise")

**Console**

1. In the devices toolbar, right-click the device and select **Create analog write task**.
2. Set **State update rate**.
3. Click **Add channel**. In **Source**, select the **Port**.
4. In **Signal**, select the **Channel type**, then set its fields. See the [channel reference](https://docs.synnaxlabs.com/reference/hardware/ni/analog-write-task#channel-reference).
5. Click (**Start**).

The Console creates the channels. For a device with the identifier `dev1`, port 0 gives the command channel `dev1_ao_0_cmd` with the index `dev1_ao_0_cmd_time`, and the state channel `dev1_ao_0_state` with the index `dev1_ao_state_time`. The Console creates no channels for a function generator.

[](https://synnax.nyc3.cdn.digitaloceanspaces.com/docs/hardware/ni/analog-write-task/9387bfacd66d-dark.mp4#t=0.001)

**Python**

Python does not create channels. Create them first.

```python
import synnax as sy
from synnax import ni

dev = client.devices.retrieve(key="<device key>")
state_time = client.channels.create(
    name="dev1_ao_state_time", is_index=True, data_type=sy.DataType.TIMESTAMP
)
state = client.channels.create(
    name="valve_setpoint_state",
    index=state_time.key,
    data_type=sy.DataType.FLOAT32,
)
cmd_time = client.channels.create(
    name="valve_setpoint_cmd_time", is_index=True, data_type=sy.DataType.TIMESTAMP
)
cmd = client.channels.create(
    name="valve_setpoint_cmd", index=cmd_time.key, data_type=sy.DataType.FLOAT32
)

task = ni.AnalogWriteTask(
    name="Valve setpoint",
    device=dev.key,
    channels=[
        ni.AOVoltageChannel(
            port=0,
            min_val=0,
            max_val=10,
            cmd_channel=cmd.key,
            state_channel=state.key,
        )
    ],
)
client.tasks.configure(task)
task.start()
```

Python creates the task on the embedded Driver of the Core. For a device on another Driver, use the Console or TypeScript.

**TypeScript**

TypeScript does not create channels. Create them first, as in the Python example.

```typescript
import { ni } from "@synnaxlabs/client";

const dev = await client.devices.retrieve({ key: "<device key>" });
const task = await client.tasks.create({
  name: "Valve setpoint",
  rack: dev.rack,
  type: "ni_analog_write",
  config: ni.analogWriteConfigZ.parse({
    device: dev.key,
    channels: [
      {
        type: "ao_voltage",
        port: 0,
        minVal: 0,
        maxVal: 10,
        cmdChannel: cmd.key,
        stateChannel: state.key,
      },
    ],
  }),
});
await task.start();
```

## Task options

| Console label     | Python field           | Default | Notes                                                                                |
| ----------------- | ---------------------- | ------- | ------------------------------------------------------------------------------------ |
| Device            | `device`               |         | The key of the device.                                                               |
| State update rate | `state_rate`           | 10 Hz   | Up to 50,000 Hz in the Console.                                                      |
| Data saving       | `data_saving_disabled` | On      | See [data saving](https://docs.synnaxlabs.com/reference/hardware/tasks#data-saving). |
| Auto start        | `auto_start`           | Off     | Starts the task each time the Driver starts.                                         |

## Channel reference

Every channel has a `port` (**Port**), a `cmd_channel`, and a `state_channel`.

Each table shows the Console label of a setting, with its Python field under it. Voltage and current channels also have **Custom scaling**.

**Voltage**

#### [Voltage](https://docs.synnaxlabs.com/reference/hardware/ni/analog-write-task#ao_voltage)

Python `AOVoltageChannel`TypeScript `ao_voltage`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__analog__output__channel_1gad278075876eeff4223fdb90ce58f0a15.html)

Outputs a voltage.

| Setting                    | Default    | Notes     |
| -------------------------- | ---------- | --------- |
| Range `min_val`, `max_val` | `0` to `1` | In volts. |

**Current**

#### [Current](https://docs.synnaxlabs.com/reference/hardware/ni/analog-write-task#ao_current)

Python `AOCurrentChannel`TypeScript `ao_current`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__analog__output__channel_1ga1ae6afadb89de214c4823ca7144ab28d.html)

Outputs a current.

| Setting                    | Default    | Notes    |
| -------------------------- | ---------- | -------- |
| Range `min_val`, `max_val` | `0` to `1` | In amps. |

**Function generator**

#### [Function generator](https://docs.synnaxlabs.com/reference/hardware/ni/analog-write-task#ao_func_gen)

Python `AOFuncGenChannel`TypeScript `ao_func_gen`[NI-DAQmx](https://www.ni.com/docs/en-US/bundle/ni-daqmx-c-api-ref/page/group__ni-daqmx__c__functions__channel__configuration__creation__create__analog__output__channel_1ga7146d8ebdf2336e5200c4d2549f67494.html)

Generates a waveform on the output from the task start to the task stop. To change the waveform, stop the task, change the settings, then start it again. This channel has no command or state channel.

Few NI devices support this channel type. On other devices, NI-DAQmx rejects the channel when the task starts. NI-DAQmx can also reject a task that has this channel type and other channel types. If it does, use a task for each type.

| Setting               | Default | Notes                                     |
| --------------------- | ------- | ----------------------------------------- |
| Wave `wave_type`      | `Sine`  | `Sine`, `Triangle`, `Square`, `Sawtooth`. |
| Frequency `frequency` | `0`     | In hertz.                                 |
| Amplitude `amplitude` | `0`     | From zero to peak, in volts.              |
| Offset `offset`       | `0`     | In volts.                                 |

### Custom scaling

Channels with **Custom scaling** convert the raw value before the Driver writes it. In the Console, the options are in the **Scale** section of the channel. In code, set `custom_scale` to one of these scales:

| Console option | Python class      | Fields                                                                                                                         |
| -------------- | ----------------- | ------------------------------------------------------------------------------------------------------------------------------ |
| None           | `NoneScale`       | No scaling. This is the default.                                                                                               |
| Linear         | `LinearScale`     | **Slope** (`slope`, 1) and **Y-intercept** (`y_intercept`, 0).                                                                 |
| Map            | `MapScale`        | **Pre-scaled min** and **max** to **Scaled min** and **max** (`pre_scaled_min`, `pre_scaled_max`, `scaled_min`, `scaled_max`). |
| Polynomial     | `PolynomialScale` | **Forward coefficients** (`forward_coeffs`) and **Reverse coefficients** (`reverse_coeffs`), from c0 up.                       |
| Table          | `TableScale`      | **Pre-scaled** and **Scaled** pairs (`pre_scaled_vals`, `scaled_vals`). A CSV file can fill them.                              |

Every scale except **None** also has **Prescaled units** (`pre_scaled_units`, `Volts`) and **Scaled units** (`scaled_units`).

## Troubleshooting

* [The outputs stop changing after a command.](https://docs.synnaxlabs.com/reference/hardware/ni/analog-write-task#the-outputs-stop-changing-after-a-command)

  * Cause

    A command was outside the **Range** of its channel. NI-DAQmx rejects it with no message, and because each command writes every output, all later commands fail too. The state channels still show the commands that were not written.

  * Fix

    Send a value inside the range to that channel. The task then writes again.

* [Port ... has already been used on another channel](https://docs.synnaxlabs.com/reference/hardware/ni/analog-write-task#port-has-already-been-used-on-another-channel)

  * Cause

    Two channels use the same port.

  * Fix

    Change the port of one of them.

* [... has no control authority - it is currently held by ...](https://docs.synnaxlabs.com/reference/hardware/ni/analog-write-task#has-no-control-authority-it-is-currently-held-by)

  * Cause

    Another running task writes to the same index channel. The error names that task.

  * Fix

    Stop the other task, or move its channels into this task.

For other problems, see [Configure an NI device](https://docs.synnaxlabs.com/reference/hardware/ni/configure-device#troubleshooting) and [Troubleshoot hardware](https://docs.synnaxlabs.com/reference/hardware/troubleshooting).
