pub struct EdfWriter { /* private fields */ }
Expand description
EDF+ file writer for creating European Data Format Plus files
The EdfWriter
provides methods to create new EDF+ files and write
biosignal data with proper metadata. It ensures compliance with the
EDF+ specification and provides validation of signal parameters.
§File Creation Workflow
- Create writer with
EdfWriter::create()
- Set patient and recording information
- Add signal definitions with
add_signal()
- Write sample data with
write_samples()
- Finalize the file with
finalize()
§Examples
§Basic EDF+ file creation
use edfplus::{EdfWriter, SignalParam};
// Create new EDF+ file
let mut writer = EdfWriter::create("output.edf")?;
// Set patient information
writer.set_patient_info("P001", "M", "01-JAN-1990", "Test Patient")?;
// Define an EEG signal
let eeg_signal = SignalParam {
label: "EEG Fp1".to_string(),
samples_in_file: 0, // Calculated automatically
physical_max: 200.0,
physical_min: -200.0,
digital_max: 32767,
digital_min: -32768,
samples_per_record: 256, // 256 Hz sampling rate
physical_dimension: "uV".to_string(),
prefilter: "HP:0.1Hz LP:70Hz".to_string(),
transducer: "AgAgCl cup electrodes".to_string(),
};
writer.add_signal(eeg_signal)?;
// Generate and write sample data
let mut samples = Vec::new();
for i in 0..256 {
let t = i as f64 / 256.0;
let value = 50.0 * (2.0 * std::f64::consts::PI * 10.0 * t).sin();
samples.push(value);
}
writer.write_samples(&[samples])?;
writer.finalize()?;
§Multi-channel recording
use edfplus::{EdfWriter, SignalParam};
let mut writer = EdfWriter::create("multi_channel.edf")?;
writer.set_patient_info("P002", "F", "15-MAR-1985", "Multi Channel Test")?;
// Add multiple signals
let signals = vec![
SignalParam {
label: "EEG C3".to_string(),
samples_in_file: 0,
physical_max: 200.0, physical_min: -200.0,
digital_max: 32767, digital_min: -32768,
samples_per_record: 256,
physical_dimension: "uV".to_string(),
prefilter: "HP:0.1Hz LP:70Hz".to_string(),
transducer: "AgAgCl electrodes".to_string(),
},
SignalParam {
label: "ECG Lead II".to_string(),
samples_in_file: 0,
physical_max: 5.0, physical_min: -5.0,
digital_max: 32767, digital_min: -32768,
samples_per_record: 256,
physical_dimension: "mV".to_string(),
prefilter: "HP:0.1Hz LP:100Hz".to_string(),
transducer: "Chest electrodes".to_string(),
},
];
for signal in signals {
writer.add_signal(signal)?;
}
// Write 10 seconds of data
for second in 0..10 {
let mut eeg_samples = Vec::new();
let mut ecg_samples = Vec::new();
for i in 0..256 {
let t = (second * 256 + i) as f64 / 256.0;
// EEG: Alpha wave (10 Hz) with noise
let eeg = 30.0 * (2.0 * std::f64::consts::PI * 10.0 * t).sin()
+ 5.0 * (2.0 * std::f64::consts::PI * 50.0 * t).sin();
eeg_samples.push(eeg);
// ECG: Heart beat pattern (60 BPM)
let ecg = 2.0 * (2.0 * std::f64::consts::PI * 1.0 * t).sin();
ecg_samples.push(ecg);
}
writer.write_samples(&[eeg_samples, ecg_samples])?;
}
writer.finalize()?;
Implementations§
Source§impl EdfWriter
impl EdfWriter
Sourcepub fn create<P: AsRef<Path>>(path: P) -> Result<Self>
pub fn create<P: AsRef<Path>>(path: P) -> Result<Self>
Creates a new EDF+ file writer
Opens a new file for writing and initializes the writer with default values. The file will be created (or truncated if it exists).
§Arguments
path
- Path where the EDF+ file should be created
§Returns
Returns a Result<EdfWriter, EdfError>
. On success, contains an EdfWriter
ready for configuration and data writing.
§Errors
EdfError::FileNotFound
- Cannot create file (permission issues, invalid path, etc.)
§Default Values
The writer is initialized with the following defaults:
- Start date: January 1, 1985
- Start time: 00:00:00
- All patient and recording fields set to “X” (anonymized)
- Data record duration: 1 second
§Examples
use edfplus::EdfWriter;
// Create a new EDF+ file
let writer = EdfWriter::create("new_recording.edf")?;
println!("EDF+ writer created successfully");
§Handling creation errors
use edfplus::EdfWriter;
match EdfWriter::create("/invalid/path/file.edf") {
Ok(_) => println!("File created"),
Err(e) => eprintln!("Failed to create file: {}", e),
}
Sourcepub fn add_signal(&mut self, signal: SignalParam) -> Result<()>
pub fn add_signal(&mut self, signal: SignalParam) -> Result<()>
Adds a signal definition to the EDF+ file
Each signal represents a data channel (e.g., EEG electrode, ECG lead). Signals must be added before writing any data. The order in which signals are added determines their index for data writing.
§Arguments
signal
- SignalParam containing all signal metadata
§Errors
EdfError::InvalidFormat
- Trying to add signal after header is writtenEdfError::PhysicalMinEqualsMax
- Invalid physical rangeEdfError::DigitalMinEqualsMax
- Invalid digital range
§Signal Parameter Requirements
physical_min
must be different fromphysical_max
digital_min
must be different fromdigital_max
samples_per_record
should match the intended sampling ratelabel
should be descriptive and follow EDF+ conventions
§Examples
use edfplus::{EdfWriter, SignalParam};
let mut writer = EdfWriter::create("signals.edf")?;
// Add an EEG signal
let eeg_signal = SignalParam {
label: "EEG Fp1-A1".to_string(),
samples_in_file: 0, // Will be calculated
physical_max: 200.0, // +200 µV
physical_min: -200.0, // -200 µV
digital_max: 32767, // 16-bit signed max
digital_min: -32768, // 16-bit signed min
samples_per_record: 256, // 256 Hz sampling
physical_dimension: "uV".to_string(),
prefilter: "HP:0.1Hz LP:70Hz N:50Hz".to_string(),
transducer: "AgAgCl cup electrodes".to_string(),
};
writer.add_signal(eeg_signal)?;
§Adding multiple signals with different sampling rates
use edfplus::{EdfWriter, SignalParam};
let mut writer = EdfWriter::create("mixed_rates.edf")?;
// High-frequency EEG signal
writer.add_signal(SignalParam {
label: "EEG C3-A1".to_string(),
samples_in_file: 0,
physical_max: 200.0, physical_min: -200.0,
digital_max: 32767, digital_min: -32768,
samples_per_record: 512, // 512 Hz
physical_dimension: "uV".to_string(),
prefilter: "HP:0.1Hz LP:200Hz".to_string(),
transducer: "Gold cup electrodes".to_string(),
})?;
// Lower-frequency physiological signal
writer.add_signal(SignalParam {
label: "Temperature".to_string(),
samples_in_file: 0,
physical_max: 40.0, physical_min: 30.0,
digital_max: 32767, digital_min: -32768,
samples_per_record: 1, // 1 Hz
physical_dimension: "degC".to_string(),
prefilter: "None".to_string(),
transducer: "Thermistor".to_string(),
})?;
Sourcepub fn set_patient_info(
&mut self,
code: &str,
sex: &str,
birthdate: &str,
name: &str,
) -> Result<()>
pub fn set_patient_info( &mut self, code: &str, sex: &str, birthdate: &str, name: &str, ) -> Result<()>
Sets patient information for the EDF+ file
Patient information is embedded in the EDF+ header and follows specific formatting requirements. This information is crucial for medical applications but can be anonymized for privacy.
§Arguments
code
- Patient identification code (max 80 chars)sex
- Patient sex: “M”, “F”, or “X” (unknown)birthdate
- Birth date in DD-MMM-YYYY format or “X”name
- Patient name or “X” for anonymized data
§Errors
EdfError::InvalidFormat
- Trying to modify after header written
§Format Requirements
- Patient code should be unique and meaningful
- Sex must be “M”, “F”, or “X”
- Birth date format: “02-MAY-1951” or “X” if unknown
- Name can be full name or “X” for anonymization
§Examples
use edfplus::EdfWriter;
let mut writer = EdfWriter::create("patient_data.edf")?;
// Set complete patient information
writer.set_patient_info(
"P001-2024", // Patient code
"F", // Female
"15-MAR-1990", // Birth date
"Jane Doe" // Patient name
)?;
§Anonymized patient data
use edfplus::EdfWriter;
let mut writer = EdfWriter::create("anonymous.edf")?;
// Anonymized information for privacy protection
writer.set_patient_info(
"ANON-001", // Anonymous code
"X", // Sex unknown/anonymized
"X", // Birth date anonymized
"X" // Name anonymized
)?;
§Research study format
use edfplus::EdfWriter;
let mut writer = EdfWriter::create("study_subject.edf")?;
// Research study patient coding
writer.set_patient_info(
"STUDY-EEG-S042", // Study-specific ID
"M", // Male
"22-JUL-1985", // Known birth date
"Subject 042" // Study identifier
)?;
Sourcepub fn set_datarecord_duration(&mut self, duration_seconds: f64) -> Result<()>
pub fn set_datarecord_duration(&mut self, duration_seconds: f64) -> Result<()>
Sets the data record duration for the EDF+ file
The data record duration determines how long each data record represents in time. This affects the temporal resolution and file organization. Most EDF+ files use 1 second data records, but other durations are possible.
§Arguments
duration_seconds
- Duration of each data record in seconds
§Errors
EdfError::InvalidFormat
- Trying to modify after header writtenEdfError::InvalidArgument
- Duration <= 0 or too large
§Common Values
- 1.0 seconds: Standard for most clinical recordings
- 0.1 seconds: Higher temporal resolution for fast events
- 10.0 seconds: Lower resolution for long-term monitoring
§Examples
use edfplus::EdfWriter;
let mut writer = EdfWriter::create("custom_duration.edf")?;
// Set 0.5 second data records for higher temporal resolution
writer.set_datarecord_duration(0.5)?;
§High-frequency recording
use edfplus::EdfWriter;
let mut writer = EdfWriter::create("high_freq.edf")?;
// Use 0.1 second records for fast neural signals
writer.set_datarecord_duration(0.1)?;
Sourcepub fn write_samples(&mut self, samples: &[Vec<f64>]) -> Result<()>
pub fn write_samples(&mut self, samples: &[Vec<f64>]) -> Result<()>
Writes sample data for all signals to the current data record
⚠️ WARNING: IRREVERSIBLE OPERATION
Once this method is called, the written data record CANNOT be modified. This library uses a sequential streaming write architecture that does not support backtracking or random access modification.
What happens when you call this method:
- Signal sample data is immediately written to the file buffer
- Annotation data for this time period is generated and written
- The internal record counter is incremented
- The written content becomes immutable
If you need to modify data:
- Collect all your data and annotations first
- Create a new file with the corrected data
- See documentation for strategies: in-memory preparation, temporary files, etc.
§Arguments
samples
- Vector of sample vectors, one per signal channel- Must contain exactly the same number of vectors as signals added
- Each vector must contain exactly
samples_per_record
samples
§Errors
EdfError::InvalidFormat
- Wrong number of sample vectors or samples per vectorEdfError::FileWriteError
- I/O error during writingEdfError::NotReady
- File headers not written yet
§Sample Organization
The samples
parameter must be organized as:
- Outer vector: one element per signal (in order added)
- Inner vectors: physical values for each signal
- All inner vectors must have the same length (matching
samples_per_record
)
§Examples
§Writing a single data record with multiple signals
use edfplus::{EdfWriter, SignalParam};
let mut writer = EdfWriter::create("multi_signal.edf")?;
// Add two signals with the same sampling rate
writer.add_signal(SignalParam {
label: "EEG Fp1".to_string(),
samples_in_file: 0,
physical_max: 100.0, physical_min: -100.0,
digital_max: 32767, digital_min: -32768,
samples_per_record: 256, // 256 samples per data record
physical_dimension: "uV".to_string(),
prefilter: "HP:0.1Hz LP:70Hz".to_string(),
transducer: "AgAgCl electrodes".to_string(),
})?;
writer.add_signal(SignalParam {
label: "ECG Lead II".to_string(),
samples_in_file: 0,
physical_max: 5.0, physical_min: -5.0,
digital_max: 32767, digital_min: -32768,
samples_per_record: 256, // Same sampling rate as EEG
physical_dimension: "mV".to_string(),
prefilter: "HP:0.1Hz LP:100Hz".to_string(),
transducer: "Chest electrodes".to_string(),
})?;
// Generate sample data (256 samples for each signal)
let mut eeg_samples = Vec::new();
let mut ecg_samples = Vec::new();
for i in 0..256 {
let t = i as f64 / 256.0; // Time within this 1-second data record
eeg_samples.push(20.0 * (2.0 * std::f64::consts::PI * 10.0 * t).sin()); // 10 Hz EEG
ecg_samples.push(1.0 * (2.0 * std::f64::consts::PI * 1.0 * t).sin()); // 1 Hz ECG
}
// Write one data record containing both signals
writer.write_samples(&[eeg_samples, ecg_samples])?;
writer.finalize()?;
§Writing multiple data records (continuous recording)
use edfplus::{EdfWriter, SignalParam};
let mut writer = EdfWriter::create("continuous.edf")?;
// Add a single signal
writer.add_signal(SignalParam {
label: "Continuous EEG".to_string(),
samples_in_file: 0,
physical_max: 100.0, physical_min: -100.0,
digital_max: 32767, digital_min: -32768,
samples_per_record: 256, // 256 Hz sampling rate (256 samples per 1-second record)
physical_dimension: "uV".to_string(),
prefilter: "HP:0.1Hz LP:70Hz".to_string(),
transducer: "AgAgCl electrodes".to_string(),
})?;
// Write 10 seconds of continuous data (10 data records)
for second in 0..10 {
let mut samples = Vec::new();
// Generate 256 samples for this 1-second data record
for i in 0..256 {
let t = (second * 256 + i) as f64 / 256.0; // Absolute time since recording start
let value = 50.0 * (2.0 * std::f64::consts::PI * 10.0 * t).sin();
samples.push(value);
}
// Write one data record (note: samples is a Vec<f64>, so we wrap it in &[samples])
writer.write_samples(&[samples])?;
}
writer.finalize()?;
§Writing multiple signals with different sampling rates
use edfplus::{EdfWriter, SignalParam};
let mut writer = EdfWriter::create("mixed_rates.edf")?;
// High-frequency EEG signal
writer.add_signal(SignalParam {
label: "EEG C3".to_string(),
samples_in_file: 0,
physical_max: 200.0, physical_min: -200.0,
digital_max: 32767, digital_min: -32768,
samples_per_record: 500, // 500 Hz sampling rate
physical_dimension: "uV".to_string(),
prefilter: "HP:0.1Hz LP:200Hz".to_string(),
transducer: "Gold cup electrodes".to_string(),
})?;
// Lower-frequency physiological signal
writer.add_signal(SignalParam {
label: "Respiration".to_string(),
samples_in_file: 0,
physical_max: 10.0, physical_min: -10.0,
digital_max: 32767, digital_min: -32768,
samples_per_record: 25, // 25 Hz sampling rate
physical_dimension: "arbitrary".to_string(),
prefilter: "LP:10Hz".to_string(),
transducer: "Strain gauge".to_string(),
})?;
// Write 5 seconds of data
for second in 0..5 {
// EEG: 500 samples for this data record
let mut eeg_samples = Vec::new();
for i in 0..500 {
let t = (second * 500 + i) as f64 / 500.0;
let value = 100.0 * (2.0 * std::f64::consts::PI * 10.0 * t).sin();
eeg_samples.push(value);
}
// Respiration: 25 samples for this data record
let mut resp_samples = Vec::new();
for i in 0..25 {
let t = (second * 25 + i) as f64 / 25.0;
let value = 5.0 * (2.0 * std::f64::consts::PI * 0.3 * t).sin(); // 0.3 Hz breathing
resp_samples.push(value);
}
// Write both signals for this data record
writer.write_samples(&[eeg_samples, resp_samples])?;
}
writer.finalize()?;
Sourcepub fn finalize(self) -> Result<()>
pub fn finalize(self) -> Result<()>
Finalizes the EDF+ file and closes it
This method must be called to complete the file writing process. It flushes any remaining data to disk and properly closes the file. After calling this method, the writer is consumed and cannot be used again.
§Errors
EdfError::FileWriteError
- I/O error during file finalization
§File Integrity
Failing to call finalize()
may result in:
- Incomplete file headers
- Missing data records
- Corrupted file structure
Always call finalize()
when finished writing data.
§Examples
use edfplus::{EdfWriter, SignalParam};
let mut writer = EdfWriter::create("final_test.edf")?;
// Add signal and write data...
writer.add_signal(SignalParam {
label: "Test Signal".to_string(),
samples_in_file: 0,
physical_max: 1.0, physical_min: -1.0,
digital_max: 32767, digital_min: -32768,
samples_per_record: 10,
physical_dimension: "V".to_string(),
prefilter: "None".to_string(),
transducer: "Test".to_string(),
})?;
let samples = vec![0.1, 0.2, 0.3, 0.4, 0.5, -0.1, -0.2, -0.3, -0.4, -0.5];
writer.write_samples(&[samples])?;
// Always finalize to ensure file integrity
writer.finalize()?;
§Error handling during finalization
use edfplus::{EdfWriter, SignalParam};
fn test_finalize() -> Result<(), Box<dyn std::error::Error>> {
let mut writer = EdfWriter::create("error_test.edf")?;
// ... add signals and write data ...
match writer.finalize() {
Ok(()) => println!("File successfully completed"),
Err(e) => {
eprintln!("Error finalizing file: {}", e);
// File may be corrupted
}
}
Ok(())
}
Sourcepub fn add_annotation(
&mut self,
onset_seconds: f64,
duration_seconds: Option<f64>,
description: &str,
) -> Result<()>
pub fn add_annotation( &mut self, onset_seconds: f64, duration_seconds: Option<f64>, description: &str, ) -> Result<()>
Adds an annotation/event to the EDF+ file
⚠️ CRITICAL TIMING CONSTRAINT
Annotations are only saved when their onset time falls within future data records.
Once a data record is written with write_samples()
, no new annotations can be
added to that time period.
Timing Rules:
- Add annotations BEFORE writing the data records that cover their time range
- Annotations with
onset_seconds
in already-written time periods will be silently lost - This is due to the sequential write architecture - no backtracking is possible
§Arguments
onset_seconds
- Time when the event occurred (seconds since recording start)duration_seconds
- Duration of the event in seconds (None for instantaneous events)description
- UTF-8 text describing the event (max 40 chars effective)
§Important Limitations
§Description Length Limit
Warning: Annotation descriptions are subject to EDF+ format constraints:
- Maximum effective length is 40 characters in the final TAL (Time-stamped Annotations Lists) data
- Longer descriptions will be automatically truncated during file writing
- UTF-8 multi-byte characters may be truncated at byte boundaries, potentially corrupting the text
- This limit is enforced by the EDF+ standard and matches edflib behavior
let mut writer = EdfWriter::create("annotations.edf")?;
// ✅ Good - within 40 character limit
writer.add_annotation(1.0, None, "Sleep stage N2")?;
// ⚠️ Warning - will be truncated to 40 chars
writer.add_annotation(2.0, None, "This is a very long annotation description that exceeds the EDF+ limit")?;
// Result: "This is a very long annotation descripti"
§Time Range Constraints
Critical: Annotations are only saved if their onset time falls within written data records:
- Annotations with
onset_seconds
>= total file duration will be silently discarded - Each data record covers a specific time range (typically 1 second)
- An annotation at time T is only saved if there’s a data record covering [T, T+duration)
// Write 5 seconds of data (5 records)
let mut writer = EdfWriter::create("annotations.edf")?;
// ✅ Good - within file duration [0.0, 5.0)
writer.add_annotation(2.5, None, "Valid event")?;
writer.add_annotation(4.999, None, "Last moment")?;
// ❌ Lost - outside file duration
writer.add_annotation(5.0, None, "Will be discarded")?;
writer.add_annotation(6.0, None, "Also discarded")?;
for i in 0..5 {
let samples = vec![0.0; 256];
writer.write_samples(&[samples])?;
}
§Best Practices
- Keep descriptions concise (≤40 characters)
- Add annotations before finalizing the file
- Ensure sufficient data records cover all annotation times
- Use ASCII characters when possible to avoid UTF-8 truncation issues
- Validate annotation times against your data duration
§Time Precision
Time values are internally stored with 100-nanosecond precision. Input values will be rounded to the nearest 100 nanoseconds.
§Errors
Returns EdfError::InvalidFormat
if:
onset_seconds
is negativeduration_seconds
is negativedescription
is emptydescription
exceeds 512 characters (pre-truncation validation)
§Examples
§Basic Usage
use edfplus::{EdfWriter, SignalParam};
let mut writer = EdfWriter::create("annotations_test.edf")?;
writer.set_patient_info("P001", "M", "01-JAN-1990", "Test Patient")?;
// Add a signal
let signal = SignalParam {
label: "EEG".to_string(),
samples_in_file: 0,
physical_max: 100.0,
physical_min: -100.0,
digital_max: 32767,
digital_min: -32768,
samples_per_record: 256,
physical_dimension: "uV".to_string(),
prefilter: "HP:0.1Hz".to_string(),
transducer: "AgAgCl".to_string(),
};
writer.add_signal(signal)?;
// Write some data FIRST to establish time range
for i in 0..10 {
let samples = vec![10.0; 256];
writer.write_samples(&[samples])?; // Creates 10 seconds of data
}
// Add annotations within the data time range [0.0, 10.0)
writer.add_annotation(0.5, None, "Recording start")?;
writer.add_annotation(2.0, Some(1.0), "Sleep stage 1")?;
writer.add_annotation(5.5, None, "Eye movement")?;
writer.add_annotation(9.999, None, "Near end")?; // Still within range
writer.finalize()?;
§Sleep Study Example with Proper Time Management
use edfplus::{EdfWriter, SignalParam};
let mut writer = EdfWriter::create("sleep_study.edf")?;
writer.set_patient_info("S001", "F", "15-MAR-1980", "Sleep Study")?;
let eeg_signal = SignalParam {
label: "C3-A2".to_string(),
samples_in_file: 0,
physical_max: 100.0,
physical_min: -100.0,
digital_max: 32767,
digital_min: -32768,
samples_per_record: 100, // 100 Hz
physical_dimension: "uV".to_string(),
prefilter: "0.1-35Hz".to_string(),
transducer: "AgAgCl".to_string(),
};
writer.add_signal(eeg_signal)?;
// Record 30 minutes (1800 seconds) of sleep data
let recording_duration_seconds = 1800;
for second in 0..recording_duration_seconds {
let mut samples = Vec::with_capacity(100);
for sample_idx in 0..100 {
let t = second as f64 + (sample_idx as f64 / 100.0);
let eeg_value = 20.0 * (2.0 * std::f64::consts::PI * 10.0 * t).sin();
samples.push(eeg_value);
}
writer.write_samples(&[samples])?;
}
// Now add sleep annotations - all within [0, 1800) seconds
writer.add_annotation(300.0, None, "Lights out")?; // 5 min
writer.add_annotation(480.0, None, "Sleep onset")?; // 8 min
writer.add_annotation(600.0, Some(1200.0), "Stage N2")?; // 10-30 min
writer.add_annotation(900.0, None, "Sleep spindle")?; // 15 min
writer.add_annotation(1200.0, Some(300.0), "REM episode")?; // 20-25 min
writer.add_annotation(1790.0, None, "Wake up")?; // 29:50 - still valid
writer.finalize()?;
Sourcepub fn annotation_count(&self) -> usize
pub fn annotation_count(&self) -> usize
Gets the current number of annotations
This can be useful for tracking how many annotations have been added before finalizing the file.
§Examples
use edfplus::{EdfWriter, SignalParam};
let mut writer = EdfWriter::create("count_test.edf")?;
writer.set_patient_info("P001", "M", "01-JAN-1990", "Test")?;
// Initially no annotations
assert_eq!(writer.annotation_count(), 0);
writer.add_annotation(1.0, None, "Event 1")?;
assert_eq!(writer.annotation_count(), 1);
writer.add_annotation(2.0, Some(0.5), "Event 2")?;
assert_eq!(writer.annotation_count(), 2);
pub fn set_subsecond_starttime(&mut self, subsecond: i64) -> Result<()>
Sourcepub fn set_number_of_annotation_signals(
&mut self,
annot_signals: usize,
) -> Result<()>
pub fn set_number_of_annotation_signals( &mut self, annot_signals: usize, ) -> Result<()>
Sets the number of annotation signals (channels)
EDF+ supports multiple annotation signals according to the standard. This follows the edflib design where you can have 1-64 annotation channels.
§Arguments
annot_signals
- Number of annotation signals (1-64)
§Errors
EdfError::InvalidFormat
- Trying to modify after header writtenEdfError::InvalidArgument
- Invalid number of annotation signals
§Examples
use edfplus::EdfWriter;
let mut writer = EdfWriter::create("multi_annot.edf")?;
// Set 3 annotation channels for complex event coding
writer.set_number_of_annotation_signals(3)?;