(Оффтоп)
Если бы я был ежом - я бы начал с выяснения вопроса, не вкусный ли это червячок? Нет? Ну хоть что-то съедобное? Тоже нет? Тема бесперспективная и абсолютно недиссертабельная.
Увы, концептуальная парадигма ежей несколько прагматична...
Давненько я не брал в руки Turbo Pascal. Хотя не так давно, как могло быть. В обозримом прошлом пришлось корректировать софт к одному старому прибору, где разработчик кое-что наврал. Любезное предоставленные им исходники компилировались только на TP, более того, исключительно на TP 5.5 (что-то он там на ассемблере вставлял хитрое). Но даже на TP, помнится, были фокусы, позволявшие брать из "кучи" более 64Кб одним куском, и даже брать из extended memory, до 4 Мб (не уверен, но возможно, его ASM-вставки как раз для этого и были, хотя, может, для фокусов с видеопамятью). Впрочем, более осмысленно идти по стопам Древних Титанов, храня такие, не влезающие в ОП, данные, во внешней памяти и подгружая по надобности (Великие Древние ухитрялись обращать матрицу размерности тысяча на тысяча при 4096 словах памяти...). И даже если хранить исходные данные в single (а они, подозреваю, снимаются с АЦП, где разрядность 12 или 14, может, 16, и можно хранить, как целочисленные отсчёты по 2 байта), то вычислять лучше всё же в double. Обращая матрицу, в частности. Маленькие ошибки могут там изрядно вывернуть обратную матрицу.
Возвращаясь к Левенбергу-Марквардту. Прежде всего - это приближение к методу Ньютона. Но упрощённое. Не требующее вычисления вторых производных от приближающей функции. Матрица вторых производных от квадратичной целевой функции (суммы квадратов невязок) включает первые производные от приближающей функции и вторые производные от неё. Упрощение в Л-М состоит в том, что вторые производные мы волевым решением приравниваем к нулю, избавляясь от
вычислений вторых производных на каждой итерации и такого же количества выписываний аналитических выражений для них. Обращаемая матрица при этом может быть вырождена или близка к вырожденной, и мы ещё более загрубляем, прибавляя к её диагонали положительные числа (одинаковые или пропорциональные диагональным элементам).
То есть нам надо уметь считать
производных по параметрам.
Если функция имеет вид
(я настаиваю на необходимости учёта фазового сдвига - даже если Вы уверены, что при
непременно
, ничто не гарантирует, что Ваш первый отсчёт, снятый с АЦП, будет соответствовать
; кроме того, использование представления в виде суммы синуса и косинуса, синфазной и квадратурной составляющей, несколько упрощает работу сравнительно с
)
то производные будут
Имея какие-то начальные приближения для параметров (лично я бы в Вашем случае частоту оценил бы через число максимумов, минимумов или пересечений ноля, а декремент затухания - проведя линейную регрессию через логарифмы максимумов и/или абсолютных величин минимумов, наклон даст Вам параметр
, а свободный член будет логарифмом
), вычисляем значения функции в точках при этих параметрах и их отклонения от наблюдаемых, составляющие вектор
, а значения производных в этих точках - матрицу Z (сержант-вычислитель Равненько из батареи к-на Очевидность подсказывает, что в программе их хранить необязательно, особенно если у Вас дефицит памяти, о векторе и матрице речь идёт лишь для удобства изложения, на практике лучше держать только матрицу
и вектор
, существенно меньшей размерности, накапливая в них значения, двигаясь по
)
Тогда поправка к значениям параметров получается, как
, но тут может быть вычислительная проблема, если матрица
будет близка к вырожденной, поэтому пользуются более устойчивой вычислительно поправкой
, где
- диагональная матрица, элементы которой либо равные малые числа, либо умноженные на малое число диагональные элементы матрицы
(насколько малые - ну, вот я увеличивал диагональные на один процент и сверх того прибавлял одну миллионную).
Скорректировав значения параметров - повторяем расчёт, следя за сходимостью.