1 /* ezunits: yet another units package for Maxima
2 * This program copyright 2008 by Robert Dodier.
3 * I release this program under the terms of the
4 * GNU General Public License.
7 (kill (all), reset (), load (ezunits), 0);
58 (a`m)*exp(sin(z))*(b`m);
59 (exp(sin(z))*a*b)`(m^2);
70 (a`m)*(b`m)*(c`m)*(d`m);
73 (a`kg/m^2)/(b`kg/m^2);
76 (a`kg*m/s)/(b`kg*m/s);
85 /* verify different cases are handled in function units */
88 declare_constvalue (x, 1000 ` W/m^2),
89 declare (y, dimensional),
90 declare (z, dimensional),
91 declare_units (z, MJ/hour),
110 [units(x[1]), units(x[2]), units(x[k])];
111 [W/m^2, W/m^2, W/m^2];
113 units(a ` mile/minute^2);
123 MJ*W*'units(y)/(hour*m^2);
128 units(z + sin(a)`MJ/hour + (10 ` MJ)/(24 ` hour));
131 units(z - 1000`MJ/hour);
134 units(y = (a ` foot)/(60 ` minute));
135 'units(y) = foot/minute;
137 units(equal(y, (a ` foot)/(60 ` minute)));
138 equal ('units(y), foot/minute);
143 (declare (nounify (a), nondimensional),
147 (remove (nounify (a), nondimensional),
151 /* diff, integrate, and at are handled below */
153 /* TODO: verify different cases are handled in function qty */
155 /* next one has result = unknown;
156 * substitute narrower test on "=" instead of equal
157 * pending simplification rule for equal applied to unitful expressions
158 is (equal (0 ` m, 0 ` kg));
165 /* begin addt'l stuff adapted from Cliff Yapp's email
166 * to the Maxima mailing list 2005/05/21.
180 a`kg/s - c`kg/s + d`kg/s;
186 a`kg*m/s^2 + c`kg*m/s^2;
189 a`kg*m/s^2 + c`kg*m/s^2 - d`kg*m/s^2;
190 (a + c - d)`(kg*m/s^2);
192 a`kg/s + c`kg/s + d`kg*m/s^2;
193 (a + c)`(kg/s) + d`(kg*m/s^2);
195 a`kg/s + c`kg*m/s^2 + d`kg*m/s^2;
196 a`kg/s + (c + d)`kg*m/s^2;
204 a`kg/s + b`N + c`kg/s + d`N + e`kg/s;
205 (a + c + e)`kg/s + (b + d)`kg*m/s^2;
207 1/60`kg/s + a`kg/s + b`kg/s + c`kg/s^2 + d`kg/s^2;
208 (1/60 + a + b)`kg/s + (c + d)`kg/s^2;
210 a/60`kg/s + a`kg/s + b`kg/s + c`kg/s^2 + d`kg/s^2;
211 (a/60 + a + b)`kg/s + (c + d)`kg/s^2;
213 (a/60)`kg/s + a*b`kg/s;
216 a`kg*m/s^2 + b`N*J + c`kg/s + d`N*J - e`kg*m/s^2;
217 (a - e)`kg*m/s^2 + c`kg/s + (b + d)`kg^2*m^3/s^4;
227 /* end stuff adapted from Cliff Yapp's email
230 (remvalue (J, N), 0);
233 /* foo(a`s) fails nondimensional_not1 test, due to presence of a`s within.
234 * => No rule triggered here.
236 (a`b)*(c`d)*foo(e`f);
237 ''(block ([simp: false], (a`b)*(c`d)*foo(e`f)));
239 (F: C*(5/9) + 32, 0);
251 /* deg and rad are units ad hoc; neither one is defined */
268 (declare ([C1, C2], constant), 0);
271 /* Constants for Planck's law */
272 [declare_constvalue (%C2, 14390.0), declare_constvalue (%C1, 3.742E+8)];
275 (C1: %C1`W*micron^4/m^2, C2: %C2`micron*K, l: %l`micron, T: %T`K, 0);
278 /* "infeval=true" is a work-around for simplification strangeness:
279 * after load("units.mac")$ kill(all)$ load("units.mac")$
280 * the simplifier doesn't try so hard to use tellsimpafter rules,
281 * but it can be coaxed by re-evaluation via ''expr or infeval=true.
283 expr: C1/(l^5*(exp(C2/(l*T)) - 1)), infeval=true;
284 %C1/(%l^5*(%e^(%C2/(%l*%T))-1)) ` W/(m^2*micron);
286 ev (expr, constvalue);
287 3.742E+8/(%l^5*(%e^(14390.0/(%l*%T))-1)) ` W/(m^2*micron);
290 3.742E+8 / (%l^5 * (%e^(2.398333333333333/%l) - 1));
292 /* Now try this -- should yield a skewed bump.
293 * plot2d (%, [%l, 0.05, 3]);
296 declare ([a1, b1, c1], dimensional);
302 expand_dimensional (a1 + b1 + c1);
303 'qty(a1)`'units(a1) + 'qty(b1)`'units(b1) + 'qty(c1)`'units(c1);
305 declare_units ('[a1, b1, c1], mph);
320 (declare_qty ('a1, 100), declare_qty ('b1, 200), declare_qty ('c1, 300));
326 expand_dimensional (a1 + b1 + c1);
332 expand_dimensional (c1 + 1000`mph);
335 expand_dimensional (c1 + 1000`kg);
338 expand_dimensional ((a1 + 500`mph)/(b1 - 100`mph));
341 map (declare_units, [aa, bb, cc, dd, ee, ff, gg], [m, kg, s, K, feet, in, acre]);
342 [m, kg, s, K, feet, in, acre];
353 catch (apply (lambda ([ff], cc^2), [gg]));
356 units (aa*bb*cc*dd*ee*ff*gg);
357 m*kg*s*K*feet*in*acre;
359 [aa: %aa`m, bb: %bb`kg, cc: %cc`s, dd: %dd`K, ee: %ee`feet, ff: %ff`in, gg: %gg`acre];
360 [%aa`m, %bb`kg, %cc`s, %dd`K, %ee`feet, %ff`in, %gg`acre];
362 ff: ee*(12`in)/(1`feet);
365 gg: ff^2*((1`yard)/(36`in))^2*(1`acre)/(55*88`yard^2);
368 declare_units (foo, m/s^2);
377 aa: expand_dimensional (foo (p, q) * cc * (100`s));
378 100 * qty (foo (p, q)) * %cc ` m;
380 declare_units (bar, kg/acre);
384 (%ee^2/43560 ` acre) * bar[n];
386 expand_dimensional (bb);
387 %ee^2 * 'qty (bar [n]) / 43560 ` kg;
392 cc: bar[11] * (57 ` s/kg) * (10 ` acre);
393 bar[11] * (570 ` acre*s/kg);
395 expand_dimensional (cc);
396 570 * qty(bar[11]) ` s;
398 kill (aa, bb, cc, dd, ee, ff, gg);
401 /* Unit conversions */
403 0 ` kg/m^2 `` lbm/acre;
416 60228605349/48828125 ` m^3;
418 declare_unit_conversion (h = hour, d = day);
421 /* Stefan-Boltzmann constant */
422 56697/10000/10^8 ` W/m^2/K^4 `` Btu/h/ft^2/R^4;
423 304821971/178031250000000000 ` Btu/h/ft^2/R^4;
425 declare_unit_conversion (MMBtu = 10^6*Btu, kW = 1000*W, kWh = kW*h, MWh = 1000*kWh);
434 (load (physical_constants), 0);
437 map (lambda ([x], featurep (x, physical_constant)), [%c, %mu_0, %e_0, %Z_0, %G, %h, %h_bar]);
438 [true, true, true, true, true, true, true];
440 map (constantp, [%c, %mu_0, %e_0, %Z_0, %G, %h, %h_bar]);
441 [true, true, true, true, true, true, true];
443 map (units, [%c, %mu_0, %e_0, %Z_0, %G, %h, %h_bar]);
444 ''([m/s, N/A^2, s^2*A^2/(m^2*N), m*N/(s*A^2), m^3/(kg*s^2), J*s, J*s]);
446 [dimensions (1), dimensions (1729), dimensions (%e)];
449 [dimensions (0 ` m/s), dimensions (0 ` kg/m^3), dimensions (0 ` W/kg)];
450 [length/time, mass/length^3, length^2/time^3];
453 'dimensions (foobar);
455 dimensions_as_list (foobar);
456 'dimensions_as_list ('dimensions (foobar));
458 fundamental_units (foobar);
459 'fundamental_units (foobar);
461 map (dimensions, [%c, %mu_0, %e_0, %Z_0, %G, %h, %h_bar]);
463 length*mass/(current^2*time^2),
464 current^2*time^4/(length^3*mass),
465 length^2*mass/(current^2*time^3),
466 length^3/(mass*time^2),
470 fundamental_dimensions;
471 [length, mass, time, current, temperature, quantity, luminous_intensity];
473 map (dimensions_as_list, [%c, %mu_0, %e_0, %Z_0, %G, %h, %h_bar]);
474 [[1, 0, - 1, 0, 0, 0, 0],
475 [1, 1, - 2, - 2, 0, 0, 0],
476 [- 3, - 1, 4, 2, 0, 0, 0],
477 [2, 1, - 3, - 2, 0, 0, 0],
478 [3, - 1, - 2, 0, 0, 0, 0],
479 [2, 1, - 1, 0, 0, 0, 0],
480 [2, 1, - 1, 0, 0, 0, 0]];
482 map (fundamental_units, [%c, %mu_0, %e_0, %Z_0, %G, %h, %h_bar]);
491 /* examples from message from ed romana to mailing list 2007-12-02, -12-03 */
493 e : 1/sqrt (%mu_0 * %e_0);
494 1/sqrt (%mu_0 * %e_0);
497 [299792458 ` m/s, 299792458 ` m/s];
499 /* Helium sound velocity at 27 C, He(Cp/Cv)=5/3, 4gr/mol */
500 e : sqrt (5/3 * %R/(4 ` g/mol) * (27 ` degC `` K));
501 sqrt(%R*(2001/16 ` mol*K/g));
503 expand_dimensional (e);
504 sqrt(2001)*sqrt('qty(%R))/4 ` sqrt(J)/sqrt(g);
510 sqrt(2079657309)/(125*2^(7/2)) ` sqrt(J)/sqrt(g);
515 u : fundamental_units (e);
519 10^(3/2)*sqrt(2079657309)/(125*2^(7/2)) ` m/s;
522 1019.719890214955 ` m/s;
524 /* decomposing units into multiple units of different "size" */
526 xx : 1000 ` m `` [foot];
527 [1250000/381 ` foot];
529 xx : map (lambda ([x], x `` m), xx);
532 xx : 1000 ` m `` [foot, inch];
533 [3280 ` foot, 1280/127 ` inch];
535 xx : map (lambda ([x], x `` m), xx);
536 [124968/125 ` m, 32/125 ` m];
541 (declare_unit_conversion (hairs_breadth = 1/100 * inch),
542 xx : 1000 ` m `` [foot, inch, hairs_breadth]);
543 [3280 ` foot, 10 ` inch, 1000/127 ` hairs_breadth];
545 xx : map (lambda ([x], x `` m), xx);
546 [124968/125 ` m, 127/500 ` m, 1/500 ` m];
551 xx : 10^9 ` s `` [year, month, day, hour, minute, s];
552 [31 ` year, 8 ` month, 7 ` day, 19 ` hour, 46 ` minute, 40 ` s];
554 xx : map (lambda ([x], x `` s), xx);
555 [978285600 ` s, 21038400 ` s, 604800 ` s, 68400 ` s, 2760 ` s, 40 ` s];
560 xx : 10^7 ` m^2 `` [mile^2, acre, yard^2, feet^2, inch^2];
561 [3 ` mile^2, 551 ` acre, 260 ` yard^2, 4 ` feet^2, 388096/16129 ` inch^2];
563 xx : map (lambda ([x], x `` m^2), xx);
564 [121405692672/15625 ` m^2, 174204522558/78125 ` m^2, 16983837/78125 ` m^2, 145161/390625 ` m^2, 6064/390625 ` m^2];
569 86400 ` s `` [hour, minute, s];
570 [24 ` hour, 0 ` minute, 0 ` s];
572 60 ` s `` [hour, minute, s];
573 [0 ` hour, 1 ` minute, 0 ` s];
575 1 ` s `` [hour, minute, s];
576 [0 ` hour, 0 ` minute, 1 ` s];
578 86401 ` s `` [day, hour, minute, s];
579 [1 ` day, 0 ` hour, 0 ` minute, 1 ` s];
581 xx : n ` m `` [yard, foot, inch];
582 [floor(1250*n/1143) ` yard,
583 floor(3*(1250*n/1143-floor(1250*n/1143))) ` foot,
584 12*(3*(1250*n/1143-floor(1250*n/1143)) -floor(3*(1250*n/1143-floor(1250*n/1143)))) ` inch];
586 xx : ev (xx, n = 100);
587 [109 ` yard, 1 ` foot, 128/127 ` inch];
589 xx : map (lambda ([x], x `` m), xx);
590 [124587/1250 ` m, 381/1250 ` m, 16/625 ` m];
595 declare_units (xyz, kg);
598 xx : xyz `` [metric_ton, kg, mg];
599 xyz `` [metric_ton, kg, mg];
601 expand_dimensional (xx);
602 [floor('qty(xyz)/1000) ` metric_ton,
603 floor(1000*('qty(xyz)/1000-floor('qty(xyz)/1000))) ` kg,
604 1000000*(1000*('qty(xyz)/1000-floor('qty(xyz)/1000))
605 - floor(1000*('qty(xyz)/1000-floor('qty(xyz)/1000)))) ` mg];
607 ev (xx, xyz = (1729 + 42/99) ` kg, nouns);
608 [1 ` metric_ton, 729 ` kg, 14000000/33 ` mg];
610 /* needs more work to get rule for diff to apply to verb ... oh well. */
611 'diff (x (t) ` inch, t ` year, 1);
612 'diff (x (t), t, 1) ` inch / year;
614 'diff (x (t) ` inch, t ` year, 2);
615 'diff (x (t), t, 2) ` inch / year^2;
617 'integrate (f (x) ` N, x ` m, 1 ` m, 10 ` m);
618 ('integrate (f (x), x, 1, 10)) ` N*m;
620 'integrate (f (x) ` N, x ` m, 1 ` inch, 10 ` inch);
621 ('integrate (f (x), x, 127/5000, 127/500)) ` N*m;
623 /* small example from mma mailing list circa 2009-05-29 */
625 block ([R, w, L, x, y, z], kill (x), R : x ` Ohm, w : z ` Hz, L : y ` H, (R + w*L) `` Ohm);
628 /* test new definitions of pound_mass, gallon, slug */
630 ((1 ` pound_force)/(1 ` pound_mass), [dimensions (%%), %% `` cm/s^2]);
631 [length/time^2, ''(980665/1000) ` cm/s^2];
633 (kill (xx), xx ` gallon `` inch^3);
636 xx ` gallon/acre `` feet;
637 ''(231*xx/(55*88*3^2)/(12^2)/12) ` feet;
639 [dimensions (slug), dimensions (slug/pound_mass)];
642 1 ` slug/pound_mass `` 1;
643 196133/6096; /* approx 32.something */
645 /* some examples suggested by Jeff Hankin; thanks, Jeff. */
647 dimensions (W / (K * m));
648 length*mass/(temperature*time^3);
651 luminous_intensity / length^2;
656 bfloat (1 ` pc `` m);
657 3.085677581491367b16 ` m;
662 bfloat (300 ` mile `` AU);
663 3.227340053309997b-6 ` AU;
666 648000000000/%pi ` AU;
668 70 ` mile/hour `` parsec / julian_year;
669 4762373*%pi/467493345937500 ` parsec/julian_year;
671 /* still more examples */
673 /* assignment to a unit symbol causes trouble;
674 * maybe rhs of "`" should never be evaluated.
675 * For now, just remvalue all unit symbols.
677 (apply (remvalue, known_units ()), 0);
680 (kill (xx), xx : 1 ` ml*lux*katal/(gray*Bq), dimensions (xx));
681 luminous_intensity * quantity * time^2 / length;
683 fundamental_units (xx);
686 (kill (uu), uu ` horsepower*julian_year/tbsp `` GJ/liter);
687 50133999444908841*uu/31501953125000 ` GJ/liter;
689 'f(uu) ` MW `` short_ton*(lbf/lbm)*mile/hour `` Btu/hour;
690 720000000*'f(uu)/211 ` Btu/hour;
692 1 ` W `` Btu/julian_year `` newton*foot/hour `` lbf*m/s `` W;
695 /* units ad hoc; no fundamental units or dimensions, just conversions */
697 declare_unit_conversion (1`elephant=10`cow, 1`cow=10`goat, 1`goat = 2`dog, 1`dog=3`cat);
700 1 ` elephant/m `` cat/inch;
703 dimensions (1 ` goat/hour);
704 'dimensions(cat) / time;
706 /* convert argument of trig function */
732 is (abs (ev (sin (40 ` degree), numer) - 0.642787609686539) < 1e-12);
735 is (abs (ev (cot (80 ` degree), numer) - 0.176326980708465) < 1e-12);
737 /* Hydrostatics examples from:
738 * http://www.ce.siue.edu/mrossow/Worked_examples_Internet_text-only/Data_files-html/Hydrostatics_list_of_examples.html
739 * via: http://designerunits.com/examples/sites/ce.siue/hydrostatics
742 (gee :(980 + 2/3) ` cm/s^2, p_AB : (10^3`kg/m^3) * gee * (5`m) `` kPa);
745 w : p_AB * 4 ` m `` kN/m;
748 (kill (F_A), e : (F_A`kN) * (3`m) - w*(3`m)*(3`m)/2, solve (first (e), F_A));
751 p : ((200 ` N)/(%pi*r^2) + (900 ` kg/m^3) * (200 ` mm) * %pi * r^2 * gee / (%pi * r^2)) `` kPa, r = (25 ` mm)/2;
752 (1280/%pi + 4413/2500) ` kPa;
754 ratsimp (W : (p * %pi * r^2) `` kN), r = (300 ` mm)/2;
755 (39717*%pi + 28800000)/1000000 ` kN;
757 ratsimp (W * 1/(200 ` N) `` 1);
758 (39717*%pi + 28800000)/200000;
763 p_B : (10^3 ` kg/m^3) * gee * (2 ` m + 3 ` m) `` kPa;
766 w_B : p_B * 4 ` m `` kN/m;
769 1/2 * w_B * (2`m + 3`m);
776 /* Miscellaneous examples from: "Metric Units and Conversion Charts"
777 * by Theodore Wildi (www.wildi-theo.com) ISBN 0-7803-1050-0
778 * via: http://designerunits.com/examples/sites/wildi-theo/chartschapter04
781 (400 ` lbm) * (3 ` cm/s^2);
784 (400 ` lbm) * (3 ` cm/s^2) `` N;
785 136077711/25000000 ` N;
787 (declare_unit_conversion (ozf = lbf/16), (6 ` ozf)/(3 ` kg) `` m/s^2);
788 8896443230521/16000000000000 ` m/s^2;
790 (4 ` mile) * (3 ` feet) * (2 ` mm) * (20 ` kg/foot^3) `` kg;
793 (150 ` lbm) * (2*%pi/(1`day))^2 * (4000 ` mile) `` N;
794 63366854089*%pi^2/270000000000 ` N;
796 (if get ('physical_constants, 'version) = false then load (physical_constants),
797 declare_unit_conversion (1 ` eV = (1 ` V) * constvalue (%%e) `` J),
798 vv : solve (Ek = 1/2 * m * v^2, v),
799 v1 : ev (second (vv), Ek = 1`eV, m = 1`lbm));
800 v = sqrt(2) ` sqrt(eV)/sqrt(lbm);
802 map (dimensions, v1);
803 'dimensions(v) = length/time;
805 map (lambda ([x], x `` cm/year), v1);
806 v `` cm/year = 39447*sqrt(1602176487)/(15625*2^(5/2)*sqrt(45359237)) ` cm/year;
808 (declare_unit_conversion (gauss = tesla/10^4, G = gauss, kG = 1000*G, mph = mile/hour), (10 ` kG) * (6 ` inch) * (60 ` mph) `` V);
811 (declare_unit_conversion (1 ` cmil = %pi * ((1/1000 ` inch) / 2)^2, microohm = Ohm/10^6),
812 (172/100 ` microohm*cm) * (8/10 ` mile) / (10400 ` cmil) `` Ohm);
813 544896/(41275*%pi) ` Ohm;
815 (declare_unit_conversion (cal_tc = 4184/1000 * J, Btu_tc = 105435026444/10^8 * J, ton = 2000 * lbm),
816 (3 ` ton) * (1000 ` degF `` R - 70 ` degF `` R) * (9/100 ` cal_tc/g/K),
818 12655227123/100 ` cal_tc;
821 6618683785329/12500000000 ` MJ;
824 1203397051878000/2396250601 ` Btu_tc;
826 ((3/10 ` Btu*inch/hour/foot^2/R) * (150 ` m^2) * ((20 ` degC `` K) - (-15 ` degC `` K)) / (8 ` cm),
827 loss : %% `` Btu/hour);
828 4921875/508 ` Btu/hour;
833 (kill (p, V, n, R, T, foo),
834 solve ([p*V = n*R*T, n = m/M], [p, n]),
835 ev (first (first (%%)), R=constvalue (%R), m=5`oz, M=40`g/mol, V=678`inch^3, T=72`degF``K),
836 foo : rhs (%%) `` Pa);
837 2506412710065636911/3199803664896 ` Pa;
839 (declare_unit_conversion (atm = 101325/1000*kPa),
841 358058958580805273/46317158049369600 ` atm;
843 (ev (nu * rho * d / eta, nu = 5 ` mph, rho = 1 ` kg/liter, d = 7/8 ` inch, eta = 8*10^-6 ` lbf*s/foot^2),
845 14984331321600000/115538223773;
856 (87 ` degF `` R - 60 ` degF `` R) `` K;
859 /* from: http://www.kc9aop.net/Doc/link_pages/motors_and_mechanical.htm
860 * via: http://designerunits.com/examples/sites/kc9aop/motors_and_mechanical
863 (declare_unit_conversion ('Hz[S] = 2*%pi*Hz, rpm = 2*%pi/(60*s)),
864 omega_mech : ev (2/npoles * 60 ` 'Hz[S] `` rpm, npoles = 2));
867 (40 ` hp)/(1725 ` rpm) `` lbf*foot;
868 8800/(23*%pi) ` foot*lbf;
870 compute_conversion_factor (hp/rpm, lbf*foot);
873 (declare_unit_conversion (radian=1),
874 (70 ` lbf)*(3 ` feet)/(1 ` radian) `` lbf*foot);
877 (30 ` hp)/(1725 ` rpm) `` lbf*foot;
878 6600/(23*%pi) ` foot*lbf;
880 (230 ` V)*(4 ` A)*82/100 `` hp;
881 37720000000000000/37284993579113511 ` hp;
883 (1725 ` rpm)*(31/10 ` lbf*foot) `` hp;
886 omega_mech : ev (2/npoles * 50 ` 'Hz[S] `` rpm, npoles = 4);
889 /* from: http://www.ibiblio.org/harris/500milemail.html
890 * "The case of the 500-mile email" -- a pleasant diversion
893 declare_unit_conversion (1 ` lightsecond = constvalue (%c) * (1 ` s), millilightsecond = lightsecond/1000);
896 3 ` millilightsecond `` mile;
897 149896229/268224 ` mile;
899 block ([fpprec : 16], 3b0 ` millilightsecond `` mile);
900 5.588471911536626b2 ` mile;
902 /* from the mailing list 2015-03-18: "Some ezunits questions" */
904 (1000 ` C+66.0*10^-9 ` F*V)*(46*10^3 ` Hz*V)``W;
905 4.6000000003036E+7 ` W;
907 /* subscripts applied to unitful expressions */
909 (kill (x, k), (x ` kg/m^2)[k]);
912 ([1, 2, 3] ` m/s^2)[3];
915 (kill (foo, i), declare_units (foo, MJ/cd), foo[i]);
916 /* verify that foo[i] not expanded to qty(foo[i]) ` MJ/cd or anything else */
919 /* "@" applied to unitful expressions */
921 (kill (foo, a, b, c), defstruct (foo (a, b, c)), 0);
924 (block ([x : new (foo ('x1, %pi, 17)) ` m/s], [x@a, x@b, x@c], ev (%%)));
925 [x1 ` m/s, %pi ` m/s, 17 ` m/s];
927 /* realpart/imagpart applied to unitful expressions
928 * ev(..., nouns) seems to be necessary to work around noun/verb strangeness ... sigh
931 (kill (x), x : (17 - %e*%i) ` s*A/kg, ['realpart (x), 'imagpart (x)], ev (%%, nouns));
932 [17 ` s*A/kg, -%e ` s*A/kg];
934 /* examples derived from dissertation of Andrew John Kennedy */
936 /* statistics of a list of numbers x:
937 * mean has same units as x
938 * variance has units = (units(x))^2
939 * std deviation has same units as x
940 * skewness is dimensionless
941 * covariance has units = units(x) * units(y)
942 * correlation is dimensionless
945 (kill (x, n), x : [2 ` kg/m^2, 3 ` kg/m^2, 5 ` kg/m^2, 7 ` kg/m^2, 11 ` kg/m^2], n : length (x), 0);
948 (kill (mean_x), mean_x : apply ("+", x) / n);
951 (kill (mean_x2, var_x), mean_x2 : apply ("+", map (lambda ([x1], x1^2), x)) / n, var_x : mean_x2 - mean_x^2);
954 (kill (std_x), std_x : sqrt (var_x));
957 (kill (mean_x3, skewness_x),
958 mean_x3 : apply ("+", map (lambda ([x1], x1^3), x)) / n,
959 moment3_x : mean_x3 - 3 * mean_x2 * mean_x + 2 * mean_x^3,
960 skewness_x : moment3_x / std_x^3);
963 (kill (y), y : [13 ` s*A, 17 ` s*A, 19 ` s*A, 23 ` s*A, 29 ` s*A], y_length : length (y), is (y_length = n));
966 (kill (mean_y), mean_y : apply ("+", y) / y_length);
969 (kill (mean_y2, var_y, std_y), mean_y2 : sum (y[i]^2, i, 1, y_length) / y_length, var_y : mean_y2 - mean_y^2, std_y : sqrt (var_y));
972 (kill (mean_xy, covar_xy), mean_xy : sum (x[i] * y[i], i, 1, n) / n, covar_xy : mean_xy - mean_x * mean_y);
975 (kill (corr_xy), corr_xy : covar_xy / std_x / std_y);
978 /* differentiation via secant approximation:
979 * diff(f(x), x) = (f(x + h) - f(x - h))/(2 h)
980 * => diff has units = units(f) / units(h) = units(f) / units(x)
981 * since units(x) = units(h)
984 (kill (f, x, y, h, e, e1),
985 declare ([f, x, y, h], dimensional),
986 declare_units (h, units(x)),
987 units ('diff (f(x), x)));
990 units ((f(x + h) - f(x - h))/(2*h));
993 /* additional examples for 'diff(...) */
995 units ('diff (f(x, y), x, 1, y, 1));
996 units(f)/(units(x)*units(y));
998 units ('diff (f(x, h), x, 1, h, 1));
1001 units ('diff (f(x, y), x, 2, y, 4));
1002 units(f)/(units(x)^2*units(y)^4);
1005 units ('diff (f(x, y), x, m, y, n)));
1006 units(f)/(units(x)^m*units(y)^n);
1008 /* second divided difference */
1009 (declare_units (x1, units(x)),
1010 declare_units (x2, units(x)),
1011 e: (f(x + h) - f(x - h))/(2*h),
1012 e1: subst (x = x1, e),
1013 e2: subst (x = x2, e),
1014 units ((e2 - e1)/(x2 - x1)));
1015 units(f)/units(x)^2;
1017 /* integration via trapezoid rule:
1018 * integral(f(x), x, a, b) = (h/2) (f(a) + 2 f(a + h) + ... + 2 f(b - h) + f(b)), h = (b - a)/n
1019 * => integral has units = units(x) * units(f)
1023 declare ([a, b], dimensional),
1024 units ('integrate (f(x), x, a, b)));
1027 /* TODO: also express summation as a 'sum(...) expression and look at units */
1028 (e1: (h/2)*(f(a) + 2*f(a + h) + 2*f(a + 2*h) + 2*f(b - 2*h) + 2*f(b - h) + f(b)),
1032 /* additional examples for 'integrate(...) */
1034 (declare_units (f, mile/hour^2),
1035 declare_units (t, hour),
1036 units ('integrate (f(t), t, %a ` hour, %b ` hour)));
1039 units ('integrate ('integrate (f(t), t), t));
1042 /* root finding via Newton-Raphson algorithm:
1043 * x[n + 1] = x[n] - f(x[n])/f'(x[n])
1044 * => each x[n] has same units as x[1]
1047 units (x[n + 1] = x[n] - f(x[n])/'at('diff(f(x), x), x = x[n]));
1048 units(x) = units(x);
1050 /* solve for units of variable in equation
1051 * see: http://groups.google.com/group/sage-support/browse_thread/thread/a60c943c224dfe87#
1054 (kill (eqn, H_l, h_c, T_a, T_l),
1055 eqn : H_l = h_c * (T_a - T_l),
1056 declare_units (H_l, calorie/cm^2/minute),
1057 declare_units ([T_a, T_l], K),
1058 declare (h_c, dimensional),
1060 calorie/(cm^2*minute) = 'units(h_c)*K;
1062 solve (eqn, units (h_c));
1063 ['units(h_c) = calorie/(cm^2*minute*K)];
1065 /* tickles bug in tellsimpafter: this example triggers an error
1066 * unless built-in simplifications are applied so that MRAT is
1067 * simplified away by the time GREAT is called.
1069 (kill (a, b, c, x), block ([x : (rat (1) ` a) * (1 ` b + c)], expand (x)));
1072 /* "*" rule now splits arguments into 3 types:
1073 * dimensional, nondimensional, and terms not known to be either one.
1074 * Thanks to Stefan Karrmann for suggesting it.
1076 (kill (a, b, c, d, e, f, g, h, foo, bar),
1077 exp (a ` b) * (c ` d) * (e ` f) * g * h);
1078 exp (a ` b) * (c * e * g * h ` d * f);
1080 (c ` d) * (e ` f) * g * h;
1081 c * e * g * h ` d * f;
1083 (c ` d) * (e ` f) * (g ` h);
1084 c * e * g ` d * f * h;
1086 foo (a ` b) * bar (c ` d) * (e ` f) * (g ` h) * 2 * %pi;
1087 foo (a ` b) * bar (c ` d) * (2 * %pi * e * g ` f * h);
1089 sin (a ` b) * bar (c ` d) * (e ` f) * (g ` h) * 2 * %pi;
1090 bar (c ` d) * (2 * %pi * e * g * sin (a ` b) ` f * h);
1092 exp (a ` b) + c ` d + e ` d + g + h;
1093 exp (a ` b) + (c + e) ` d + g + h;
1095 c ` d + e ` d + g + h;
1096 (c + e) ` d + g + h;
1101 foo (a ` b) + c ` d + e ` d + 2 + %pi;
1102 (c + e) ` d + foo (a ` b) + 2 + %pi;
1104 /* test rules for relational expressions */
1107 block ([a : 17 ` m, b : x ` mm],
1108 [a < b, a <= b, a >= b, a > b,
1109 /* SEE NOTE ABOUT SIMPLIFICATION OF DIMENSIONAL "=" IN EZUNITS_FUNCTIONS !!
1112 equal (a, b), notequal (a, b)]));
1113 [17 < x/1000, 17 <= x/1000, 17 >= x/1000, 17 > x/1000,
1115 17 = x/1000, 17 # x/1000,
1117 equal (17, x/1000), notequal (17, x/1000)];
1119 /* I'M NOT COMFORTABLE WITH IMPLICIT CONVERSION OF 0 TO DIMENSIONAL !!
1120 block ([a : b ` kg],
1127 equal (a, 0), equal (0, a),
1128 notequal (a, 0), notequal (0, a)]);
1135 equal (b, 0), equal (0, b),
1136 notequal (b, 0), notequal (0, b)];
1139 /* sin, cos, etc of dimensionless quantities */
1141 (foo1 : [sin, cos, tan, csc, sec, cot, exp, log],
1143 z : (x ` m)/(y ` foot) `` 1);
1146 map (lambda ([f1], f1((x ` m)/(y ` foot))), foo1);
1147 ''(makelist (f1(z), f1, foo1));
1149 atan2 (x ` m, y ` foot);
1150 atan2 (x, 381*y/1250);
1152 exp (- (t ` hour)/(T ` s));
1155 /* in this next example, %%k*(x ` K)/(y ` J) is dimensionless,
1156 * but it is a little too complex to be detected by the rule for
1157 * dimensionless argument of exp.
1158 * We'll help out a little.
1160 foo: exp (-%%k*(x ` K)/(y ` J));
1161 exp (%%k*((-x/y) ` K/J));
1163 map (lambda ([e], if dimensions(e) = 1 then qty(e) else e), foo);
1164 exp (-qty(%%k)*x/y);
1166 /* fractions of a farad */
1169 1/1000000000000 ` A$
1177 /* Reported on mailing list by Antonio Lapira 2015-04-04 - FIXED */
1181 /* ensure nondimensional/(sum of dimensional) `` whatever = nondimensional/((sum of dimensional) `` 1/whatever)
1182 * inspired by mailing list 2018-12-12: "ezunits: strange multiplication behaviour?"
1185 1/(sqrt(1`henry*1`farad)) `` 1/s;
1188 1/(1`s+sqrt(1`henry*1`farad)) `` 1/s;
1191 /* other examples */
1193 (%e + %pi) / (100 ` hour - 100 ` s + x ` ms) `` Hz;
1194 (%e + %pi) / (x/1000 + 359900) ` Hz;
1196 /* SF bug #3789: "package ezunits: ev(dimensions(u), nouns) stack overflow" */
1198 (foo: 81*sin(acos((77-x)/81)-atan(7/20)), 0);
1201 /* primary test here is just the absence of stack overflow error;
1202 * numerical value not really crucial
1204 is (abs (find_root (foo - 50.58515344111066, x, 5, 55, abserr = 1e-6) - 34.0) <= 1e-6);
1207 (kill(u), ev (dimensions(u), nouns));
1211 * plot2d (foo, [x, 5, 55]);