2013年8月9日金曜日

おまけの計算

おまけの計算
CyUtilモジュールのbcd関数を使えば5アームクランクのbcd(ボルト=サークル=ダイアメーター(クランクのpcd)が分かります。
例えばあるクランクの隣りあったチェーンリング取り付けボルト穴の距離(ピッチ)を測って
76mmだった時、
 CyUtil> bcd 76
129.29892

ですのでこのクランクのpcdは130となります。
これは、半径rの円に内接する正5角形の1辺の長さからrを求める計算です。

上図の三角形abcで辺acはピッチの半分、∠acbは直角、∠abcは360÷(5×2)ですので
三角関数のサインを適用すればいいことが分かります。

Prelude> (76/2) / sin ((3.14*2)/10) *2
129.35564152105735

(簡易計算としてはピッチを1.7倍してもよい

Prelude> 76*1.7
129.2

pcdはほぼ決まっているのでこれで十分です。


****************

pcd関数を使えばチェーンリングのpcdが分かります。この場合のpcdはチェーンのピンが形作る仮想円です。

例えば歯数50Tのチェーンリングのpcdは

Prelude> :l CyUtil.hs
Ok, modules loaded: CyUtil.
Prelude CyUtil> pcd 50
202.25983

ですので、逆にチェーンリングのpcdを測って、202mmであればそのチェーンリングの歯数は50Tだと分かります。
pcdは測りづらいので歯底距離を測ります。

Prelude CyUtil> grd 50
194.41385

前もって歯底距離の一覧表を作っておけば、チェーンリング、コグの歯数を調べることができます。

Prelude CyUtil> map (\x-> (x, round1 (grd x))) [10..60]
[(10,"32.9"),(11,"37.3"),(12,"40.9"),(13,"45.3"),(14,"49.0"),(15,"53.3"),(16,"57.0"),(17,"61.3"),(18,"65.1"),(19,"69.4"),(20,"73.2"),(21,"77.4"),(22,"81.2"),(23,"85.5"),(24,"89.3"),(25,"93.5"),(26,"97.4"),(27,"101.6"),(28,"105.5"),(29,"109.7"),(30,"113.5"),(31,"117.7"),(32,"121.6"),(33,"125.8"),(34,"129.7"),(35,"133.9"),(36,"137.8"),(37,"142.0"),(38,"145.9"),(39,"150.0"),(40,"153.9"),(41,"158.1"),(42,"162.0"),(43,"166.2"),(44,"170.1"),(45,"174.3"),(46,"178.2"),(47,"182.3"),(48,"186.3"),(49,"190.4"),(50,"194.4"),(51,"198.5"),(52,"202.4"),(53,"206.6"),(54,"210.5"),(55,"214.7"),(56,"218.6"),(57,"222.7"),(58,"226.7"),(59,"230.8"),(60,"234.8")]


またpcdはシングルバイクのチェーン長を計算する時にも使います。


import CyUtil
import System.Environment

class Gear a where
getPhase :: a -> IO Float
getL :: a -> IO Float

data FG = FG Int deriving Show
data RG = RG Int deriving Show

instance Gear FG where
getPhase _ = getG >>= return . (*2) . (+ d90)
getL f@(FG a) = getPhase f >>= calL a
instance Gear RG where
getPhase _ = getG >>= return . (*2) . (+ d90) . negate
getL r@(RG a) = getPhase r >>= calL a
calL a = return . (*(fromIntegral a)) . (/ yen)
getG = do
(FG a,RG b,c) <- mkGS
let l = pcr a - pcr b
return $ asin (l / c)

mkGS = do
[a,b,c] <- getArgs
return $ (FG (read a), RG (read b), (read c))

chLen = do
(_,_,c) <- mkGS
t <- getG
return $ myCos (c, t) / lOfLink * 2
main = do
(a,b,c) <- mkGS
l <- getL a
ll <- getL b
lll <- chLen
print $ l+ll+lll



補助線を1本加えますと計算方法がわかりやすくなります。
直角三角形abcの各辺の長さを計算します。
辺acはチェーンステイ長。辺bcは前後ギヤのPCDの差から。辺abは他辺から三平方の定理で計算できます。

すこし面倒なのが前後ギヤへのチェーンの巻きつき量ですが、
 角bdeの角度がわかれば計算できます。
上図から角bdeは角bacに等しいようです。

角bacは三角関数の逆関数アークサイン(haskellではasin)で求めます。

ghcでコンパイル。

$ ghc g.hs
Linking g ...

コマンドライン引数で数値を渡します。
他のページ(カスタムジャパンさん)の計算結果を参考にします。


$ ./g 48 16 405
96.594635

**********************************************

Gui版


--chainLen.hs 
import Graphics.UI.Gtk
import CyUtil
import Control.Monad
import MySpin
initData :: [Double]
initData = [48,16,405]
data GearSystem = GS{fg::FG,rg::RG,csl::Double} deriving Show
mkGS :: [Double] -> GearSystem
mkGS [a,b,c] = GS (FG(round a)) (RG(round b)) c 
getG :: GearSystem -> Double
getG (GS (FG a) (RG b) c) = 
let l = pcr a - pcr b
in asin (l / c)
class Gear a where
getPhase :: GearSystem -> a -> Double 
getL :: GearSystem -> a -> Double
data FG = FG Int deriving Show
data RG = RG Int deriving Show
instance Gear FG where
getPhase gs (FG _) = (d90 + getG gs) / d180
getL gs fg@(FG t) = fromIntegral t * getPhase gs fg
instance Gear RG where
getPhase gs (RG _) = (d90 - getG gs) / d180
getL gs rg@(RG t) = fromIntegral t * getPhase gs rg
chLen :: GearSystem -> Double
chLen gs@(GS _ _ c) = 
let t = getG gs
in myCos (c, t) / lOfLink * 2
links :: [Double] -> Double
links ds = let gs@(GS a b c) = mkGS ds in  getL gs a + getL gs b + chLen gs 

main = do
initGUI
window  <- windowNew
hbox <- hBoxNew False 0
vbox <- vBoxNew False 0
boxPackStart vbox hbox PackNatural 0
let [a,b,c] = initData
let spmods = [ ("前ギヤ(T)" ,20, 60 ,1,a),
("後ろギヤ(T)" ,6, 30 ,1,b),
("チェーンステイ長(mm)" ,300, 1000 ,1,c)]
spins <- myAddSpinButtons hbox spmods
label <- labelNew Nothing 
update label spins
mapM (\x->  onValueSpinned x (update label spins)) spins
boxPackStart vbox label PackNatural 0
containerAdd window vbox
widgetShowAll window
onDestroy window mainQuit
mainGUI

update label spins = do
ds <- mapM (\x -> get x spinButtonValue) spins
let l = links ds
labelSetText label ("チェーン長(リンク数)=" ++ (round1 l))


***********************************************
--CyUtil.hs
module CyUtil where

import Data.Complex
rad d = ((2*pi)/360)*d
dig r = r / (yen/360)
yen = rad 360 
d90 = rad 90
d180 = rad 180
dist1 c1 c2 = magnitude (c1-c2)
dist ((a,b),(c,d)) = 
let
c1 = mkPolar a b
c2 = mkPolar c d
in dist1 c1 c2
pita l1 l2 = dist1 (0 :+ l1) (l2 :+ 0)
myCos (a,b) = realPart $ mkPolar a b
round1 x = a ++ take 2 b
where (a,b) = break (=='.') $ show x

d1 = 7.75 -- チェーン ローラー の半径(mm) 
lOfLink = 25.4 / 2 -- チェーンリンク長(mm) 
rOfPolygon n l = (l / 2) / sin ((yen / n) / 2) 
r5 = rOfPolygon 5
bcd = (* 2) . r5 
pcr x = rOfPolygon (fromIntegral x) lOfLink 
pcd = (*2) . pcr
grd x = if odd x
then pcd x - d1
else dist ((r, rad (-180)),(r, yen / (fromIntegral x) / 2))
        where r = pcd x / 2 - (d1 / 2)

CyUtil も少し書き換えていると思いますので、再録します。

実行例
**********************************************************

にソースファイルがあります。

0 件のコメント:

コメントを投稿