;; ;; Based on code by Dmitry A. Kazakov and Gordon S. Novak ;; ;; TODO: implement non-strict conversion (e.g. mass <-> energy, mass <-> weight) ;; (module unitconv (unit-factor-eval (define-quantity quantity-expr-eval) (define-unit unit-factor-eval) make-unit-prefix unitconv:error make-quantity quantity? quantity-name quantity-int make-unit unit? unit-equal? unit-name unit-factor unit-prefix unit-convert Unity Length Time Temperature Mass Current Luminosity Substance Currency Information ;; ;; Geometry ;; Area Volume ;; ;; Mechanics ;; Velocity Acceleration Force Pressure Energy Power ;; ;; Electricity ;; Charge Potential Capacitance Resistance Conductance Inductance ;; ;; Chemistry ;; Concentration Density ;; ;; Optic ;; Luminance ;; ;; Other ;; Frequency unitless ;; SI unit prefixes yocto zepto atto femto pico nano micro milli centi deci deca hecto kilo mega giga tera peta exa zetta yotta ;; Time multiples twelve sixty ;; Angles (dimensionless ratio) radian degree ;; Units of length meter inch foot angstrom parsec millimeter micrometer micron ;; Units of area and volume square-meter square-inch square-micron square-millimeter cubic-meter liter ;; Units of mass kilogram gram milligram pound slug atomic-mass-unit ;; Units of time second hour ;; Units of acceleration meters-per-second-squared ;; Units of frequency hertz ;; Units of force newton pound-force ;; Units of power watt horsepower ;; Units of energy joule electron-volt kilowatt-hour calorie erg british-thermal-unit ;; Units of current ampere ;; Units of electric charge coulomb ;; Units of electric potential volt ;; Units of resistance ohm ;; Units of capacitance farad microfarad picofarad ;; Units of conductance siemens ;; Units of inductance henry millihenry microhenry ;; Units of substance mole ;; Units of density rho ;; Units of concentration molarity parts-per-million ;; Units of temperature degK ;; Units of information quantity, evidence, and information entropy ;; bit = log_2(p) (Shannon) bit ;; byte = 8 bits byte ;; nat = log_e(p) (Boulton and Wallace) nat ;; ban = log_10(p) (Hartley, Turing, and Good) ban ;; The deciban is the smallest weight of evidence discernible by a human ;; deciban = 10*log_10(p) deciban ;; bits kilobit megabit gigabit terabit petabit exabit zettabit yottabit kibibit mebibit gibibit tebibit pebibit exbibit zebibit yobibit ;; bytes kilobyte megabyte gigabyte terabyte petabyte exabyte zettabyte yottabyte kibibyte mebibyte gibibyte tebibyte pebibyte exbibyte zebibyte yobibyte ;; bit rates bits-per-second kilobits-per-second megabits-per-second gigabits-per-second terabits-per-second petabits-per-second exabits-per-second zettabits-per-second yottabits-per-second ;; byte rates bytes-per-second kilobytes-per-second megabytes-per-second gigabytes-per-second terabytes-per-second petabytes-per-second exabytes-per-second zettabytes-per-second yottabytes-per-second ) (import scheme chicken data-structures extras srfi-4) (require-extension datatype matchable srfi-4) (import-for-syntax matchable chicken) (define pi 3.14159265358979) (define (unitconv:error x . rest) (let ((port (open-output-string))) (let loop ((objs (cons x rest))) (if (null? objs) (begin (newline port) (error 'unitconv (get-output-string port))) (begin (display (car objs) port) (display " " port) (loop (cdr objs))))))) (define-record quantity name int) (define-record-printer (quantity x out) (if (zero? (quantity-int x)) (fprintf out "#(quantity Unity)") (fprintf out "#(quantity ~S ~S)" (quantity-name x) (quantity-int x)))) ;; The number of base quantities defined (define Q 9) (define dref s32vector-ref) ;; The sizes of the field assigned to each base quantity; a field size ;; of 20 allows a value range of +-9 for the power of that quantity (define dimsizes (s32vector 20 20 20 10 10 10 10 10 20)) ;; Multipliers that can be used to move a vector value to its proper ;; field position; defined as follows: ;; ;; dimvals_{0} = 1 ;; dimvals_{i} = dimvals_{i-1} * dimsizes_{i-1} i > 0 ;; (define dimvals (let loop ((i 1) (lst (list 1))) (if (< i Q) (let ((x (* (car lst) (dref dimsizes (- i 1))))) (loop (+ 1 i) (cons x lst))) (list->s32vector (reverse lst))))) ;; (s32vector 1 20 400 8000 80000 800000 8000000 80000000)) ;; A value that, when added to a dimension integer will make it ;; positive and will bias each vector component within its field by ;; half the size of the field; defined as: ;; ;; dimbias = sum_{i=0}^{7}\frac{dimvals_{i} * dimsizes_{i}}{2} ;; (define dimbias (let loop ((i 0) (sum 0)) (if (< i Q) (loop (+ i 1) (+ sum (/ (* (dref dimvals i) (dref dimsizes i)) 2))) sum))) ;; 444444210 ;; Compute a dimension integer from a dimension vector ;; ;; For example, the dimension integer for force can be calculated as ;; follows: ;; ;; force = length * time^{-2} * mass ;; ;; (dimint (s32vector 1 -2 0 1 0 0 0 0)) ;; => 7961 ;; (define (dimint v) (let loop ((i (- Q 1)) (sum 0)) (if (fx<= 0 i) (loop (fx- i 1) (+ sum (* (dref dimvals i) (dref v i)))) sum))) (define-syntax define-base-quantity (lambda (x r c) (let ((name (cadr x)) (value (caddr x)) (%define (r 'define))) `(,%define ,name (make-quantity ',name ,value))))) (define-base-quantity Unity 0) (define-base-quantity Length (dref dimvals 0)) (define-base-quantity Time (dref dimvals 1)) (define-base-quantity Temperature (dref dimvals 2)) (define-base-quantity Mass (dref dimvals 3)) (define-base-quantity Current (dref dimvals 4)) (define-base-quantity Luminosity (dref dimvals 5)) (define-base-quantity Substance (dref dimvals 6)) (define-base-quantity Currency (dref dimvals 7)) (define-base-quantity Information (dref dimvals 8)) (define-record unit name dims factor abbrevs) (define (unit-equal? x y) (and (= (quantity-int (unit-dims x)) (quantity-int (unit-dims y))) (= (unit-factor x) (unit-factor y)))) (define-record-printer (unit x out) (let ((dims (unit-dims x)) (abbrevs (unit-abbrevs x))) (if (null? abbrevs) (fprintf out "#(unit ~S " (unit-name x)) (fprintf out "#(unit ~S ~S " (unit-name x) (unit-abbrevs x))) (fprintf out "[~S] ~S)" (quantity-name (unit-dims x)) (unit-factor x)))) (define (unit-prefix prefix u abbrevs) (or (and (unit? prefix) (unit? u)) (unitconv:error 'unit-prefix ": invalid unit: " u)) (if (not (= 0 (quantity-int (unit-dims prefix)))) (unitconv:error 'unit-prefix ": prefix must be dimensionless: " prefix)) (if (zero? (quantity-int (unit-dims u))) (unitconv:error 'unit-prefix ": unit must not be dimensionless: " u)) (make-unit (string->symbol (string-append (symbol->string (unit-name prefix)) (symbol->string (unit-name u)))) (unit-dims u) (* (unit-factor prefix) (unit-factor u)) abbrevs)) ;; ;; Unit conversion ;; (define (unit-convert src dest . vals) (or (and (unit? src) (unit? dest)) (unitconv:error 'unit-convert ": invalid unit: " src dest)) (if (= (quantity-int (unit-dims src)) (quantity-int (unit-dims dest))) (let ((f (/ (unit-factor src) (unit-factor dest)))) (if (null? vals) f ((lambda (x) (if (null? (cdr x)) (car x) x)) (map (lambda (x) (* f x)) vals)))) (unitconv:error 'unit-convert ": given units are of different dimensions: source=" src "; dest= " dest))) (define-syntax quantity-expr-eval (lambda (x r c) (let ((expr (cadr x)) (left? (caddr x)) (%let (r 'let)) (%cond (r 'cond)) (%else (r 'else)) (integer? (r 'integer?)) (not (r 'not)) (and (r 'and)) (x1 (r 'x1)) (y1 (r 'y1)) (quantity-expr-eval (r 'quantity-expr-eval)) (quantity? (r 'quantity?)) (quantity-int (r 'quantity-int))) (match expr ((op x y) `(,%let ((,x1 (,quantity-expr-eval ,x #t)) (,y1 (,quantity-expr-eval ,y ,left?))) ,(case op ((**) `(* ,x1 ,y1)) ((*) `(+ ,x1 ,y1)) ((/) `(- ,x1 ,y1)) (else (unitconv:error 'quantity-expr-eval ": unknown quantity operation " op))))) (x `(,%cond ((,quantity? ,x) (,quantity-int ,x)) ((,and (,not ,left?) (,integer? ,x)) ,x) ((,and ,left? (,integer? ,x)) (unitconv:error 'quantity-expr-eval "integers are not allowed as the left operand of quantity expression")) (,%else (unitconv:error 'quantity-expr-eval ": unknown quantity " ,x)))))))) (define-syntax define-quantity (lambda (x r c) (let ((name (cadr x)) (expr (caddr x)) (%define (r 'define)) (make-quantity (r 'make-quantity)) (quantity-expr-eval (r 'quantity-expr-eval))) `(,%define ,name (,make-quantity ',name (,quantity-expr-eval ,expr #f)))))) (define-for-syntax (binop-fold op lst) (if (null? lst) lst (match lst ((x) x) ((x y) `(,op ,x ,y)) ((x y . rest) `(,op (,op ,x ,y) ,(binop-fold op rest))) ((x . rest) `(,op ,x ,(binop-fold op rest)))))) (define-syntax unit-factor-eval (lambda (x r c) (let ((expr (cadr x)) (%let (r 'let)) (%cond (r 'cond)) (%else (r 'else)) (x1 (r 'x1)) (y1 (r 'y1)) (unit? (r 'unit?)) (unit-factor (r 'unit-factor)) (number? (r 'number?))) (match expr ((op x y) `(,%let ((,x1 (unit-factor-eval ,x)) (,y1 (unit-factor-eval ,y))) ,(case op ((*) `(* ,x1 ,y1)) ((/) `(/ ,x1 ,y1)) (else (unitconv:error 'unit-factor-eval ": unknown unit factor operation " op))))) ((op x . y) `(unit-factor-eval ,(binop-fold op (cons x y)))) (x `(cond ((,unit? ,x) (,unit-factor ,x)) ((,number? ,x) ,x) (else (unitconv:error 'unit-factor-eval ": unknown unit " ,x)))))))) (define-syntax define-unit (lambda (x r c) (let ((name (cadr x)) (dims (caddr x)) (factor (cadddr x)) (abbrevs (cddddr x)) (%define (r 'define))) `(,%define ,name (make-unit ',name ,dims (unit-factor-eval ,factor) ',abbrevs))))) (define-syntax make-unit-prefix (lambda (x r c) (let ((prefix (cadr x)) (unit (caddr x)) (abbrevs (cdddr x))) `(unit-prefix ,prefix ,unit ',abbrevs)))) ;; ;; Geometry ;; (define-quantity Area (** Length 2)) (define-quantity Volume (** Length 3)) ;; ;; Mechanics ;; (define-quantity Velocity (/ Length Time)) (define-quantity Acceleration (/ Length (** Time 2))) (define-quantity Force (* Mass Acceleration)) (define-quantity Pressure (/ Force Area)) (define-quantity Energy (* Force Length)) (define-quantity Power (/ Energy Time)) ;; ;; Electricity ;; (define-quantity Charge (* Current Time)) (define-quantity Potential (/ Energy Charge)) (define-quantity Capacitance (/ Charge Potential)) (define-quantity Resistance (/ Potential Current)) (define-quantity Conductance (/ Current Potential)) (define-quantity Inductance (/ (* Potential Time) Current)) ;; ;; Chemistry ;; (define-quantity Concentration (/ Substance Volume)) (define-quantity Density (/ Mass Volume)) ;; ;; Optic ;; (define-quantity Luminance (/ Luminosity Area)) ;; ;; Other ;; (define-quantity Frequency (/ Unity Time)) ;; ;; Information ;; (define-quantity Rate (/ Information Time)) (define-unit unitless Unity 1.0) ;; SI unit prefixes (define-unit yocto Unity 1.0e-24) (define-unit zepto Unity 1.0e-21) (define-unit atto Unity 1.0e-18) (define-unit femto Unity 1.0e-15) (define-unit pico Unity 1.0e-12) (define-unit nano Unity 1.0e-9) (define-unit micro Unity 1.0e-6) (define-unit milli Unity 1.0e-3) (define-unit centi Unity 1.0e-2) (define-unit deci Unity 1.0e-1) (define-unit deca Unity 1.0e1) (define-unit hecto Unity 1.0e2) (define-unit kilo Unity 1.0e3) (define-unit mega Unity 1.0e6) (define-unit giga Unity 1.0e9) (define-unit tera Unity 1.0e12) (define-unit peta Unity 1.0e15) (define-unit exa Unity 1.0e18) (define-unit zetta Unity 1.0e21) (define-unit yotta Unity 1.0e24) ;; IEC standard prefixes (define-unit kibi Unity 1024) (define-unit mebi Unity 1048576) (define-unit gibi Unity 1073741824) (define-unit tebi Unity 1099511627776) (define-unit pebi Unity 1125899906842624) (define-unit exbi Unity 1152921504606846976) (define-unit zebi Unity 1180591620717411303424) (define-unit yobi Unity 1208925819614629174706176) ;; Time multiples (define-unit twelve Unity 12) (define-unit sixty Unity 60) ;; Angles (dimensionless ratio) (define-unit radian Unity 1.0 rad radians) (define-unit degree Unity (/ pi 180) deg degrees) ;; Units of length (define-unit meter Length 1.0 m meters) (define-unit inch Length 0.0254 in inches) (define-unit foot Length 0.3048 ft feet) (define-unit angstrom Length 1.0e-10 ang angstroms) (define-unit parsec Length 3.083e16 parsecs) (define millimeter (make-unit-prefix milli meter mm millimeters)) (define micrometer (make-unit-prefix micro meter um micron microns micrometers)) (define micron micrometer) ;; Units of area and volume (define-unit square-meter Area (* meter meter) m^2 m2 meter-squared meters-squared square-meters) (define-unit square-inch Area (* inch inch) in^2 inch-squared inches-squared square-inches) (define-unit square-micron Area (* micrometer micrometer) um^2 micrometer-squared micrometers-squared micron-squared microns-squared square-microns) (define-unit square-millimeter Area (* millimeter millimeter) mm^2 millimeter-squared millimeters-squared square-millimeters) (define-unit cubic-meter Volume (* meter (* meter meter)) m^3 meter-cubed meters-cubed cubic-meters ) (define-unit liter Volume (* 0.001 cubic-meter) L litre liters) ;; Units of mass (define-unit kilogram Mass 1.0 kg kilograms) (define-unit gram Mass 1e-3 g grams) (define milligram (make-unit-prefix milli gram mg milligrams)) (define-unit pound Mass (* gram 453.59237) lb pounds) (define-unit slug Mass (* pound 32.17405) slugs) (define-unit atomic-mass-unit Mass 1.6605402e-27 amu atomic-mass-units) ;; Units of time (define-unit second Time 1.0 s seconds) (define-unit hour Time (* sixty (* sixty second)) h hrs hours) ;; Units of acceleration (define-unit meters-per-second-squared Acceleration (/ meter (* second second)) m/s2 m/s^2 m/sec2 m/sec^2) ;; Units of frequency (define-unit hertz Frequency 1.0 hz) ;; Units of force (define-unit newton Force (/ (* kilogram meter) (* second second)) nt newtons) (define-unit pound-force Force (/ (* slug foot) (* second second)) lbf) ;; Units of power (define-unit watt Power (/ (* kilogram meter meter) (* second second second)) W watts) (define-unit horsepower Power (* 550 (/ (* foot pound-force) second)) hp) ;; Units of energy (define-unit joule Energy (* newton meter) J joules) (define-unit electron-volt Energy (* 1.60217733e-19 joule) ev electron-volts) (define-unit kilowatt-hour Energy (* kilo (* watt hour)) kwh kilowatt-hours) (define-unit calorie Energy (* 4.184 joule) cal calories) (define-unit erg Energy (* 1.0e-7 joule) ergs) (define-unit british-thermal-unit Energy (* 1055.056 joule) btu btus) ;; Units of current (define-unit ampere Current 1.0 A amp amps amperes) ;; Units of electric charge (define-unit coulomb Charge (* ampere second) C coulombs) ;; Units of electric potential (define-unit volt Potential (/ (* kilogram meter meter) (* ampere second second second)) V volts) ;; Units of resistance (define-unit ohm Resistance (/ volt ampere) ohms) ;; Units of capacitance (define-unit farad Capacitance (/ coulomb volt) F farads) (define microfarad (make-unit-prefix micro farad uF microfarads)) (define picofarad (make-unit-prefix pico farad pF picofarads)) ;; Units of conductance (define-unit siemens Conductance (/ ampere volt) S mho) ;; Units of inductance (define-unit henry Inductance (/ (* meter meter kilogram) (* ampere ampere second second)) H) (define millihenry (make-unit-prefix milli henry mH)) (define microhenry (make-unit-prefix micro henry uH)) ;; Units of substance (define-unit mole Substance 1.0 mol moles) ;; Units of density (define-unit rho Density (/ kilogram cubic-meter)) ;; Units of concentration (define-unit molarity Concentration (/ mole liter) M mol/L) (define-unit parts-per-million Concentration (/ milligram kilogram) ppm) ;; Units of temperature (define-unit degK Temperature 1.0 K) ;; Units of information quantity, evidence, and information entropy ;; bit = log_2(p) (Shannon) (define-unit bit Information 1 b bits shannon shannons Sh) ;; byte = 8 bits (define-unit byte Information 8 B bytes) ;; nat = log_e(p) (Boulton and Wallace) (define-unit nat Information 1.44269504088896 nats nit nits nepit nepits) ;; ban = log_10(p) (Hartley, Turing, and Good) (define-unit ban Information 3.32192809488736 bans hartley hartleys Hart Harts dit dits) ;; The deciban is the smallest weight of evidence discernible by a human ;; deciban = 10*log_10(p) (define-unit deciban Information (/ ban 10) db decibans) ;; bits (define kilobit (make-unit-prefix kilo bit kb kilobits)) (define megabit (make-unit-prefix mega bit Mb megabits)) (define gigabit (make-unit-prefix giga bit Gb gigabits)) (define terabit (make-unit-prefix tera bit Tb terabits)) (define petabit (make-unit-prefix peta bit Pb petabits)) (define exabit (make-unit-prefix exa bit Eb exabits)) (define zettabit (make-unit-prefix zetta bit Zb zettabits)) (define yottabit (make-unit-prefix yotta bit Yb yottabits)) (define kibibit (make-unit-prefix kibi bit Kib kibibits)) (define mebibit (make-unit-prefix mebi bit Mib mebibits)) (define gibibit (make-unit-prefix gibi bit Gib gibibits)) (define tebibit (make-unit-prefix tebi bit Tib tebibits)) (define pebibit (make-unit-prefix pebi bit Pib pebibits)) (define exbibit (make-unit-prefix exbi bit Eib exbibits)) (define zebibit (make-unit-prefix zebi bit Zib zebibits)) (define yobibit (make-unit-prefix yobi bit Yib yobibits)) ;; bytes (define kilobyte (make-unit-prefix kilo byte kB kilobytes)) (define megabyte (make-unit-prefix mega byte MB megabytes)) (define gigabyte (make-unit-prefix giga byte GB gigabytes)) (define terabyte (make-unit-prefix tera byte TB terabytes)) (define petabyte (make-unit-prefix peta byte PB petabytes)) (define exabyte (make-unit-prefix exa byte EB exabytes)) (define zettabyte (make-unit-prefix zetta byte ZB zettabytes)) (define yottabyte (make-unit-prefix yotta byte YB yottabytes)) (define kibibyte (make-unit-prefix kibi byte KiB kibibytes)) (define mebibyte (make-unit-prefix mebi byte MiB mebibytes)) (define gibibyte (make-unit-prefix gibi byte GiB gibibytes)) (define tebibyte (make-unit-prefix tebi byte TiB tebibytes)) (define pebibyte (make-unit-prefix pebi byte PiB pebibytes)) (define exbibyte (make-unit-prefix exbi byte EiB exbibytes)) (define zebibyte (make-unit-prefix zebi byte ZiB zebibytes)) (define yobibyte (make-unit-prefix yobi byte YiB yobibytes)) ;; bit rates (define-unit bits-per-second Rate (/ bit second) bps) (define-unit kilobits-per-second Rate (/ kilobit second) kbps) (define-unit megabits-per-second Rate (/ megabit second) Mbps) (define-unit gigabits-per-second Rate (/ gigabit second) Gbps) (define-unit terabits-per-second Rate (/ terabit second) Tbps) (define-unit petabits-per-second Rate (/ petabit second) Pbps) (define-unit exabits-per-second Rate (/ exabit second) Ebps) (define-unit zettabits-per-second Rate (/ zettabit second) Zbps) (define-unit yottabits-per-second Rate (/ yottabit second) Ybps) ;; byte rates (define-unit bytes-per-second Rate (/ byte second) Bps) (define-unit kilobytes-per-second Rate (/ kilobyte second) kBps) (define-unit megabytes-per-second Rate (/ megabyte second) MBps) (define-unit gigabytes-per-second Rate (/ gigabyte second) GBps) (define-unit terabytes-per-second Rate (/ terabyte second) TBps) (define-unit petabytes-per-second Rate (/ petabyte second) PBps) (define-unit exabytes-per-second Rate (/ exabyte second) EBps) (define-unit zettabytes-per-second Rate (/ zettabyte second) ZBps) (define-unit yottabytes-per-second Rate (/ yottabyte second) YBps) )