Форум: "Начинающим";
Текущий архив: 2009.11.15;
Скачать: [xml.tar.bz2];
ВнизTFileStream и array of extended Найти похожие ветки
← →
SergejM © (2009-09-28 17:31) [0]Здравствуйте.
Возникает проблема при записи в поток и последующем чтении массива extended. Пишутся и читаются не те данные, которые ожидаются.
Вот примерный код (все, не относящееся непосредственно к записи или чтению, выкинуто):type
TArrayOfExtended = array of Extended;
...
procedure First;
var
Data:TArrayOfExtended;
Stream:TFileStream;
DataSize: Integer;
...
begin
...
SetLength(Data, DataSize);
...
Stream.Write(Data[Low(Data)], Length(Data)*SizeOf(Extended));
...
end;
procedure Second;
var
Data:TArrayOfExtended;
Stream:TFileStream;
DataSize: Integer;
...
begin
...
SetLength(Data, DataSize);
Stream.Read(Data[Low(Data)], DataSize*SizeOf(Extended));
...
end;
В процедуре First в массиве данных находились дробные числа в диапазоне от -100 до 100. После загрузки в процедуре Second массив содержит в себе дробные числа в диапазоне от -1e-4000 до 1e4000. В качестве дополнения при просмотре сохраненного файла видно, что в него попадают куски из совершенно другой области - фрагменты журнала работы программы. Первое такое попадание случается спустя 8192 байта от начала и дальше спустя каждые 10240 байт. Значение переменной DataSize кратно 4096 байт.
Вопрос - что в приведенном коде может заставлять поток сохранения брать данные из другой области памяти?..
← →
Leonid Troyanovsky © (2009-09-28 18:12) [1]
> SergejM © (28.09.09 17:31)
> DataSize: Integer;
И откуда он берется?
> Вот примерный код (все, не относящееся непосредственно к
> записи или чтению, выкинуто):
Приводить код нужно не минимальный,
а необходимый и достаточный, дабы пожелавшие его
испытать могли сделать это легким движением руки.
И, еще, как там у нас с конфликтами имен?
--
Regards, LVT.
← →
SergejM © (2009-09-28 18:25) [2]DataSize вычисляется по исходным параметрам. В данном случае он равен 1024. Это размер порции данных, которые обрабатываются в выкинутых кусках. Но я не уверен, что вызов функции быстрого преобразования Фурье, оставшийся в выкинутом коде, может привести к таким фатальным результатам...
Могу привести и весь код процедуры First целиком, но она длинная и запись (а во второй, соответственно, чтение) - лишь очень малый ее участок. И перед записью, и после я проверяю содержимое массива в отладке - не меняется.
С именами все в порядке, никаких ошибок в том, какой массив куда передавать и из какого модуля вызывать функции тоже нет.
← →
Leonid Troyanovsky © (2009-09-28 18:46) [3]
> SergejM © (28.09.09 18:25) [2]
> он равен 1024. Это размер порции данных, которые обрабатываются
Ну, а где же тот самый необходимый и достаточный код?
У мну, например, есть несколько колов времени для изощрения ума,
но мне лениво осмысливать все "..." (кроме того, их же _надо_ менять).
Надо начинать с простейших способов ловли: сначала на червя, потом
на блесну, а затем плавно переходим к .. динамиту и электроудочке [ОНР]
--
Regards, LVT.
← →
qwer_qwer (2009-09-28 19:27) [4]
> SergejM © (28.09.09 18:25) [2]
Ну так сделай простой пример со входными данными, в котором у тебя неправильно получается, чтобы посмотреть можно было.
← →
Сергей М. © (2009-09-28 19:51) [5]
> Low(Data)
С Low можно и не выёживаться - нижняя граница значения индекса у любой размерности дин.массива всегда равна 0.
> Stream.Read
> Stream.Write
Заимей полезную привычку использовать ReadBuffer и WriteBuffer.
← →
Сергей М. © (2009-09-28 19:54) [6]А уж если "вредная привычка" использовать Read и Write чем-то оправдана, то заведи другую "полезную привычку - получать и анализировать результаты выполнения этих функциональных (!!!) методов.
← →
Anatoly Podgoretsky © (2009-09-28 21:10) [7]> Сергей М. (28.09.2009 19:51:05) [5]
Тоже мы слышали про Integer и про String.
Делать надо правильно, возможно завтра это будет не так, и код с Low будет продолжать работать.
Кроме это хорошая практика писать правильно.
← →
Сергей М. © (2009-09-29 08:43) [8]
> Anatoly Podgoretsky © (28.09.09 21:10) [7]
> возможно завтра это будет не так
Сомневаюсь)
Впрочем я не настаиваю - можно и повыёживаться, на сабж это никак не влияет)
← →
SergejM © (2009-09-29 10:40) [9]Здравствуйте. Не смог вчера ответить.
Вот полный код функции, осуществляющей запись, без сокращений - скопировал все целиком из проекта.
Исходные данные, получаемые ранее и используемые в расчетах:
Nfft = 1024
NSum = 10
FDiscreet = 80 * 1e6
FreqMain = 70 * 1e6
FreqRes = 70 * 1e6
Функция ChannelFilter1.ChannelFilter на вход получает массив размерностью R и на выход передает одно значение. Для простоты можно считать, что выходное значение - первый элемент массива.procedure TCorrelationThread.ModeChannelFilter;
/// Процедура, реализующая режим работы "Фильтрация и выгрузка в файл"
var
DataFile: TFileStream;
WriteFile1: TFileStream;
WriteFile2: TFileStream;
M: Integer;
R: Integer;
N: Integer;
Fs: Extended;
Fc2: Extended;
FileChannel1Name: String;
FileChannel2Name: String;
DataArray: array of Byte;
DataSize: Integer;
cntRead: Integer;
cntWrite: Integer;
cntIndex: Integer;
DataChannel1: TReal1DArray;
DataChannel2: TReal1DArray;
ChannelFilter1: TChannelFilter;
ChannelFilter2: TChannelFilter;
tmpChannel1: ArrayOfExtended;
tmpChannel2: ArrayOfExtended;
i: Integer;
j: Integer;
k: Integer;
begin
DataFile := TFileStream.Create(MainForm.fldFileNameCorrelation,
fmOpenRead or fmShareDenyWrite);
try//DataFile := TFileStream.Create(MainForm.fldFileNameCorrelation);
FileChannel1Name := ChangeFileExt(MainForm.fldFileNameCorrelation, ".ch1");
FileChannel2Name := ChangeFileExt(MainForm.fldFileNameCorrelation, ".ch2");
WriteFile1 := TFileStream.Create(FileChannel1Name, fmCreate);
try//WriteFile1 := TFileStream.Create(FileChannel1Name, fmCreate);
WriteFile1.Position := 0;
WriteFile2 := TFileStream.Create(FileChannel2Name, fmCreate);
try//WriteFile2 := TFileStream.Create(FileChannel2Name, fmCreate);
WriteFile2.Position := 0;
//Настраиваем массивы конечных данных
SetLength(DataChannel1, Nfft);
SetLength(DataChannel2, Nfft);
SetLength(SumChannel1, Nfft);
SetLength(SumChannel2, Nfft);
//Задаем параметры для будущих канальных фильтров
Fs := 200 * 1e6;//Тактовая частота первого DDS
//Тактовая частота второго DDS в R раз меньше
Fc2 := 500 * 1e3;//Несущая частота второго DDS
M := 3;//Кол-во каскадов
R := Trunc(200 * 1e6 / fDiscreet);//Коэффициент децимации
N := 2;//Задержка гребенчатой секции
//Настраиваем массив чтения из файла
//Длина одной порции кратна кол-ву каналов - одному или двум
DataSize := 2 * (Nfft * Nsum * R) * cntChannels;
SetLength(DataArray, DataSize);
DataFile.Position := 0;
//Задаем размерность временных массивов
SetLength(tmpChannel1, R);
SetLength(tmpChannel2, R);
//Создаем канальные фильтры для первого и второго каналов
ChannelFilter1 := TChannelFilter.Create(Fs, FreqMain, Fc2,
M, R, N, MainForm.fldFileNameCoeffs);
try//ChFilter1 := TChannelFilter.Create(Fs,FreqMain,Fc2,M,R,N,MainForm.fldFileNameCoeffs);
ChannelFilter2 := TChannelFilter.Create(Fs, FreqRes, Fc2,
M, R, N, MainForm.fldFileNameCoeffs);
try//ChFilter2 := TChannelFilter.Create(Fs,FreqRes,Fc2,M,R,N,MainForm.fldFileNameCoeffs);
while (DataFile.Position <= DataFile.Size) and
MainForm.flgStatusCorrelation do
begin
//Считываем порцию файла. Если файл кончился, выходим
cntRead := DataFile.Read(DataArray[Low(DataArray)], DataSize);
if cntRead < DataSize then
Exit;
//Обнуляем массивы сумм для усредения
for i := Low(SumChannel1) to High(SumChannel1) do
begin
SumChannel1[i] := 0;
SumChannel2[i] := 0;
end;//for i := Low(SumChannel1) to High(SumChannel1) do
//Цикл по усреднениям
for i := 0 to NSum - 1 do
begin
if not MainForm.flgStatusCorrelation then
Break;
//Цикл по одному преобразованию
for j :=
0 to DataSize div (NSum * 2 * cntChannels * R) - 1 do
begin
//Цикл по тактам работы канального фильтра
for k := 0 to R - 1 do
begin
cntIndex :=
i * Nfft * R * 2 * cntChannels + j *
R * 2 * cntChannels + k * 2 * cntChannels;
tmpChannel1[k] :=
DataArray[cntIndex + 0] * 256 +
DataArray[cntIndex + 1];
if tmpChannel1[k] > 32767 then
tmpChannel1[k] := tmpChannel1[k] - 65536;
tmpChannel2[k] :=
DataArray[cntIndex + 2] * 256 +
DataArray[cntIndex + 3];
if tmpChannel2[k] > 32767 then
tmpChannel2[k] := tmpChannel2[k] - 65536;
end;//for k := 0 to R - 1 do
DataChannel1[j] := ChannelFilter1.ChannelFilter(tmpChannel1);
DataChannel2[j] := ChannelFilter2.ChannelFilter(tmpChannel2);
end;//for j := 1 to DataSize div (NSum * 2 * cntChannels) do
//Сохраняем отсчеты временной области в файлы
cntWrite :=
WriteFile1.Write(DataChannel1[Low(DataChannel1)],
SizeOf(Extended) * Length(DataChannel1));
if cntWrite <> SizeOf(Extended) * Length(DataChannel1) then
Exit;
cntWrite :=
WriteFile2.Write(DataChannel2[Low(DataChannel2)],
SizeOf(Extended) * Length(DataChannel2));
if cntWrite <> SizeOf(Extended) * Length(DataChannel2) then
Exit;
//Проводим быстрое преобразование Фурье
RealFastFourierTransform(DataChannel1, Nfft, False);
RealFastFourierTransform(DataChannel2, Nfft, False);
← →
SergejM © (2009-09-29 10:41) [10]
//Усредняем
for j := 0 to Length(DataChannel1) - 1 do
begin
SumChannel1[j] :=
SumChannel1[j] + Abs(DataChannel1[j]) / NSum;
SumChannel2[j] :=
SumChannel2[j] + Abs(DataChannel2[j]) / NSum;
end;//for i := 0 to Length(DataChannel1) do
end;//for j := 1 to Nsum do
//Выводим данные на график
Synchronize(UpdateChart);
end;//while (DataFile.Position <= DataFile.Size) and MainForm.flgStatusCorrelation do
finally//ChFilter2 := TChannelFilter.Create(Fs,FreqRes,Fc2,M,R,N,MainForm.fldFileNameCoeffs);
ChannelFilter2.Free;
end;//ChFilter2 := TChannelFilter.Create(Fs,FreqRes,Fc2,M,R,N,MainForm.fldFileNameCoeffs);
finally//ChFilter1 := TChannelFilter.Create(Fs,FreqMain,Fc2,M,R,N,MainForm.fldFileNameCoeffs);
ChannelFilter1.Free;
end;//ChFilter1 := TChannelFilter.Create(Fs,FreqMain,Fc2,M,R,N,MainForm.fldFileNameCoeffs);
finally//WriteFile2 := TFileStream.Create(FileChannel2Name, fmCreate);
WriteFile2.Free;
end; //WriteFile2 := TFileStream.Create(FileChannel2Name, fmCreate);
finally//WriteFile1 := TFileStream.Create(FileChannel1Name, fmCreate);
WriteFile1.Free;
end; //WriteFile1 := TFileStream.Create(FileChannel1Name, fmCreate);
finally//DataFile := TFileStream.Create(MainForm.fldFileNameCorrelation);
DataFile.Free;
end;//DataFile := TFileStream.Create(MainForm.fldFileNameCorrelation);
end;
Все целиком не влезло.
← →
Anatoly Podgoretsky © (2009-09-29 10:50) [11]> Сергей М. (29.09.2009 08:43:08) [8]
А я вообще то не столько о динамических массивах, сколько о привычке не использовать литералы, для указания границ. Не составит труда сделать это привычкой, а не думать прокатит или нет, а что будет завтра, а что будет если я изменю тип и так далее. Это приведет к меньшему количеству ошибок. Использование литералов наживается хесткое кодирование (Hard Coded) и является вредной, плохой привычкой.
← →
Сергей М. © (2009-09-29 10:54) [12]А в основном потоке этот код работает правильно ?
← →
SergejM © (2009-09-29 11:50) [13]В основном потоке код работает точно также, без малейших изменений.
Вот первые пять элементов записываемого массива:-0,0230583879
-94,343305337
-1424,1663944
-7650,9707988
-22555,084089
А вот перыве пять элементов считанного массива:-2,3438792137e+4353
3,6754775808e+2720
-1,3877469433e+2695
-3,6754775808e+65
7,8405128178e+3745
Причем значение 3,6754775808 повторяется во многих элементах массива, но с разным знаком и разной экспонентой. А при просмотре считанного массива в отладке поэлементно эти элементы показываются пустыми.
← →
qwer_qwer (2009-09-29 12:49) [14]
> MainForm.flgStatusCorrelation
Это переменная типа Boolean или компонент?
← →
SergejM © (2009-09-29 13:01) [15]Это Boolean.
← →
qwer_qwer (2009-09-29 13:04) [16]
> SergejM © (29.09.09 13:01) [15]
По коду пока вроде бы ничего не заметно.
У тебя проект с данными засекречен или можешь на тестирование дать?
← →
Sapersky (2009-09-29 13:12) [17]Но я не уверен, что вызов функции быстрого преобразования Фурье, оставшийся в выкинутом коде, может привести к таким фатальным результатам...
Наверняка что-то между вводом-выводом и приводит. Включи Range Check, попробуй закомментировать всё кроме операций с файлами.
← →
SergejM © (2009-09-29 13:13) [18]В принципе, там особо секретного ничего нету, но отправить могу только вечером. Правда, исходные данные, считывающиеся в tmpChannel1 и 2, точно не дам - это файл в полтора Гб:) Отсчеты функции, для тестирования использовался синус.
Хотя в других местах никаких обращений к этим данным нет, все только здесь. И в основном потоке отношение к данным имеет только вызов потока.
← →
qwer_qwer (2009-09-29 13:16) [19]
> В принципе, там особо секретного ничего нету, но отправить
> могу только вечером. Правда, исходные данные, считывающиеся
> в tmpChannel1 и 2, точно не дам - это файл в полтора Гб:
> ) Отсчеты функции, для тестирования использовался синус.
> Хотя в других местах никаких обращений к этим данным нет,
> все только здесь. И в основном потоке отношение к данным
> имеет только вызов потока.
Если есть возможность кусок данных кинуть, было бы нормально, потому что всё-таки тестировать надо на конкретных входных данных, потому что на другой информации можно и не получить того результата.
Выслать можно на palmih@gmail.com
← →
Сергей М. © (2009-09-29 13:20) [20]Не знаю.
Разбираться в этом барахле нет ни малейшего желания.
Вот демо-пример, приближенный к боевым условиям.
Пробуй и убедись сам, что FileStream ничего не портит:procedure TForm1.Button6Click(Sender: TObject);
var
src_arr, dst_arr: array of Extended;
fs: TFileStream;
i: Integer;
begin
SetLength(src_arr, 65536);
SetLength(dst_arr, 65536);
for i := Low(src_arr) to High(src_arr) do
src_arr[i] := Random;
fs := TFileStream.Create("c:\stream_test.dat", fmCreate);
try
fs.WriteBuffer(src_arr[Low(src_arr)], Length(src_arr) * SizeOf(Extended));
finally
fs.Free;
end;
fs := TFileStream.Create("c:\stream_test.dat", fmOpenRead);
try
fs.ReadBuffer(dst_arr[Low(dst_arr)], Length(dst_arr) * SizeOf(Extended));
finally
fs.Free;
end;
if CompareMem(@src_arr[Low(src_arr)], @dst_arr[Low(dst_arr)], Length(src_arr) * SizeOf(Extended)) then
ShowMessage("Содержимое оригинального и восстановленного массивов идентично")
else
ShowMessage("Содержимое оригинального и восстановленного массивов отличается");
end;
← →
SergejM © (2009-09-29 13:26) [21]> Sapersky
Range Check включен. А закомментировать там и нечего больше - если убрать функцию канального фильтра и быстрое преобразование Фурье, задача сведется к тому, что написано в самом первом сообщении. Что интересно, мусор в виде фрагментов журнала событий программы все равно попадает в результирующий файл.
> qwer_qwer
Кусок - сложно... Попробую выдрать пару первых блоков.
> Сергей М.
Что FileStream ничего не портит, я знаю. Я впервые столкнулся именно с такой ситуацией. А тестовые функции, естественно, что записали, то и считывают, я проверял.
← →
Sapersky (2009-09-29 17:35) [22]Какого типа элементы TReal1DArray?
← →
SergejM © (2009-09-29 17:49) [23]Real, одномерный массив.
Осознал свою неправоту...
Спасибо.
← →
Sapersky (2009-09-29 19:20) [24]На будущее - можно вместо SizeOf(тип) писать SizeOf(DataChannel1[0]).
Ну и разбивать неохватных размеров функции на несколько мелких, в которых подобные глупые ошибки видны с первого-второго взгляда.
← →
Leonid Troyanovsky © (2009-09-29 19:55) [25]
> Sapersky (29.09.09 19:20) [24]
Ээ..х, хотелось еще что-то пожелать автору.
Но, так и не сумел сформулировать внятно :)
Поэтому отступаю, отступаю.
--
Regards, LVT.
Страницы: 1 вся ветка
Форум: "Начинающим";
Текущий архив: 2009.11.15;
Скачать: [xml.tar.bz2];
Память: 0.55 MB
Время: 0.135 c