Spectrometers are chemistry instruments. They understand samples, experiments, wavenumber ranges, and resolution parameters. They do not understand patients, medical record numbers, clinical workflows, or HL7 messages.
This is a problem if you want to deploy a spectroscopy-based diagnostic test in a clinical setting.
Bruker's OPUS knows how to acquire an FTIR spectrum. Horiba's LabSpec knows how to collect a Raman measurement. Thermo's OMNIC knows how to run an NIR scan. None of them know how to associate that measurement with a patient, route a classification result to an EMR, or generate a billable event. A clinician cannot sit down in front of OPUS and run a diagnostic test. The interface was designed for spectroscopists, not nurses.
Someone has to build the bridge between the instrument and the clinical workflow. This article describes the architecture of that bridge - the design decisions, component layers, and integration patterns we use at SpectraDx to turn lab-grade spectrometers into deployable clinical diagnostic devices.
The fundamental mismatch
Consider what happens when a research group develops a spectroscopy-based diagnostic test and wants to deploy it clinically. They have an instrument, a trained ML model, and clinical validation data. What they do not have is any way to actually run the test in a clinic.
What the clinician needs to do:
- Identify the patient (scan MRN barcode or enter manually)
- Prepare the sample and place it on the instrument
- Press a single button to run the test
- See a clear result: positive, negative, or indeterminate
- Have that result flow into the patient's medical record
- Have the test logged for billing
What OPUS requires them to do:
- Open OPUS (not a clinical application - a spectroscopy workbench)
- Load the correct measurement parameters (experiment file)
- Click "Measure" and wait for acquisition
- Open the spectral library search tool
- Interpret library search results (hit quality index, compound matches)
- Manually enter the result somewhere
- Manually associate the result with a patient somehow
- Manually notify the ordering physician somehow
These are completely different workflows. The first one takes 90 seconds and requires no spectroscopy knowledge. The second takes 5-10 minutes and requires training on instrument software that was never designed for clinical staff.
Every spectroscopy vendor - Bruker, Horiba, Renishaw, Thermo Fisher, Agilent - has this same problem. Their software is built for scientists, not clinicians. And none of them are building the clinical workflow layer. That is the gap.
Architecture overview
The clinical workflow platform sits between the clinician and the spectrometer, abstracting away everything the clinician should not need to think about. Here is the component stack:
Clinician UI (React web app)
│
▼
Application Server (Python / FastAPI)
│
├──► Instrument Service ──► OPUS / LabSpec / OMNIC / Spectrometer
│
├──► ML Classification Engine
│
├──► Results Engine ──► HL7v2 / FHIR ──► LIS / EHR
│
└──► Central Platform (cloud DB, billing, analytics)
Each layer has a specific responsibility and a clean interface to the layers above and below it. Let me walk through each one.
Layer 1: The clinician interface
The UI is a React web application that runs in a browser on the instrument PC or a nearby tablet. It is designed for one thing: running diagnostic tests. Not spectroscopy. Not data analysis. Diagnostic tests.
The interface has exactly three screens that matter:
The test initiation screen. The clinician enters or scans a patient MRN. The system validates the MRN against the facility's patient index (if connected) or accepts it as a free-text identifier. The clinician selects the test type (if the site runs more than one), confirms sample placement, and presses "Run Test." One button. No parameters to configure, no experiment files to load, no measurement settings to adjust.
The results screen. After acquisition and classification, the result appears in unambiguous clinical language: "Positive," "Negative," or "Indeterminate." Not "Hit Quality Index: 847" or "Library Match: Streptococcus pyogenes (92.3%)." Those details are available in an expandable section for supervisory review, but the primary display is the clinical interpretation.
Confidence scoring deserves careful thought. An ML model outputs a probability. Displaying "87.3% confidence" to a clinician is actively unhelpful - what are they supposed to do with that number? Instead, the UI maps confidence into actionable categories:
- High confidence (above threshold A): Result displayed normally. No additional action required.
- Moderate confidence (between threshold A and B): Result displayed with a review flag. Supervisor review recommended before release.
- Low confidence (below threshold B): Result displayed as "Indeterminate." Repeat test or defer to reference method.
The thresholds are configured per assay based on clinical validation data. They are not user-adjustable - changing them would alter the test's clinical performance characteristics, which is a regulatory concern.
The worklist screen. A table of recent and pending tests. Status indicators: queued, in progress, complete, released to LIS, review required. Sortable and filterable. This screen is where supervisors spend most of their time.
UX principles for clinical software
A few hard-learned principles that apply specifically to clinical instrument software:
No spectroscopy jargon in the primary interface. No "wavenumber," no "absorbance," no "interferogram." The spectral details exist in the system for troubleshooting and QC review, but they are not in the clinician's face.
Error states must be actionable. "Instrument Error 0x4A2F" is useless. "Sample may not be in contact with the crystal - please clean the ATR surface and re-seat the sample" tells the operator what to do.
Offline resilience. The instrument PC may lose network connectivity. The UI must continue to function for test acquisition and result display. Results queue for LIS transmission when connectivity returns.
Session management. Clinical environments have shared workstations. Every action is attributed to the logged-in operator for audit trail purposes. Session timeouts comply with facility security policies.
Layer 2: Instrument abstraction
This is the layer that makes the architecture instrument-agnostic. The application server communicates with the spectrometer through an abstraction layer - a pluggable adapter interface that hides vendor-specific protocols behind a uniform API.
Why is this necessary? Because every instrument vendor does things differently:
Bruker OPUS communicates via DDE (Dynamic Data Exchange) on Windows - a messaging protocol from the 1980s that is still the primary programmatic interface. You send string commands like MeasureSample and parse string responses. The brukeropus Python library wraps some of this, but the DDE layer is fundamentally synchronous and fragile. OPUS must be running as a visible Windows application.
Horiba LabSpec provides a proprietary SDK for instrument control. The API surface is different from Bruker's. Acquisition parameters are specified differently. Status reporting works differently.
Renishaw WiRE has its own automation interface. Yet another protocol, yet another set of conventions.
Thermo OMNIC can be controlled through COM automation or file-based workflows. Different again.
Generic instruments (especially handheld devices) may simply write spectral files to a directory. No API at all - you watch a folder for new files.
The adapter interface normalizes all of this into a small set of operations:
class InstrumentAdapter:
"""Abstract interface for spectrometer control."""
async def connect(self) -> ConnectionStatus:
"""Establish connection to instrument."""
...
async def get_status(self) -> InstrumentStatus:
"""Get current instrument state (idle, busy, error)."""
...
async def configure(self, method: MeasurementMethod) -> None:
"""Load measurement parameters."""
...
async def acquire(self) -> AcquisitionResult:
"""Trigger measurement and return raw spectral data."""
...
async def disconnect(self) -> None:
"""Release instrument connection."""
...Each vendor gets a concrete implementation of this interface. The BrukerOpusAdapter handles DDE commands, OPUS process management, and .0 file parsing. The HoribaAdapter handles the LabSpec SDK. The FileWatcherAdapter monitors a directory for new spectral files from instruments that do not offer programmatic control.
The application server never talks to the instrument directly. It talks to the adapter. When a customer switches from a Bruker Alpha II to a Thermo Nicolet, you swap the adapter plugin. The rest of the stack - UI, ML pipeline, results engine, billing - does not change.
The DDE problem (Bruker-specific)
Bruker's reliance on DDE deserves special attention because it creates architectural constraints that ripple through the entire system.
DDE is a Windows IPC mechanism. It requires both the client (your application) and the server (OPUS) to be running Windows GUI processes. DDE does not work over a network. It does not work from a Linux container. It does not work from a headless process reliably.
This means the application server for a Bruker-based deployment must run on the same Windows PC that runs OPUS. You cannot containerize it. You cannot run it on a separate server. The instrument PC is the application server.
This is a hard constraint that shapes the entire deployment architecture. For Bruker sites, the local instrument PC runs FastAPI as a Windows service alongside OPUS. The React frontend is served as static files from the same machine or pulled from a CDN. For a deep dive into Bruker's programmatic interfaces, see our complete guide to OPUS integration. For automating FTIR workflows beyond OPUS, see our guide to automating FTIR with Python.
For vendors with network-capable APIs, you have more flexibility - the application server can run on a separate machine. But the architecture must handle both cases.
Layer 3: ML classification pipeline
Raw spectrum in, clinical classification out. This layer is conceptually simple and practically complex.
The pipeline has four stages:
Preprocessing. The raw spectrum needs cleaning before classification. The typical preprocessing steps include:
- Baseline correction (rubber band, asymmetric least squares, polynomial fitting)
- Normalization (min-max, SNV, area normalization)
- Spectral range selection (e.g., 4000-400 cm-1 for FTIR microbial ID)
- Savitzky-Golay smoothing to reduce high-frequency noise
- Derivative computation (optional) for resolving overlapping peaks
The specific preprocessing steps and parameters are defined per assay during method development and locked down in production - changing them changes the test's analytical performance.
Feature extraction. Depending on the classification approach, the preprocessed spectrum may be used directly (full-spectrum methods) or reduced to a feature vector. Principal Component Analysis (PCA) is common for dimensionality reduction. Some methods use specific peak ratios or band areas as features.
Model inference. The classification model runs against the features and outputs a prediction with a confidence score. Common model types in spectroscopy diagnostics:
- Spectral library search (e.g., OPUS library search) - correlation-based matching against a reference library. Not technically ML, but widely used and well-understood by regulatory bodies.
- Support Vector Machines (SVM) - effective for binary and multi-class classification of spectral data, especially with moderate training set sizes.
- Random Forests - robust to overfitting, interpretable feature importance.
- Convolutional Neural Networks (CNN) - 1D CNNs operating on spectral data. Higher accuracy potential but require larger training sets and are harder to validate for regulatory purposes.
Result interpretation. The model output (class label + probability) is mapped to a clinical result using the threshold scheme described in Layer 1. This mapping is configured per assay and is part of the validated method.
Where the model runs matters
This is critically important and is the subject of its own article: SaMD classification for diagnostic spectroscopy.
The short version: if the ML model runs inside the instrument vendor's software (e.g., OPUS's built-in library search), your workflow software is displaying a result from a cleared device. It is probably not Software as a Medical Device (SaMD).
If the ML model runs in your software - your own Python code executing a trained SVM or CNN - then your software is making the clinical interpretation. It is almost certainly SaMD, which triggers FDA regulatory requirements including IEC 62304, design controls, and potentially a De Novo submission.
This distinction drives architectural decisions. If you can use the instrument's built-in classification, do it. If you need custom ML (and there are good reasons you might), budget for the regulatory path.
Layer 4: Results and integration
The classification result needs to flow into the hospital's information systems. This means generating structured messages that the Laboratory Information System (LIS) and Electronic Health Record (EHR) can consume.
HL7v2 ORU^R01
Most hospital LIS systems speak HL7v2. The specific message type for lab results is ORU^R01 (Observation Result / Unsolicited). We have a detailed guide to generating ORU^R01 messages from spectral classification results, but here is the architectural view.
An ORU^R01 message for a spectroscopy result maps like this:
MSH - Message header (sending app, receiving app, timestamp, message type)
PID - Patient identification (MRN, name, DOB)
PV1 - Patient visit (encounter context)
OBR - Observation request (test order details, specimen info)
OBX - Observation result (the actual classification result)
OBX-2: Observation value type (CE = coded entry)
OBX-3: Observation identifier (LOINC code for the test)
OBX-5: Observation value (the result - positive/negative/indeterminate)
OBX-8: Abnormal flags
OBX-11: Observation result status (F = final, P = preliminary)
The challenge is mapping spectroscopy-specific concepts into HL7's vocabulary. HL7 was designed for blood chemistry, hematology, and microbiology culture results - not spectral classifications. Our HL7v2 spectroscopy integration guide covers the complete ORU^R01 message mapping, and our FHIR R4 spectroscopy integration guide covers the modern RESTful approach. LOINC codes may not exist for novel spectroscopy-based tests. You may need to request new codes or use local codes initially.
The message is transmitted to the LIS via TCP/MLLP (Minimum Lower Layer Protocol), which is the standard transport for HL7v2 in healthcare. The LIS parses the message, files the result in the patient's record, and makes it available to clinicians in the EHR.
FHIR DiagnosticReport
For newer systems supporting FHIR, results can be represented as a DiagnosticReport resource containing Observation resources. FHIR adoption in clinical labs is still early - most production deployments use HL7v2 as the primary integration path and FHIR as a secondary output.
Integration architecture
The results engine maintains an outbound message queue. Completed tests are queued for transmission with exponential backoff on failures. This queue-based approach is essential - LIS systems go down, networks drop, and the instrument PC may process results faster than the LIS can accept them. The queue decouples test processing from result delivery and ensures no results are lost.
Layer 5: Compliance and audit
In a clinical environment - and especially in an FDA-regulated environment - the software must maintain a complete, tamper-evident audit trail of every action.
21 CFR Part 11
The FDA's regulation on electronic records and electronic signatures applies to any software used in a regulated clinical or pharmaceutical environment. The key requirements:
Audit trail. Every create, modify, and delete action on a record must be logged with: who did it, when, what the previous value was, and what the new value is. The audit trail itself must be tamper-evident - records can be appended but never modified or deleted.
Electronic signatures. When a result is released, the releasing operator's identity must be verified. This can be a username/password combination (21 CFR Part 11 does not require biometrics). The signature is cryptographically bound to the record it applies to.
Access controls. Role-based access control with separate permissions for operators, supervisors, and administrators. Operators can run tests. Supervisors can release results and review QC data. Administrators can configure the system but not alter test results.
System validation. The software must be validated per GAMP 5 guidelines - IQ, OQ, PQ with documented test protocols and pass/fail criteria.
Operator qualification tracking
The platform tracks which operators are qualified to run which tests. An unqualified operator can log in but cannot initiate a test they have not been trained on. Regulatory inspections will ask to see these records. If they are in a spreadsheet on someone's desktop, you have a finding. If they are in the platform with timestamps and supervisor signatures, you do not.
Data integrity
Spectral data is immutable after acquisition. The raw spectrum, as acquired from the instrument, is stored in its original format and is never modified. Preprocessing creates derived data - the original is always preserved. Classification results reference both the raw spectrum and the preprocessed version that was actually classified.
This chain of custody - raw spectrum to preprocessed spectrum to classification result to clinical result to HL7 message - must be traceable for any individual test. An auditor should be able to pick any result and walk backward through every step to the original acquisition.
Why Python and FastAPI
The technology choice is driven by practical constraints, not preference.
The instrument libraries are Python. brukeropus for OPUS files, NumPy/SciPy for spectral preprocessing, scikit-learn/PyTorch for model inference - the entire spectroscopy computing stack is Python. And Bruker's DDE protocol requires Windows, so the pywin32 library provides DDE client functionality. The application server must run on Windows for Bruker deployments.
FastAPI serves dual duty: it serves the React frontend as static files and exposes REST API endpoints from the same process. The instrument PC runs FastAPI as a Windows service alongside OPUS. The clinician opens a browser to http://localhost:8000 and gets the full application. No Docker, no Nginx, one process. FastAPI's async support keeps the server responsive during 15-60 second spectral acquisitions.
Why not Electron? We considered it and rejected it. It adds a 150MB+ runtime, complicates updates, and creates a second application for clinical IT to manage. A browser tab pointed at localhost is simpler and easier to update.
Multi-site architecture
A single-site deployment is straightforward - everything runs on the instrument PC. Multi-site is where the architecture gets interesting.
A diagnostic company with pilot deployments at 3-5 clinical sites needs centralized visibility, method deployment, and aggregated billing. The architecture:
Site A: Instrument PC Site B: Instrument PC
├── FastAPI + React ├── FastAPI + React
├── Bruker Alpha II (DDE) ├── Horiba LabRAM (SDK)
├── Local SQLite DB ├── Local SQLite DB
└── Sync agent ─────────┐ ┌────── Sync agent
│ │
▼ ▼
Central Platform (Cloud)
├── PostgreSQL
├── Method repository
├── Analytics dashboard
├── Billing aggregation
└── Admin portal
Each site runs independently. The local SQLite database stores all test data, results, and audit trail entries. If the internet connection drops, the site continues to function. The sync agent runs in the background, uploading completed test records to the central platform when connectivity is available.
Method deployment works in the opposite direction. When an administrator publishes a new method version (updated model, revised preprocessing, new confidence thresholds), the sync agent pulls it down to each site. Method updates require supervisor acknowledgment at each site before activation - you do not silently change the behavior of a clinical test.
The central platform provides:
- Analytics - test volumes, instrument uptime, QC trends
- Method management - version-controlled methods with deployment tracking and rollback
- Billing aggregation across all sites
- Centralized user management
Notice that the architecture is heterogeneous by design. Site A runs a Bruker with the DDE adapter. Site B runs a Horiba with the SDK adapter. The central platform does not care - it receives standardized test records from both. This is the practical benefit of the instrument abstraction layer. For modality-specific integration guidance, see our articles on Raman clinical integration and NIR instrument integration.
What we learned
Building clinical workflow software for spectrometers is not a traditional software engineering problem. It is an integration problem with regulatory constraints, hardware dependencies, and users who are not technologists.
The hardest parts are not the ones you would expect:
Instrument communication is harder than ML inference. Getting a trained model to classify a spectrum takes an afternoon. Getting reliable, production-grade communication with a Bruker spectrometer via DDE takes weeks of debugging edge cases - OPUS process crashes, DDE timeouts, file locking conflicts, Windows service session isolation. The instrument adapter is the highest-maintenance component in the stack.
HL7 integration is negotiation, not engineering. Generating a syntactically correct HL7 message is easy. Getting it accepted by a specific hospital's LIS is hard - every LIS has custom field mappings, local code tables, and vendor-specific quirks. Budget 2-4 weeks per site for LIS integration.
Regulatory compliance is not a feature you add later. Audit trails, electronic signatures, access controls, and data integrity must be architectural decisions, not afterthoughts. If you build the system without them and try to add them later, you are effectively rebuilding the system.
Clinicians will find every edge case. "What happens if I scan a patient, start the test, then realize I scanned the wrong patient?" "What happens if the instrument errors mid-acquisition?" "What happens if two people try to run a test at the same time?" Every one of these scenarios needs a defined behavior, an error message, and an audit trail entry.
This is what SpectraDx does
The architecture described in this article is not theoretical. It is the SpectraDx platform - the clinical workflow layer between the spectrometer and the clinician, built to work across FTIR, Raman, and NIR instruments from multiple vendors.
If you are developing a spectroscopy-based diagnostic test and need clinical workflow software - instrument control, clinician UI, ML integration, HL7/FHIR output, billing, compliance - see our solutions overview for the full platform picture.

