среда, 4 декабря 2019 г.

Спектр опалесценции

Опалесценция коллоидных частиц — очень красивое явление природы. Посмотрев на просвет пробирку с опалесцирующими частицами мы увидим, что раствор как будто окрашен, однако, это не так — сами частицы состоят из вещества не поглощающего свет. Всё дело в том, как наночастицы рассеивают излучение.

Раз мы наблюдаем цвет, и это не иллюзия, то возможно записать спектр поглощения коллоида. Затем, полученный спектр вычислим теоретически, чтобы убедиться в том, как теория рассеяния света работает в этом случае. Для расчётов нам понадобится теория Густава Ми. Для расчётов я использовал язык программирования Julia и модуль MieScatter.

Нужный модуль штатно подсоединяется к набору пакетов Julia:

pkg> add https://github.com/dronir/MieScatter.jl
после чего мы можем с ним работать.
using MieScatter
const nm = 0.001
const nλ = 1000

particle_area = π*(1.0nm)^2
x = size_parameter(1.0nm, 400nm)

S, Qsca, Qext, Qback = compute_mie(x, 2.0, [0.0])
σ_sc_mie = Qsca*particle_area

Qsca_rayleigh(λ, α, m) = 2/3π*λ^2*α^6*((m^2 - 1)/(m^2 + 2))^2
σ_sc_ray = Qsca_rayleigh(400nm, x, 2.0)
Здесь мы проверили, что в предельном случае рассеяние Ми переходит в рэлеевское рассеяние. Переходим к расчёту спектра опалесценции 1500 нм частиц полистирола в воде:
using MieScatter
# индексы преломления воды и полистирола 
# взяты с https://refractiveindex.info/
ref_indx_core(λ) = sqrt(1 + 1.4435λ^2/(λ^2 - 0.020216))
ref_indx_medium(λ) = sqrt(1.46659 + 0.293555*λ^2/(λ^2-0.0155008)) # 1.3378

const nm = 0.001
const nλ = 1000

const r_NP = 1500nm/2

λs0 = LinRange(250nm, 1000nm, nλ)

λs  = λs0 ./ ref_indx_medium.(λs0)
xs  = size_parameter.(r_NP, λs)

Qexts = zeros(nλ)

for i=1:nλ
      n_rel = ref_indx_core(λs0[i])/ref_indx_medium(λs0[i])
      S, Qscas, Qexts[i], Qback = compute_mie(xs[i], n_rel, [0.0])
end

using Printf
for i=1:nλ
       Printf.@printf("%f %f\n",λs0[i]/nm, Qexts[i])
end
Вывод спектра осуществляется командой
julia Mie-PS-latex.jl > PS-1500nm.data
Затем, файл PS-1500nm.data отрисовываем в программе Gnuplot. Результат представлен на картинке ниже. Фиолетовая кривая — наш расчёт, бирюзовая — экспериментальный спектр.

четверг, 31 октября 2019 г.

Определение ширины запрещенной зоны

В этой заметке мы разберем метод определения ширины запрещенной зоны полупроводника методом Tauc plot Для этого нам понадобится коллоид наночастиц Cu2O. Запишем его спектр оптического поглощения.
Пересчитаем его в координатах $h\nu$ и $(\alpha h\nu)^{1/r}$ с помощью Gnuplot
Всё это делается следующими командами Gnuplot:
plot [200:800] 'Cu2O-UV' u 1:2 w l
f(x) = a*x + b
fit [2.6:5.4] f(x) 'Cu2O-UV' u (1239.84/$1):(($2*1239.84/$1)**2.0) via a, b
plot [1.4:5.5][0:] 'Cu2O-UV'' u (1239.84/$1):(($2*1239.84/$1)**2.0) w l, f(x)
Мы вычислили ширину запрещенной зоны для прямого (оптического) разрешенного перехода ($1/r=2$), т.е. direct allowed transitions Которая в нашем случае составила для наночастиц Cu2O величину примерно 2.7 эВ. Исходный спектр наночастиц приведён ниже.
УФ-спектр поглощения наночастиц Cu2O в воде
#Wavelength (nm), Abs           
800.0065308     0.01255773753           
799.0047607     0.01218323782   
798.0027466     0.01219668239   
797.0001831     0.01253567543   
795.9973755     0.01253399719   
794.9940796     0.01296904404   
793.9903564     0.01214655396   
792.9862061     0.01250969805   
792.0164185     0.0135039594    
791.0114746     0.01286672056   
790.0062256     0.01290997211   
789.0004883     0.01305279788   
787.9944458     0.0125807859    
786.987915      0.0130309239    
786.0158081     0.01278518885   
785.0085449     0.01281648781   
784.0008545     0.01323791314   
782.9927979     0.01318590343   
781.984375      0.01365568861   
781.0102539     0.01331232395   
780.0010986     0.01353285369   
778.991394      0.01332254708   
778.0162354     0.01390814502   
777.0058594     0.01335658133   
775.9950562     0.01409311779   
774.9838257     0.0137343118    
774.0071411     0.01386717241   
772.9951172     0.01411656942   
771.9828491     0.01425818726   
771.0049438     0.01449209731   
769.9918823     0.01421974879   
769.0133667     0.01449563075   
767.9994507     0.01421009284   
766.9851685     0.01431409828   
766.0054321     0.01427431777   
764.9904175     0.01469930355   
764.0100098     0.01491946634   
762.9942017     0.01480291598   
762.0131226     0.0144878421    
760.996521      0.01485190634   
760.0147095     0.01523965318   
758.9973755     0.01526694745   
758.0147705     0.01522278972   
756.9967041     0.01474587061   
756.0134277     0.0149769634    
754.9945679     0.01559713017   
754.010498      0.0152889872    
752.9909668     0.01539904345   
752.0061646     0.01548933052   
750.9858398     0.01522563118   
750.0003662     0.01579884999   
749.0144653     0.01544944197   
747.993042      0.01573120616   
747.0064697     0.01572175883   
745.984314      0.01584682427   
744.9970093     0.01605798118   
744.0093994     0.01611122303   
742.986084      0.01628071629   
741.9977417     0.01606273651   
741.0090332     0.01629778184   
739.9846191     0.01623089425   
738.9951782     0.01637296006   
738.0054932     0.01652152836   
737.0153809     0.01672308519   
735.989563      0.01651633717   
734.9987183     0.01687960327   
734.0075073     0.01710722968   
733.0160522     0.01714875177   
731.9887085     0.0169135686    
730.996521      0.01691623218   
730.0039673     0.01719504409   
729.0110474     0.01724174619   
727.9822998     0.01751605235   
726.9887085     0.01720902324   
725.994751      0.0174853541    
725.0004883     0.01768118702   
724.0057983     0.01791956648   
723.0108643     0.01785682328   
722.0155029     0.01784937829   
720.984314      0.01792501472   
719.9883423     0.01779915951   
718.9919434     0.01790211163   
717.9953003     0.01830177382   
716.99823       0.01826988719   
716.0009155     0.01829729229   
715.0031738     0.01874212548   
714.005127      0.01859150082   
713.0067749     0.01836093515   
712.0081177     0.01848198287   
711.0090332     0.01882881299   
710.0096436     0.01875728928   
709.0098877     0.01897573471   
708.0098267     0.01897446252   
707.0094604     0.01919783279   
706.008728      0.01928141713   
705.0077515     0.01934753172   
704.0062866     0.0195805449    
703.0045776     0.01946081594   
702.0025635     0.01961572282   
701.000061      0.01967197657   
699.9974365     0.02019479685   
698.9943848     0.02007281035   
697.9910278     0.0199986957    
696.9873047     0.02028426901   
695.9832764     0.02009731904   
695.0147705     0.02053797618   
694.0101318     0.02018847875   
693.005127      0.02062222548   
691.9997559     0.0205725804    
690.9940796     0.02087914571   
689.9881592     0.02096962743   
689.0177612     0.02111510187   
688.0111694     0.02122754231   
687.0041504     0.02149066888   
685.9968872     0.02144301869   
684.9893188     0.02157159336   
684.017395      0.02141171694   
683.0091553     0.02139314264   
682.0006714     0.02195215598   
680.9916992     0.02219744213   
679.982605      0.02200016193   
679.0090942     0.02228021435   
677.9992676     0.02210335247   
676.9890747     0.02252617665   
676.0147705     0.02261212096   
675.0039673     0.02257498167   
673.9928589     0.02293606661   
673.0177002     0.02245635912   
672.0059204     0.02308834344   
670.9938965     0.02286119014   
670.0176392     0.02327197045   
669.0050659     0.02328958549   
667.9920654     0.02335617878   
667.0149536     0.02344786189   
666.0014038     0.02376376279   
664.9874878     0.0238016881    
664.0095215     0.02386964485   
662.9949951     0.02396050468   
662.0164795     0.02422679774   
661.0012817     0.02447854728   
659.9858398     0.02476848103   
659.0063477     0.02478029206   
657.9902954     0.02475190163   
657.0101929     0.02486309409   
655.9935913     0.02503217198   
655.0129395     0.02538087033   
653.9956665     0.02541234903   
653.0144653     0.02567500249   
651.996582      0.0256686043    
651.0147705     0.02554625086   
649.9962769     0.02593149617   
649.013855      0.0260120444    
647.994812      0.02634021454   
647.0117798     0.0264705494    
645.9921875     0.02660194412   
645.0084839     0.02649333142   
643.9883423     0.02697256394   
643.0042114     0.02722307108   
641.9832764     0.0270539932    
640.9985962     0.02723329701   
640.0135498     0.02735973895   
638.9918213     0.02774118818   
638.0062866     0.02797165327   
636.9839478     0.02804664336   
635.9977417     0.02823406458   
635.0114136     0.02833410539   
633.9881592     0.02852886543   
633.0011597     0.02862814441   
632.013916      0.02882809937   
630.9898682     0.02895542234   
630.0020142     0.02926336601   
629.013916      0.02936372906   
627.9889526     0.02950569615   
627.0002441     0.02971877903   
626.0113525     0.02983202785   
624.9855347     0.03016354144   
623.9960327     0.03013365902   
623.0062256     0.03032914363   
622.0162354     0.03061634302   
620.9892578     0.03083049878   
619.9986572     0.0308754947    
619.0077515     0.03108630143   
618.0166626     0.03135196492   
616.9885254     0.03150791675   
615.9968262     0.03184898943   
615.0048828     0.03189952299   
614.0126953     0.03209290653   
612.9834595     0.03255640343   
611.9906616     0.03241039068   
610.9976196     0.0326844044    
610.0043335     0.03288466856   
609.0106812     0.0332332775    
608.0168457     0.03345035017   
606.9859619     0.03378813714   
605.9915161     0.03373643383   
604.9969482     0.0341822803    
604.0020142     0.03433927894   
603.0068359     0.03444056958   
602.0113525     0.03497575969   
601.015686      0.03504571319   
599.9827881     0.03524816781   
598.9865112     0.03563725948   
597.9900513     0.03583759815   
596.9932251     0.0359008275    
595.9961548     0.03613237664   
594.9989014     0.03643836081   
594.0014038     0.03700096905   
593.00354       0.03720205277   
592.0054321     0.03721034154   
591.0071411     0.03741646186   
590.0084839     0.03777129948   
589.0096436     0.03812450171   
588.0105591     0.038303148     
587.0111694     0.03862968087   
586.0115356     0.03893264383   
585.0116577     0.03915283829   
584.0115356     0.03956064582   
583.0111694     0.03984799981   
582.010498      0.03996400535   
581.0095825     0.04025168717   
580.0084229     0.0405857414    
579.006958      0.04098618776   
578.0053101     0.04119595885   
577.0033569     0.04158967361   
576.0012207     0.04182969034   
574.9987793     0.04217999429   
573.9960938     0.04247548431   
572.9931641     0.04265424609   
571.9899292     0.04301890731   
570.9865112     0.04338707402   
569.9828491     0.04367044941   
569.0160522     0.04403888434   
568.0119019     0.04455630109   
567.0074463     0.04462853074   
566.0027466     0.04513696954   
564.9978638     0.04567059129   
563.9926758     0.04583427683   
562.9872437     0.04619689286   
561.9816284     0.04647484794   
561.0129395     0.0469233878    
560.0068359     0.04736566544   
559.0003662     0.04789697379   
557.9937744     0.04808093235   
556.9868774     0.04858992994   
556.0170288     0.04902373627   
555.0095825     0.0492442362    
554.0020142     0.04967173189   
552.9942017     0.05007870495   
551.986145      0.05037406459   
551.0151367     0.05099974573   
550.0065308     0.05135813728   
548.9977417     0.05164206773   
547.9887085     0.05228476226   
547.0167236     0.05259138718   
546.0073242     0.05308455229   
544.9974365     0.05347757787   
543.9874878     0.05408833548   
543.0147095     0.0545225963    
542.0042114     0.05512821674   
540.9934692     0.05529350415   
539.9825439     0.05591556802   
539.0088501     0.05649780855   
537.9974365     0.05688458309   
536.9857178     0.05744938925   
536.0112915     0.05786782876   
534.9992676     0.05855218321   
533.9869385     0.05906975642   
533.0118408     0.05951721966   
531.9990234     0.06014343724   
530.9859619     0.06079196557   
530.0102539     0.06130618975   
528.9965270     0.0624561049    
527.0066528     0.06295644492   
525.9924316     0.06359872967   
525.015564      0.06417462975   
524.0010376     0.06487485766   
522.986145      0.06550232321   
522.008667      0.06605187804   
520.9933472     0.0668611154    
520.0154419     0.06744816154   
518.9996338     0.06822665781   
517.9837036     0.06887964159   
517.0050659     0.06944867224   
515.9887085     0.07041721791   
515.0097046     0.0709015578    
513.9927368     0.07171079516   
513.0134277     0.07245271653   
511.9960632     0.07326298207   
511.0162048     0.07398687303   
509.9984131     0.07491657138   
509.018158      0.07569009811   
508.0000305     0.07657518983   
506.9815674     0.07765888423   
506.0006714     0.07825426757   
504.981781      0.0792080611    
504.0004883     0.08016499132   
502.9811707     0.08133704215   
501.9994507     0.08223600686   
501.0174866     0.08315198869   
499.9975281     0.084142223     
499.0151978     0.08521377295   
497.9947815     0.08622671664   
497.0120239     0.08736762404   
495.991272      0.08837035298   
495.0080872     0.08980119973   
493.9868774     0.09094394743   
493.0032043     0.09230054915   
491.9815674     0.09336166084   
490.9975891     0.09461408108   
490.0133667     0.09621798247   
488.9911499     0.09751337767   
488.0064697     0.09872315079   
486.9838257     0.1001481488    
485.9988403     0.1017531902    
485.0135498     0.1032905579    
483.9902649     0.1047433689    
483.0046387     0.1062881351    
482.0187683     0.108003296     
480.9949036     0.1098260134    
480.008667      0.1117500216    
478.984314      0.1135132164    
477.9977112     0.1153559536    
477.0108948     0.1173111126    
475.9859619     0.1194883958    
474.9987183     0.1213757768    
474.0112915     0.1235824302    
472.9858093     0.1256736517    
471.9979553     0.127500087     
471.0099792     0.1299407184    
469.9837952     0.1322698444    
468.9954834     0.1343719959    
468.006897      0.136580646     
467.018158      0.1388962567    
465.9912109     0.1415064037    
465.0020447     0.1440091878    
464.0127563     0.1463292092    
462.9851379     0.1490950286    
461.9954224     0.1514825821    
461.0054932     0.1537575722    
460.0154419     0.1561527997    
458.9870911     0.1589318961    
457.9966125     0.1613219082    
457.0059814     0.1637553275    
456.0151367     0.1664267927    
454.9860229     0.1690883189    
453.994812      0.1714437157    
453.0033875     0.1735293865    
452.0117798     0.1763572991    
450.981842      0.1790753901    
449.9898987     0.1813954711    
448.9977417     0.1837027669    
448.0054626     0.1859440804    
447.0129395     0.1882166415    
445.9820862     0.1905896664    
444.9892273     0.1927859038    
443.9961243     0.1947074085    
443.0028687     0.1970398128    
442.009491      0.1992138922    
441.0158691     0.2012152523    
439.9838867     0.2031671405    
438.9899292     0.2050726712    
437.9957886     0.2070022821    
437.0014648     0.2088708282    
436.0069885     0.2107375115    
435.0123291     0.2125622183    
434.0174561     0.2143542022    
432.9841309     0.2159832418    
431.9889221     0.2178158909    
430.9935608     0.2195139378    
429.9979858     0.220932737     
429.0022583     0.2225941569    
428.0063477     0.2242125869    
427.0102844     0.2257309854    
426.0139771     0.2276166826    
425.0175781     0.2288288921    
423.982666      0.2304789126    
422.9858398     0.2320256829    
421.9888916     0.2335039675    
420.9917908     0.2351029813    
419.9945068     0.2363699824    
418.9969788     0.2378083616    
417.9993286     0.2392594665    
417.0015564     0.2407241017    
416.0036011     0.2423740774    
415.0054321     0.2437465191    
414.0071106     0.2451779395    
413.0086365     0.246764943     
412.0099792     0.2483499199    
411.0111389     0.2500455678    
410.0121765     0.2512839437    
409.013031      0.2528226078    
408.0136719     0.2545606494    
407.0142212     0.2561466098    
406.0145569     0.2576802075    
405.0147705     0.2591069043    
404.0147705     0.2607487738    
403.0146179     0.2624567449    
402.0143433     0.2641362548    
401.0138245     0.2659447491    
400.0132141     0.2674967051    
399.0124207     0.2694134712    
398.0114441     0.2710880041    
397.0103149     0.2728696764    
396.0090637     0.2747395039    
395.0075989     0.2765857279    
394.006012      0.2783995569    
393.0042419     0.2802259624    
392.0023193     0.2822113633    
391.0002441     0.284006536     
389.9979858     0.2859140635    
388.995575      0.2875141501    
387.9930115     0.289519608     
386.9902954     0.2915418446    
385.9874268     0.293518573     
384.9844055     0.2952962816    
383.9812012     0.2969563305    
383.0164795     0.2988653183    
382.0129395     0.3008533716    
381.0093384     0.3028095365    
380.0054932     0.3045793474    
379.0015564     0.306284368     
377.9974365     0.3083942533    
376.9931641     0.3102215528    
375.988739      0.3120807409    
374.9841614     0.3139910102    
374.0180969     0.3155599535    
373.0132446     0.3174476624    
372.0082092     0.3195008636    
371.0030518     0.3214408755    
369.9977112     0.3231185675    
368.9922485     0.3245065808    
367.9866028     0.3264555335    
366.980835      0.3282990754    
366.0136108     0.3302026391    
365.0075378     0.3315865397    
364.0013123     0.3329133391    
362.9949646     0.3345375359    
361.9884338     0.3360665441    
360.981781      0.3373195529    
360.0137024     0.3387392163    
359.0067749     0.3398883939    
357.9996948     0.3413062096    
356.9924316     0.3423948288    
355.9850769     0.343518883     
355.0162659     0.3446127176    
354.008606      0.3455503881    
353.0007935     0.3462450802    
351.9928589     0.3474620581    
350.9847412     0.3481847942    
350.0152588     0.3487376571    
349.0069275     0.3493920267    
347.9983826     0.3500837684    
346.9897461     0.3506371379    
345.9809265     0.3509123623    
345.0108337     0.3514224589    
344.0017395     0.3517419696    
342.9925232     0.3519333899    
341.9831543     0.3521957397    
341.0124817     0.3520888388    
340.0028687     0.3525113463    
338.993103      0.3524944186    
337.9832153     0.3527641892    
337.0120239     0.3526249826    
336.0018311     0.3524917662    
334.9915466     0.3524803817    
333.9810791     0.3526809216    
333.0093689     0.3527384698    
331.9986877     0.3528383374    
330.9878235     0.3529728055    
330.0157471     0.3528104722    
329.0046082     0.3530774117    
327.9933777     0.3532334864    
326.9819946     0.3536608815    
326.0093689     0.3537948132    
324.9977722     0.3541184962    
323.9859924     0.3545587361    
323.013031      0.35516271      
322.0010071     0.3558099568    
320.9888611     0.3561401963    
320.0154724     0.3569248021    
319.0030823     0.3578017354    
317.9905396     0.3586034179    
317.0168152     0.3594931662    
316.0040283     0.3607389927    
314.9911194     0.3619912267    
314.0169983     0.3630000055    
313.0038147     0.3642749786    
311.9905396     0.3657827973    
311.0161133     0.3671698272    
310.002533      0.3687185347    
308.9888916     0.3702765703    
308.0140686     0.3719595969    
307.0001221     0.3737115562    
305.986084      0.3754031062    
305.0108948     0.3773103058    
303.9966431     0.3790136874    
302.9821777     0.3810620904    
302.0066833     0.3829732239    
300.9920654     0.3850145936    
300.0163269     0.3869015574    
299.0014038     0.3886863291    
297.9863892     0.3905514181    
297.0103149     0.392455101     
295.9950562     0.3941937387    
295.0187378     0.3958979547    
294.0032654     0.39745         
292.9876404     0.3990533054    
292.0109863     0.400521636     
290.9951172     0.4017695785    
290.018219      0.4031996727    
289.0021667     0.4043375552    
287.9859924     0.4051796496    
287.0087891     0.4060237408    
285.9923706     0.4067691565    
285.0149231     0.4074435532    
283.9982605     0.4077593386    
282.9815369     0.4082051218    
282.0037842     0.4085300565    
280.9867859     0.4087808132    
280.0087891     0.4089276791    
278.9915771     0.4090313315    
278.0133972     0.4090982676    
276.9959717     0.408959657     
276.0175171     0.4092032313    
274.9998779     0.4090636373    
273.9821167     0.4088105559    
273.003418      0.408798933     
271.9854126     0.4085874557    
271.0064697     0.4084347486    
269.9883118     0.4084289074    
269.0091553     0.4083512127    
267.9907532     0.4082684815    
267.0113831     0.4083483219    
265.9927673     0.4084282219    
265.0132141     0.4082923532    
263.9943848     0.4081104696    
263.0146179     0.4081658721    
261.995575      0.4083960652    
261.015625      0.407962054     
259.9963684     0.4083657265    
259.0162048     0.4085684419    
257.9967346     0.4084689021    
257.0163879     0.4084433019    
255.9967346     0.4083847404    
255.0161743     0.408451438     
253.9962921     0.4080747664    
253.015564      0.4079721868    
251.9955139     0.4079269469    
251.0145416     0.4079419374    
249.9942627     0.4074141085    
249.0131531     0.4074421227    
247.992691      0.4073877633    
247.0113525     0.4077083468    
245.9906769     0.4075018167    
245.0091858     0.4075708985    
243.988327      0.4076016247    
243.0066071     0.4079410434    
241.9855499     0.4086118937    
241.0036774     0.4093708396    
239.9824219     0.4102807343    
239.000351      0.4111827612    
238.0182037     0.4121513069    
236.9966736     0.4134986699    
236.014328      0.4148510695    
234.9925842     0.4160552025    
234.0101013     0.4172031879    
232.9881897     0.4180876911    
232.0054779     0.4191904366    
230.9833679     0.4201743007    
230.0005035     0.4204597771    
229.0175323     0.4209492803    
227.9951935     0.4212741852    
227.0120697     0.4207710922    
225.9895172     0.4205128253    
225.0061798     0.4195667207    
223.9834747     0.4186830223    
222.9999695     0.4173018038    
222.0164185     0.4158354998    
220.9934235     0.4143491983    
220.0096893     0.4120408297    
218.9865112     0.4099385142    
218.0026398     0.4071815014    
217.018631      0.4044723809    
215.995224      0.4015476406    
215.0110474     0.3987031579    
213.9874725     0.3956611753    
213.0031433     0.3923184872    
212.0187531     0.3889003098    
210.9948883     0.385818392     
210.0103607     0.3819032907    
208.9863281     0.3789326847    
208.0015869     0.3753180206    
207.0168152     0.3720583916    
205.9925385     0.3696687222    
205.0075989     0.3671162128    
203.9831543     0.3650553524    
202.9980621     0.363494426     
202.0128632     0.3625882268    
200.9881897     0.362157464     
200.0028687     0.3625331521    

среда, 30 октября 2019 г.

Динамическое светорассеяние

Суть эксперимента

Определение размеров частиц в коллоиде методом динамического рассеяния света основан на анализе флуктуаций интенсивности рассеянного света в разные моменты времени [1, 2]. При облучении лазером случайно-неоднородных объектов, таких как шероховатая поверхность или прозрачная среда с флуктуирующим в пространстве показателем преломления, возникает спекл-структура (от англ. speckle -- крапинка, пятнышко).
Изменение длины волны фотона, рассеянного коллоидной частицей или молекулой, связано с эффектом Доплера: фотон от движущейся навстречу детектору частицы имеет более короткую волну, чем от частицы уходящей от детектора. Рассеянные от частиц фотоны с длинами волн $\lambda\pm\Delta$ случайным образом дают максимумы и минимумы при интерференции образуя на экране спеклы. Изменения в интерференционной картине связаны с броуновским движением частиц, причём спад интенсивности происходит как из-за несовпадения длин волн (разные направления и скорости движения рассеивающих частиц), так и флуктуаций положения самих частиц в объёме. Последний случай выглядит так: частица пересекла луч -- появилась искра отраженного от него луча, ушла -- искра потухла. Таким образом, интенсивность рассеянного света $I(t)$ представляет собой свёртку двух функций.
Регистрируемая зависимость флуктуаций интенсивности излучения $I(t)$.
\begin{equation} I(t)=h(t)*w(t)\label{eq:DLS-Intensity-conv} \end{equation} где $h(t)$ описывает зависимость интенсивности рассеянного света от характера броуновского движения частицы (интерференция луча с длиной волны $\lambda$ и рассеянного света с длиной волны $\lambda\pm\Delta$), а $w(t)$ -- шум, случайное появление в объеме частиц пересекающих луч. Спад интенсивности $h(t)$ связанный с характером броуновского движения частицы зависит только от времени $\tau$ от начала наблюдения спекла именно этой частицы, а не от абсолютного времени $t$. Пересечение частицами луча описываются белым шумом $w(t)$, а изменение интенсивности отдельного спекла -- функцией $h(\tau)$ [3]. Свертка двух функций по определению \begin{equation} I(t)=\int_{0}^{t}h(\tau)\cdot w(t-\tau)d\tau\label{eq:DLS-Int-conv2} \end{equation} От экспериментальной установки требуется по регистрируемой зависимости $I(t)$ получить зависимость $h(\tau)$, а из неё определить свойства броуновской частицы.

Анализ данных

Автокорреляционная функция от $I(t)$ выявляет характерные масштабы времени $\tau$, на которых движение рассеивающих центров обладает корреляцией. Наблюдение корреляций во времени рассеянного излучения требует использование лазерного излучения, так как лазер светит строго на одной длине волны $\lambda$. Прибор регистрирует зависимость $I(t)$ в течении некоего времени скана. Введем автокорреляционную функцию электрического поля рассеянного света \begin{equation} g^{(1)}(q,\,\tau)=\frac{\left\langle E(q,\,0)\cdot E^{\star}(q,\,\tau)\right\rangle }{\left\langle E(q)\right\rangle ^{2}}\label{eq:G1} \end{equation} где скобки $\left\langle \right\rangle $ означают усреднение по всему ансамблю частиц, а волновой вектор $q$ определяется следующим образом \begin{equation} q=\frac{4\pi n}{\lambda}\sin\left(\frac{\theta}{2}\right)\label{eq:wave-q} \end{equation} где $n$ -- показатель преломления среды, $\lambda$ -- длина волны лазера, $\theta$ -- угол между волновыми векторами падающей и рассеянной световой волны. Функции $g^{(2)}(q,\tau)$ и $g^{(1)}(q,\tau)$ связаны между собой соотношением Зигерта \begin{equation} g^{(2)}(\tau)=B+\beta\left[g^{(1)}(\tau)\right]^{2}\label{eq:Zigert} \end{equation} где $B=1$ в теории, но на практике отличается (примерно на $\sim10^{-4}$) из-за наличия шумов в эксперименте, а $\beta$ -- фактор когерентности, зависящий от лазерного пучка и настроек инструментальной оптики, как правило, $\beta\approx0.7$. В простейшем случае невзаимодействующих сферических частиц одного размера \begin{equation} g^{(1)}(\tau)=e^{-\Gamma\cdot\tau}\label{eq:g1-monodisp} \end{equation} Ключевое слово здесь -- невзаимодействующих. В этом случае эволюция системы в собственном времени $\tau$, очевидно, полностью определяется свойствами самой системы, т.е. \begin{equation} \frac{dg^{(1)}(\tau)}{d\tau}=-\Gamma\cdot g^{(1)}(\tau)\label{eq:evolut} \end{equation} и решение дифференциального уравнения приводит к экспоненциальной зависимости. Коэффициент спада равен \begin{equation} \Gamma=D\cdot q^{2}\label{eq:Gamma} \end{equation} где $q$ -- волновой вектор, а $D$ -- коэффициент диффузии. Коэффициент диффузии $D$ связан с размером частиц соотношением Стокса — Эйнштейна Предполагается, что форма частиц сферическая и сила $F$ противодействующая шару в среде с вязкостью $\eta$ описывается формулой Стокса \begin{equation} F=3\pi\cdot\eta\cdot d\cdot v\label{eq:Stokes-law} \end{equation} где $d$ -- гидродинамический диаметр, а $v$ -- скорость частицы. Принимая во внимание соотношение Эйнштейна — Смолуховского \begin{equation} D=\mu\cdot k_{B}T\label{eq:Ein} \end{equation} где $k_{B}$ -- константа Больцмана, $T$ -- абсолютная температура, $\mu$ -- подвижность частицы, т.е. её средняя скорость $v$ делённая на силу $F$ \begin{equation} \mu=\frac{v}{F}\label{eq:mobility} \end{equation} находим коэффициент диффузии сферических частиц \begin{equation} D=\frac{k_{B}T}{3\pi\cdot\eta\cdot d}\label{eq:Ein-Smol} \end{equation}
Итак, в эксперименте:
  1. детектор регистрирует рассеяние луча лазера от кюветы с образцом броуновских частиц $I(t)$
  2. коррелятор прибора собирает $g^{(2)}(\tau)$
  3. подгонкой модели $A\cdot e^{-\Gamma\cdot\tau}$ (варьируемые параметры: $A$ и $\Gamma$) под экспериментальные точки $\sqrt{g^{(2)}(\tau)-B}$ находится коэффициент диффузии $D=\Gamma/q^{2}$ (параметры съемки задают волновой вектор $q$)
  4. гидродинамический диаметр частиц оценивается как $d=\frac{k_{B}T}{3\pi\cdot\eta\cdot D}$

Пример

Стандартный образец монодисперсных 60 нм частиц полистирола в дистиллированной воде при температуре 25 С, измеряют на приборе Malvern Zetasizer NS. Прибор работает на лазере с длиной волны 633 нм. Данные съёмки экспортируют в текстовый файл File|Export (записи: Correlation Delay Times, Correlation Data). Необработанные данные представляют собой корреляционную функцию интенсивности $g^{(2)}(\tau)-B$. От неё вычисляют корреляционную функцию поля рассеянного света. \begin{equation} g^{(1)}(\tau)=\sqrt{g^{(2)}(\tau)-B}\label{eq:g1-malvern} \end{equation} Последняя функция описывается моделью \begin{equation} \ln\left[g^{(1)}(\tau)\right]=A-\Gamma\cdot\tau\label{eq:g1-model} \end{equation} под которую производится подгонка параметров $A$ и $\Gamma=q^{2}D$ методом наименьших квадратов. Нам понадобятся: программа Gnuplot и файл с исходными данными 60nm-latex (он приведён в конце заметки). Вводим команды:
f(x) = a - b*x
fit [1:600] f(x) '60nm-latex' u 1:(0.5*log($2)) via a, b
plot [0:1000] '60nm-latex' u 1:(sqrt($2)) w l title "60 nm PS", exp(f(x)) title "fit"
Корреляционная функция светорассеяния 60 нм частиц полистирола в воде и модельная кривая, полученная в программе Gnuplot.
Выполнение команды fit приведет к подгонке параметров модели, вывод Gnuplot показан ниже:
gnuplot> fit [1:600] f(x) '60nm-latex' u 1:(0.5*log($2)) via a, b
iter      chisq       delta/lim  lambda   a             b            
   0 2.0177074471e+06   0.00e+00  1.34e+02    1.000000e+00   1.000000e+00
   1 1.9029201805e+02  -1.06e+09  1.34e+01    1.001210e+00   1.742615e-02
   2 2.6476900322e+01  -6.19e+05  1.34e+00    8.325550e-01   8.254375e-03
   3 7.9551269000e-02  -3.32e+07  1.34e-01    4.544939e-03   5.537308e-03
   4 1.5793031238e-02  -4.04e+05  1.34e-02   -3.817541e-02   5.397163e-03
   5 1.5793014266e-02  -1.07e-01  1.34e-03   -3.819746e-02   5.397090e-03
iter      chisq       delta/lim  lambda   a             b            

After 5 iterations the fit converged.
final sum of squares of residuals : 0.015793
rel. change during last iteration : -1.07466e-06

degrees of freedom    (FIT_NDF)                        : 55
rms of residuals      (FIT_STDFIT) = sqrt(WSSR/ndf)    : 0.0169454
variance of residuals (reduced chisquare) = WSSR/ndf   : 0.000287146

Final set of parameters            Asymptotic Standard Error
=======================            ==========================
a               = -0.0381975       +/- 0.002868     (7.509%)
b               = 0.00539709       +/- 1.511e-05    (0.28%)

correlation matrix of the fit parameters:
                a      b      
a               1.000 
b               0.623  1.000 
Берём значение b -- это искомый параметр $\Gamma$ и вычисляем. $\Gamma=0.0054\times10^{6}$ $с^{-1}$. По условиям съёмки, коэффициент преломления воды $n=1.33$, динамическая вязкость воды $\eta=0.8872\times0.001$ Па·с, а угол рассеяния $\theta=173^{\circ}$. Тогда, средний гидродинамический диаметр частиц \begin{equation} d=\frac{k_{B}T}{3\pi\cdot\eta\cdot\Gamma}\cdot q^{2}\label{eq:zav} \end{equation} Подставляя численные значения, находим \begin{align*} d & =\frac{1.38\times10^{-23}\cdot298.15}{3\cdot3.14\cdot0.8879\times10^{-3}\cdot0.0054\times10^{6}}\cdot\left[\frac{4\cdot3.14\cdot1.33}{633\cdot10^{-9}}\cdot\sin\left(\frac{173^{\circ}}{2}\right)\right]^{2}=\\ & =63.2\times10^{-9} \end{align*} т.е. диаметр частиц примерно 63 нм.

Вычисление распределения частиц по размерам

Поскольку в образце присутствуют частицы разного размера, то корреляционная функция представляет собой свертку \begin{equation} g^{(1)}(\tau)=\int_{0}^{\infty}G(\Gamma)\cdot e^{-\Gamma\cdot\tau}d\Gamma\label{eq:conv-correlation} \end{equation} где $\Gamma=D\cdot q^{2}$, а функция $G(\Gamma)$ представляет собой распределение по величинам $\Gamma$, пропорциональное распределению частиц по размерам. В методе кумулянтов экспонента записывается в виде \begin{align} e^{-\Gamma\cdot\tau}\equiv e^{-\bar{\Gamma}\cdot\tau}\cdot e^{-(\Gamma-\bar{\Gamma})\cdot\tau} & =\label{eq:cumulant} \end{align} \[ =e^{-\bar{\Gamma}\cdot\tau}\cdot\left[1-\left(\Gamma-\bar{\Gamma}\right)\cdot\tau+\left(\Gamma-\bar{\Gamma}\right)^{2}\cdot\frac{\tau^{2}}{2!}+\ldots\right] \] где выражение в скобках -- разложение экспоненты в ряд Тейлора. В случае достаточно узкого мономодального распределения члены ряда Тейлора быстро убывают и при разложении ограничиваются первыми двумя членами после единицы. \begin{align} g^{(1)}(\tau) & =\int_{0}^{\infty}G(\Gamma)\cdot e^{-\Gamma\cdot\tau}d\Gamma=\nonumber \\ & =e^{-\bar{\Gamma}\cdot\tau}\cdot\left(\int_{0}^{\infty}G(\Gamma)d\Gamma-\tau\int_{0}^{\infty}G(\Gamma)\cdot(\Gamma-\bar{\Gamma})d\Gamma+\frac{\tau^{2}}{2}\int_{0}^{\infty}G(\Gamma)\cdot(\Gamma-\bar{\Gamma})^{2}d\Gamma\right)\label{eq:g1-conv} \end{align} Среднее и дисперсия распределения $G(\Gamma)$ по определению \begin{align} \bar{\Gamma} & =\int_{0}^{\infty}G(\Gamma)\cdot\Gamma d\Gamma\label{eq:mean-and-variance}\\ \sigma^{2} & =\int_{0}^{\infty}G(\Gamma)\cdot\left(\Gamma-\bar{\Gamma}\right)^{2}d\Gamma\nonumber \end{align} что позволяет переписать уравнение \begin{equation} g^{(1)}(\tau)=e^{-\bar{\Gamma}\cdot\tau}\cdot\left(1+\frac{\sigma^{2}\cdot\tau^{2}}{2}\right)\label{eq:cumulant-exp1} \end{equation}

Классическая реализация

Следуя описаному алгоритму в работе Koppel D.E. 1972, заметим, что при $\sigma^{2}\tau^{2}\ll1$ выражение упрощается до \begin{equation} g^{(1)}(\tau)=e^{-\bar{\Gamma}\cdot\tau+\frac{\sigma^{2}\cdot\tau^{2}}{2}}\label{eq:cumulant-exp2} \end{equation} так как $e^{x}\simeq1+x$ при $x\ll1$. Таким образом мы получаем новую модель для подгонки параметров, отличающуюся от простого экспоненциального спада учётом параметров распределения частиц по размерам: среднее $\bar{\Gamma}$ и дисперсия $\sigma^{2}$. \[ \sqrt{g^{(2)}(\tau)-B}=A\cdot e^{-\bar{\Gamma}\cdot\tau+\frac{\sigma^{2}\cdot\tau^{2}}{2}} \] подгонка осуществляется для логарифмической формы \begin{equation} \ln\left[g^{(2)}(\tau)-B\right]^{\frac{1}{2}}=\ln A-\bar{\Gamma}\cdot\tau+\frac{\sigma^{2}}{2}\cdot\tau^{2}\label{eq:final-cumulant} \end{equation} Анализ кумулянтов корректен при быстром убывании членов ряда. Мерой этого является индекс полидисперсности \begin{equation} \text{PdI}=\left(\frac{\sigma}{\bar{\Gamma}}\right)^{2}\label{eq:Pdl} \end{equation}

Непосредственная подгонка $g^{(2)}(\tau)$

Подстановка разложения \begin{equation} g^{(1)}(\tau)=e^{-\bar{\Gamma}\cdot\tau}\cdot\left(1+\frac{\sigma^{2}\cdot\tau^{2}}{2}\right) \end{equation} в соотношение Зигерта приводит к несколько иной модели \begin{equation} g^{(2)}(\tau)=B+\beta\left[g^{(1)}(\tau)\right]^{2}=B+\beta\cdot e^{-2\bar{\Gamma}\cdot\tau}\cdot\left(1+\frac{\sigma^{2}\cdot\tau^{2}}{2}\right)^{2}\label{eq:non-linear-cum} \end{equation} для которой требуется нелинейная подгонка параметров, в отличие от более простого выражения Koppel D.E. 1972. Тем не менее, последнее выражение удобно тем, что в отличие от него, оно обладает правильным поведением при $\tau\rightarrow\infty$, так как в нем нет условия $\sigma^{2}\tau^{2}\ll1$, как указано в работе Barbara J. Frisken 2001 Мы воспользуемся именно этим способом при анализе коллоида частиц Cu2O с помощью подгонки Gnuplot.
set xtics nomirror out
set ytics nomirror
set logscale x
set mxtics 10
set ylabel "Correlation function, g^{(2)}(t)"
set xlabel "Correlation delay times, 10^{-6} s"
g(x) = B + beta*exp(-2.0*Gamma*x)*(1.0 + 0.5*sigma2*x**2)**2.0
B=0.01
beta=0.7
Gamma=0.01
sigma2=0.0001
fit g(x) 'Cu2O-R-raw.data' u 1:2 via B, beta, Gamma, sigma2
plot [0.5:10000] 'Cu2O-R-raw.data' u 1:2 title "Cu_2O NP", g(x) title "fit"
В результате мы получили параметры:
Final set of parameters            Asymptotic Standard Error
=======================            ==========================
B               = 0.00104527       +/- 0.0001155    (11.05%)
beta            = 0.894224         +/- 0.0003207    (0.03586%)
Gamma           = 0.00220168       +/- 4.222e-06    (0.1918%)
sigma2          = 5.93369e-07      +/- 2.6e-08      (4.381%)
Из которых следует, что распределение частиц Cu2O в воде имеет средний гидродинамический диаметр 155 нм и индекс полидисперсности 0.122. Для сравнения ниже приведены данные программы Zetasizer 7.12.
Исходные данные для 60 нм частиц полистирола
# Sample Name           60nm Polystyrene Latex
# Temperature (°C)      25.0
# Viscosity (cP)        0.8872
# Correlation Delay Times, (µs) Correlation Data
0.500   0.922
1.00    0.919
1.50    0.915
2.00    0.909
2.50    0.905
3.00    0.899
3.50    0.895
4.00    0.891
4.50    0.887
5.50    0.876
6.50    0.869
7.50    0.857
8.50    0.849
9.50    0.841
10.5    0.831
11.5    0.823
12.5    0.812
14.5    0.798
16.5    0.779
18.5    0.763
20.5    0.746
22.5    0.731
24.5    0.715
26.5    0.698
28.5    0.683
32.5    0.655
36.5    0.628
40.5    0.601
44.5    0.575
48.5    0.551
52.5    0.527
56.5    0.505
60.5    0.484
68.5    0.444
76.5    0.407
84.5    0.373
92.5    0.342
101     0.314
109     0.287
117     0.263
125     0.241
141     0.201
157     0.169
173     0.142
189     0.119
205     0.100
221     0.0838
237     0.0702
253     0.0595
285     0.0414
317     0.0293
349     0.0209
381     0.0144
413     0.0103
445     0.00672
477     0.00538
509     0.00400
573     0.00231
637     0.00173
701     9.78e-4
765     8.14e-4
829     0.00131
893     0.00200
957     0.00246
1020    0.00173
Исходные данные для наночастиц Cu2O
# Sample Name           Cu2O NP
# Temperature (°C)      25.0
# Viscosity (cP)        0.8872
# Correlation Delay Times, (µs) Correlation Data
0.500      0.884
1.00       0.892
1.50       0.890
2.00       0.888
2.50       0.886
3.00       0.883
3.50       0.882
4.00       0.881
4.50       0.878
5.50       0.875
6.50       0.870
7.50       0.867
8.50       0.863
9.50       0.859
10.5       0.855
11.5       0.851
12.5       0.847
14.5       0.841
16.5       0.833
18.5       0.826
20.5       0.819
22.5       0.812
24.5       0.805
26.5       0.798
28.5       0.791
32.5       0.777
36.5       0.763
40.5       0.750
44.5       0.737
48.5       0.725
52.5       0.711
56.5       0.699
60.5       0.688
68.5       0.664
76.5       0.641
84.5       0.620
92.5       0.598
101        0.578
109        0.558
117        0.540
125        0.521
141        0.487
157        0.455
173        0.426
189        0.398
205        0.372
221        0.349
237        0.326
253        0.306
285        0.269
317        0.236
349        0.208
381        0.184
413        0.162
445        0.143
477        0.126
509        0.112
573        0.0877
637        0.0683
701        0.0530
765        0.0418
829        0.0332
893        0.0265
957        0.0212
1020       0.0180
1150       0.0132
1280       0.00955
1400       0.00772
1530       0.00686
1660       0.00553
1790       0.00515
1920       0.00590
2040       0.00626
2300       0.00476
2560       0.00360
2810       0.00322
3070       0.00294
3320       0.00175
3580       0.00134
3840       0.00217
4090       0.00277
4600       0.00519
5120       0.00307
5630       0.00319
6140       0.00186
6650       0.00186
7160       0.00192
7680       0.00130
8190       0.00247
9210       6.70e-5
1.02e4     0.00249

суббота, 16 февраля 2019 г.

FORTH


Встреча с FORTH

 

Cистемы типа Matlab/Octave можно рассматривать как своего рода калькуляторы, только высокого уровня: в них есть векторы, матрицы — всё, что нужно для реализации научных вычислений. Однако, они большие и требуют мощного компьютера с операционной системой. Интересно, что давным давно, во времена, когда персональные компьютеры были немногим сильнее калькулятора, как, например, мой HP 35s существовало интересное решение.
 
Например, персональный компьютер Jupiter Ace со встроенным языком программирования FORTH. Особенность этого языка программирования в том, что ему не нужна ни операционная система, ни файлы, ровным счетом ничего, кроме чистого железа. Это позволило оснащать довольно слабые по современным меркам компьютеры даже офисным программным обеспечением, как например, компьютер Canon Cat. Набор приложений был записан в ПЗУ. В него входили: стандартный пакет офисных программ, орфографический словарь на 90 000 слов, программа связи и средства программирования на Форт и языке ассемблера.
Canon Cat.jpg
FORTH использует технологию «шитого кода». Проще говоря, это массив вызовов подпрограмм. Указатель выполнения кода последовательно принимает адреса подпрограмм, которые исполняются. Передача параметров происходит через стек.

Шитый код используется в программировании калькулятора HP 35s

Автомат FORTH функционирует следующим образом. Из входного потока (программы на языке FORTH) читается очередное слово. Синтаксис языка крайне прост: слово — это любая последовательность символов не включающая пробел, табуляцию или перевод строки. Если принятое слово литерал (например, число), то оно кладётся на стек. Если нет, ищется в словаре. Если FORTH в состоянии интерпретации — слово исполняется, если в состоянии компиляции (определении нового слова) то адрес определения слова или подшивается к текущему определению, или немедленно исполняется (если слово имело атрибут IMMEDIATE). Если слова не было в словаре — FORTH выдает ошибку исполнения.

Контрольные слова (для определений ветвлений и циклов) имеют атрибут IMMEDIATE. FORTH позволяет управлять входным потоком слов и определять управляющие конструкции, т. е. слова с инструкциями для состояния интерпретации и компиляции.

Вот пример корректной программы на FORTH:

: НАЛИТЬ-ВОДУ КРАНЫ ОТКРЫТЬ ДО-НАПОЛНЕНИЯ КРАНЫ ЗАКРЫТЬ ; 
: ПОЛОСКАТЬ НАЛИТЬ-ВОДУ СТИРАТЬ ВЫЛИТЬ-ВОДУ ; 
: СТИРАЛЬНАЯ-МАШИНА СТИРАТЬ ВЫКРУЧИВАТЬ ПОЛОСКАТЬ ВЫКРУЧИВАТЬ ;


Сразу отмечу, что FORTH -  не способ программирования на естественном языке, это скорее метод формализации естественного языка на строгий алгоритмический язык конечного автомата с несколькими стеками. Простота достигается за счёт применения стеков и обратной польской записи, а также за счёт отсутствия синтаксиса, типов данных и прочих абстракций программирования. Однако, если какие-то абстракции нужны - их всегда можно определить, так как вам угодно, а не создателям языка.
Nick Morgan любезно предоставил всем желающим попробовать FORTH прямо в окне браузера.

Знакомство 

Далее я перечислю места, где в настоящее время встречается FORTH. 

В космических аппаратах!
Philae lander (transparent bg).png
Солидный список здесь. Отдельная история - чипы RTX2000-RTX2010. Читайте.

Программирование микроконтроллеров: семейства AtmelAVR8 Atmega, Microchip 8-bit PIC18F и 16-bit PIC24, 30, 33 и Arduino UNO и многих других. Читайте тут.

Встроенный скриптовый язык:
Игровая платформа настольных игр на ПК - Zillions of Games, в ней FORTH это способ разрабатывать свои игры, см. пост.
Zillion of games challenge
Скриптовый язык в XYPLOT - Extensible Plotting and Data Analysis Program for 32-bit x86 GNU/Linux, в планировщике задач nnCron и других приложениях.

Подводные камни

Обратная польская нотация очень удобна в калькуляторах, однако, она не всегда подходит для решения задач. Попытки избавиться от традиционного подхода с переменными бывают трагичны. В самом деле, как отмечает в своем блоге Yossi Kreinin, для стека подходят деревья выражений



https://upload.wikimedia.org/wikipedia/commons/thumb/9/98/Exp-tree-ex-11.svg/250px-Exp-tree-ex-11.svg.png
тогда как более общая структура, граф выражения уже требует операций со стеком: перестановок, копирования и т.п.
Сравните выражение в обычной и обратной польской нотации (a + b)*c+7 = a b + c * 7 + и попробуйте записать (a + b)/(a + b*c)! В итоге программы на FORTH начинают выглядеть как жонглирование элементами стека.

: siftDown                             ( a e s -- a e s)
  swap >r swap >r dup                  ( s r)
  begin                                ( s r)
    dup 2* 1+ dup r'@ <                ( s r c f)
  while                                ( s r c)
    dup 1+ dup r'@ <                   ( s r c c+1 f)
    if                                 ( s r c c+1)
      over over r@ precedes if swap then
    then drop                          ( s r c)
    over over r@ precedes              ( s r c f)
  while                                ( s r c)
    tuck r@ exchange                   ( s r)
  repeat then                          ( s r)
  drop drop r> swap r> swap            ( a e s)
;
Всё это приводит к тому, что язык Си кажется единственным, кто может с этим справиться. Одна из таких трагедий описана у Yossi Kreinin.  

Почему бы не решить проблему переменными? Они есть в FORTH. Кажущаяся проблема в том, что переменные глобальны и не связаны с единственным определяемым словом. В Си-подобных языках избегают глобальных переменных из-за того, что исчерпываются уникальные имена, сложно отслеживать значение переменной, если доступ к ней возможен из любого места программы...
Я написал кажущаяся проблема, потому что на самом деле проблемы нет вовсе. Странно, что об этой особенности FORTH не упоминается в книгах явно и с предупреждением, но глобальные переменные FORTH ведут себя не так, как в Си.
Единственная книга, в которой обсуждается способ взаимодействия определения с окружением это книга Christian Queinnec. Lisp In Small Pieces. Поведение определений в FORTH попадает в класс гиперстатического связывания. Проще показать на примере.
: foo ." foo!" ;
: bar foo ."  bar!" ;
bar foo! bar! ok.
: foo ." bizzle!" ; Redefine foo.  ok.
foo bizzle! ok.
bar foo! bar! ok.
Слово bar состоит из foo и вывода строки ."  bar!". Однако, когда термин foo оказывается переопределён, то поведение bar остаётся неизменным! Определение слова сохраняет его контекст, слова в определении имеют ровно то значение, которое было на тот момент.
Отсюда следует, что нет никакой причины беспокоиться о том, что кончатся имена переменных и так далее. Вам нужна новая переменная my_variable? Так и назовите её, ничего из того, что связано было с ней ранее не изменится. Нет смысла вводить новый синтаксис и правила обращения с локальными переменными (хотя таких попыток в FORTH было много и разных), достаточно перед тем словом, где нужна переменная определить её, а после него определить новую с тем же самым именем.

Подытожим. FORTH это

  1. Шитый код
  2. Обратная польская запись
  3. Гиперстатическое связывание
С этих теоретических понятий уже можно собрать свой FORTH. Каноническая инструкция как это сделать написана Richard W.M. Jones, читайте по ссылке.

FORTH на вкус

Далее я расскажу о своем опыте погружения в античные времена MS DOS и существовавшей для него среды FORTH.

В dosbox'е устанавливаю F-PC 3.60 (читайте C.H. Ting. F-PC: FORTH optimized for IBM-PC // SIGFORTH Newsl. 1(1) (1989) 15-17 DOI:10.1145/382122.382928)
 

Это полноценная IDE с редактором кода
Справочником-помощью
а также отладчиком
Словом, весь джентльменский набор!

Поскольку FORTH интересовал меня с точки зрения математических вычислений, альтернатива Matlab и прочим Scientific Python, то я избавился от жонглирования стеком и режущими глаз мушками вроде f@ - чтение переменной/ f! - запись значения в переменную.

Вот как это работает.
fload sfloat.seq
fload eval.seq

macro: get-name bl word count r@ place ;
macro: $name  r@ count ;
macro: .. pad +place ;

: cell:
  here >r get-name
  " variable *" pad place $name .. 
  "  : :" .. $name .. "  *" .. $name .. "  ! ; " ..
  "  : "  .. $name .. "  *" .. $name .. "  @ ; " ..
  r> drop pad count eval ;

: float:
  here >r get-name
  " fvariable *" pad place $name ..
  "  : :" .. $name .. "  *" .. $name .. "  f! ; " ..
  "  : "  .. $name .. "  *" .. $name .. "  f@ ; " ..
  r> drop pad count eval ;

: cells:  ( n -- ) 0 do cell:  ( name ) loop ;
: floats: ( n -- ) 0 do float: ( name ) loop ;
Теперь если в каком-то определении нужны переменные, то перед ним я пишу
3 floats: x y z
Присваиваю им значения при помощи автоматически созданных слов
0.0e :x 0.0e :y 1.0e :z
и получаю их значения на стек легко и естественно
x x f* y y f*  z z f*  f+ f+ fsqrt
как если бы делал это на калькуляторе. При необходимости легко переопределить имена x, y, z - на работе предыдущих слов это никак не скажется. Гиперстатическое связывание - удобная штука!
Алгоритмы на FORTH получаются компактные, сам язык очень способствует факторизации кода. Например, сортировка:
\ Heapsort is an in-place sorting algorithm with worst case
\ and average complexity of O(n*log[n]). The basic idea is
\ to turn the array into a binary heap structure, which has
\ the property that it allows efficient retrieval and removal
\ of the maximal element. We repeatedly "remove" the maximal
\ element from the heap, thus building the sorted list from
\ back to front.

0 1 2constant endless

defer item@
defer item!
defer greater?

6 cells: arr n p q r s

: maxi :r :q :p :n :arr
  p :s
  q n < if arr q item@ arr s item@ greater? if q :s then
  then
  r n < if arr r item@ arr s item@ greater? if r :s then
  then s ;

: downheap :p :n :arr
  endless do
    arr n p p 2* 1+ p 2* 2 + maxi :q
    q p = if leave then
    arr p item@ arr q item@
    arr p item! arr q item!
    q :p
  loop ;
2 cells: arr n

: heapsort :arr
  arr @ :n
  0 n 2 - 2/ do arr n i downheap -1 +loop
  n 0 do
    arr n i - 1- item@  arr 0 item@
    arr n i - 1- item!  arr 0 item!
    arr n i - 1- 0 downheap
  loop ;

: item-get item @ ;
' item-get is item@
: item-set item ! ;
' item-set is item!
' > is greater?
Стоит обратить внимание на конструкцию
defer word
 
...
 
' method is word 
Которая позволяет отложить определение какого-либо слова в определении термина до того момента, пока оно не станет известено. А вот реализация метода нахождения корня уравнения, её вполне можно сопоставить с таковой в других языках.
\ Using Ridder's method, return the root of a function func
\ known to lie between x1 and x2.

fload vars.seq

defer f(x)
10 floats: x1 x2 xm xnew  fl fm fh fnew  s result

-1.11e30 fconstant UNLIKELY-VALUE
 1.0e-9  fconstant ACCURACY
     50   constant MAXIT
      
: fsign ( r1 -- r1 ) f0< dup not - ifloat ;
: f~ ( r1 r2 r3 -- flag ) f-rot f- fabs f> ;

: root-not-bracketed? ( fl fh -- flag )
  fdup   f0< fover  f0> and
  ( fh ) f0> ( fl ) f0< and or not ;

: ridder ( r1 r2 -- r1 ) :x2 :x1
  x1 f(x) :fl
  x2 f(x) :fh
  fl f0= if x1 exit then
  fh f0= if x2 exit then
  fl fh root-not-bracketed?
  if abort" root must be bracketed in zriddr" then
  UNLIKELY-VALUE :result
  false
  MAXIT 0
  do
    x1 x2 f+ 2.0e f/ :xm  xm f(x) :fm
    fm fdup f* fl fh f* f- fsqrt :s
    s f0= if result true leave then
    fl fh f- fsign xm x1 f- f* fm f* s f/ xm f+ :xnew
    xnew result ACCURACY f~
    if result true leave then
    xnew :result  xnew f(x) :fnew
    fnew f0= if result true leave then
    fnew fsign fm f* fm f= not
    if xm :x1  fm :fl  result :x2  fnew :fh
    else fnew fsign fl f* fl f= not
      if result :x2  fnew :fh then
      fnew fsign fh f* fh f= not
      if result :x1  fnew :fl then
    then
    x1 x2 ACCURACY f~
    if result true leave then
  loop
  if result drop
  else ." zriddr exceed maximum iterations" drop then ;

float: x
\ : func :x x fcos x x x f* f* f- ; \ 0.0-1.0 x = 0.865474
: func :x x x x f* f* 10.0e x x f* f* f- 5.0e f+ ; \ 0.6-0.8 x=0.7346

' func is f(x)
0.6e 0.8e ridder f(x) f. cr 
Не хуже чем Matlab? Учитывая, что это может работать на микроконтроллере, без колдовства с компилятором. На то можно возразить, что в Matlab'е есть средства высокого уровня, а тут где они? Продолжение следует.