# Guided wave radar level transmitter

Guided wave radar (TDR) level transmitter: single rigid probe, process seal, neck and Ex d head with LCD on a flanged top connection (port process, facing down, origin on the flange face). With chamber: true it sits on an external cage with two flanged side connections (ports upper and lower), a blind bottom with drain valve and a side vent; length is then the centre-to-centre of the connections.

**Standards:** IEC 62828, IEC 60079-1, ASME B16.5, API RP 551

## Installation

```bash
npx -y https://decktwin.com/cli/deck-twin-0.2.2.tgz add guided-wave-radar
```

Copies `instruments/guided-wave-radar.tsx`, any helper files it imports and the shared `lib/` into `src/components/deck-twin/`. Needs `three`, `@react-three/fiber` and `@react-three/drei`.

## Usage

```tsx
import { Canvas } from '@react-three/fiber'
import { OrbitControls } from '@react-three/drei'
import { Stage } from './components/deck-twin/lib/stage'
import { GuidedWaveRadar } from './components/deck-twin/instruments/guided-wave-radar'

export default function Scene() {
  return (
    <Canvas shadows camera={{ position: [8, 5, 9], fov: 35 }}>
      <Stage>
        <GuidedWaveRadar length={1} />
      </Stage>
      <OrbitControls makeDefault />
    </Canvas>
  )
}
```

## Props

| Prop | Type | Default | Range |
| --- | --- | --- | --- |
| `chamber` | `boolean` | `false` |  |
| `length` | `number (m)` | `1.5` | 0.3 – 6 |
| `nps` | `number (NPS, in)` | `2` |  |
| `chamberNps` | `number (NPS, in)` | `3` |  |
| `rating` | `150 \| 300 \| 600 \| 900 \| 1500 \| 2500` | `300` |  |
| `housing` | `"actuatorBlue" \| "stainless" \| "aluminium" \| "equipmentPaintDark"` | `"actuatorBlue"` |  |
| `tag` | `string` | `"LT-1101"` |  |
| `...group` | position, rotation, scale… |  |  |

## Ports

Flange faces in the component's local frame, metres. Origin: pipe centreline, flow along X.

| Id | Label | Position | Direction | Size | Class |
| --- | --- | --- | --- | --- | --- |
| `process` | Process connection | 0.000, 0.000, 0.000 | 0, -1, 0 | 2" | 300 |

## P&ID

LT / LIT field bubble on top of an external chamber (cage) bolted to the vessel by an upper and a lower connection, with a probe line hanging down inside the chamber; or the bubble sits directly on a vessel top nozzle.

ISA LT · ISA LIT · ISA LE · ISA 5.1 (field-mounted instrument bubble)

A bridle (vertical standpipe) carrying several instruments is common: the LT, an LG (magnetic-level-gauge) and LSHH / LSLL switches all hang off it. Non-contact radar uses the same LT bubble without a probe. Interface level is LT with the service written beside it.

Level transmitter specification form (ISA-TR20.00.01) fields and the props they set:

| Field | Prop |
| --- | --- |
| External chamber | `chamber` |
| Probe length | `length` |
| Process connection size | `nps` |
| Chamber size | `chamberNps` |
| Flange rating | `rating` |
| Housing material / finish | `housing` |
| Tag number | `tag` |

## Typical suppliers

Emerson (Rosemount). The geometry is generic and sized from public standards. It is not vendor CAD.

## Source

`instruments/guided-wave-radar.tsx`. This is the component file only: it imports shared code, so install it with the command above rather than pasting it alone. https://decktwin.com/r/guided-wave-radar.json has every file.

```tsx
// Guided wave radar level transmitter: probe, process seal and Ex d head on a flanged top connection, optionally in an external cage with side connections. IEC 62828, ASME B16.5.
import { Kit, type MatKey, type V3 } from '../lib/kit'
import { KitMesh, useKit, type GroupProps } from '../lib/mesh'
import { port, type Port } from '../lib/ports'
import { GASKET_SPIRAL_WOUND, flange as flangeDims, type Rating } from '../lib/standards'
import { SS, chamber, exHead, tag as tagPlate, valveHandle, segFor } from './_parts'

export interface GuidedWaveRadarProps {
  /** external cage with two side process connections */
  chamber?: boolean
  /** probe length (direct mount) or centre-to-centre of the side connections (chamber), m */
  length?: number
  /** process connection size (direct-mount flange or cage side connections), inches */
  nps?: number
  /** cage pipe size, inches */
  chamberNps?: number
  rating?: Rating
  housing?: MatKey
  tag?: string
}

export const defaults = { chamber: false, length: 1.5, nps: 2, chamberNps: 3, rating: 300 as Rating, housing: 'actuatorBlue' as MatKey, tag: 'LT-1101' }

type P = typeof defaults

const STANDOUT = 0.25 // typical side-connection face distance from the cage axis

export function ports(props: GuidedWaveRadarProps = {}): Port[] {
  const p = { ...defaults, ...props }
  if (!p.chamber) return [port('process', 'Process connection', [0, 0, 0], [0, -1, 0], p.nps, p.rating)]
  return [
    port('upper', 'Upper connection', [-STANDOUT, p.length / 2, 0], [-1, 0, 0], p.nps, p.rating),
    port('lower', 'Lower connection', [-STANDOUT, -p.length / 2, 0], [-1, 0, 0], p.nps, p.rating),
  ]
}

export function GuidedWaveRadar(props: GuidedWaveRadarProps & GroupProps) {
  const { chamber: cage, length, nps, chamberNps, rating, housing, tag, ...group } = { ...defaults, ...props }
  const p = { chamber: cage, length, nps, chamberNps, rating, housing, tag }
  const data = useKit((k) => build(k, p), Object.values(p))
  return (
    <group {...group}>
      <KitMesh data={data} />
    </group>
  )
}

export default GuidedWaveRadar

/** Instrument flange (RF facing -Y at y0) with process seal, neck and head above. */
function head(k: Kit, y0: number, nps: number, rating: Rating, housing: MatKey, tag: string) {
  const f = flangeDims(nps, rating)
  const rf = f.raisedFaceHeight
  const t = f.thickness
  k.lathe('machined', [[0.004, y0], [f.raisedFace / 2, y0], [f.raisedFace / 2, y0 + rf]], [0, 0, 0], 'y', segFor(f.od))
  k.lathe('flangeSteel', [[f.raisedFace / 2, y0 + rf], [f.od / 2, y0 + rf], [f.od / 2, y0 + rf + t], [0.02, y0 + rf + t]], [0, 0, 0], 'y', segFor(f.od))
  let y = y0 + rf + t
  k.cyl(SS, 0.028, 0.012, [0, y + 0.006, 0], 'y', 20)
  k.hex(SS, 0.062, 0.03, [0, y + 0.027, 0])
  k.cyl(SS, 0.022, 0.07, [0, y + 0.077, 0], 'y', 16)
  k.hex(SS, 0.046, 0.016, [0, y + 0.12, 0])
  y += 0.128
  const c: V3 = [0, y + 0.011 + 0.048 - 0.004, 0]
  exHead(k, c, housing, { r: 0.054 })
  tagPlate(k, tag, [0, y + 0.03, 0.0225], 'z', 0.06)
}

function build(k: Kit, p: P) {
  const g = GASKET_SPIRAL_WOUND
  if (!p.chamber) {
    head(k, 0, p.nps, p.rating, p.housing, p.tag)
    // single rigid lead with centring disc and end weight
    k.cyl(SS, 0.012, 0.03, [0, -0.015, 0], 'y', 16)
    k.cyl(SS, 0.004, p.length - 0.03, [0, -0.03 - (p.length - 0.03) / 2, 0], 'y', 12)
    k.cyl(SS, 0.011, 0.05, [0, -p.length + 0.025, 0], 'y', 16)
    return
  }
  const c = chamber(k, { cc: p.length, chamberNps: p.chamberNps, connNps: p.nps, rating: p.rating, standout: STANDOUT, top: 'gwr', mat: 'pipePaint' })
  const f = flangeDims(p.chamberNps, p.rating)
  head(k, c.yTop + g, p.chamberNps, p.rating, p.housing, p.tag)
  k.cyl('gasket', f.raisedFace / 2 + 0.006, g, [0, c.yTop + g / 2, 0], 'y', segFor(f.raisedFace))
  const span = 2 * (f.thickness + f.raisedFaceHeight) + g
  const studL = span + f.boltDia * 2.6
  const y0 = c.yTop + g / 2 - studL / 2
  k.boltCircle('boltXylan', 'nut', f.bolts, f.boltCircle / 2, [0, y0, 0], 'y', f.boltDia, studL, [f.boltDia * 0.8, studL - f.boltDia * 0.8])
  // vent on the cage side below the top flange
  const yv = c.yTop - f.hubLength - f.raisedFaceHeight - 0.07
  k.cyl(SS, 0.0107, 0.05, [c.D / 2 + 0.022, yv, 0], 'x', 12)
  k.box(SS, [0.04, 0.034, 0.034], [c.D / 2 + 0.065, yv, 0])
  valveHandle(k, [c.D / 2 + 0.065, yv, 0.017], [0, 0, 1], 'actuatorRed', 0.9)
  k.cyl(SS, 0.0107, 0.026, [c.D / 2 + 0.098, yv, 0], 'x', 12)
  k.hex(SS, 0.026, 0.014, [c.D / 2 + 0.115, yv, 0], 'x')
}
```
