Этот пример показывает, как создать и использовать два различных Системных объекта, чтобы упростить потоковую передачу данных в и из MATLAB: dspdemo.TextFileReader
и dspdemo.TextFileWriter
.
Объекты, обсужденные в этом примере, обращаются ко многим реалистическим вариантам использования, и они могут быть настроены, чтобы достигнуть усовершенствованных и более специализированных задач.
Этот пример показывает, как создать и использовать новые типы Системных объектов для чтения файла и записи. Внутренне, эти Системные объекты используют стандартные низкоуровневые функции ввода-вывода файлов, доступные в MATLAB (например, fscanf
, fprintf
, fread
, fwrite
). Путем абстракции далеко большинства деталей использования тех функций, они стремятся делать задачу из чтения и записи переданных потоком данных более простой и более эффективной.
Этот пример включает использование многих усовершенствованных построений, чтобы создать Системные объекты. Для более основного введения в объекты авторской системы обратитесь к примерам в разделе Define New System Objects документации DSP System Toolbox.
Системные объекты являются классами MATLAB, которые выводят от matlab.System
. В результате Системные объекты, все наследовали общий открытый интерфейс, который включает следующие стандартные методы:
настройка-
инициализировать объект, обычно в начале симуляции
сброс-
очистить внутреннее состояние объекта, возвращая его его состоянию постинициализации по умолчанию
шаг-
выполнить базовую функциональность объекта, опционально принимая некоторый вход и/или возвращая некоторый выходной параметр
релиз-
высвобождать любые средства (например, память, оборудование, или специфичный для ОС) используемый внутренне объектом
Когда вы создаете новые виды Системных объектов, вы обеспечиваете определенные реализации для всех предыдущих методов, чтобы определить его поведение.
В этом примере мы обсуждаем внутреннюю структуру и использование следующих двух Системных объектов:
dspdemo.TextFileReader
Все Системные объекты в предыдущем списке совместно используют общую структуру. Например, dspdemo.TextFileReader
включает следующие разделы
1. Оператор определения класса, который подразумевает этот класс, выведен и от matlab.System
и от matlab.system.mixin.FiniteSource
.
classdef TextFileReader < matlab.System & matlab.system.mixin.FiniteSource
matlab.System
требуется и является базовым классом для всех Системных объектов
matlab.system.mixin.FiniteSource
указывает, что этот класс является источником сигнала с конечным числом выборок данных. Это подразумевает, что в дополнение к обычному интерфейсу Системный объект также представит метод isDone. Когда isDone возвращает true, объект достиг конца доступных данных.
2. Много публичных свойств. В этом случае два являются ненастраиваемыми (они не могут быть изменены после первого вызова шага) и у всех есть значение по умолчанию. Значения по умолчанию присвоены соответствующим свойствам, когда ничто иное не задано пользователем. Публичные свойства могут быть изменены пользователем, чтобы настроить поведение объекта к его конкретному приложению.
properties (Nontunable) Filename = 'tempfile.txt' HeaderLines = 4 end
properties DataFormat = '%g' Delimiter = ',' SamplesPerFrame = 1024 PlayCount = 1 end
3. Много частных свойств. Они не видимы пользователю и могут служить многим целям, включая
Держаться за значения вычисляло только иногда (например, во время инициализации, когда setup
называется или когда step
называется впервые), и затем использованный последующими вызовами step
. Это может сохранить перевычисление их во времени выполнения, и следовательно улучшать производительность базовой функциональности
Задавать внутреннее состояние объекта. Например, pNumEofReached
хранит число раз, что индикатор конца файла был достигнут
properties(Access = private) pFID = -1 pNumChannels pLineFormat pNumEofReached = 0 end
4. Конструктор. Это называется, когда новый экземпляр dspdemo.TextDataReader
создается пользователем. При вызове метода setProperties
в конструкторе позволяет пользователям устанавливать свойства объекта путем обеспечения пар "имя-значение" при конструкции.
methods function obj = TextFileReader(varargin) setProperties(obj, nargin, varargin{:}); end end
5. Много переопределенных методов от базового класса matlab.System
. Открытые методы, характерные для всех Системных объектов, у каждого есть соответствующие защищенные методы, которые они вызывают внутренне. Имена этих защищенных методов все включают постфикс Impl
. Они могут быть реализованы при определении класса, чтобы программировать определенное поведение конкретного Системного объекта.
Для получения дополнительной информации о соответствии между стандартными открытыми методами и их внутренними реализациями, обратитесь к Синхронизации Методов.
Например, конкретные методы внедрения, которые заменены для dspdemo.TextFileReader
,
setupImpl
resetImpl
stepImpl
releaseImpl
isDoneImpl
processTunedPropertiesImpl
loadObjectImpl
saveObjectImpl
6. Много закрытых методов. Эти методы только доступны из других методов того же класса. Они могут использоваться, чтобы сделать остальную часть кода более читаемой. Они могут также улучшить возможность многократного использования кода путем группировки в соответствии с отдельным кодом стандартных программ, который используется многократно в различных частях класса.
Код, который следует, дает простую демонстрацию того, как эти новые объекты могли использоваться. Следующие задачи показывают
Создайте текстовый файл, содержащий выборки двух различных синусоидальных сигналов с помощью dspdemo.TextFileWriter
Читайте из текстового файла с помощью dspdemo.TextFileReader
и запишите во второй файл в двоичной форме, на этот раз с помощью dsp.BinaryFileWriter
Считайте выборки сигнала циклически из нового двоичного файла с помощью dsp.BinaryFileReader
и анализируйте результаты графически.
Чтобы запуститься, новый текстовый файл создается, чтобы сохранить два синусоидальных сигнала частотами 50 Гц и 60 Гц, соответственно. Для каждого сигнала хранимые данные будут состоять из 800 выборок на уровне выборки 8 кГц.
Следующее готовит данные
% Create data samples fs = 8000; tmax = 0.1; t = (0:1/fs:tmax-1/fs)'; N = length(t); f = [50,60]; data = sin(2*pi*t*f); % Optionally, form a header string to describe the data in a readable way % for future use fileheader = sprintf(['The following contains %d samples of two ',... 'sinusoids,\nwith frequencies %d Hz and %d Hz and a sample rate of',... ' %d kHz\n\n'], N, f(1),f(2),fs/1000);
Чтобы сохранить сигнал к текстовому файлу, создайте экземпляр средства записи текстового файла. Конструктору dspdemo.TextFileWriter
нужно имя конечного файла и некоторых дополнительных параметров, которые могут быть переданы в как пары "имя-значение".
TxtWriter = dspdemo.TextFileWriter('Filename','sinewaves.txt',... 'Header',fileheader) %#ok<NOPTS>
TxtWriter = dspdemo.TextFileWriter with properties: Filename: 'sinewaves.txt' Header: 'The following contains 800 samples of two sinusoids,...' DataFormat: '%.18g' Delimiter: ','
dspdemo.TextFileWriter
записывает данные к разделенным от разделителя ASCII-файлам. Его публичные свойства включают следующее
FileName :
имя файла, который будет записан. Если файл с этим именем уже существует, это перезаписывается. Когда операции запускаются, объект начинает запись к файлу сразу после заголовка - это затем добавляет новые данные в каждом последующем вызове шага, пока это не выпущено. Вызов сброса продолжает писать с начала файла.
Header
: символьная строка, часто состоящая из нескольких строк и отключенная символом новой строки (\n
). Это задано пользователем и может быть изменено, чтобы встроить человекочитаемую информацию, которая описывает фактические данные.
DataFormat
: формат раньше хранил каждую выборку данных. Это может принять любое значение, присваиваемое как Спецификатор Преобразования в строке formatSpec
, используемой встроенной функцией MATLAB fprintf
. DataFormat
применяется ко всем каналам, записанным в файл. Значением по умолчанию для этого свойства является '%.18g'
, который позволяет сохранять данные с плавающей запятой двойной точности в полной точности.
Delimiter
: символ раньше разделял выборки от различных каналов одновременно момент. Каждая строка записанных карт файлов к моменту времени, и это включает столько же выборок сколько количество каналов, обеспеченных, как введено (т.е. количество столбцов в матричном входе передало step
).
Чтобы записать все доступные данные в файл, один вызов step
может использоваться можно следующим образом
% Write to file with data as input % Note: |TxtWriter(data)| is equivalent to |step(TxtWriter, data)| TxtWriter(data) % Release control of file release(TxtWriter)
Данные теперь хранимы в новом файле. Чтобы осмотреть файл визуально вводят edit('sinewaves.txt')
. Из-за заголовка обратите внимание, что данные запускаются на строке 4, после 3 строк заголовка.
В этом простом случае длина целого сигнала является маленькой, и это соответствует удобно на системной памяти. Поэтому данные могут быть созданы целиком и записаны в файл на одном шаге, как только показано.
Существуют случаи, когда этот подход не возможен или практичен. Например, данные могут быть слишком большими, чтобы поместиться в одну переменную MATLAB (т.е. слишком большой, чтобы соответствовать на системной памяти), или это может быть создано циклически в цикле или передано потоком в MATLAB из внешнего источника. Во всех этих случаях может быть удобно передать данные потоком в файл при помощи подхода, подобного следующему
% Use a streamed sine wave generator to create a frame of data per step frameLength = 32; SineWave = dsp.SineWave('Frequency',[50,60], 'SampleRate', fs, ... 'SamplesPerFrame', frameLength); % Run the desired number of iterations to create the data and store it into % the file tmax = 10; % Write more data in this scenario t = (0:1/fs:tmax-1/fs)'; N = length(t); data = sin(2*pi*t*f); numCycles = N/frameLength; for k = 1:numCycles dataFrame = SineWave(); TxtWriter(dataFrame) end % Release control of file and sine wave generator release(TxtWriter) release(SineWave)
Следующий шаг состоит в чтении данных из недавно созданного файла и записи его в новый двоичный файл.
Чтобы читать из текстового файла, создайте экземпляр dspdemo.TextFileReader
.
% Create a text file reader TxtReader = dspdemo.TextFileReader('Filename','sinewaves.txt',... 'HeaderLines',3,'SamplesPerFrame',frameLength) %#ok<NOPTS>
TxtReader = dspdemo.TextFileReader with properties: Filename: 'sinewaves.txt' HeaderLines: 3 DataFormat: '%g' Delimiter: ',' SamplesPerFrame: 32 PlayCount: 1
dspdemo.TextFileReader
считывает числовые данные из разделенных от разделителя ASCII-файлов. Его свойства подобны тем из dspdemo.TextFileWriter
. Некоторые различия следуют
HeaderLines
получает количество строк, используемых заголовком в файле, заданном в Filename
. Первый вызов step
начинает читать из номера строки HeaderLines+1
. Последующие вызовы step
продолжают читать из строки сразу после ранее прочитанной строки. Вызов reset
продолжит читать из строки HeaderLines+1
.
Delimiter
является снова символом, используемым, чтобы разделить выборки от различных каналов одновременно момент. В этом случае это также используется, чтобы определить количество каналов данных, сохраненных в файле: когда step
будет сначала назван, числа объектов количество символов Delimiter
в строке HeaderLines+1
, скажите numDel
; это затем принимает в течение каждого раза момент, это должно считать числовые значения numChan = numDel+1
с форматом DataFormat
. Матрица, возвращенная шагом, имеет размер SamplesPerFrame
x numChan
.
SamplesPerFrame
является количеством строк, прочитанных каждым вызовом step
, т.е. количеством строк матрицы, возвращенной, как выведено. Когда последние доступные строки данных достигнуты, это может произойти, что они - меньше, чем необходимый SamplesPerFrame
. В этом случае доступные данные дополнены нулями, чтобы получить матрицу размера SamplesPerFrame
x numChan
. Если все данные считаны, шаг просто возвращает zeros(SamplesPerFrame,numChan)
до reset
, или release
называется.
PlayCount
является числом раз, данные в файле считаны циклически. Если объект достигает конца файла, и файл еще не был считан неоднократно равный PlayCount
, читая резюме с начала данных (т.е. строка HeaderLines+1
). Если последние строки файла не обеспечивают достаточно выборок, чтобы сформировать полную выходную матрицу размера SamplesPerFrame
x numChan
, то кадр завершается с помощью исходных данных. Если файл является чтением времена PlayCount
, выходная матрица, возвращенная шагом, заполнена нулями, и все вызовы isDone
возвращают true, если не сброшено, или релиз называется. Чтобы циклично выполниться через доступные данные неопределенно, PlayCount
может быть установлен в Inf
.
Чтобы записать в новый двоичный файл, создайте экземпляр dsp.BinaryFileWriter
BinWriter = dsp.BinaryFileWriter('Filename','sinewaves.bin',... 'HeaderStructure',struct('Info',fileheader));
Данные, переданные как вход dsp.BinaryFileWriter
, хранятся с помощью его собственного типа данных. Например, вход с плавающей точкой с двойной точностью будет использовать 8 байтов за выборку. Выборки данных хранятся в порядке времени, и чередованы несколько каналов. Как следствие входные матрицы, переданные step
, добавлены к файлу с помощью главного строкой подхода (т.е. первая строка хранится сначала, слева направо, затем вторая строка, и так далее).
Чтобы передать данные из текстового файла в двоичный файл, более общий переданный потоком подход используется. Это также относится к контакту с очень большими файлами данных.
% Write binary data using single-precision floating point % Preallocate a data frame with |frameLength| rows and 2 columns dataFrame = zeros(frameLength,2,'single'); % Read from the text file and write to the binary file, whilst data is % present in the source text file. Notice how the method |isDone| is used % to control the execution of the while loop while(~isDone(TxtReader)) dataFrame(:) = TxtReader(); BinWriter(dataFrame) end % Release control of both files release(TxtReader) release(BinWriter)
sinewaves.bin
содержит целое число периодов для обеих синусоид, т.е. 500 периодов на уровне 50 Гц и 600 на уровне 60 Гц. Такие сигналы могут читаться циклически и использоваться, чтобы сгенерировать синусоиды произвольной длины. В последней части этой демонстрации dsp.BinaryFileReader
используется, чтобы сделать точно это. Когда данные считаны, эти две синусоиды визуализируются во временном интервале, и их продукт анализируется в частотном диапазоне.
frameLength = 1024; % Create an instance of a binary file reader BinReader = dsp.BinaryFileReader('Filename','sinewaves.bin',... 'HeaderStructure',struct('Info',zeros(1,numel(fileheader),'uint8')),... 'NumChannels',2,... 'DataType','single',... 'SamplesPerFrame',frameLength) %#ok<NOPTS> header = BinReader.readHeader.Info; % Display the header read from the file: char(header)
BinReader = dsp.BinaryFileReader with properties: Filename: 'sinewaves.bin' HeaderStructure: [1x1 struct] SamplesPerFrame: 1024 NumChannels: 2 DataType: 'single' IsDataComplex: false ans = 'The following contains 800 samples of two sinusoids, with frequencies 50 Hz and 60 Hz and a sample rate of 8 kHz '
Интерфейс dsp.BinaryFileReader
в основном очевиден. Следующее стоит заметить
HeaderStructure
задает ожидаемый заголовок в начале файла.
NumChannels
задает, сколько чередованных выборок ожидается в течение каждого раза момент. Это также определяет количество столбцов выходной матрицы, возвращенной объектом. Когда выполняется, объект возвращает матрицу размера SamplesPerFrame
x NumChannels
, сохраненный в файле главным строкой способом.
Следующее создает компоненты, которые помогают с визуальным анализом переданных потоком сигналов, и во время и в частотном диапазоне
Для визуализации временного интервала создается экземпляр dsp.TimeScope
. Это используется, чтобы построить все кадры данных для обеих синусоид, когда они читаются из файла.
TimeScope = dsp.TimeScope('SampleRate',fs,'TimeSpan',frameLength/fs,... 'ShowGrid',true,'YLimits',[-1 1],'TimeSpanOverrunAction','Scroll');
Для визуализации частотного диапазона создается экземпляр dsp.SpectrumAnalyzer
. Это используется, чтобы анализировать спектр продукта между этими двумя синусоидами, ожидая два тональных компонента в (60-50) Гц и (60+50) Гц, соответственно.
Поскольку отношение между частотами в сигнале и частоте дискретизации является очень низким, сигналы сначала подкошены фактором 16 с экземпляром dsp.SampleRateConverter
. Это понижает частоту дискретизации до 500 Гц и делает частотные составляющие из целевого более легко идентифицируемого использования сигнала стандартного спектрального анализа.
RateConverter = dsp.SampleRateConverter('InputSampleRate', 8000, ... 'OutputSampleRate', 500, 'Bandwidth', 100); % Note how a single spectral snapshot with the following settings % requires 16384 input samples, far more than the 800 actually stored in % the file SpectAnalyzer = dsp.SpectrumAnalyzer(... 'FrequencyResolutionMethod', 'WindowLength', 'WindowLength', 1024,... 'FFTLengthSource', 'Property', 'FFTLength', 2048, 'SampleRate',500,... 'PlotAsTwoSidedSpectrum', false, 'SpectralAverages', 16);
Следующий цикл с условием продолжения считывает данные из файла и визуализирует сигналы, когда они читаются. Это запускает в течение 10 минут ценность времени симуляции, независимо от фактического количества выборок в файле. Графики в двух переданной потоком визуализации совпадают с ожидаемым поведением.
simtime = 0; % Run the loop until the simulation time is less than 10*60 seconds while(simtime < 600) % Rewind file if there are no more new samples if isDone(BinReader) reset(BinReader) end % Read from binary file, 1024 samples per frame dataFrame = BinReader(); % Visualize a single frame of both channels in the time domain TimeScope(dataFrame) % Decimate the two channels down to a new sample rate of 500 Hz, % resulting in a new frame length of 64 samples dataDecimated = RateConverter(dataFrame); % Analyze the product of the two sine waves in the frequency domain, by % accumulating multiple data frames internally and updating the % visualization when ready SpectAnalyzer(prod(dataDecimated,2)) % Update value of simulation time elapsed simtime = simtime + frameLength/fs; end % Release control of files and scopes release(BinReader) release(RateConverter) release(TimeScope) release(SpectAnalyzer)
Этот пример проиллюстрировал, как создать и использовать Системные объекты, чтобы читать из и записать в файлы числовых данных. Все используемые объекты (т.е. dspdemo.TextFileReader
, dspdemo.TextFileWriter
, dsp.BinaryFileReader
и dsp.BinaryFileWriter
) могут быть отредактированы, чтобы выполнить файл специального назначения читающие и пишущие операции.
Для получения дополнительной информации об объектах авторской системы для пользовательских алгоритмов см. Создание системных объектов.