diff --git a/applications/lofar2/doc/prestudy/station2_sdp_transient_buffer.txt b/applications/lofar2/doc/prestudy/station2_sdp_transient_buffer.txt index 7b11f321ca3c51170c2005b9d4d4002f59c736dd..4f7028dc031bdaa52e648e09a075ebd907349205 100644 --- a/applications/lofar2/doc/prestudy/station2_sdp_transient_buffer.txt +++ b/applications/lofar2/doc/prestudy/station2_sdp_transient_buffer.txt @@ -8,8 +8,9 @@ Detailed design: Transient Buffer (TBuf) function for LIFT project 4) TBuf (Transient Buffer) Design 5) TBuf ICD SC-SDP, SDPTR-SDPFW 6) TBuf ICD STAT/SDP-CEP -7) Transient detection (TDet) Design -8) Planning +7) Crossbar +10) Planning +11) Transient detection (TDet) Design References: @@ -35,7 +36,7 @@ References: - needs ring, because 6 antennas per event are typically not connected to one FPGA -1) DDR4 memory per receiver input +1a) DDR4 memory size per receiver input Bottom up: @@ -62,6 +63,13 @@ Defineer TBuf functie per receiver input: . zodat de TBuf functie makkelijk uitbreidbaar is naar meer inputs en naar meer DDR4 modules. . data capture en uitlezen van een receiver input onafhankelijk kan van de andere receiver inputs +1b) DDR4 memory IO rate and data width +The DDR4 IP runs at 800 MHz (minimum 625 MHz) so at DDR this yields 1600 MTps of DQ = 64 bit each. +The DDR4 IP user rate is a quarter so 200 MHz. +The factor is rsl = 1600 / 200 = 8, so therefore the controller data width is 8 * 64 = 512 bits. +Using 800 MTps to have rsl = 4 and 256 controller data width is not possible, because the minimum +DDR4 frequency is 625 MHz and because the user rate is fixed at a quarter. + 2) Meeting EK-BH 24 okt 2022 [2] Design decision 16GByte DDR4 na L2SDP-854, 850 @@ -83,6 +91,7 @@ Design decision 16GByte DDR4 na L2SDP-854, 850 - Buffer lengte versus nof antennes - Self trigger +The CP FPGA_beamlet_output_nof_beamlets_RW is not supported in SDPTR and SDPFW yet. I was n 3) TBB (Transient Buffer Board) LOFAR1 - From 2.3 in [4] @@ -96,9 +105,35 @@ Design decision 16GByte DDR4 na L2SDP-854, 850 - buffer raw data, no need to buffer subbands -- choose fixe 14b data, so not e.g. 8 Msbits for lighting and 8 Lsbits for +- choose fixed 14b data, so not e.g. 8 Msbits for lighting and 8 Lsbits for cosmic ray. Always using full W_adc = 14b makes design and usage more clear. +- choose to store data per antenna input, so dual polarion because: + . science always use both polarizations + . otherwise CEP will combine the two polarizations + . beamlets are also dual polarization + +- choose to record all antenna inputs per FPGA in parallel, instead of recording + control per antenna input: + . save FPGA logic and RAM resources by not having to implement a A_pn = 6 to 1 + multiplexer with 6 * 512b --> 512b data widths + . allows record control per FPGA, so simpler CP and simpler memory access + +- choose to not provide a peek/pook MM access interface to DDR4 + . Avoid implement a 2 to 1 multiplexer + . Logic MP are are sufficient, no need to MM read RSN in DDR4 + . Dumping data is sufficient to read DDR4 + +- choose to store RSN + samples + CRC in memory: + . CRC covers BSN + samples + . RSN can also be kept in logic and then derive other RSN from page index in memory, + but having RSN also in memory helps to make sure that the data is indeed of that + timestamp + . choose to use RSN and CRC per antenna input, so not one RSN for all + . pack antenna input from 28b to 64b to be able to prepend 64b RSN and append 64b CRC + per antenna input + + - Station --> CEP --> Data Writer . SDP output UDP directly to CEP or to LCU so that LCU can pass it on via TCP, to recover from data loss @@ -108,14 +143,14 @@ Design decision 16GByte DDR4 na L2SDP-854, 850 - treat all signal inputs independently (even though X and Y are always needed together) - timing - . Use sample sequence number (SSN) or mem_bsn: - - SSN increments by nof_samples_per_page = 8176 + . Use sample sequence number (RSN) or mem_bsn: + - RSN increments by nof_samples_per_page = 8176 - mem_bsn increments by 1 per page, so per block of nof_samples_per_page = 8176. - . SSN counts sample periods (5 ns) since t_epoch = 1970, can fit + . RSN counts sample periods (5 ns) since t_epoch = 1970, can fit 2**64 / (365.25 * 24 * 3600 / 5e-9) > 2922 years . TBuf uses sop and eop to mark nof_samples_per_page = 8176 . TBuf does not need sync ? - . Start SSN or mem BSN at same time as SDP BSN by FPGA_processing_enable_RW. + . Start RSN or mem BSN at same time as SDP BSN by FPGA_processing_enable_RW. - CP per signal input buffer . flexible start and end address (so flexible buffer time per signal input) @@ -127,46 +162,22 @@ Design decision 16GByte DDR4 na L2SDP-854, 850 - Block diagram: - per si: pack 14b to 64b --> add mem hdr (= ssn or bsn) --> add crc --> pack 64b to 256b + per si: pack 14b to 64b --> add mem hdr (= rsn or bsn) --> add crc --> pack 64b to 256b mux 12 si to 1 --> mux with + 1 MM --> write to DDR4 read from DDR4 --> demux to . 1 MM - . 1 retrieve --> unpack 256b to 64b --> check CRC --> add output hdr - --> pass on via ring --> - --> dump via 10GbE + . 1 dump --> unpack 256b to 64b --> check CRC --> add output hdr + --> pass on via ring --> + --> dump via 10GbE - support MP on buffer state . signal input index . frozen, buffering, reading . start address (time), end address (time) -- unb2c_test_ddr_16G resource usage - . git/hdl/boards/uniboard2c/designs/unb2c_test/revisions/unb2c_test_ddr_16G/unb2c_test_ddr_16G_resource_usage.jpg - . DDR4 max_burst_size = 64 --> 64 * 256b words = 64 * 32B = 2 kB - . M20k = 20 kbit = 2.5 kB - . per module: - wr_fifo 13 M20K - tech_ddr 9 M20K - rd_fifo 4 M20K - diag db 0 M20K - diag bg 0 M20K - --> Total 26 M20K/DDR4 module - . board common: - MMM : 69 M20K voor Nios memory - ctrl: 42 M20K voor MMAP ROM en 1GbE - -- Provide direct MM access interface to DDR4 - . New access multiplexer component (crossbar) to interface with io_ddr with: - . write 12 signal input streams for TBuf recording + 1 MM write stream - . read 1 stream for TBuf readout + 1 MM read stream - . Write multiplexer for 12 + 1 = 13 inputs will take ~100 M20K, - because it needs to multiplex and FIFO streams of 256 bit each and - 256 bit requires 256 /40 = 7 M20K in parallel, so 13 * 7 = 91 M20K. - . One M20K = 20b * 1024 words = 40b * 512 words, 512 words of 256b = - 16 kByte, so FIFO can fit (almost) two 8 kB payloads, which seems - sufficient. + - Use 1 DDR4 module / FPGA . Because 16GB is enough for T_tbuf = 3.3 s @@ -190,10 +201,10 @@ Design decision 16GByte DDR4 na L2SDP-854, 850 - packetize voor buffer write of na buffer read? --> voor . packtetize at 64b or 256b ? . 16b -> 64b packetize --> 64b --> 256b store - . ddr page packet format: SSN + packed data + CRC + . ddr page packet format: RSN + packed data + CRC - 8 KByte page to have integer number of pages (= slots) in 16G memory, so that DDR4-I can wrap without a gap or extend to DDR-II without a gap. - - SSN = 64b = 8B + - RSN = 64b = 8B - 14b packed data . nof_samples_per_page = 8K - 8 - 8 = 8192 - 16 = 8176 B / 14b = 4672 . 4672 * 5 ns = 23.36 us per page, so ~42.8 pages / ms @@ -209,8 +220,8 @@ Design decision 16GByte DDR4 na L2SDP-854, 850 . send packed 14b data - 12 input multiplexer with 12 x 256b in and 256b out to write 256b words @ 200 MHz -- use SSN as timestamp, SSN = BSN * N_fft, so can be derived from bsn_source BSN, - or do we need a dp_ssn_source.vhd? +- use RSN as timestamp, RSN = BSN * N_fft, so can be derived from bsn_source BSN, + or do we need a dp_rsn_source.vhd? - store and send 14b packed data . so do not use 16b (with 2b sign extension), to optimize for memory usage and @@ -233,7 +244,7 @@ Design decision 16GByte DDR4 na L2SDP-854, 850 circular buffer per si, wrap after nof_pages keep track of nof_recorded pages, when > nof pages then circular buffer is full and carries only fresh data - keep track of ssn + page index of last recorded page + keep track of rsn + page index of last recorded page @@ -251,43 +262,116 @@ Design decision 16GByte DDR4 na L2SDP-854, 850 * In LOFAR1 bepaald LCU welke si uitgelezen moet worden richting CEP. De TBB uP zorgt dan dat de nof pages verstuurd worden. - . FPGA_tbuf_record_RW [pn][si] # True = start/continue, False = stop/freeze recording immediately - . FPGA_tbuf_record_stop_timed_RW [pn][si] # Stop recording at specified SSN time, not needed for raw data ??? + . FPGA_tbuf_record_enable_RW[pn] # True = start/continue, False = stop/freeze recording immediately - . FPGA_tbuf_retrieve_inter_packet_gap_RW --> wait time between packets send to CEP in FPGA_tbuf_sample_period_R units - FPGA_tbuf_retrieve_timestamp_RW [pn][si] - FPGA_tbuf_retrieve_nof_pre_pages_RW [pn][si] - FPGA_tbuf_retrieve_nof_post_pages_RW [pn][si] - . FPGA_tbuf_retrieve_enable_RW - - total nof pages = nof_pre_pages + 1 (pointed by ssn) + nof_post_pages + . FPGA_tbuf_record_all_antenna_RW[pn] # True = record all antenna inputs, False = record only half of the antenna inputs, the once that have even index. + + + + . FPGA_tbuf_dump_inter_packet_gap_RW --> wait time between packets send to CEP in FPGA_tbuf_sample_period_R units + FPGA_tbuf_dump_timestamp_range_RW[pn][rsn] --> [0] = from rsn, [1] to rsn, SDPTR translates between float timestamp and int RSN + FPGA_tbuf_dump_enable_RW[pn][ai] --> boolean, SC takes care that only one global ai is TRUE + --> SC / dump tool loops global ai via FPGA_tbuf_dump_enable_RW and + FPGA_tbuf_dumping_R + --> SC / dump tool needs to take care that only one global ai is selected at + a time to avoid 10GbE link overload + --> use FPGA_tbuf_dumping_R to see when dump is busy or done, hoe als het heel snel klaar is ??? + + FPGA_tbuf_clear_total_counts_RW[pn] --> clear all TBuf total counts in pn + + Not: FPGA_tbuf_dump_enable_RW[pn] -- antenna index + Not: TR_tbuf_dump_enable_RW -- antenna index . FPGA_tbuf_output_hdr_eth_destination_mac_RW . FPGA_tbuf_output_hdr_ip_destination_address_RW . FPGA_tbuf_output_hdr_udp_destination_port_RW - . FPGA_tbuf_output_enable_RW - - . FPGA_tbuf_memory_address_RW[pn] - . FPGA_tbuf_memory_read_nof_words_RW[pn] --> read nof words (256b) from FPGA_tbuf_memory_address_RW - FPGA_tbuf_memory_read_data_R[pn] --> read data results from FPGA_tbuf_memory_read_nof_words_RW - . FPGA_tbuf_memory_write_data_words_RW[pn] --> write data words (256b) to FPGA_tbuf_memory_address_RW + . FPGA_tbuf_output_enable_RW[pn] - Monitor Points (MP): - . FPGA_tbuf_ddr4_present_R --> True is ddr4 memory is availabe, False is ddr4 calibration failed/ ddr4 not present - . FPGA_tbuf_total_nof_pages_R --> 16GB / 8kB = 2M - . FPGA_tbuf_page_size_R --> 8 kByte - . FPGA_tbuf_nof_samples_per_page_R --> 4672 # = (8kB - 16) * 8b / 14b - . FPGA_tbuf_nof_bits_per-sample_R --> 14 b - . FPGA_tbuf_sample_period_R --> 5 ns - - . FPGA_tbuf_page_period_R # = FPGA_tbuf_sample_period_R * 23.36 us - . FPGA_tbuf_recording_R [pn][si] - . FPGA_tbuf_retrieving_R [pn][si] --> boolean of report remaining nof pages + * Raw data: + . FPGA_tbuf_nof_bits_per_sample_R --> 14 b = W_adc + . FPGA_tbuf_sample_period_R --> 5 ns + + * RSN monitor (dp_bsn_monitor) + . sync interval 1 s + . block size = 2000 + + * Memory (DDR4): + + With streaming use of io_ddr then the dvr_wr_flush_en = '0' (so ctlr_wr_flush_en = 0 in MP), because + the sequencer takes of writing and reading blocks like in reorder_transpose.vhd. Use MP to check FIFOs. + + Support onl MP for DDR4 module in slot I. + + REG_IO_DDR_MB_I in io_ddr: + [3] RESIZE_UVEC(rd_fifo_full_reg & wr_fifo_full_reg, c_mem_reg_dat_w) # gets cleared upon read + [2] RESIZE_UVEC(ctlr_wr_fifo_usedw, c_mem_reg_dat_w) & + [1] RESIZE_UVEC(ctlr_rd_fifo_usedw, c_mem_reg_dat_w) & + [0] RESIZE_UVEC(ctlr_tech_mosi.wr & ctlr_tech_miso.rdval & ctlr_tech_miso.cal_fail & ctlr_tech_miso.cal_ok & + ctlr_rst_out_i & ctlr_wr_flush_en & ctlr_tech_miso.waitrequest_n & ctlr_tech_miso.done, c_mem_reg_dat_w); + + Use ddr_ for DDR4 in slot I, in case in future DDR4 slot II is also used, then use e.g. ddr_ii for that module. + . FPGA_ddr_calibrated_R = cal_ok && !cal_fail --> True is ddr4 memory is available, False is ddr4 calibration failed or ddr4 not present + . FPGA_ddr_wr_fifo_full_R = wr_fifo_full_reg, True if write FIFO to ddr4 memory got full since last MP read, else False. Should remain False. + . FPGA_ddr_rd_fifo_full_R = rd_fifo_full_reg, True if read FIFO from ddr4 memory got full since last MP read, else False. Should remain False. + . FPGA_ddr_wr_fifo_usedw_R = ctlr_wr_fifo_usedw, current fill level of write FIFO to ddr4 memory in number of 512b words, should be 0 when not recording + . FPGA_ddr_rd_fifo_usedw_R = ctlr_rd_fifo_usedw, current fill level of read FIFO from ddr4 memory in number of 512b words, should be 0 when not dumping + + No need for CP of: + - dvr_wr_flush_en, because io_ddr and DDR4 should work without need to flush when they operate OK. + No need to MP for: + - ctlr_tech_mosi.wr, because controlled by streaming sequencer + - ctlr_rst_out_i, because also used as reset for io_ddr itself + - ctlr_tech_miso.waitrequest_n ? could show hanging io_ddr_driver + - ctlr_tech_miso.done ? could show hanging io_ddr_driver + + REG_TBUF_RAW new in node_sdp_transient_buffer_raw.vhd + . nof_bytes_in_ddr_R = 16 * 1024**3 (16GiB) + . nof_bytes_per_ddr_word_R = 64 Bytes (= 512b) + . nof_ddr_words_per_page_R = 657 or 329, depends on FPGA_tbuf_record_all_antenna_RW + ==> SDPTR: ddr_total_nof_pages = floor(nof_bytes_in_ddr_R / (nof_ddr_words_per_page_R * nof_bytes_per_ddr_word_R) + + . last_recorded_page_index_R --> last page that was recorded in ddr, restarts at 0 when recording starts, increments during recording + . last_recorded_rsn_R --> RSN of block at last_recorded_page_index + . first_recorded_page_index_R --> restarts at 0 when recording starts, equals last_recorded_page_index + 1 when recording has + filled the circular buffer once and continues recording + . first_recorded_rsn_R --> RSN of block at first_recorded_page_index + + SDPTR based on: + . FPGA_tbuf_dump_timestamp_range_RW[pn][rsn] (from_rsn, to_rsn) + . FPGA_tbuf_dump_enable_RW[pn][ai] + sets: + . dump_first_page_W = page index of from_rsn + . dump_nof_pages_W = nof pages in range from_rsn, to_rsn + . dump_antenna_input_W = active ai in FPGA_tbuf_dump_enable_RW + . dump_enable <-- enable to dump ai, + + * Recording: + . FPGA_tbuf_recording_R[pn] --> pn is recording, all ai or half of ai (dependent on FPGA_tbuf_record_all_antenna_RW) + + . FPGA_tbuf_last_timestamp_R[pn] = last_recorded_rsn * FPGA_tbuf_sample_period_R + . FPGA_tbuf_first_timestamp_R[pn] = first_recorded_rsn * FPGA_tbuf_sample_period_R + . FPGA_tbuf_recorded_time_R[pn] = FPGA_tbuf_last_timestamp_R - FPGA_tbuf_first_timestamp_R + + + * Dumping: + . FPGA_tbuf_dumping_R[pn] --> boolean or report remaining nof packets to predict when it will be done + + . FPGA_tbuf_total_nof_memory_errors_R[pn][ai] --> count per ai, because each ai has own CRC + FPGA_tbuf_total_nof_dumped_packets_R[pn][ai] --> count per ai Maybe: - . FPGA_tbuf_last_page [pn][si] --> index of last recorded page - . FPGA_tbuf_last_ssn [pn][si] --> ssn of last recorded page - . FPGA_tbuf_nof_recorded_pages[pn][si] --> number of fresh recorded pages <= alloc nof_pages + . Not: FPGA_tbuf_last_page [pn][si] --> index of last recorded page + . Not: FPGA_tbuf_nof_recorded_pages[pn][si] --> number of fresh recorded pages <= alloc nof_pages + + + Not (no peek and poke): + . FPGA_tbuf_memory_address_RW[pn] + . FPGA_tbuf_memory_read_nof_words_RW[pn] --> read nof words (512b) from FPGA_tbuf_memory_address_RW + FPGA_tbuf_memory_read_data_R[pn] --> read data results from FPGA_tbuf_memory_read_nof_words_RW + . FPGA_tbuf_memory_write_data_words_RW[pn] --> write data words (512b) to FPGA_tbuf_memory_address_RW + Not: FPGA_tbuf_page_period_R # = FPGA_tbuf_sample_period_R * 23.36 us 6) TBuf ICD STAT/SDP-CEP @@ -300,8 +384,8 @@ Design decision 16GByte DDR4 na L2SDP-854, 850 . 8b rcu_id --> 8b signal_input_index (0-191) . 8b sample_freq in MHz --> 1b f_adc sample period is 5 ns or 6.25 ns (as in beamlet packet) . 32b seqnr --> not needed - . 32b time in seconds --> 64b SSN = Sample Sequence Number - . 32b samplenr in current sec --> 64b SSN = Sample Sequence Number + . 32b time in seconds --> 64b RSN = Sample Sequence Number + . 32b samplenr in current sec --> 64b RSN = Sample Sequence Number 10b bandnr + 22b slicenr --> for spectral data, not needed . 512b bandsel --> for spectral data, not needed . 16b spare @@ -312,29 +396,26 @@ Design decision 16GByte DDR4 na L2SDP-854, 850 - beamlets application header fields (32 bytes = 4 * 64b) - tbuf application header fields (20 bytes + 4 reserved bytes = 24 bytes = 3 * 64b): - . 8b marker + ==> JDM: combine X and Y in one packet, like beamlets + ==> ETH CRC covers network errors, packet will get dropped in case of CRC error + . 8b marker ('t') . 8b version_id - . 16b station_id + - 32b observation_id --> like for beamlets, may be useful for cosmic ray piggy back, not in LOFAR1 + . 16b station_info + - 1b hba_antenna_field (HBA-0, HBA-1) + - 15b station_id . 16b source_info (as in beamlet packet) - - 2b reserved + - 3b reserved - 1b antenna_band_index (LB, HB) - 2b nyquist_zone_index - 1b f_adc --> sample clock rate, period is 5 ns or 6.25 ns - - 1b memory_error --> based on DDR4 read CRC - 4b sample_width --> 14b, where 16b is represented by 0 - 5b gn_index --> purpose fault analysis . 32b reserved - . 8b signal_input_index --> 0..191 + . 8b signal_input_index --> 0..191 ==> antenna_input_index 0..95 . 16b nof_samples_per_packet --> (8kB - 16) / 14b = 4672 (= 1022 words of 64b) --> log2() = 13b - . 24b nof_packets_remaining in current dump (log2(2M pages) = 21b ??? to detect lost packets and progress - . 64b SSN = Sample Sequence Number + . 64b RSN = Sample Sequence Number --> is prefered over a BSN, because RSN can start at any sample, whereas a BSN has to fit start at 1970. -Not needed ???: - - 32b observation_id --> like for beamlets, not needed, also not in LOFAR1 - - 1b udp_error --> based on ETH/IP/UDP CRC error in case LCU does UDP to TCP, - no needed, because CRC error packets will be dropped - - header_crc (covered by eth crc) - - payload_crc (covered by eth crc and by memory_error bit) - headers: 14 + 20 + 8 + 24 = 66 bytes crc: 4 bytes @@ -343,26 +424,31 @@ Not needed ???: --> packet overhead is (66 + 4) / 8246 = 0.85 % -7) Transient detection (TDet) Design +SigMF: -- no self triggering yet for MVP +Tammo Jan 25 nov 2022: -- will use Hilbert transform of real input and > 30MHz BPF - https://nl.mathworks.com/help/signal/ug/single-sideband-modulation-via-the-hilbert-transform.html - For the FIR Hilbert transformer we will use an odd length filter which is - computationally more efficient than an even length filter. Albeit even - length filters enjoy smaller passband errors. The savings in odd length - filters is a result that these filters have several of the coefficients that - are zero. Also, using an odd length filter will require a shift by an - integer time delay, as opposed to a fractional time delay that is required - by an even length filter. For an odd length filter, the magnitude response - of a Hilbert Transformer is zero for w=0 and w=π. For even length filers the - magnitude response doesn't have to be 0 at π, therefore they have increased - bandwidths. So for odd length filters the useful bandwidth is limited to - 0 < w < π. +Hoi Eric, over het opslaan van complex voltage data, dat ik gisteren tijdens de group meeting even noemde: het metadataformaat heet SigMF. . Het is gewoon een json-bestandje dat je naast een databestand met alleen complex voltages opslaat. Een prima viewer hiervoor is inspectrum ( https://github.com/miek/inspectrum ). Als data formaat voor streaming complex voltages gebruiken we difi (een subset van vita49) over ZeroMQ. + + +7) Crossbar + +* It is not possible to combine 3 * 12 * 14b = 3 * 168b = 514b into one controller word, + because it must be possible to individually record and stop signal inputs. Therefore + it is not possible to multiplex all signal inputs per controller word. Instead each + controller word should contain only write data from one signal input. +* Each burst of controller word also shoul contain write data from one signal input. The + maximum burst size is 64 (= 2**7 - 1 = 63) controller words 64 * 512b / 8b = 4kB. Actual burst + size can be between 1 and 63. -8) Planning + +* Using burstcount = 1 yields 512b / 14b = 36 * 14b samples + 8b not used per controller word. + Burstcount > 4 is probably needed for sufficient efficiency. + efficiency = n / (n + CAS + command latency) = n / (n + 1.5 + 9), n = burstcount for read + + +10) Planning - ICD STAT-CEP --> tbuf packet format - ICD SC-SDP --> OPC-UA CP and MP @@ -385,3 +471,22 @@ Not needed ???: - Verify TBuf within SDP on HW - Integration effort with SC +11) Transient detection (TDet) Design + +- no self triggering yet for MVP + +- will use Hilbert transform of real input and > 30MHz BPF + https://nl.mathworks.com/help/signal/ug/single-sideband-modulation-via-the-hilbert-transform.html + For the FIR Hilbert transformer we will use an odd length filter which is + computationally more efficient than an even length filter. Albeit even + length filters enjoy smaller passband errors. The savings in odd length + filters is a result that these filters have several of the coefficients that + are zero. Also, using an odd length filter will require a shift by an + integer time delay, as opposed to a fractional time delay that is required + by an even length filter. For an odd length filter, the magnitude response + of a Hilbert Transformer is zero for w=0 and w=π. For even length filers the + magnitude response doesn't have to be 0 at π, therefore they have increased + bandwidths. So for odd length filters the useful bandwidth is limited to + 0 < w < π. + +