Главная страница
    Top.Mail.Ru    Яндекс.Метрика
Форум: "Начинающим";
Текущий архив: 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
15-1253012690
boriskb
2009-09-15 15:04
2009.11.15
С кем поделиться?


1-1208019148
TIF
2008-04-12 20:52
2009.11.15
Свойство DropDownCount в ComboBox по Vista


15-1253050186
Nic
2009-09-16 01:29
2009.11.15
Москвичи!!!


1-1224572864
Gurd
2008-10-21 11:07
2009.11.15
TXMLDocument


15-1253039747
GanibalLector
2009-09-15 22:35
2009.11.15
Самопроизвольная остановка службы "Телефония"





Afrikaans Albanian Arabic Armenian Azerbaijani Basque Belarusian Bulgarian Catalan Chinese (Simplified) Chinese (Traditional) Croatian Czech Danish Dutch English Estonian Filipino Finnish French
Galician Georgian German Greek Haitian Creole Hebrew Hindi Hungarian Icelandic Indonesian Irish Italian Japanese Korean Latvian Lithuanian Macedonian Malay Maltese Norwegian
Persian Polish Portuguese Romanian Russian Serbian Slovak Slovenian Spanish Swahili Swedish Thai Turkish Ukrainian Urdu Vietnamese Welsh Yiddish Bengali Bosnian
Cebuano Esperanto Gujarati Hausa Hmong Igbo Javanese Kannada Khmer Lao Latin Maori Marathi Mongolian Nepali Punjabi Somali Tamil Telugu Yoruba
Zulu
Английский Французский Немецкий Итальянский Португальский Русский Испанский