Delivered-To: gmkarl@gmail.com Received: by 2002:a05:6359:61a:b0:dc:b30d:6501 with SMTP id eh26csp1499590rwb; Wed, 16 Nov 2022 18:14:02 -0800 (PST) X-Received: by 2002:a5e:c809:0:b0:6cf:8cf0:91ac with SMTP id y9-20020a5ec809000000b006cf8cf091acmr436599iol.186.1668651242621; Wed, 16 Nov 2022 18:14:02 -0800 (PST) ARC-Seal: i=1; a=rsa-sha256; t=1668651242; cv=none; d=google.com; s=arc-20160816; b=zivXBf2J1WNYau7Wgu03OUDSJgAUYps/brqp6yflSmH/dIa0/y/kulB9QeT66jp2LB tY9FsP9QHgg/HLP6RTALRH1hFjO4h8kOoH5XlTSfkwv+VPcegQPkqmM4Wpp0biP/v5oC 29/kK5X4QvAEi2jLpNnt9c50+cTtYhtkf7gqdoUI4GfnEJAfzxVrsG7uXLr7ZFO0VvOw S7cWjJ8r66QhmCfUGIb9GN9DOBe6veG0UliR0uOY4dcayDfxpzfe2+YX6MObUM1vmJF9 MFM2JZfEZ6aiFGqgftGbKQL59IxrjsxOqhqBbetTxlUbQxjV9tX9d3PgM5hdFAE9Cdnl XILA== ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=google.com; s=arc-20160816; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :dkim-signature; bh=uWzWupM8ZsMAaL3UVaGRywmqII/kQMZRlpUlSxbz0cA=; b=hL5akYD0NDpaHxUsJVJOwngHm6zg+oflnzoEoIIDkgjc8s/8hMgbze2djAATu1RSHS Nk2VxZVhy272ZcLf9elTBlNDRhVxbake+ybDbbSlIj5PDSDrPekxwViNgiC11DwX8r1K RP5XESaXI2fg5FqToQcS4iKPBWFqxerQCeR8NqS/8yXceCPZH0uNLP227FhaNK3iOshb 4VP6aMwHExhgZx6C4DXn0eYarpVi5mkN+3eXIPp77aqK8o1CNhdiK2bHKRhmcFpff72s fix0nJPpO58K7bKwjVclBlT0IPQFASn/ySZu0kX2ck/Ccg7sRHdhkGSy/+4N/MmgOv51 bJFQ== ARC-Authentication-Results: i=1; mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b="Gg/TNszV"; spf=pass (google.com: domain of ilsa.bartlett@gmail.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=ilsa.bartlett@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com Return-Path: Received: from mail-sor-f41.google.com (mail-sor-f41.google.com. [209.85.220.41]) by mx.google.com with SMTPS id m22-20020a023c16000000b003740078d360sor5175837jaa.123.2022.11.16.18.14.02 for (Google Transport Security); Wed, 16 Nov 2022 18:14:02 -0800 (PST) Received-SPF: pass (google.com: domain of ilsa.bartlett@gmail.com designates 209.85.220.41 as permitted sender) client-ip=209.85.220.41; Authentication-Results: mx.google.com; dkim=pass header.i=@gmail.com header.s=20210112 header.b="Gg/TNszV"; spf=pass (google.com: domain of ilsa.bartlett@gmail.com designates 209.85.220.41 as permitted sender) smtp.mailfrom=ilsa.bartlett@gmail.com; dmarc=pass (p=NONE sp=QUARANTINE dis=NONE) header.from=gmail.com DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=gmail.com; s=20210112; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :from:to:cc:subject:date:message-id:reply-to; bh=uWzWupM8ZsMAaL3UVaGRywmqII/kQMZRlpUlSxbz0cA=; b=Gg/TNszVuIibGQMTfEOiNgswM6NfvAVP1lCZiLzb9ixhRkm4OZq7MezZyqdKCnhObX 1XPJX0hcPolep1LryQm16BEAGI0C2XFVi50U4eViVLCR4snaGM+DhOMudPdpihR6ZGAT kxAckuwAE1+usqQyRDPJSY3Enr3Nu+7f/2Cq8eyccSGz4t95HQ/8P6yqSFdOG0m1U3XC vjPG7z++b7uBcw0neKUcXHvMRz+ntAXLZ6kXNG0muMrrwkvqpsNFKET5Gv8dmhZdpeAq oLDoWTxPHvOZvkryoB5/h0MIK8oZtesLHt5hgUIvKoL2FC+Mn9oJiBByD8d/JVnmLTFw 5fpg== X-Google-DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=1e100.net; s=20210112; h=to:subject:message-id:date:from:in-reply-to:references:mime-version :x-gm-message-state:from:to:cc:subject:date:message-id:reply-to; bh=uWzWupM8ZsMAaL3UVaGRywmqII/kQMZRlpUlSxbz0cA=; b=NuOjyZFIatRqDDMxWlYE9hIERDPupbGq3iKFIOWLVCl/osLWjMNsaqyj3oBFR+oPhu scveHJ2dxiof/tecSncxPMFSUS0ro4lIqvplbnl4GBZ1kRUvomcnWhzsCCLmJ5UsM8D3 Msd61c34bIYIsRgFD8jLxTezTFW/9It/+cY+iRUoyADLSJ4e91P/NwrzHDAC8gWVOsBo qr+EiNflHyVv47vbuTleNuMnWXpPWfPj9HOeAEkcJhGV3UCGeubMzpkREk8IXbefuu6H cxzN5sMG7dzuhlozTxykh0LPrClRCivaq8NLOYf62vh2A5d94zzWBaCSwNOhupy9xw/M 3yJQ== X-Gm-Message-State: ANoB5pkYUSq+GXU7pnUF77HdDUV/W/IP7uHF9q6AZsGcdVyGixb9vMIM c/wPKxZCEQ+hEg2mnaxGJIfzGvYBi46Z/mgKEVCP8Okj X-Google-Smtp-Source: AA0mqf5gKEzvK5p6y9UTPUt5ySyvfa6j2P5mwOGRo1pKNwhWc8/tvC6iaIJA5ayfjD9nuW7SPHJ9ORIxfUK6kUDDuuU= X-Received: by 2002:a02:94c1:0:b0:375:fc59:201b with SMTP id x59-20020a0294c1000000b00375fc59201bmr161873jah.12.1668651242160; Wed, 16 Nov 2022 18:14:02 -0800 (PST) MIME-Version: 1.0 References: In-Reply-To: From: ilsa Date: Wed, 16 Nov 2022 18:13:49 -0800 Message-ID: Subject: Re: [ot][spam][random][crazy][random][crazy] To: "Undescribed Horrific Abuse, One Victim & Survivor of Many" Content-Type: multipart/alternative; boundary="0000000000008b04eb05eda124c0" --0000000000008b04eb05eda124c0 Content-Type: text/plain; charset="UTF-8" Thanks On Wed, Nov 16, 2022, 5:38 PM Undescribed Horrific Abuse, One Victim & Survivor of Many wrote: > according to numpy my square wave matrix is singular. > > something for me to think about! > > i'm guessing a big issue is that my wavelet function doesn't have a > way to shift phase. > > i don't really know much about wavelets; it's a word i remember from > being a teenager, learning about these things in the resources i knew > how to find. > > i don't know if it's the cause, but my wavelet will need a way to have > phase. > > i could interpret the complex argument in terms of angle and > magnitude, and simply phase shift the output. this seems like it would > work fine, at first. but i'm not sure if it would survive the whole > process, with no complex output. > > the trick with the sinusoids is that in frequency space, the phase is > held as an angle in the complex plane. > when the freq2time matrix is created, where does the complex output > come from, and what meaning does it hold? > it has only real-domain frequencies, and yet produces a matrix that > converts from complex frequency. > > it takes the frequencies, and scales them by the offsets, and turns > that into time parameters > it passes the time parameters to the sinusoids. > this produces a matrix that can process complex frequency data, and > convert it to time data. > each frequency is a magnitude and a phase. > > i can make a function that takes complex frequency data > but the frequencies that are passed in are not complex: they are > negative and positive. > where the negative is the complex conjugate i.e. the angle iand hence > phase is treated as negative. > > there are various things i could try but i'm trying to figure out > what's going on in general. > > exp(2i pi x) produces a complex number rotated with an angle x > > how does this produce real-domain data? if i pass in a single > frequency with a 0 angle, what does it do? > > i tried this: > (Pdb) p np.array([0,1,0,1]) @ create_freq2time(4) > array([ 5.00000000e-01+0.j, 3.06161700e-17+0.j, -5.00000000e-01+0.j, > -9.18485099e-17+0.j]) > > so how does that work? > > (Pdb) p create_freq2time(4).round(2) > array([[ 0.25+0.j , 0.25+0.j , 0.25+0.j , 0.25+0.j ], > [ 0.25+0.j , 0. +0.25j, -0.25+0.j , -0. -0.25j], > [ 0.25+0.j , -0.25-0.j , 0.25+0.j , -0.25-0.j ], > [ 0.25+0.j , 0. -0.25j, -0.25-0.j , -0. +0.25j]]) > > columns are freq, rows are samps > The first sample gets 0.25 + 0.25 = 0.5 > The second sample is the only one with complex domain stuff, and its > 0.25 components cancel each other. > The third has -0.25 at the two indices. > The fourth cancels again. > > I'm going to paste it again. > array([[ 0.25+0.j , 0.25+0.j , 0.25+0.j , 0.25+0.j ], > [ 0.25+0.j , 0. +0.25j, -0.25+0.j , -0. -0.25j], > [ 0.25+0.j , -0.25-0.j , 0.25+0.j , -0.25-0.j ], > [ 0.25+0.j , 0. -0.25j, -0.25-0.j , -0. +0.25j]]) > > It's 4 complex sinusoids, but they oppose each other in the complex > domain. Because a real-valued signal has both negative and complex > frequencies equal, and because the complex component of the wavelet > function is odd, the two cancel. > > That would work fine for phaseless square wave data. You'd provide an > even function square wave for the real component, and an odd function > square wave for the imaginary component. > > What about phase offset? > > (Pdb) p (np.array([0,1+1j,0,1+1j]) @ create_freq2time(4)).round(3) > array([ 0.5+0.5j, 0. +0.j , -0.5-0.5j, -0. -0.j ]) > When I specify complex numbers for the frequencies, it actually > produces a wave with the same phase, that has complex value, not a > phased wave ! > > I thought the angle of the frequency was the phase, but it isn't? > > (Pdb) p np.fft.ifft(np.array([0,1+1j,0,1+1j])).round(3) > array([ 0.5+0.5j, 0. +0.j , -0.5-0.5j, 0. +0.j ]) > > That appears to be so. > > That doesn't seem very useful to me, it seems it would be more useful > if it were. > > Ohhhh I need to use the complex conjugate! > > (Pdb) p (np.array([0,1+1j,0,1-1j]) @ create_freq2time(4)).round(3) > array([ 0.5+0.j, -0.5+0.j, -0.5+0.j, 0.5+0.j]) > > There we go. I offset it by 45 degrees? > > (Pdb) p (np.array([0,1,0,1]) @ create_freq2time(4)).round(3) > array([ 0.5+0.j, 0. +0.j, -0.5+0.j, -0. +0.j]) > > I'm guessing the peaks for 45 degrees were between the samples. 90 > might be clearer. > > Yeah here's 90 degrees offset: > (Pdb) p (np.array([0,1j,0,-1j]) @ create_freq2time(4)).round(3) > array([ 0. +0.j, -0.5+0.j, -0. +0.j, 0.5+0.j]) > > So how does that happen? > (Pdb) p create_freq2time(4).round(3) > array([[ 0.25+0.j , 0.25+0.j , 0.25+0.j , 0.25+0.j ], > [ 0.25+0.j , 0. +0.25j, -0.25+0.j , -0. -0.25j], > [ 0.25+0.j , -0.25-0.j , 0.25+0.j , -0.25-0.j ], > [ 0.25+0.j , 0. -0.25j, -0.25-0.j , -0. +0.25j]]) > > Passing (0,1j,0,-1j) ... > The first two frequencies have opposing components so they cancel. > That would work with a 90 degree square wave. > In the second .. it's 1j and -1j. the j's multiply to -1, and we get > -.25 and -.25, which sum to 0.5 . > > the 90 degree case would work with square waves. but why does it work > for sinusoids? > cos(x) + sin(x)j = exp(2j pi x) is applied, not to the input data x, > but rather to the frequency. > then when the input data comes in, it is multiplied against that result. > so if it's real, the sinusoid components cancel and the cosine is > extracted. this then produces a real cosine wave. > if it's imaginary and self-opposing, the cosines cancel from the > self-opposingness, whereas the sines amplify, producing a wave that is > 90 degrees off. > > how would a 45 degree wave be produced? what is that? > it seems it would be a sum of the 0 degree and 90 degree waves, not sure. > > i looked at trigonometric identities and i found a relation that looked > complex. > let's see how it goes > > (Pdb) p create_freq2time(4).round(3) > array([[ 0.25+0.j , 0.25+0.j , 0.25+0.j , 0.25+0.j ], > [ 0.25+0.j , 0. +0.25j, -0.25+0.j , -0. -0.25j], > [ 0.25+0.j , -0.25-0.j , 0.25+0.j , -0.25-0.j ], > [ 0.25+0.j , 0. -0.25j, -0.25-0.j , -0. +0.25j]]) > (Pdb) p (np.array([0,1+1j,0,1-1j]) @ create_freq2time(4)).round(3) > array([ 0.5+0.j, -0.5+0.j, -0.5+0.j, 0.5+0.j]) > > first sample: (1+1j)(0.25) + (1-1j)(0.25) = 0.5 > second sample: (1+1j)(0.25j) + (1-1j)(-0.25j) = -0.5 > > so the first sample is just the real component > then again the second sample is just the complex component > it really is two waves, rising at different times, offset by 90 degrees, > or such > > (Pdb) p (np.array([0,0.5+1j,0,0.5-1j]) @ create_freq2time(4)).round(3) > array([ 0.25+0.j, -0.5 +0.j, -0.25+0.j, 0.5 +0.j]) > > One could think of it as outputting the data in pairs. > It outputs a real component, then a complex component, both in the real > domain. > Because one is offset by 90 degrees, this can provide for the > construction of waves smoothly. > > It may work for the square wave. > > I guess I'll try it. > > 1600 > > I made a complex square wave. Basically the real and imaginary parts > are juts off by 1/4 . > The forward matrix it produces has an inverse, and the pseudoinverse > passes np.allclose() with it. > The assertion still doesn't pass, but again it should now be a closed > system. > > 1603 I'm looking a little at the real-domain matrix produced for the > square wave, and I'm not yet sure about it. > > (Pdb) list > 174 forward_mat = np.linalg.pinv(inverse_mat) > 175 if not is_complex: > 176 # todo: remove test data > 177 time_data = np.random.random(inverse_mat.shape[1]) > 178 freq_data = time_data @ forward_mat > 179 -> forward_mat = np.concatenate([ > 180 forward_mat[:,:tail_idx], > 181 forward_mat[:,tail_idx:neg_start_idx].conj() > 182 ], axis=1) > 183 return forward_mat > 184 > (Pdb) normal_forward_mat = np.linalg.pinv(create_freq2time(time_count, > freqs)) > (Pdb) p normal_forward_mat[6].round(3) > array([ 1. +0.j , -0.707-0.707j, -0. +1.j , 0.707-0.707j, > -1. -0.j , 0.707+0.707j, -0. -1.j , -0.707+0.707j, > 1. -0.j , -0.707-0.707j, -0. +1.j , 0.707-0.707j, > -1. -0.j , 0.707+0.707j, 0. -1.j , -0.707+0.707j]) > (Pdb) p forward_mat[6].round(3) > array([-0.5+0.5j, 0.5+0.5j, -0.5-0.5j, -0.5+0.5j, 0.5-0.5j, -0.5-0.5j, > 0.5+0.5j, 0.5-0.5j, -0.5+0.5j, 0.5+0.5j, -0.5-0.5j, -0.5+0.5j, > 0.5-0.5j, -0.5-0.5j, 0.5+0.5j, 0.5-0.5j]) > > In the normal dft matrix, the negative frequencies that occupy the > second half, are the reverse-order complex conjugates of the positive > frequencies that occupy the first half. > In the forward_mat here, where the the square wave is being used, this > complex conjugate situation does not hold. It's 1609. > > Basically, the even-numbered indices are conjugates, whereas the odds > are opposites. > > It might be possible this could relate to the evaluation of the square > wave at its discontinuous points. > > With real frequencies, the implication is that there are never > frequencies equal to 0.125, for example. Looking a little further I'm > not immediately discerning a pattern. > > 1640 > > having trouble developing behaviors and energy and stuff around this next > step. > > i'm looking at inverse_mat and it seems to have a similar issue. > > i'm thinking that the real component of the waveform is not an even > function, and that that is the issue here. > > trying out numbers, it kind of looks like the wavelet is getting > indexed in a way that is rounding negative, rather than toward zero. > that's something i can look into! > > this is what I have: > > SINE = lambda x: np.sin(2 * np.pi * x) > SQUARE = lambda x: np.floor(x * 2) * 2 - 1 > > def complex_wavelet(wavelet, x): > return wavelet((x + 0.25) % 1) + wavelet(x % 1) * 1j > > and I'm getting this: > >>> complex_wavelet(SQUARE, -.25) > (-1+1j) > >>> complex_wavelet(SQUARE, .25) > (1-1j) > > the real component should have the same sign for correct behavior. > > other than the cutoff point, it is even: > >>> complex_wavelet(SQUARE, .24) > (-1-1j) > >>> complex_wavelet(SQUARE, -.24) > (-1+1j) > >>> complex_wavelet(SQUARE, .26) > (1-1j) > >>> complex_wavelet(SQUARE, -.26) > (1+1j) > > >>> SINE(0) > 0.0 > >>> SINE(0.5) > 1.2246467991473532e-16 > >>> SQUARE(0) > -1.0 > >>> SQUARE(0.5) > 1.0 > > The sine function has 0 and 1/2 equal, whereas the square function > does not. If the square function had 1.0 | x==0 or 1.0 | x > 0.5, it > would work, but instead it has 1.0 | x >= 0.5 . > > The difference stems from floor(x * 2). With the floor function, lower > values are included in the range, and upper values are not. > > I wonder if it would be appropriate to offset things by 0.125 simply > to make the behavior look even when sampled at the points : but this > wouldn't work for denser sampling, of course, which I imagine is > needed. > > 1703 > I changed SQUARE to (x > 0.5) * 2 - 1, which kinda works because True > is treated like 1 and False treated like 0. Assertion still failing. > > Note: if an even function is required for a wavelet to work, it would > make sense to define them as even functions. > > 2036 > I ended up doing other things. The matrix did look better with the > change. I would like to look at it more. > --0000000000008b04eb05eda124c0 Content-Type: text/html; charset="UTF-8" Content-Transfer-Encoding: quoted-printable
Thanks

On Wed, Nov 16, 2022, 5:38 PM Undescribed Horrific = Abuse, One Victim & Survivor of Many <gmkarl@gmail.com> wrote:
according to numpy my square wave matrix is singular.

something for me to think about!

i'm guessing a big issue is that my wavelet function doesn't have a=
way to shift phase.

i don't really know much about wavelets; it's a word i remember fro= m
being a teenager, learning about these things in the resources i knew
how to find.

i don't know if it's the cause, but my wavelet will need a way to h= ave phase.

i could interpret the complex argument in terms of angle and
magnitude, and simply phase shift the output. this seems like it would
work fine, at first. but i'm not sure if it would survive the whole
process, with no complex output.

the trick with the sinusoids is that in frequency space, the phase is
held as an angle in the complex plane.
when the freq2time matrix is created, where does the complex output
come from, and what meaning does it hold?
it has only real-domain frequencies, and yet produces a matrix that
converts from complex frequency.

it takes the frequencies, and scales them by the offsets, and turns
that into time parameters
it passes the time parameters to the sinusoids.
this produces a matrix that can process complex frequency data, and
convert it to time data.
each frequency is a magnitude and a phase.

i can make a function that takes complex frequency data
but the frequencies that are passed in are not complex: they are
negative and positive.
where the negative is the complex conjugate i.e. the angle iand hence
phase is treated as negative.

there are various things i could try but i'm trying to figure out
what's going on in general.

exp(2i pi x) produces a complex number rotated with an angle x

how does this produce real-domain data? if i pass in a single
frequency with a 0 angle, what does it do?

i tried this:
(Pdb) p np.array([0,1,0,1]) @ create_freq2time(4)
array([ 5.00000000e-01+0.j,=C2=A0 3.06161700e-17+0.j, -5.00000000e-01+0.j,<= br> =C2=A0 =C2=A0 =C2=A0 =C2=A0-9.18485099e-17+0.j])

so how does that work?

(Pdb) p create_freq2time(4).round(2)
array([[ 0.25+0.j=C2=A0 ,=C2=A0 0.25+0.j=C2=A0 ,=C2=A0 0.25+0.j=C2=A0 ,=C2= =A0 0.25+0.j=C2=A0 ],
=C2=A0 =C2=A0 =C2=A0 =C2=A0[ 0.25+0.j=C2=A0 ,=C2=A0 0.=C2=A0 +0.25j, -0.25+= 0.j=C2=A0 , -0.=C2=A0 -0.25j],
=C2=A0 =C2=A0 =C2=A0 =C2=A0[ 0.25+0.j=C2=A0 , -0.25-0.j=C2=A0 ,=C2=A0 0.25+= 0.j=C2=A0 , -0.25-0.j=C2=A0 ],
=C2=A0 =C2=A0 =C2=A0 =C2=A0[ 0.25+0.j=C2=A0 ,=C2=A0 0.=C2=A0 -0.25j, -0.25-= 0.j=C2=A0 , -0.=C2=A0 +0.25j]])

columns are freq, rows are samps
The first sample gets 0.25 + 0.25 =3D 0.5
The second sample is the only one with complex domain stuff, and its
0.25 components cancel each other.
The third has -0.25 at the two indices.
The fourth cancels again.

I'm going to paste it again.
array([[ 0.25+0.j=C2=A0 ,=C2=A0 0.25+0.j=C2=A0 ,=C2=A0 0.25+0.j=C2=A0 ,=C2= =A0 0.25+0.j=C2=A0 ],
=C2=A0 =C2=A0 =C2=A0 =C2=A0[ 0.25+0.j=C2=A0 ,=C2=A0 0.=C2=A0 +0.25j, -0.25+= 0.j=C2=A0 , -0.=C2=A0 -0.25j],
=C2=A0 =C2=A0 =C2=A0 =C2=A0[ 0.25+0.j=C2=A0 , -0.25-0.j=C2=A0 ,=C2=A0 0.25+= 0.j=C2=A0 , -0.25-0.j=C2=A0 ],
=C2=A0 =C2=A0 =C2=A0 =C2=A0[ 0.25+0.j=C2=A0 ,=C2=A0 0.=C2=A0 -0.25j, -0.25-= 0.j=C2=A0 , -0.=C2=A0 +0.25j]])

It's 4 complex sinusoids, but they oppose each other in the complex
domain. Because a real-valued signal has both negative and complex
frequencies equal, and because the complex component of the wavelet
function is odd, the two cancel.

That would work fine for phaseless square wave data. You'd provide an even function square wave for the real component, and an odd function
square wave for the imaginary component.

What about phase offset?

(Pdb) p (np.array([0,1+1j,0,1+1j]) @ create_freq2time(4)).round(3)
array([ 0.5+0.5j,=C2=A0 0. +0.j , -0.5-0.5j, -0. -0.j ])
When I specify complex numbers for the frequencies, it actually
produces a wave with the same phase, that has complex value, not a
phased wave !

I thought the angle of the frequency was the phase, but it isn't?

(Pdb) p np.fft.ifft(np.array([0,1+1j,0,1+1j])).round(3)
array([ 0.5+0.5j,=C2=A0 0. +0.j , -0.5-0.5j,=C2=A0 0. +0.j ])

That appears to be so.

That doesn't seem very useful to me, it seems it would be more useful if it were.

Ohhhh I need to use the complex conjugate!

(Pdb) p (np.array([0,1+1j,0,1-1j]) @ create_freq2time(4)).round(3)
array([ 0.5+0.j, -0.5+0.j, -0.5+0.j,=C2=A0 0.5+0.j])

There we go. I offset it by 45 degrees?

(Pdb) p (np.array([0,1,0,1]) @ create_freq2time(4)).round(3)
array([ 0.5+0.j,=C2=A0 0. +0.j, -0.5+0.j, -0. +0.j])

I'm guessing the peaks for 45 degrees were between the samples. 90
might be clearer.

Yeah here's 90 degrees offset:
(Pdb) p (np.array([0,1j,0,-1j]) @ create_freq2time(4)).round(3)
array([ 0. +0.j, -0.5+0.j, -0. +0.j,=C2=A0 0.5+0.j])

So how does that happen?
(Pdb) p create_freq2time(4).round(3)
array([[ 0.25+0.j=C2=A0 ,=C2=A0 0.25+0.j=C2=A0 ,=C2=A0 0.25+0.j=C2=A0 ,=C2= =A0 0.25+0.j=C2=A0 ],
=C2=A0 =C2=A0 =C2=A0 =C2=A0[ 0.25+0.j=C2=A0 ,=C2=A0 0.=C2=A0 +0.25j, -0.25+= 0.j=C2=A0 , -0.=C2=A0 -0.25j],
=C2=A0 =C2=A0 =C2=A0 =C2=A0[ 0.25+0.j=C2=A0 , -0.25-0.j=C2=A0 ,=C2=A0 0.25+= 0.j=C2=A0 , -0.25-0.j=C2=A0 ],
=C2=A0 =C2=A0 =C2=A0 =C2=A0[ 0.25+0.j=C2=A0 ,=C2=A0 0.=C2=A0 -0.25j, -0.25-= 0.j=C2=A0 , -0.=C2=A0 +0.25j]])

Passing (0,1j,0,-1j) ...
The first two frequencies have opposing components so they cancel.
That would work with a 90 degree square wave.
In the second .. it's 1j and -1j. the j's multiply to -1, and we ge= t
-.25 and -.25, which sum to 0.5 .

the 90 degree case would work with square waves. but why does it work
for sinusoids?
cos(x) + sin(x)j =3D exp(2j pi x) is applied, not to the input data x,
but rather to the frequency.
then when the input data comes in, it is multiplied against that result. so if it's real, the sinusoid components cancel and the cosine is
extracted. this then produces a real cosine wave.
if it's imaginary and self-opposing, the cosines cancel from the
self-opposingness, whereas the sines amplify, producing a wave that is
90 degrees off.

how would a 45 degree wave be produced? what is that?
it seems it would be a sum of the 0 degree and 90 degree waves, not sure.
i looked at trigonometric identities and i found a relation that looked com= plex.
let's see how it goes

(Pdb) p create_freq2time(4).round(3)
array([[ 0.25+0.j=C2=A0 ,=C2=A0 0.25+0.j=C2=A0 ,=C2=A0 0.25+0.j=C2=A0 ,=C2= =A0 0.25+0.j=C2=A0 ],
=C2=A0 =C2=A0 =C2=A0 =C2=A0[ 0.25+0.j=C2=A0 ,=C2=A0 0.=C2=A0 +0.25j, -0.25+= 0.j=C2=A0 , -0.=C2=A0 -0.25j],
=C2=A0 =C2=A0 =C2=A0 =C2=A0[ 0.25+0.j=C2=A0 , -0.25-0.j=C2=A0 ,=C2=A0 0.25+= 0.j=C2=A0 , -0.25-0.j=C2=A0 ],
=C2=A0 =C2=A0 =C2=A0 =C2=A0[ 0.25+0.j=C2=A0 ,=C2=A0 0.=C2=A0 -0.25j, -0.25-= 0.j=C2=A0 , -0.=C2=A0 +0.25j]])
(Pdb) p (np.array([0,1+1j,0,1-1j]) @ create_freq2time(4)).round(3)
array([ 0.5+0.j, -0.5+0.j, -0.5+0.j,=C2=A0 0.5+0.j])

first sample: (1+1j)(0.25) + (1-1j)(0.25) =3D 0.5
second sample: (1+1j)(0.25j) + (1-1j)(-0.25j) =3D -0.5

so the first sample is just the real component
then again the second sample is just the complex component
it really is two waves, rising at different times, offset by 90 degrees, or= such

(Pdb) p (np.array([0,0.5+1j,0,0.5-1j]) @ create_freq2time(4)).round(3)
array([ 0.25+0.j, -0.5 +0.j, -0.25+0.j,=C2=A0 0.5 +0.j])

One could think of it as outputting the data in pairs.
It outputs a real component, then a complex component, both in the real dom= ain.
Because one is offset by 90 degrees, this can provide for the
construction of waves smoothly.

It may work for the square wave.

I guess I'll try it.

1600

I made a complex square wave. Basically the real and imaginary parts
are juts off by 1/4 .
The forward matrix it produces has an inverse, and the pseudoinverse
passes np.allclose() with it.
The assertion still doesn't pass, but again it should now be a closed s= ystem.

1603 I'm looking a little at the real-domain matrix produced for the square wave, and I'm not yet sure about it.

(Pdb) list
174=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0forward_mat =3D np.linalg.pinv(inverse= _mat)
175=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0if not is_complex:
176=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0# todo: remove test data=
177=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0time_data =3D np.random.= random(inverse_mat.shape[1])
178=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0freq_data =3D time_data = @ forward_mat
179=C2=A0 ->=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0forward_mat =3D np.concate= nate([
180=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0forward_ma= t[:,:tail_idx],
181=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0forward_ma= t[:,tail_idx:neg_start_idx].conj()
182=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0], axis=3D1)
183=C2=A0 =C2=A0 =C2=A0 =C2=A0 =C2=A0return forward_mat
184
(Pdb) normal_forward_mat =3D np.linalg.pinv(create_freq2time(time_count, fr= eqs))
(Pdb) p normal_forward_mat[6].round(3)
array([ 1.=C2=A0 =C2=A0+0.j=C2=A0 =C2=A0, -0.707-0.707j, -0.=C2=A0 =C2=A0+1= .j=C2=A0 =C2=A0,=C2=A0 0.707-0.707j,
=C2=A0 =C2=A0 =C2=A0 =C2=A0-1.=C2=A0 =C2=A0-0.j=C2=A0 =C2=A0,=C2=A0 0.707+0= .707j, -0.=C2=A0 =C2=A0-1.j=C2=A0 =C2=A0, -0.707+0.707j,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 1.=C2=A0 =C2=A0-0.j=C2=A0 =C2=A0, -0.707-0.707j= , -0.=C2=A0 =C2=A0+1.j=C2=A0 =C2=A0,=C2=A0 0.707-0.707j,
=C2=A0 =C2=A0 =C2=A0 =C2=A0-1.=C2=A0 =C2=A0-0.j=C2=A0 =C2=A0,=C2=A0 0.707+0= .707j,=C2=A0 0.=C2=A0 =C2=A0-1.j=C2=A0 =C2=A0, -0.707+0.707j])
(Pdb) p forward_mat[6].round(3)
array([-0.5+0.5j,=C2=A0 0.5+0.5j, -0.5-0.5j, -0.5+0.5j,=C2=A0 0.5-0.5j, -0.= 5-0.5j,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 0.5+0.5j,=C2=A0 0.5-0.5j, -0.5+0.5j,=C2=A0 0.5+= 0.5j, -0.5-0.5j, -0.5+0.5j,
=C2=A0 =C2=A0 =C2=A0 =C2=A0 0.5-0.5j, -0.5-0.5j,=C2=A0 0.5+0.5j,=C2=A0 0.5-= 0.5j])

In the normal dft matrix, the negative frequencies that occupy the
second half, are the reverse-order complex conjugates of the positive
frequencies that occupy the first half.
In the forward_mat here, where the the square wave is being used, this
complex conjugate situation does not hold. It's 1609.

Basically, the even-numbered indices are conjugates, whereas the odds
are opposites.

It might be possible this could relate to the evaluation of the square
wave at its discontinuous points.

With real frequencies, the implication is that there are never
frequencies equal to 0.125, for example. Looking a little further I'm not immediately discerning a pattern.

1640

having trouble developing behaviors and energy and stuff around this next s= tep.

i'm looking at inverse_mat and it seems to have a similar issue.

i'm thinking that the real component of the waveform is not an even
function, and that that is the issue here.

trying out numbers, it kind of looks like the wavelet is getting
indexed in a way that is rounding negative, rather than toward zero.
that's something i can look into!

this is what I have:

SINE =3D lambda x: np.sin(2 * np.pi * x)
SQUARE =3D lambda x: np.floor(x * 2) * 2 - 1

def complex_wavelet(wavelet, x):
=C2=A0 =C2=A0 return wavelet((x + 0.25) % 1) + wavelet(x % 1) * 1j

and I'm getting this:
>>> complex_wavelet(SQUARE, -.25)
(-1+1j)
>>> complex_wavelet(SQUARE, .25)
(1-1j)

the real component should have the same sign for correct behavior.

other than the cutoff point, it is even:
>>> complex_wavelet(SQUARE, .24)
(-1-1j)
>>> complex_wavelet(SQUARE, -.24)
(-1+1j)
>>> complex_wavelet(SQUARE, .26)
(1-1j)
>>> complex_wavelet(SQUARE, -.26)
(1+1j)

>>> SINE(0)
0.0
>>> SINE(0.5)
1.2246467991473532e-16
>>> SQUARE(0)
-1.0
>>> SQUARE(0.5)
1.0

The sine function has 0 and 1/2 equal, whereas the square function
does not. If the square function had 1.0 | x=3D=3D0 or 1.0 | x > 0.5, it=
would work, but instead it has 1.0 | x >=3D 0.5 .

The difference stems from floor(x * 2). With the floor function, lower
values are included in the range, and upper values are not.

I wonder if it would be appropriate to offset things by 0.125 simply
to make the behavior look even when sampled at the points : but this
wouldn't work for denser sampling, of course, which I imagine is
needed.

1703
I changed SQUARE to (x > 0.5) * 2 - 1, which kinda works because True is treated like 1 and False treated like 0. Assertion still failing.

Note: if an even function is required for a wavelet to work, it would
make sense to define them as even functions.

2036
I ended up doing other things. The matrix did look better with the
change. I would like to look at it more.
--0000000000008b04eb05eda124c0--