! Well, it's hard to see very clearly, because the big variation ! happens when the amplitude is very small. The real point is that ! it's impossible to DEFINE this number lambda_tone except in ! the isolated case when you have a trig identity (ie A=1); ! and even then its true meaning is suspect. ! ! If you have a complex valued function z (such as e^{i(w_0)t} + e^{iwt} ) ! you can define the "instantaneous circular frequency" by ! ! Im(z-dot/z) ! ! where z-dot is the velocity function (also complex valued). ! ! If you work this out for z = e^{(a+bi)t} you will find the constant ! frequency b , which is good. ! ! If you do this for a sum of two sines of different frequencies, ! you'll get something that varies with time, even if the amplitudes ARE ! equal. ! ! Sorry about the confusion! In any case, by varying A from 1 down to 0, ! you can see that the formula I suggested for lambda_tone can't possibly ! be right. ! (1) the lambda_sum should not actually appear. I was wrong ! in thinking that it made sense. This formula is correct if A = 1, ! but not otherwise - certainly not if A = 0, for example. ! In fact the "tone frequency" varies with t except in those cases. ! I think we should leave it out. ! ! I finally worked out what the envelope should be in our beats tool. ! ! I thought about what must happen as A is pushed from 1 to 0. ! At 1, the 'tone frequency' is the average of the two initial ! frequencies. But this can't be the sitation for other values of A. ! At A = 0, for example, the tone frequency is obviously omega_n. ! In fact, the best thing to say is that the pitch varies in a beat; ! it goes up when the beat is loud, and down when it's soft. ! ??? is this true ??? ! This made me annoyed enough to work out what the story actually is. ! There is a perfectly good envelope: ! ! g(t) = sqrt(1 + A^2 + 2*A*cos((omega-omega_0)*t + phi)). ! The beat frequency fb = f2 - f1, where f2 > f1. The tone frequency ft = (f1 + f2)/2. ! beat period is 2pi/(w-w_n) and w_n=1 !! File: Beats !! August 25, 2003 Hubert Hohn PUBLIC PCFlag,Mac5Flag,M68KFlag,UnixFlag,xmax,ymax PUBLIC toolLft,toolRgt,toolBas,toolTop,toolhdr,toolHgt,toolWid ! tool boundaries PUBLIC winLft,winRgt,winBas,winTop,winHgt,winWid ! window PUBLIC workLft,workRgt,workBas,workTop,workMidx ! work area PUBLIC backclr,black,drkgry,drkmid,midgry,litmid,litgry,white PUBLIC red,yellow,green,cyan,blue,magenta,pink,colorscheme PUBLIC planeclr,gridclr,rimclr,axisclr,axislabelclr,titleclr,rightsclr PUBLIC numberlineclr,slotdrkclr,slotlgtclr,slideclr PUBLIC largefonts, title$, SLUmode LET toolHgt= 560 LET toolWid= 780 LET window$= "The d'Arbeloff Interactive Math Project" LET colorscheme= 0 LET title$ = "Beats" SUB ThisProgram CALL SineSumBeats CLEAR END SUB !! --------------------------------------------------------- !! ------ Start TB4 Mac Header and Subs ------ !LET M68KFlag = 1 !LIBRARY "MacTools*", "HHLib.trc" !ASK PIXELS winWid,winHgt !LET winLft= 0 !LET winTop= 0 !LET winRgt= winWid-1 !LET winBas= winHgt-1 !SET WINDOW 0,winRgt,winBas,0 !CALL Palette !CLEAR ! !CALL ToolPanel !CALL ThisProgram ! !END !EXTERNAL ! !MODULE Mac4Parts ! SUB SetTextFont(font,size,style$) ! CALL MacTextFont(font) ! CALL MacTextSize(size) ! CALL MacTextFace(style$) ! END SUB ! ! SUB StringWidth(sw$,sl) ! DECLARE DEF MacStringWidth ! LET sl= MacStringWidth(sw$) ! END SUB ! ! SUB SetLineWeight(wgt) ! CALL MacPenSize(wgt,wgt) ! END SUB ! ! SUB BoxDisk(Lft,Rgt,Bas,Top) ! CALL MacPaintOval(Lft,Rgt,Bas,Top) ! END SUB !END MODULE !! --- End TB4 Mac Header and Subs --- !!--------------------------------------------------------- !!--- Start TB5 Cross-Platform header and subs --- LIBRARY "c:\TB Gold\TBLibs\TrueCtrl.trc" ! windows LIBRARY "c:\TB Gold\TBLibs\HHLib.trc" !LIBRARY ":TBLibs:TrueCtrl.trc" ! macintosh !LIBRARY "HHLib.trc" ! PUBLIC WinID DECLARE PUBLIC OBJM_SET,OBJM_SYSINFO LET winHgt= toolHgt LET winWid= toolWid DIM values(1) CALL TC_Init CALL Object(OBJM_SYSINFO,WinID,"MACHINE",system$,values()) IF system$="MAC" then LET Mac5Flag= 1 ELSE IF system$="WIN32" then LET PCFlag = 1 END IF CALL TC_SetUnitsToPixels ! 5.1 and up needs this CALL TC_GetScreenSize(scrnLft,scrnRgt,scrnBas,scrnTop) LET winLft= int((scrnRgt-scrnLft-winWid)/2) LET winRgt= winLft+winWid-1 LET winTop= int((scrnBas-scrnTop-winHgt)/2) + 10 LET winBas= winTop+winHgt-1 CALL TC_Win_Create (WinID,"TITLE",winLft,winRgt,winBas,winTop) LET values(1)= 2 CALL Object(OBJM_SET, WinID, "TYPE", "", values()) IF PCFlag=1 then ! kill dithering LET values(1)= 1 CALL Object(OBJM_SET, WinID, "SOLID MIX", "", values()) END IF LET values(1)= 0 CALL TC_SetRect(WinID,winLft,winRgt,winBas,winTop) CALL TC_Win_SetTitle(WinID,window$) CALL TC_Show(WinID) SET MODE "COLORSTANDARD" ASK PIXELS winWid,winHgt ! must follow set mode LET winLft= 0 LET winTop= 0 LET winRgt= winWid-1 LET winBas= winHgt-1 SET WINDOW 0,winRgt,winBas,0 CALL Palette IF PCFlag=1 then LET values(1)= 0 ! now force solid colors CALL Object(OBJM_SET, WinID, "SOLID MIX", "", values()) CALL TC_Win_RealizePalette(WinID) ! some PCs need this CALL TC_Win_SetFont(WinID,"arial",9,"plain") CALL StringWidth("0",sw) IF sw>7 then LET largefonts=1 else LET largefonts=0 END IF CALL TC_Win_Switch(WinID) CALL ToolPanel CALL ThisProgram CALL SetTextFont(1,12,"bold") ! now shut down and clean up LET quit$= "click the mouse or press a key to close..." CALL PlotTextCJ(workmidx,(workbas+worktop)/2,quit$,yellow) CALL TC_CleanUp END EXTERNAL MODULE TB5Parts SUB StringWidth(sw$,sl) DECLARE PUBLIC WinID LET sl= StrWidth(WinID,sw$) END SUB SUB SetLineWeight(wgt) DECLARE PUBLIC OBJM_SET DECLARE PUBLIC WinID DIM values(1) LET values(1)= wgt CALL Object(OBJM_SET,WinID, "WIDTH", "", values()) END SUB SUB SetTextFont(font,size,style$) DECLARE PUBLIC WinID,Mac5Flag,PCFlag,largefonts IF Mac5Flag=1 then SELECT CASE font CASE 4 LET font$= "Courier" CASE 16 LET font$= "Times" CASE else LET font$= "Geneva" END SELECT ELSE IF PCFlag=1 then IF largefonts=1 then IF size<12 then LET size= 6 ELSE IF size=14 then LET size= 10 ELSE IF size=18 then LET size= 12 ELSE IF size=24 then LET size= 14 ELSE IF size=12 then LET size= 8 ELSE LET size= round(72/96 * size * .8) END IF ELSE IF size<12 then LET size= 7 ELSE IF size=14 then LET size= 12 ELSE IF size=12 then LET size= 9 ELSE IF size=18 then LET size= 14 ELSE IF size=24 then LET size= 18 ELSE LET size= round(72/96 * size) END IF END IF SELECT CASE font CASE 4 LET font$= "Courier New" CASE 16 LET font$= "Times New Roman" CASE else LET font$= "Verdana" END SELECT END IF IF style$= "normal" then LET style$= "plain" CALL TC_Win_SetFont(WinID,font$,size,style$) END SUB SUB BoxDisk(Lft,Rgt,Bas,Top) BOX DISK Lft,Rgt,Bas,Top END SUB END MODULE ! --- End TB5 Cross-platform header and subs --- !! --------------------------------------------------------- !! --- Start Unix Header and Subs --- !library "HHLib.trc" !LET UnixFlag= 1 !ASK PIXELS winWid,winHgt !LET winLft= 0 !LET winTop= 0 !LET winRgt= winWid-1 !LET winBas= winHgt-1 !SET WINDOW 0,winRgt,winBas,0 !CALL Palette ! !CALL ToolPanel !CALL ThisProgram ! !END !EXTERNAL ! !MODULE UnixParts ! SHARE CharWidth ! ! SUB SetTextFont(font,size,style$) ! LET font$= "-adobe-courier-" ! IF style$= "normal" then ! LET style$= "medium-r-normal--" ! ELSE ! LET style$= "bold-r-normal--" ! END IF ! IF size=9 then ! LET size$= str$(10) ! ELSE ! LET size$= str$(size) ! END IF ! LET test= SetFont(font$&style$&size$&"*") ! ! IF size=9 then ! LET CharWidth= 6 ! ELSE IF size=12 then ! numeric output - axis labels ! LET CharWidth= 7 ! ELSE IF size=14 then ! rare ! LET CharWidth= 8 ! ELSE IF size=18 then ! rare ! LET CharWidth= 10 ! END IF ! END SUB ! ! SUB StringWidth(sw$,sl) ! string width in pixels ! ! LET sl= StrWidth(sw$) ! LET chars= len(sw$) ! LET sl = chars*CharWidth ! END SUB ! ! SUB SetLineWeight(wgt) ! ! CALL PenSize(wgt,wgt) ! END SUB ! ! SUB BoxDisk(Lft,Rgt,Bas,Top) ! CALL Fill_Circle(Lft,Rgt,Bas,Top) ! END SUB !END MODULE !! ------ End of TB Unix Header and Subs ------ ! ----------------------------------------------------------- ! *** SUB SineSumBeats DECLARE PUBLIC black,drkgry,drkmid,midgry,litmid,litgry,white DECLARE PUBLIC red,yellow,green,cyan,blue,magenta,colorscheme DECLARE PUBLIC planeclr,gridclr,rimclr,axisclr,axislabelclr,slideclr DECLARE PUBLIC workLft,workRgt,workBas,workTop,workMidx DECLARE PUBLIC true,false DECLARE DEF quitWithin, infoWithin ! --- help screen array --- DIM info$(1:15) MAT READ info$ DATA "Beats" DATA "" DATA "This tool supports graphical exploration of the formation of beats in the sum of two sinusoidal waveforms." ! DATA "The formula for the period of the beats can be derived experimentally." DATA "" DATA "Drag the mouse cursor over the upper time series plane to display crosshairs and the values of t and x at the cursor position." DATA "" DATA "Click or drag the omega slider to change the frequency of g(t). Click among the omega slider hash marks to jump to the nearest tenth for omega." DATA "Click or drag the A slider to change the amplitude of g(t). Click among the A slider hash marks to jump to the nearest tenth for A." DATA "Click or drag the phi slider to change the phase shift of g(t). Click among the phi slider hash marks to jump to the nearest pi/2 for phi." DATA "" DATA "Click the [Envelope] button to toggle the graph of the envelope curve for the wave sum in the upper plane on or off." DATA "Click the [Zoom] button to toggle between time ranges of 20 pi and 60 pi." DATA "" DATA "Click the checkboxes under the upper plane to overlay any combination of" DATA "f(t), g(t), sin(((1+omega)/2)t), or sin((w-1)t)" ! A "zoom" button toggles between a time range from 0 to 20 pi and from 0 to 60 pi. ! The bottom plane shows the graphs of f(t) = sin(t) in red and g(t) = A sin(omega t - phi) in yellow. ! The amplitude A , the circular frequency omega , and the phase lag theta, can each be controlled by the sliders at the bottom. ! Hash marks on sliders are active, and arrow keys on the omega slider allow for fine adjustments. ! ! Rolling the cursor over the top window to produces crosshairs and readouts of t and x. ! ! An "envelope" button displays the graph of an enveloping curve in the top window. ! Toggles allow any combination of f(t), g(t), or sin(((1+omega)/2)t) to be displayed in the top window. ! ---------- Utility functions --- DECLARE DEF clamp,roundn,e ! --- functions and parameters LET f3= 2*3 LET f5= 2*3*4*5 DEF pi2 = 2*pi DEF f(x)= sin(x) ! fixed wave DEF g(x)= a * sin(w*x - p*pi) ! adjustable wave ! the DE? simple harmonic - x" + x' + x = 0 ! s^2 + s + 1 = 0 ! -1 +- sqrt(1 - 4) / 2 ??? ! g(t) = sqrt(1 + A^2 + 2*A*cos((omega-omega_0)*t - phi)). ! I've switched from omega_n to omega_0 , because I don't want to ! encourage the notion that there's some system out there with ! undamped natural frequency omega_n. ! Is there a difference between undamped natural frequency and ! natural frequency? ! in this equation, I assume omega is the value from the slider. ! is the value of omega_0 just 1? ! I renamed the natural frequency from omega_0 to omega_n in damping ratio ! after we talked to Trumper. Do I need to change it back to omega_0? DEF notanum= .0123454321 ! SUB Amplitudes ! BOX CLEAR 0,500,90,0 ! SET CURSOR 1,1 ! PRINT a,w ! ! ! A (wt - (wt)^3/3! + (wt)^5/5!) + t - t^3/3! + t^5/5! = 0 ! ! Awt - A(wt)^3/3! + A(wt)^5/5! + t - t^3/3! + t^5/5! = 0 ! ! (Aw + 1)t - (Aw^3+ 1)t^3/3! + (Aw^5+ 1)t^5/5! = 0 ! ! divide by t ! ! (Aw + 1) - (Aw^3+ 1)t^2/3! + (Aw^5+ 1)t^4/5! = 0 ! ! let t^2 = k ! ! (Aw + 1) - (Aw^3+ 1)k/3! + (Aw^5+ 1)k^2/5! = 0 ! ! now its a quadratic in k ! ! k = { (Aw^3+1)/3! + sqrt[((Aw^3+1)/3!)^2 - 4 (Aw +1)(Aw^5+1)/5!] } / 2(Aw +1) ! ! k = { (Aw^3+1)/3! - sqrt[((Aw^3+1)/3!)^2 - 4 (Aw +1)(Aw^5+1)/5!] } / 2(Aw +1) ! ! LET t1= (A*w^3+1)/3 ! LET t2= ((A*w^3+1)/f3)^2 ! LET t3= 4*(A*w +1)*(A*w^5+1)/f5 ! LET t4= 2*(A*w+1) ! ! WHEN error in ! LET k1 = 4*pi * (t1 + sqr(abs(t2-t3)) / t4) ! USE ! LET k1 = notanum ! END WHEN ! PRINT k1 ! WHEN error in ! LET k2 = 4*pi * (t1 - sqr(abs(t2-t3)) / t4) ! USE ! LET k2 = notanum ! END WHEN ! PRINT k2 ! END SUB DEF env(x) LET env = sqr(1 + a^2 + 2*a*cos((w-1)*x - p*pi)) END DEF ! ---------- Graphing plane parameters and methods ---------- LET wwid = 600 LET whgt = 128 LET frgt = 200 LET orange= 9 ! ------------------------------------------ ! --- w1 plane data --- DECLARE PUBLIC w1Lft,w1Rgt,w1Bas,w1Top,w1Midx,w1Midy DECLARE PUBLIC w1fLft,w1fRgt,w1fBas,w1fTop,w1x0,w1y0 DECLARE PUBLIC w1xFirst, w1xSTik, w1xLTik, w1xLabel, w1xGridstep DECLARE PUBLIC w1yFirst, w1ySTik, w1yLTik, w1yLabel, w1yGridstep DECLARE PUBLIC w1xPiFlag, w1xMult, w1yPiFlag, w1yMult DECLARE PUBLIC w1wWid, w1fWid, w1wHgt, w1fHgt, w1Aspect LET w1Flag = 1 LET w1xPiFlag= 1 LET w1xMult = pi LET w1yPiFlag= 0 LET w1yMult = 1 LET w1clr = green LET w1Lft = worklft+90 ! pixel window bounds LET w1Rgt = w1Lft+wwid LET w1Top = workTop+35 LET w1Bas = w1Top+whgt LET w1fLft= 0 ! function bounds * pi LET w1fRgt= 30 LET w1fTop= 2 ! function bounds LET w1fBas= -2 LET w1xGridstep= 0 ! horizontal grid intervals LET w1yGridstep= 0 ! vertical grid intervals LET w1xAx$= "t" ! axis labels LET w1yAx$= "x = f(t) + g(t)" LET w1xSTik = 0 ! horizontal axis Tik marks LET w1xLTik = 2 LET w1xLabel = 10 LET w1xFirst = w1fLft LET w1ySTik = 0 ! vertical axis Tik marks LET w1yLTik = 1 LET w1yLabel = 1 LET w1yFirst = w1fBas ! --- w1 plane methods --- DECLARE DEF w1fncx, w1fncy, w1wndx, w1wndy ! window/function transforms DECLARE DEF w1wWithin CALL w1Variables SUB w1InitPlane CALL w1SetBounds CALL w1DrawPlane(1,1,1) ! xaxis, yaxis, zeroaxes CALL SetTextFont(1,12,"bold") CALL PlotTextLJ(w1Rgt+8,w1y0+3,w1xAx$,axislabelclr) ! axis labels CALL PlotTextLJ(w1x0-3,w1Top-12,w1yAx$,w1clr) CALL w1KeepGridLayer END SUB SUB w1SetBounds SELECT CASE zoomState CASE 0 LET w1fLft = 0 ! function bounds * pi LET w1fRgt = 60 LET w1xSTik = 0 ! horizontal axis Tik marks LET w1xLTik = 2 LET w1xLabel= 10 LET w1xFirst= w1fLft CASE 1 LET w1fLft = 0 ! function bounds * pi LET w1fRgt = 20 LET w1xSTik = 0.5 ! horizontal axis Tik marks LET w1xLTik = 1 LET w1xLabel= 5 LET w1xFirst= w1fLft END SELECT CALL w1Variables END SUB ! --- w2 plane data --- DECLARE PUBLIC w2Lft, w2Rgt, w2Bas, w2Top, w2Midx, w2Midy DECLARE PUBLIC w2fLft, w2fRgt, w2fBas, w2fTop, w2x0, w2y0 DECLARE PUBLIC w2xFirst, w2xSTik, w2xLTik, w2xLabel, w2xGridstep DECLARE PUBLIC w2yFirst, w2ySTik, w2yLTik, w2yLabel, w2yGridstep DECLARE PUBLIC w2xPiFlag, w2xMult, w2yPiFlag, w2yMult DECLARE PUBLIC w2wWid, w2fWid, w2wHgt, w2fHgt, w2Aspect LET w2Flag = 1 ! pixel window visibility LET w2xPiFlag= 1 ! pi switch for x axis LET w2xMult = pi LET w2yPiFlag= 0 ! pi switch for y axis LET w2yMult = 1 LET w2clr = red LET w2clr = yellow LET w2Lft = workLft+90 ! pixel window bounds LET w2Rgt = w2Lft+wwid LET w2Top = w1Bas + 115 LET w2Bas = w2Top + 128 LET w2fLft= 0 ! function bounds LET w2fRgt= w1fRgt LET w2fTop= 2 LET w2fBas= -2 LET w2xAx$= "t" ! axis labels LET w2yAx$= "f(t) = sin(t)" LET w2yAx$= "g(t) = A sin(wt+phi)" LET w2xGridstep= 0 ! horizontal grid intervals LET w2yGridstep= 0 ! vertical grid intervals LET w2xSTik = 0 ! horizontal axis Tik marks LET w2xLTik = 2 LET w2xLabel= 10 LET w2xFirst= w2fLft LET w2ySTik = 0 ! vertical axis Tik marks LET w2yLTik = 1 LET w2yLabel= 1 LET w2yFirst= -2 ! --- w2 Plane methods --- DECLARE DEF w2fncx,w2fncy,w2wndx,w2wndy ! window/function transforms DECLARE DEF w2wWithin CALL w2Variables SUB w2InitPlane CALL w2SetBounds CALL w2DrawPlane(1,1,1) ! x axis, y axis, zeroaxes CALL SetTextFont(1,12,"bold") CALL PlotTextLJ(w2Rgt+8,w2y0+3,w2xAx$,axislabelclr) ! axis labels LET bas1 = w2Top - 30 LET bas2 = w2Top - 12 LET w2Eqx= w2x0 + 28 CALL PlotTextRJ(w2Eqx,bas2,"f(t) = ",red) CALL PlotTextLJ(w2Eqx,bas2,"sin(t)",red) CALL PlotTextRJ(w2Eqx,bas1,"g(t) = ",w2Clr) CALL StringWidth("A sin(w",sw) CALL SwapOmega(w2Eqx,bas1,"A sin(w","w",w2Clr) CALL SwapPhi(w2Eqx+sw+2,bas1,"t - p)","p",w2Clr) CALL w2KeepGridLayer END SUB SUB w2SetBounds LET w2fLft = w1fLft ! function bounds * pi LET w2fRgt = w1fRgt LET w2xSTik = w1xSTik ! horizontal axis Tik marks LET w2xLTik = w1xLTik LET w2xLabel= w1xLabel LET w2xFirst= w1xFirst CALL w2Variables END SUB ! ----------- horizontal sliders ------------ LET slideWidth= 100 ! --- horizontal slider 1 --- DECLARE PUBLIC h1axis,h1wLft,h1wRgt,h1wBas,h1wTop,h1fLft,h1fRgt DECLARE PUBLIC h1name$,h1form$,h1clr,h1First,h1STik,h1LTik,h1Label DECLARE PUBLIC h1PiAxis,h1Mult,h1fMin,h1fMax DECLARE DEF h1Within ! window/function transforms LET h1PiAxis= 0 LET h1Mult = 1 LET h1clr = yellow LET h1name$ = "A" LET h1form$ = "%.##" LET h1Places= 2 LET h1Click = 0.1 LET h1axis = workbas - 25 LET h1wLft = w2Lft LET h1wRgt = h1wLft+100 LET h1fLft = 0 LET h1fRgt = 1 LET h1STik = 0.1 ! short tick marks LET h1LTik = 0.5 ! long tick marks LET h1Label = 0.5 ! labels LET h1First = h1fLft ! first tick mark CALL h1SliderVariables SUB h1InitSlider CALL h1DrawSlider(h1name$,a) END SUB ! --- horizontal slider 2 --- DECLARE PUBLIC h2axis,h2wLft,h2wRgt,h2wBas,h2wTop,h2fLft,h2fRgt DECLARE PUBLIC h2name$,h2form$,h2clr,h2First,h2STik,h2LTik,h2Label DECLARE PUBLIC h2PiAxis,h2Mult,h2fMin,h2fMax DECLARE DEF h2Within ! window/function transforms LET h2PiAxis= 0 LET h2Mult = 1 LET h2clr = yellow LET h2name$ = "" ! omega LET h2form$ = "%.###" LET h2Places= 3 LET h2Click = 0.05 LET h2axis = h1axis - 45 LET h2wLft = w2Lft LET h2wRgt = w2Rgt LET h2fLft = 0 LET h2fRgt = 2 LET h2STik = 0.05 ! short tick marks LET h2LTik = 0.1 ! long tick marks LET h2Label = 0.5 ! labels LET h2First = h2fLft ! first tick mark DECLARE DEF h2LstpWithin , h2RstpWithin DECLARE DEF h2LmoveWithin, h2RmoveWithin LET h2AnimStep= 0.001 LET h2MoveStep= 0.002 SUB h2InitSlider CALL h2SliderVariables CALL h2DrawSlider(h2name$,w) CALL SwapOmega(h2wLft-18,h2wbas-2,"w","w",h2Clr) ! CALL h2MoveButtons END SUB ! --- horizontal slider 3 --- DECLARE DEF h3Within ! window/function transforms DECLARE PUBLIC h3axis,h3wLft,h3wRgt,h3wBas,h3wTop,h3fLft,h3fRgt DECLARE PUBLIC h3name$,h3form$,h3clr,h3First,h3STik,h3LTik,h3Label DECLARE PUBLIC h3PiAxis,h3Mult,h3fMin,h3fMax LET h3piAxis= 1 LET h3Mult = pi LET h3clr = yellow LET h3name$ = "" LET h3form$ = "%.##" LET h3Places= 2 LET h3Click = pi/2 LET h3axis = h1axis LET h3wLft = h1wRgt + 100 LET h3wRgt = h3wLft + 100 LET h3fLft = 0 LET h3fRgt = 2 LET h3STik = 0 ! short tick marks LET h3LTik = 0.5 ! long tick marks LET h3Label = 1 ! labels LET h3First = h3fLft ! first tick mark CALL h3SliderVariables DECLARE DEF h3Fncx SUB h3InitSlider CALL h3SliderVariables CALL h3DrawSlider(h3name$,p) CALL SwapPhi(h3wLft-15,h3wbas-2,"p","p",h3clr) LET h3piAxis= 0 LET h3Mult = 1 BOX SHOW h3pi$ at h3wRgt+42,h3wBas-3 END SUB ! ---------- Text Output Rects ---------- ! --- text rectangle 1 --- ! LET t1BasLn = w1Bas + 38 ! LET t1Lft = w1Lft + 160 ! LET t1Rgt = t1Lft + 150 ! LET t1Bas = t1BasLn + 5 ! LET t1Top = t1BasLn - 15 ! LET t1Label$= "_[sum] = " ! LET t1Eqx = t1lft + 55 ! LET t1vBasLn= t1BasLn + 20 ! LET t1vBas = t1vBasLn + 5 ! LET t1vTop = t1vBasLn - 15 ! LET t1clr = green ! ! SUB t1Label ! CALL SetTextFont(1,9,"bold") ! CALL StringWidth("tone",sw9) ! CALL SetTextFont(1,12,"bold") ! CALL StringWidth(" = ",sw22) ! LET sw= sw9+sw22 ! ! CALL SuperSubScriptRJ(t1Eqx-sw22-2,t1BasLn,"_[sum]",t1Clr) ! CALL DrawLam(t1Eqx-sw-10,t1BasLn,t1Clr) ! CALL PlotTextRJ(t1Eqx,t1BasLn,"= ",t1Clr) ! CALL PlotTextRJ(t1Eqx,t1vBasLn,"= ",t1Clr) ! END SUB ! ! SUB t1Set ! CALL PlotTextLJ(t1Eqx,t1BasLn,"2",t1Clr) ! CALL StringWidth("2",sw) ! LET lft = t1Eqx + sw + 1 ! BOX SHOW t1pi$ at lft,t1BasLn ! LET lft = lft + 12 ! LET txt$= " / ((w_[n]+w)/2)" ! CALL SuperSubScriptOmegaLJ(lft,t1BasLn,txt$,"w",t1Clr) ! END SUB ! ! SUB t1vSet ! CALL t1vClear ! IF (1+w)<>0 then ! LET t1$= trim$(using$("---%.##",4/(1+a*w))) ! CALL PlotTextLJ(t1Eqx,t1vBasLn,t1$,t1Clr) ! CALL StringWidth(t1$,sw) ! BOX SHOW t1pi$ at t1Eqx+sw+4,t1vBasLn ! ELSE ! CALL SwapInf(t1Eqx+2,t1vBasLn,"8","8",t1Clr) ! END IF ! END SUB ! ! SUB t1Clear ! BOX CLEAR t1Lft-2,t1Rgt,t1Bas,t1Top ! END SUB ! ! SUB t1vClear ! BOX CLEAR t1Eqx-2,t1Rgt,t1vBas,t1vTop ! END SUB ! ! SUB t1Init ! CALL t1Label ! CALL t1Set ! END SUB ! ! ! --- text rectangle 2 --- ! ! LET t2BasLn = t1BasLn ! LET t2Lft = w1Rgt - 165 ! LET t2Rgt = w1Rgt + 20 ! LET t2Bas = t2BasLn + 5 ! LET t2Top = t2BasLn - 15 ! LET t2Label$= "_[packet] = " ! LET t2Eqx = t2Lft + 75 ! LET t2vBasLn= t2BasLn + 20 ! LET t2vBas = t2vBasLn + 5 ! LET t2vTop = t2vBasLn - 15 ! LET t2Clr = cyan ! ! SUB t2Label ! CALL SetTextFont(1,9,"bold") ! CALL StringWidth("packet",sw9) ! CALL SetTextFont(1,12,"bold") ! CALL StringWidth(" = ",sw22) ! LET sw= sw9+sw22 ! ! CALL SuperSubScriptRJ(t2Eqx,t2BasLn,t2Label$,t2Clr) ! CALL DrawLam(t2Eqx-sw-10,t2BasLn,t2Clr) ! CALL PlotTextRJ(t2Eqx,t2vBasLn,"= ",t2Clr) ! END SUB ! ! SUB t2Set ! LOCAL z$ ! IF a-w<>0 then ! CALL SetTextFont(1,12,"bold") ! LET t2$= "(2/|w_[n]-w|)" ! CALL SuperSubScriptOmegaLJ(t2Eqx,t2BasLn,t2$,"w",t2Clr) ! LET t2$= "(2/|wn-w|)" ! CALL StringWidth(t2$,sw) ! BOX SHOW t2pi$ at t2Eqx+sw+4,t2BasLn ! ELSE ! ! END IF ! CALL t2vSet ! END SUB ! ! SUB t2vSet ! CALL t2vClear ! CALL SetTextFont(1,12,"bold") ! LET t2a= 1 ! IF t2a-w<>0 then ! LET t2$= trim$(using$("----%.##",2/abs(t2a-w))) ! CALL PlotTextLJ(t2Eqx,t2vBasLn,t2$,t2Clr) ! CALL StringWidth(t2$,sw) ! BOX SHOW t2pi$ at t2Eqx+sw+4,t2vBasLn ! ELSE ! CALL SwapInf(t2Eqx+2,t2vBasLn,"8","8",t2Clr) ! END IF ! END SUB ! ! SUB t2vClear ! BOX CLEAR t2Eqx-2,t2Rgt,t2vBas,t2vTop ! END SUB ! ! SUB t2Init ! CALL t2Label ! CALL t2Set ! END SUB ! ! ! --- t3 Natural Frequency --- ! ! LET t3NatLft= h3wRgt + 100 ! LET t3NatBas= h3wBas - 3 ! ! SUB t3Init ! CALL SuperSubScriptOmegaLJ(t3NatLft,t3NatBas,"w_[n] = 1","w",litgry) ! END SUB ! ------ t4 text output - initial values ------- CALL SetTextFont(1,12,"bold") LET t4BasLn1 = w1Bas + 38 LET t4BasLn2 = t4BasLn1 + 20 CALL StringWidth("x = 55.55",sw) LET t4Lft = w1Rgt - sw - 12 LET t4Rgt = w1Rgt - 12 LET t4Bas = t4BasLn2 + 5 LET t4Top = t4BasLn1 - 15 LET t4clr1 = litgry LET t4clr2 = litgry LET t4Label1$= "t = " LET t4Label2$= "x = " CALL StringWidth(t4Label2$,sw) LET t4Eqx = t4Lft + sw SUB t4Init CALL t4Clear CALL PlotTextRJ(t4Eqx,t4BasLn1,t4Label1$,t4clr1) CALL PlotTextRJ(t4Eqx,t4BasLn2,t4Label2$,t4clr2) ! CALL t4Values END SUB SUB t4Clear BOX CLEAR t4Lft-2,t4Rgt+2,t4Bas,t4Top END SUB SUB t4ClearValues BOX CLEAR t4Eqx-2,t4Rgt+15,t4Bas,t4Top END SUB SUB t4Values CALL t4ClearValues LET n1$= using$("--%.##",t) LET n2$= using$("-%.##",x) CALL PlotTextRJ(t4Rgt,t4BasLn1,n1$,t4clr1) CALL PlotTextRJ(t4Rgt,t4BasLn2,n2$,t4clr2) BOX SHOW w2pi$ at t4Rgt+2,t4BasLn1 END SUB ! --- Rollover parameters and cleanup --- LET rolft = w1Lft - 25 LET rorgt = w1Rgt + 40 LET robasln= w1Top - 27 LET robas = robasln+ 5 LET rotop = robasln-10 SUB ClearRollText BOX CLEAR rolft,rorgt,robas,rotop END SUB SUB ClearRollover CALL w2ShowGraphLayer CALL w1ShowGraphLayer CALL t4ClearValues !CALL ClearRollText LET clearflag= 0 END SUB ! --- Buttons --- LET zlft= w1Lft LET zrgt= zlft + 50 LET ztop= w1Bas + 25 LET zbas= ztop + 18 SUB ZoomButton(state) CALL SetTextFont(1,12,"Bold") CALL DrawButton(zlft,zrgt,zbas,ztop,5,"zoom") END SUB LET elft= zRgt + 2 LET ergt= elft + 78 LET etop= w1Bas + 25 LET ebas= etop + 18 SUB EnvButton(state) CALL SetTextFont(1,12,"Bold") CALL DrawButton(elft,ergt,ebas,etop,5,"envelope") END SUB SUB Buttons CALL SetTextFont(1,12,"Bold") CALL DrawButton(zlft,zrgt,zbas,ztop,5,"zoom") CALL DrawButton(elft,ergt,ebas,etop,5,"envelope") END SUB ! --- checkbox - overlay --- DECLARE PUBLIC cb1Lft,cb1Rgt,cb1Bas,cb1Top,cb1Txt$,cb1Clr,cb1State DECLARE DEF cb1Within LET cb1Lft = ergt+40 LET cb1Bas = w1Bas + 41 LET cb1Txt$= "sin(((1+w)/2)t)" LET cb1Clr = cyan CALL cb1Variables ! --- check boxes --- DECLARE PUBLIC c1cnt, c1stp, c1siz DECLARE PUBLIC c1lft, c1rgt, c1bas, c1top DECLARE PUBLIC c1NameList$(),c1ColorList(),c1Switch() LET c1cnt= 4 ! box count LET c1top= w1Bas + 28 LET c1stp= 18 ! box interval LET c1siz= 12 ! box size LET c1bas= c1top + (c1cnt-1)*c1stp + c1siz LET c1lft= ergt + 40 LET c1rgt= c1lft + c1siz MAT redim c1NameList$(1:c1cnt) ! DATA "g(t)","f(t)","sin(((1+w)/2)t)","sin((w-1)t)" DATA "","","","" MAT READ c1NameList$ MAT redim c1ColorList(1:c1cnt) DATA 24,23,26,28 MAT READ c1ColorList MAT redim c1Switch(1:c1cnt) DATA 0,0,0,0 MAT READ c1Switch SUB c1Init CALL c1DrawCheckBoxes CALL c1SetCheckBox LET basy= c1Top+10+0*18 CALL PlotTextLJ(c1Rgt+8,basy,"g(t)",c1ColorList(1)) LET basy= c1Top+10+1*18 CALL PlotTextLJ(c1Rgt+8,basy,"f(t)",c1ColorList(2)) LET basy= c1Top+10+2*18 CALL SwapOmega(c1Rgt+8,basy,"sin(((1+w)/2)t)","w",c1ColorList(3)) LET basy= c1Top+10+3*18 CALL SwapOmega(c1Rgt+8,basy,"sin((w-1)t)","w",c1ColorList(4)) END SUB ! ! --- radio buttons --- ! ! DECLARE PUBLIC r1cnt,r1stp,r1siz ! DECLARE PUBLIC r1lft,r1rgt,r1bas,r1top,r1Name$,r1NameClr ! DECLARE PUBLIC r1NameList$(),r1ColorList() ! ! MAT redim r1NameList$(1:4) ! MAT READ r1NameList$ ! DATA "g(t)","f(t)","sin(((1+w)/2)t)","sin((w-1)t)" ! ! MAT redim r1ColorList(1:4) ! MAT READ r1ColorList ! DATA 24,23,26,28 ! ! LET r1cnt= 4 ! LET r1Lft= ergt + 40 ! LET r1Top= w1Bas + 28 ! LET r1Name$= "" ! LET r1NameClr= 21 ! ! DECLARE DEF r1Within ! ! CALL r1SetVars ! --- Default Parameters --- LET a,olda= 1 LET w,oldw= 1.05 LET p,oldp= 0 LET r1num = -1 LET AverageState = 0 CALL InitPi(worklft+1,worktop+10,yellow,h3pi$) CALL InitPi(worklft+1,worktop+10,litgry,w2pi$) LET envelopeFlag= 0 IF a=1 then LET EnvBtnFlag= 1 ! --- Draw the screen --- CALL InitScreen SUB InitScreen BOX CLEAR worklft,workrgt,workbas,worktop CALL w1InitPlane CALL w2InitPlane CALL h1InitSlider CALL h2InitSlider CALL h3InitSlider CALL Buttons CALL w2DrawGraph CALL w2KeepGridLayer CALL DrawGraphs(1) CALL t4Init ! CALL c1Init CALL cb1Init END SUB ! ----------------- Event manager ----------------- DO LET clearflag= 0 LET oldmx = -99999 CALL SetTextFont(1,12,"Bold") DO GET MOUSE: mx,my,ms IF w1wWithin(mx,my)=true then CALL Rollover ELSE IF clearflag=true then CALL ClearRollover END IF LOOP until ms=2 IF clearflag=1 then CALL ClearRollover IF h1Within(mx,my)=true then IF myh2fLft and wh2fLft and wc1Lft and mxc1Top and myeLft and mxeTop and myzlft and mxzTop and myoldmx or my<>oldmy then LET oldmx= mx LET oldmy= my SET COLOR litgry CALL w1ShowGraphLayer SET COLOR litgry PLOT mx,w1Bas-1; mx,w1Top+1 ! SET COLOR green PLOT w1Lft+1,my; w1Rgt-1,my SET COLOR litgry CALL w2ShowGraphLayer PLOT mx,w2Bas-1; mx,w2Top+1 LET t = w1Fncx(mx)/pi LET x = w1Fncy(my) CALL t4Values LET clearflag= 1 END IF END SUB ! --- h1 slider events --- SUB h1MouseClick CALL h1GetClickVal(ms,h1Click,a) CALL h1MouseAction(1) END SUB SUB h1MouseDrag DO CALL h1GetDragVal(ms,h1Places,a) CALL h1MouseAction(2) LOOP until ms=3 CALL DrawGraphs(1) END SUB SUB h1MouseAction(drawstep) IF a<>olda then LET olda= a CALL DrawGraphs(drawstep) END IF END SUB ! --- h2 slider events --- SUB h2MouseClick CALL h2GetClickVal(ms,h2Click,w) CALL h2MouseAction(1) END SUB SUB h2MouseDrag DO CALL h2GetDragVal(ms,h2Places,w) CALL h2MouseAction(2) LOOP until ms=3 CALL DrawGraphs(1) END SUB SUB h2MouseAction(drawstep) IF w<>oldw then CALL DrawGraphs(drawstep) LET oldw= w END IF END SUB ! --- h3 slider events - multiply p by pi in calculations SUB h3MouseClick CALL MouseUp(mx,my,ms) LET mx= Clamp(mx,h3wLft,h3wRgt) LET p = h3Fncx(mx) LET p = roundn(p,.5) CALL h3MouseAction(2) CALL h3MouseAction(1) END SUB SUB h3MouseDrag DO GET MOUSE: mx,my,ms LET mx= Clamp(mx,h3wLft,h3wRgt) LET p = h3Fncx(mx) CALL h3MouseAction(2) LOOP until ms=3 CALL DrawGraphs(1) END SUB SUB h3MouseAction(drawstep) IF p<>oldp then LET oldp= p CALL h3Mark(p) CALL DrawGraphs(drawstep) BOX SHOW h3pi$ at h3wRgt+42,h3wBas-3 END IF END SUB ! --- graph drawing routines --- SUB w2DrawGraph ! addend waves CALL w2ShowGridLayer SET COLOR red FOR wx= w2lft to w2rgt LET x = w2Fncx(wx) LET y1= f(x) LET wy= w2Wndy(y1) PLOT wx,wy; NEXT wx PLOT CALL w2KeepGraphLayer END SUB SUB DrawEnvelope(estp) IF w<>1 then SET COLOR litmid FOR wx= w1lft to w1rgt step estp LET x = w1Fncx(wx) LET y1= env(x) LET wy= w1Wndy(y1) IF wy>w1Top and wyw1Top and wy1 means animation CALL w1ShowGridLayer ! sum curve (beats- upper plane) IF envelopeFlag=1 then CALL DrawEnvelope(stp/2) SET COLOR w1clr FOR wx= w1lft to w1rgt step stp LET x = w1Fncx(wx) LET y1= g(x)+f(x) LET wy= w1Wndy(y1) PLOT wx,wy; NEXT wx PLOT CALL w2ShowGridLayer ! addend curve (lower plane) SET COLOR w2clr FOR wx= w2lft to w2rgt step stp LET x = w2Fncx(wx) LET y2= g(x) LET wy= w2Wndy(y2) PLOT wx,wy; NEXT wx PLOT ! --- ! when a=1 we need (w+1)/2, average frequency as in the books ! when a=0 we need (1+1)/2, 1 cycle per 2pi ! when a=1, (w^a+1)/2 = (w+1)/2 ! when a=0, (w^a+1)/2 = (1+1)/2 ! LET ft= (w^a+1)/2 ! LET dif= a * abs(1-((w+1)/2)) ! LET omega_tone = 1 + a*abs(1-((w+1)/2)) ! LET ft= 1 + dif LET ft= (1+w)/2 LET fb= abs(w-1) IF atFlag=1 then SET COLOR cyan ! tone frequency FOR wx= w1lft to w1rgt step stp LET x = w1Fncx(wx) LET y1= sin(ft*x) LET wy= w1Wndy(y1) PLOT wx,wy; NEXT wx PLOT END IF IF btFlag=1 then SET COLOR magenta ! beat frequency FOR wx= w1lft to w1rgt step stp LET x = w1Fncx(wx) LET y1= sin(fb*x) LET wy= w1Wndy(y1) PLOT wx,wy; NEXT wx PLOT END IF IF ftFlag=1 then SET COLOR red ! simple sine FOR wx= w1lft to w1rgt LET x = w1Fncx(wx) LET y1= f(x) LET wy= w1Wndy(y1) PLOT wx,wy; NEXT wx PLOT END IF IF gtFlag=1 then SET COLOR w2clr ! addend curve (lower plane) FOR wx= w1lft to w1rgt step stp LET x = w1Fncx(wx) LET y2= g(x) LET wy= w1Wndy(y2) PLOT wx,wy; NEXT wx PLOT END IF IF stp=1 then ! keep for rollover CALL w2KeepGraphLayer CALL w1KeepGraphLayer END IF END SUB END SUB ! --- end of Sine sum beats code -------------------