or run

npx @tessl/cli init
Log in

Version

Tile

Overview

Evals

Files

Files

docs

format-conversion.mdindex.mdio-operations.mdplotting.mdsignal-processing.md

format-conversion.mddocs/

0

# Format Conversion

1

2

Utilities for converting between WFDB and other common biomedical data formats including EDF, MATLAB, CSV, WAV, and TFF. This module enables interoperability with various data acquisition systems and analysis tools used in biomedical research.

3

4

## Capabilities

5

6

### EDF Conversion

7

8

Convert between WFDB and European Data Format (EDF/EDF+) files commonly used in sleep studies and clinical neurophysiology.

9

10

```python { .api }

11

def read_edf(file_name: str, pn_dir: str = None, rd_time: bool = True,

12

digital: bool = False, header_only: bool = False,

13

verbose: bool = False) -> Record:

14

"""

15

Read EDF/EDF+ files and convert to WFDB Record format.

16

17

Parameters:

18

- file_name: str, EDF file name or path

19

- pn_dir: str, directory containing the file

20

- rd_time: bool, read time information from EDF+

21

- digital: bool, return digital values instead of physical

22

- header_only: bool, read header information only

23

- verbose: bool, print detailed file information

24

25

Returns:

26

Record object containing the EDF data

27

"""

28

29

def wfdb_to_edf(record_name: str, pn_dir: str = None, sampfrom: int = 0,

30

sampto: Union[int, str] = 'end', channels: List[int] = None,

31

write_dir: str = '', edf_file: str = None,

32

file_type: str = 'EDF', digital: bool = False,

33

header_only: bool = False) -> None:

34

"""

35

Convert WFDB record to EDF format.

36

37

Parameters:

38

- record_name: str, WFDB record name

39

- pn_dir: str, directory containing WFDB files

40

- sampfrom: int, starting sample for conversion

41

- sampto: int or 'end', ending sample for conversion

42

- channels: list of int, specific channels to convert

43

- write_dir: str, output directory for EDF file

44

- edf_file: str, output EDF file name

45

- file_type: str, 'EDF' or 'EDF+' format

46

- digital: bool, write digital values instead of physical

47

- header_only: bool, write header only

48

"""

49

50

def rdedfann(edf_file: str, ann_file: str = None, ann_ext: str = 'atr',

51

pn_dir: str = None, encoding: str = 'latin-1') -> Annotation:

52

"""

53

Read EDF+ annotations and convert to WFDB Annotation format.

54

55

Parameters:

56

- edf_file: str, EDF+ file containing annotations

57

- ann_file: str, optional separate annotation file

58

- ann_ext: str, annotation file extension

59

- pn_dir: str, directory containing files

60

- encoding: str, text encoding for annotation strings

61

62

Returns:

63

Annotation object containing the EDF+ annotations

64

"""

65

```

66

67

### MATLAB Conversion

68

69

Convert WFDB records to MATLAB format for analysis in MATLAB/Octave environments.

70

71

```python { .api }

72

def wfdb_to_mat(record_name: str, pn_dir: str = None, sampfrom: int = 0,

73

sampto: Union[int, str] = 'end', channels: List[int] = None,

74

write_dir: str = '') -> None:

75

"""

76

Convert WFDB record to MATLAB (.mat) format.

77

78

Parameters:

79

- record_name: str, WFDB record name

80

- pn_dir: str, directory containing WFDB files

81

- sampfrom: int, starting sample for conversion

82

- sampto: int or 'end', ending sample for conversion

83

- channels: list of int, specific channels to convert

84

- write_dir: str, output directory for MAT file

85

86

The output .mat file contains:

87

- val: signal values matrix (samples x channels)

88

- tm: time vector

89

- Fs: sampling frequency

90

- units: cell array of signal units

91

- signame: cell array of signal names

92

"""

93

```

94

95

### CSV Conversion

96

97

Convert between WFDB format and comma-separated values (CSV) files for spreadsheet analysis.

98

99

```python { .api }

100

def csv_to_wfdb(file_name: str, fs: float, units: List[str], sig_name: List[str],

101

record_name: str = None, start_time: str = None,

102

use_checksum: bool = True, write_dir: str = '') -> None:

103

"""

104

Convert CSV file to WFDB format.

105

106

Parameters:

107

- file_name: str, input CSV file name

108

- fs: float, sampling frequency in Hz

109

- units: list of str, signal units for each column

110

- sig_name: list of str, signal names for each column

111

- record_name: str, output record name (default: CSV filename stem)

112

- start_time: str, record start time in HH:MM:SS format

113

- use_checksum: bool, calculate and store file checksums

114

- write_dir: str, output directory for WFDB files

115

116

CSV format requirements:

117

- First row: optional column headers

118

- Subsequent rows: numeric signal values (one sample per row)

119

"""

120

121

def csv2ann(file_name: str, fs: float, record_name: str) -> None:

122

"""

123

Convert CSV annotation file to WFDB annotation format.

124

125

Parameters:

126

- file_name: str, input CSV annotation file name

127

- fs: float, sampling frequency for time conversion

128

- record_name: str, associated record name for annotations

129

130

CSV annotation format:

131

- Column 1: time in seconds or sample numbers

132

- Column 2: annotation symbols

133

- Column 3: (optional) auxiliary notes

134

"""

135

```

136

137

### WAV Conversion

138

139

Convert between WFDB and WAV audio formats for acoustic physiological signals.

140

141

```python { .api }

142

def wfdb_to_wav(record_name: str, pn_dir: str = None, sampfrom: int = 0,

143

sampto: Union[int, str] = 'end', channels: List[int] = None,

144

write_dir: str = '', write_frequency: int = 8000) -> None:

145

"""

146

Convert WFDB record to WAV audio format.

147

148

Parameters:

149

- record_name: str, WFDB record name

150

- pn_dir: str, directory containing WFDB files

151

- sampfrom: int, starting sample for conversion

152

- sampto: int or 'end', ending sample for conversion

153

- channels: list of int, specific channels to convert

154

- write_dir: str, output directory for WAV files

155

- write_frequency: int, output sampling frequency for WAV

156

157

Note: Signals are automatically scaled and converted to appropriate

158

bit depth for audio playback.

159

"""

160

161

def read_wav(record_name: str, pn_dir: str = None, delete_file: bool = True,

162

record_only: bool = False) -> Union[Record, Tuple[Record, str]]:

163

"""

164

Read WAV file and convert to WFDB Record format.

165

166

Parameters:

167

- record_name: str, WAV file name (without .wav extension)

168

- pn_dir: str, directory containing WAV file

169

- delete_file: bool, delete temporary files after conversion

170

- record_only: bool, return only Record object

171

172

Returns:

173

Record object, or (Record, file_path) tuple if record_only=False

174

"""

175

```

176

177

### TFF Conversion

178

179

Read Text File Format (TFF) files used by some acquisition systems.

180

181

```python { .api }

182

def rdtff(file_name: str, cut_end: bool = False) -> Record:

183

"""

184

Read TFF (Text File Format) files and convert to WFDB Record.

185

186

Parameters:

187

- file_name: str, TFF file name or path

188

- cut_end: bool, remove trailing zero values

189

190

Returns:

191

Record object containing the TFF data

192

193

TFF format consists of:

194

- Header lines with metadata

195

- Data rows with tab-separated numeric values

196

"""

197

```

198

199

## Usage Examples

200

201

### EDF to WFDB Conversion

202

203

```python

204

import wfdb

205

import os

206

207

# Read EDF file

208

edf_record = wfdb.io.convert.read_edf('sleep_study.edf', verbose=True)

209

print(f"EDF record: {edf_record.sig_name}")

210

print(f"Duration: {edf_record.sig_len / edf_record.fs:.1f} seconds")

211

print(f"Channels: {edf_record.n_sig}")

212

213

# Write as WFDB format

214

edf_record.wrsamp('sleep_study_wfdb')

215

216

# Convert WFDB back to EDF

217

wfdb.io.convert.wfdb_to_edf('sleep_study_wfdb',

218

edf_file='converted_back.edf',

219

file_type='EDF+')

220

```

221

222

### MATLAB Integration

223

224

```python

225

import wfdb

226

import scipy.io

227

228

# Convert WFDB to MATLAB format

229

wfdb.io.convert.wfdb_to_mat('100', pn_dir='mitdb',

230

sampfrom=0, sampto=3600) # First 10 seconds

231

232

# Load in Python using scipy

233

mat_data = scipy.io.loadmat('100.mat')

234

print("MATLAB file contents:")

235

for key, value in mat_data.items():

236

if not key.startswith('__'):

237

print(f" {key}: {type(value)} {getattr(value, 'shape', '')}")

238

239

# Access signal data

240

signals = mat_data['val'] # Signal values

241

time_vec = mat_data['tm'].flatten() # Time vector

242

fs = mat_data['Fs'][0, 0] # Sampling frequency

243

sig_names = [name[0] for name in mat_data['signame'].flatten()]

244

```

245

246

### CSV Data Processing

247

248

```python

249

import wfdb

250

import pandas as pd

251

import numpy as np

252

253

# Create sample CSV data

254

data = {

255

'ECG_Lead_I': np.random.randn(1000),

256

'ECG_Lead_II': np.random.randn(1000),

257

'Respiration': np.random.randn(1000) * 0.1

258

}

259

df = pd.DataFrame(data)

260

df.to_csv('sample_signals.csv', index=False)

261

262

# Convert CSV to WFDB

263

wfdb.io.convert.csv_to_wfdb(

264

'sample_signals.csv',

265

fs=250, # 250 Hz sampling

266

units=['mV', 'mV', 'V'],

267

sig_name=['ECG I', 'ECG II', 'Resp'],

268

record_name='csv_converted'

269

)

270

271

# Read back as WFDB record

272

converted_record = wfdb.rdrecord('csv_converted')

273

print(f"Converted record: {converted_record.sig_name}")

274

275

# Create annotation CSV

276

ann_data = pd.DataFrame({

277

'time': [1.0, 2.5, 4.2, 6.8],

278

'symbol': ['N', 'V', 'N', 'N'],

279

'note': ['Normal', 'PVC', 'Normal', 'Normal']

280

})

281

ann_data.to_csv('annotations.csv', index=False)

282

283

# Convert annotation CSV to WFDB

284

wfdb.io.convert.csv2ann('annotations.csv', fs=250, record_name='csv_converted')

285

```

286

287

### WAV Audio Conversion

288

289

```python

290

import wfdb

291

import soundfile as sf

292

293

# Read physiological signal

294

record = wfdb.rdrecord('100', pn_dir='mitdb', channels=[0])

295

296

# Convert to WAV for audio analysis

297

wfdb.io.convert.wfdb_to_wav('100', pn_dir='mitdb',

298

channels=[0],

299

write_frequency=8000) # 8 kHz audio

300

301

# Read WAV file back

302

wav_record = wfdb.io.convert.read_wav('100')

303

print(f"WAV conversion: {wav_record.fs} Hz, {wav_record.sig_len} samples")

304

305

# Alternative: use soundfile for direct WAV handling

306

if os.path.exists('100.wav'):

307

audio_data, sample_rate = sf.read('100.wav')

308

print(f"Audio data shape: {audio_data.shape}")

309

print(f"Sample rate: {sample_rate} Hz")

310

```

311

312

### Batch Format Conversion

313

314

```python

315

import wfdb

316

import os

317

from pathlib import Path

318

319

def convert_directory_to_matlab(input_dir, output_dir):

320

"""Convert all WFDB records in directory to MATLAB format."""

321

322

# Find all .hea files (WFDB headers)

323

header_files = list(Path(input_dir).glob('*.hea'))

324

325

os.makedirs(output_dir, exist_ok=True)

326

327

for hea_file in header_files:

328

record_name = hea_file.stem

329

print(f"Converting {record_name}...")

330

331

try:

332

# Convert to MATLAB

333

wfdb.io.convert.wfdb_to_mat(

334

record_name,

335

pn_dir=input_dir,

336

write_dir=output_dir

337

)

338

print(f" ✓ {record_name}.mat created")

339

340

except Exception as e:

341

print(f" ✗ Error converting {record_name}: {e}")

342

343

# Example usage

344

# convert_directory_to_matlab('./wfdb_data', './matlab_data')

345

346

def batch_edf_to_wfdb(edf_directory, output_directory):

347

"""Convert multiple EDF files to WFDB format."""

348

349

edf_files = list(Path(edf_directory).glob('*.edf'))

350

os.makedirs(output_directory, exist_ok=True)

351

352

for edf_file in edf_files:

353

try:

354

# Read EDF

355

record = wfdb.io.convert.read_edf(str(edf_file))

356

357

# Write as WFDB

358

output_name = edf_file.stem

359

record.wrsamp(output_name, write_dir=output_directory)

360

361

print(f"Converted {edf_file.name} -> {output_name}")

362

363

except Exception as e:

364

print(f"Error converting {edf_file.name}: {e}")

365

366

# Example usage

367

# batch_edf_to_wfdb('./edf_files', './wfdb_output')

368

```

369

370

### Format Validation and Compatibility

371

372

```python

373

import wfdb

374

import numpy as np

375

376

def validate_conversion_accuracy(original_record_name, pn_dir=None):

377

"""Test conversion accuracy by round-trip conversion."""

378

379

# Read original WFDB record

380

original = wfdb.rdrecord(original_record_name, pn_dir=pn_dir)

381

382

# Convert to MATLAB and back

383

wfdb.io.convert.wfdb_to_mat(original_record_name, pn_dir=pn_dir)

384

385

# Note: Direct MAT to WFDB conversion not available

386

# This demonstrates concept - actual implementation would require

387

# manual MAT file reading and WFDB writing

388

389

# Convert to CSV and back

390

# First, save as CSV manually for this test

391

import pandas as pd

392

df = pd.DataFrame(original.p_signal, columns=original.sig_name)

393

df.to_csv('temp_conversion.csv', index=False)

394

395

# Convert CSV back to WFDB

396

wfdb.io.convert.csv_to_wfdb(

397

'temp_conversion.csv',

398

fs=original.fs,

399

units=original.units,

400

sig_name=original.sig_name,

401

record_name='temp_converted'

402

)

403

404

# Read converted record

405

converted = wfdb.rdrecord('temp_converted')

406

407

# Compare signals

408

signal_diff = np.abs(original.p_signal - converted.p_signal)

409

max_error = np.max(signal_diff)

410

mean_error = np.mean(signal_diff)

411

412

print(f"Conversion validation for {original_record_name}:")

413

print(f" Max error: {max_error:.6f}")

414

print(f" Mean error: {mean_error:.6f}")

415

print(f" Original shape: {original.p_signal.shape}")

416

print(f" Converted shape: {converted.p_signal.shape}")

417

418

# Cleanup

419

os.remove('temp_conversion.csv')

420

for ext in ['.hea', '.dat']:

421

if os.path.exists(f'temp_converted{ext}'):

422

os.remove(f'temp_converted{ext}')

423

424

return max_error < 1e-10 # Tolerance for floating point precision

425

426

# Example usage

427

# success = validate_conversion_accuracy('100', pn_dir='mitdb')

428

```

429

430

### Cross-Platform Data Exchange

431

432

```python

433

import wfdb

434

import json

435

436

def create_conversion_metadata(record_name, pn_dir=None):

437

"""Create metadata file for converted records."""

438

439

# Read original record

440

record = wfdb.rdrecord(record_name, pn_dir=pn_dir)

441

442

# Create metadata dictionary

443

metadata = {

444

'original_format': 'WFDB',

445

'record_name': record.record_name,

446

'sampling_frequency': record.fs,

447

'signal_length': record.sig_len,

448

'n_signals': record.n_sig,

449

'signal_names': record.sig_name,

450

'units': record.units,

451

'comments': record.comments,

452

'conversion_timestamp': pd.Timestamp.now().isoformat(),

453

'available_formats': []

454

}

455

456

# Convert to multiple formats

457

formats_to_convert = ['matlab', 'csv', 'wav']

458

459

for fmt in formats_to_convert:

460

try:

461

if fmt == 'matlab':

462

wfdb.io.convert.wfdb_to_mat(record_name, pn_dir=pn_dir)

463

metadata['available_formats'].append('matlab')

464

465

elif fmt == 'csv':

466

# Save signals as CSV

467

df = pd.DataFrame(record.p_signal, columns=record.sig_name)

468

df.to_csv(f'{record_name}_signals.csv', index=False)

469

metadata['available_formats'].append('csv')

470

471

elif fmt == 'wav':

472

wfdb.io.convert.wfdb_to_wav(record_name, pn_dir=pn_dir)

473

metadata['available_formats'].append('wav')

474

475

except Exception as e:

476

print(f"Could not convert to {fmt}: {e}")

477

478

# Save metadata

479

with open(f'{record_name}_metadata.json', 'w') as f:

480

json.dump(metadata, f, indent=2)

481

482

return metadata

483

484

# Example usage

485

# metadata = create_conversion_metadata('100', pn_dir='mitdb')

486

# print(f"Created conversions: {metadata['available_formats']}")

487

```