Метод Рунге-Кутты 4го порядка Pascal
Здравствуйте. Нужен взгляд человека понимающего Pascal. Расчёт уравнений двигателя постоянного тока по второму закону Киргофа методом Рунге-Кутты 4го порядка, кратко о нём: 1.Закон Киргофа для ДПТ: U=I*R+L*∂I/∂t+ω*Ce; I*Cm=J*∂ω/∂t+Mст далее уравнения приводятся к форме задачи Коши: ∂I/∂t=(U-I-R-ω*Ce)/L ∂ω/∂t=(I*Cm-Mст)/J далее уравнения дифференцируют для удобства записи (на шаге k+1): Ik+1=Ik+Δt*(U-Ik-R-ωk*Ce)/L ωk+1=ωk+Δt*(Ik*Cm-Mст)/J и собственно сам метод Рунге-Кутты k11 = dt*((U-Ik*R-ωk*Ce)/L) k21 = dt*((U-Ik*R-ωk*Ce)/L) + k11/2 k31 = dt*((U-Ik*R-ωk*Ce)/L) + k21/2 k41 = dt*((U-Ik*R-ωk*Ce)/L) + k31/2
k12 = dt*((Ik*Cm-Mc)/J) k22 = dt*((Ik*Cm-Mc)/J) + k12/2 k32 = dt*((Ik*Cm-Mc)/J) + k22/2 k42 = dt*((Ik*Cm-Mc)/J) + k32/2 тогда Ik=(Ik+1/6*(k11+k21*2+k31*2+k41)) ωk=(ωk+1/6*(k12+k22*2+k32*2+k42))
Теперь пытаюсь осуществить этот метод на Pascal. В 20 строке вещественное переполнение, могут быть и другие ошибки, поэтому и прошу вашей помощи.
var i , n : integer ;
Ua , Ra , La , Cef , Cmf , Js , Mc : real ;
fi_ , fw_ : array [ 0 .. 1000 ] of real ;
k1 , k2 , k3 , k4 , k11 , k21 , k31 , k41 , dt , t , tmax : real ;
function difurI ( Ua , fi_ , Ra , Cef , fw_ , La : real ) : real ;
difurI := ( Ua - fi_ * Ra - Cef * fw_ ) / La;
function difurW ( Cmf , fi_ , Mc , Js : real ) : real ;
difurW := ( Cmf * fi_ - Mc ) / Js;
write ( 'Calculating Runge-Kutta4. ' ) ;
while ( n< 100 ) do begin
k1 := dt * difurI ( t + dt , fi_ [ n ] , fw_ [ n ] , Ua , Ra , La ) ;
k2 := dt * ( difurI ( t + dt , fi_ [ n ] , fw_ [ n ] , Ua , Ra , La ) + k1 / 2 ) ;
k3 := dt * ( difurI ( t + dt , fi_ [ n ] , fw_ [ n ] , Ua , Ra , La ) + k2 / 2 ) ;
k4 := dt * ( difurI ( t + dt , fi_ [ n ] , fw_ [ n ] , Ua , Ra , La ) + k3 ) ;
k11 := dt * difurW ( t + dt , fi_ [ n ] , Mc , Js ) ;
k21 := dt * ( difurW ( t + dt , fi_ [ n ] , Mc , Js ) + k11 / 2 ) ;
k31 := dt * ( difurW ( t + dt , fi_ [ n ] , Mc , Js ) + k21 / 2 ) ;
k41 := dt * ( difurW ( t + dt , fi_ [ n ] , Mc , Js ) + k31 ) ;
t := t + dt; inc ( n ) ;
fi_ [ n ] := fi_ [ n - 1 ] + ( k1 + k2 * 2 + k3 * 2 + k4 ) / 6 ;
fw_ [ n ] := fw_ [ n - 1 ] + ( k11 + k21 * 2 + k31 * 2 + k41 ) / 6 ;
end ; writeln ( 'Done!' ) ;
begin clrscr; assign ( ff , 'n.txt' ) ; rewrite ( ff ) ;
tmax := 100.0 ; dt := 0.001 ;
for i := 1 to n do begin fi_ [ 0 ] := 0.0 ; END ; fi_ [ 1 ] := 999 ;
T := 0.0 ; writeln ( ff , ' (t) (i) (w);' ) ;
while ( t < = tmax ) do begin difurI ( t + dt , fi_ [ n ] , fw_ [ n ] , Ua , Ra , La ) ; end ; begin difurW ( t + dt , fi_ [ n ] , Mc , Js ) ; end ; T := T + dt; write ( ff , T : 12 : 5 ) ; for i := 1 to n do begin write ( ff , fi_ [ n ] : 12 : 5 ) ; end ; begin write ( ff , fw_ [ n ] : 12 : 5 ) ; end ;
writeln ( ff , '' ) ; end ;
15 ответов
Pascal ABC не знает double
Это зачем такое
for i := 1 to n do begin fi_ [ 0 ] := 0.0 ; END ;
for i := 1 to n do begin write ( ff , fi_ [ n ] : 12 : 5 ) ; end ;
Это зачем такое
for i := 1 to n do begin fi_ [ 0 ] := 0.0 ; END ;
for i := 1 to n do begin write ( ff , fi_ [ n ] : 12 : 5 ) ; end ;
что бы результаты вычислений записывались в файл
Pascal ABC не знает double
Попробуйте тип extended.
1) В основной программе La не инициализирована. Видимо по умолчанию инициализируется нулем или чем-то очень близким. При первом же вызове diffurI происходит деление на ноль.
2) Это что за ересь? Что это код, по вашему, должен делать?
странно,может я не там использую их
1) В основной программе La не инициализирована. Видимо по умолчанию инициализируется нулем или чем-то очень близким. При первом же вызове diffurI происходит деление на ноль.
2) Это что за ересь? Что это код, по вашему, должен делать?
1) как её инициализировать? 2)Код должен дифференцировать уравнения, пока время не достигнет максимального
1) В основной программе La не инициализирована. Видимо по умолчанию инициализируется нулем или чем-то очень близким. При первом же вызове diffurI происходит деление на ноль.
2) Это что за ересь? Что это код, по вашему, должен делать?
1) как её инициализировать? 2)Код должен дифференцировать уравнения, пока время не достигнет максимального
1) Написать La := <число> Это вы уж сами думайте, какое там число должно быть в соответствии с методом
2) Обратите внимание, difurI будет выполняться в цикле, но difurW находится уже после цикла и выполнится только один раз. Поизучайте синтаксис паскаля.
1) Написать La := <число> так там написано La:=0.01
2)В цикле это так?
while (t <= tmax) do begin difurI(t+dt,fi_[n],fw_[n],Ua,Ra,La);
Ага, вот оно как. А зачем еще один begin перед clrscr ?
Второй вариант правильный. А отступы в паскале вообще никакого значения не имеют, можно хоть всю программу в одну строчку написать.
можно и без него. Всё равно вещественное переполнение в строке difurI:=(Ua-fi_*Ra-Cef*fw_)/La;
while (t <= tmax) do begin difurI(t+dt,fi_[n],fw_[n],Ua,Ra,La);
Вот здесь эти две команды будут выполняться в цикле. Но все последующие (которые после end) - уже вне цикла. Это не может быть правильным, так как в этих двух строках не изменяются вообще никакие переменные и цикл будет бесконечным. Возвращаемые значения difurI и difurW также остаются неиспользованными.
end перед close(ff) вовсе не означает конец цикла, как вы могли от него ожидать, а является парным к begin перед clrscr
Ну, батенька, это полный бред сивой кобылы. Что вы написали в исходном коде. Если отформатировать нормально код, то получится:
Program RK_4; uses crt; var i , n : integer ; Ua , Ra , La , Cef , Cmf , Js , Mc : real ; //Cef, Cmf - не используются fi_ , fw_ : array [ 0 .. 1000 ] of real ; k1 , k2 , k3 , k4 , k11 , k21 , k31 , k41 , dt , t , tmax : real ; ff : text;
function difurI ( Ua , fi_ , Ra , Cef , fw_ , La : real ) : real ; begin difurI := ( Ua - fi_ * Ra - Cef * fw_ ) / La; end ;
function difurW ( Cmf , fi_ , Mc , Js : real ) : real ; begin difurW := ( Cmf * fi_ - Mc ) / Js; end ;
BEGIN Ua := 220.0 ; Ra := 0.03 ; Cef := 0.2 ; //не используется Cmf := 1.2 ; //не используется La := 0.01 ; Js := 1.0 ; Mc := 1000.0 ; fi_ [ 0 ] := 0 ; fw_ [ 0 ] := 0 ; t := 0 ; dt := 0.001 ; n := 0 ;
write ( 'Calculating Runge-Kutta4. ' ) ; while ( n < 100 ) do begin // почему до 100, а не до 1000, если массивы объявлены так: fi_, fw_: array [0 .. 1000] k1 := dt * difurI ( t + dt , fi_ [ n ] , fw_ [ n ] , Ua , Ra , La ) ; k2 := dt * ( difurI ( t + dt , fi_ [ n ] , fw_ [ n ] , Ua , Ra , La ) + k1 / 2 ) ; k3 := dt * ( difurI ( t + dt , fi_ [ n ] , fw_ [ n ] , Ua , Ra , La ) + k2 / 2 ) ; k4 := dt * ( difurI ( t + dt , fi_ [ n ] , fw_ [ n ] , Ua , Ra , La ) + k3 ) ; k11 := dt * difurW ( t + dt , fi_ [ n ] , Mc , Js ) ; k21 := dt * ( difurW ( t + dt , fi_ [ n ] , Mc , Js ) + k11 / 2 ) ; k31 := dt * ( difurW ( t + dt , fi_ [ n ] , Mc , Js ) + k21 / 2 ) ; k41 := dt * ( difurW ( t + dt , fi_ [ n ] , Mc , Js ) + k31 ) ; t := t + dt; inc ( n ) ; fi_ [ n ] := fi_ [ n - 1 ] + ( k1 + k2 * 2 + k3 * 2 + k4 ) / 6 ; fw_ [ n ] := fw_ [ n - 1 ] + ( k11 + k21 * 2 + k31 * 2 + k41 ) / 6 ; end ; writeln ( 'Done!' ) ;
begin // зачем тут begin и соответственно внизу предпоследний end clrscr; // сперва выводим на экран сообщения, и не давая прочитать пользователю, сразу стираем . - бред. assign ( ff , 'n.txt' ) ; rewrite ( ff ) ;
tmax := 100.0 ; dt := 0.001 ;
for i := 1 to n do begin fi_ [ 0 ] := 0.0 ; // 100 раз присвоить fi_[0] нуль %) END ; fi_ [ 1 ] := 999 ; //в цикл, если надо, не попало
t := 0.0 ; //в цикл, если надо, не попало writeln ( ff , ' (t) (i) (w);' ) ;
while ( t < = tmax ) do begin difurI ( t + dt , fi_ [ n ] , fw_ [ n ] , Ua , Ra , La ) ; // функция не изменяет параметров, значение ничему не присваивается - нафиг тогда она?? end ;
begin difurW ( t + dt , fi_ [ n ] , Mc , Js ) ; //в цикл, если надо, не попало, + см выше по ф-ции difurI end ; t := t + dt; //в цикл, если надо, не попало write ( ff , t : 12 : 5 ) ; //в цикл, если надо, не попало for i := 1 to n do begin write ( ff , fi_ [ n ] : 12 : 5 ) ; end ;
begin write ( ff , fw_ [ n ] : 12 : 5 ) ; //в цикл, если надо, не попало end ;
writeln ( ff , '' ) ; end ;
, а разобраться нормально с кодом. PS скачай Notepad++ и выбери Синтаксис-Pascal. Он тебе покажет, что к чему относиться.
PSPS Кстати, забыл самое главное:
tmax := 100.0; dt := 0.001; . t := 0.0; . while (t <= tmax) do begin difurI(t + dt, fi_[n], fw_[n], Ua, Ra, La); end;
begin difurW(t + dt, fi_[n], Mc, Js); end; t := t + dt;
while (t <= tmax) do - будет бесконечным. Т.к. t наращивается вне цикла.